quartz: Remove superfluous pointer casts.
[wine] / dlls / iphlpapi / ipstats.c
1 /* Copyright (C) 2003,2006 Juan Lang
2  * Copyright (C) 2007 TransGaming Technologies Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  * This file implements statistics getting using the /proc filesystem exported
19  * by Linux, and maybe other OSes.
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_ALIAS_H
32 #include <alias.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_SYS_SOCKETVAR_H
38 #include <sys/socketvar.h>
39 #endif
40 #ifdef HAVE_SYS_TIMEOUT_H
41 #include <sys/timeout.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_SYSTM_H
47 #include <netinet/in_systm.h>
48 #endif
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NET_IF_H
53 #include <net/if.h>
54 #endif
55 #ifdef HAVE_NET_IF_DL_H
56 #include <net/if_dl.h>
57 #endif
58 #ifdef HAVE_NET_IF_TYPES_H
59 #include <net/if_types.h>
60 #endif
61 #ifdef HAVE_NET_ROUTE_H
62 #include <net/route.h>
63 #endif
64 #ifdef HAVE_NET_IF_ARP_H
65 #include <net/if_arp.h>
66 #endif
67 #ifdef HAVE_NETINET_IF_ETHER_H
68 #include <netinet/if_ether.h>
69 #endif
70 #ifdef HAVE_NETINET_IF_INARP_H
71 #include <netinet/if_inarp.h>
72 #endif
73 #ifdef HAVE_NETINET_IP_H
74 #include <netinet/ip.h>
75 #endif
76 #ifdef HAVE_NETINET_TCP_H
77 #include <netinet/tcp.h>
78 #endif
79 #ifdef HAVE_NETINET_IP_VAR_H
80 #include <netinet/ip_var.h>
81 #endif
82 #ifdef HAVE_NETINET_TCP_FSM_H
83 #include <netinet/tcp_fsm.h>
84 #endif
85 #ifdef HAVE_NETINET_IN_PCB_H
86 #include <netinet/in_pcb.h>
87 #endif
88 #ifdef HAVE_NETINET_TCP_TIMER_H
89 #include <netinet/tcp_timer.h>
90 #endif
91 #ifdef HAVE_NETINET_TCP_VAR_H
92 #include <netinet/tcp_var.h>
93 #endif
94 #ifdef HAVE_NETINET_IP_ICMP_H
95 #include <netinet/ip_icmp.h>
96 #endif
97 #ifdef HAVE_NETINET_ICMP_VAR_H
98 #include <netinet/icmp_var.h>
99 #endif
100 #ifdef HAVE_NETINET_UDP_H
101 #include <netinet/udp.h>
102 #endif
103 #ifdef HAVE_NETINET_UDP_VAR_H
104 #include <netinet/udp_var.h>
105 #endif
106 #ifdef HAVE_SYS_PROTOSW_H
107 #include <sys/protosw.h>
108 #endif
109 #ifdef HAVE_SYS_SYSCTL_H
110 #include <sys/sysctl.h>
111 #endif
112
113 #ifndef ROUNDUP
114 #define ROUNDUP(a) \
115         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
116 #endif
117 #ifndef ADVANCE
118 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
119 #endif
120
121 #include "windef.h"
122 #include "winbase.h"
123 #include "iprtrmib.h"
124 #include "ifenum.h"
125 #include "ipstats.h"
126
127 #ifndef HAVE_NETINET_TCP_FSM_H
128 #define TCPS_ESTABLISHED  1
129 #define TCPS_SYN_SENT     2
130 #define TCPS_SYN_RECEIVED 3
131 #define TCPS_FIN_WAIT_1   4
132 #define TCPS_FIN_WAIT_2   5
133 #define TCPS_TIME_WAIT    6
134 #define TCPS_CLOSED       7
135 #define TCPS_CLOSE_WAIT   8
136 #define TCPS_LAST_ACK     9
137 #define TCPS_LISTEN      10
138 #define TCPS_CLOSING     11
139 #endif
140
141 #ifndef RTF_MULTICAST
142 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
143 #endif
144
145 #ifndef RTF_LLINFO
146 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
147 #endif
148
149 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
150
151 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
152 {
153 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
154   int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
155 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
156
157   size_t needed;
158   char *buf, *end;
159   struct if_msghdr *ifm;
160   struct if_data ifdata;
161   if (!name || !entry)
162     return ERROR_INVALID_PARAMETER;
163
164   if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
165   {
166       ERR ("failed to get size of iflist\n");
167       return ERROR_NOT_SUPPORTED;
168   }
169   buf = HeapAlloc (GetProcessHeap (), 0, needed);
170   if (!buf) return ERROR_NOT_SUPPORTED;
171   if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
172   {
173       ERR ("failed to get iflist\n");
174       HeapFree (GetProcessHeap (), 0, buf);
175       return ERROR_NOT_SUPPORTED;
176   }
177   else
178       for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
179       {
180           ifm = (struct if_msghdr *) buf;
181           if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
182           {
183               ifdata = ifm->ifm_data;
184               entry->dwMtu = ifdata.ifi_mtu;
185               entry->dwSpeed = ifdata.ifi_baudrate;
186               entry->dwInOctets = ifdata.ifi_ibytes;
187               entry->dwInErrors = ifdata.ifi_ierrors;
188               entry->dwInDiscards = ifdata.ifi_iqdrops;
189               entry->dwInUcastPkts = ifdata.ifi_ipackets;
190               entry->dwInNUcastPkts = ifdata.ifi_imcasts;
191               entry->dwOutOctets = ifdata.ifi_obytes;
192               entry->dwOutUcastPkts = ifdata.ifi_opackets;
193               entry->dwOutErrors = ifdata.ifi_oerrors;
194               HeapFree (GetProcessHeap (), 0, buf);
195               return NO_ERROR;
196           }
197       }
198       HeapFree (GetProcessHeap (), 0, buf);
199       return ERROR_NOT_SUPPORTED;
200 #else
201   /* get interface stats from /proc/net/dev, no error if can't
202      no inUnknownProtos, outNUcastPkts, outQLen */
203   FILE *fp;
204
205   if (!name || !entry)
206     return ERROR_INVALID_PARAMETER;
207   fp = fopen("/proc/net/dev", "r");
208   if (fp) {
209     char buf[512] = { 0 }, *ptr;
210     int nameLen = strlen(name), nameFound = 0;
211
212
213     ptr = fgets(buf, sizeof(buf), fp);
214     while (ptr && !nameFound) {
215       while (*ptr && isspace(*ptr))
216         ptr++;
217       if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
218         nameFound = 1;
219       else
220         ptr = fgets(buf, sizeof(buf), fp);
221     }
222     if (nameFound) {
223       char *endPtr;
224
225       ptr += nameLen + 1;
226       if (ptr && *ptr) {
227         entry->dwInOctets = strtoul(ptr, &endPtr, 10);
228         ptr = endPtr;
229       }
230       if (ptr && *ptr) {
231         entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
232         ptr = endPtr;
233       }
234       if (ptr && *ptr) {
235         entry->dwInErrors = strtoul(ptr, &endPtr, 10);
236         ptr = endPtr;
237       }
238       if (ptr && *ptr) {
239         entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
240         ptr = endPtr;
241       }
242       if (ptr && *ptr) {
243         strtoul(ptr, &endPtr, 10); /* skip */
244         ptr = endPtr;
245       }
246       if (ptr && *ptr) {
247         strtoul(ptr, &endPtr, 10); /* skip */
248         ptr = endPtr;
249       }
250       if (ptr && *ptr) {
251         strtoul(ptr, &endPtr, 10); /* skip */
252         ptr = endPtr;
253       }
254       if (ptr && *ptr) {
255         entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
256         ptr = endPtr;
257       }
258       if (ptr && *ptr) {
259         entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
260         ptr = endPtr;
261       }
262       if (ptr && *ptr) {
263         entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
264         ptr = endPtr;
265       }
266       if (ptr && *ptr) {
267         entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
268         ptr = endPtr;
269       }
270       if (ptr && *ptr) {
271         entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
272         ptr = endPtr;
273       }
274     }
275     fclose(fp);
276   }
277   else
278   {
279      ERR ("unimplemented!\n");
280      return ERROR_NOT_SUPPORTED;
281   }
282
283   return NO_ERROR;
284 #endif
285 }
286
287 DWORD getICMPStats(MIB_ICMP *stats)
288 {
289 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
290   int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
291 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
292   size_t needed;
293   struct icmpstat icmp_stat;
294   int i;
295
296   if (!stats)
297     return ERROR_INVALID_PARAMETER;
298
299   needed = sizeof(icmp_stat);
300   if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
301   {
302       ERR ("failed to get icmpstat\n");
303       return ERROR_NOT_SUPPORTED;
304   }
305
306
307   /*in stats */
308   stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
309   for(i = 0; i <= ICMP_MAXTYPE; i++)
310       stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
311
312   stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
313
314   stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
315   stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
316   stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
317   stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
318   stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
319   stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
320   stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
321   stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
322   stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
323   stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
324   stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
325
326
327   /* out stats */
328   stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
329   for(i = 0; i <= ICMP_MAXTYPE; i++)
330   stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
331
332   stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
333
334   stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
335   stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
336   stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
337   stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
338   stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
339   stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
340   stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
341   stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
342   stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
343   stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
344   stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
345
346   return NO_ERROR;
347 #else
348   FILE *fp;
349
350   if (!stats)
351     return ERROR_INVALID_PARAMETER;
352
353   memset(stats, 0, sizeof(MIB_ICMP));
354   /* get most of these stats from /proc/net/snmp, no error if can't */
355   fp = fopen("/proc/net/snmp", "r");
356   if (fp) {
357     static const char hdr[] = "Icmp:";
358     char buf[512] = { 0 }, *ptr;
359
360     do {
361       ptr = fgets(buf, sizeof(buf), fp);
362     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
363     if (ptr) {
364       /* last line was a header, get another */
365       ptr = fgets(buf, sizeof(buf), fp);
366       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
367         char *endPtr;
368
369         ptr += sizeof(hdr);
370         if (ptr && *ptr) {
371           stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
372           ptr = endPtr;
373         }
374         if (ptr && *ptr) {
375           stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
376           ptr = endPtr;
377         }
378         if (ptr && *ptr) {
379           stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
380           ptr = endPtr;
381         }
382         if (ptr && *ptr) {
383           stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
384           ptr = endPtr;
385         }
386         if (ptr && *ptr) {
387           stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
388           ptr = endPtr;
389         }
390         if (ptr && *ptr) {
391           stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
392           ptr = endPtr;
393         }
394         if (ptr && *ptr) {
395           stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
396           ptr = endPtr;
397         }
398         if (ptr && *ptr) {
399           stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
400           ptr = endPtr;
401         }
402         if (ptr && *ptr) {
403           stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
404           ptr = endPtr;
405         }
406         if (ptr && *ptr) {
407           stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
408           ptr = endPtr;
409         }
410         if (ptr && *ptr) {
411           stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
412           ptr = endPtr;
413         }
414         if (ptr && *ptr) {
415           stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
416           ptr = endPtr;
417         }
418         if (ptr && *ptr) {
419           stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
420           ptr = endPtr;
421         }
422         if (ptr && *ptr) {
423           stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
424           ptr = endPtr;
425         }
426         if (ptr && *ptr) {
427           stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
428           ptr = endPtr;
429         }
430         if (ptr && *ptr) {
431           stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
432           ptr = endPtr;
433         }
434         if (ptr && *ptr) {
435           stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
436           ptr = endPtr;
437         }
438         if (ptr && *ptr) {
439           stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
440           ptr = endPtr;
441         }
442         if (ptr && *ptr) {
443           stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
444           ptr = endPtr;
445         }
446         if (ptr && *ptr) {
447           stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
448           ptr = endPtr;
449         }
450         if (ptr && *ptr) {
451           stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
452           ptr = endPtr;
453         }
454         if (ptr && *ptr) {
455           stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
456           ptr = endPtr;
457         }
458         if (ptr && *ptr) {
459           stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
460           ptr = endPtr;
461         }
462         if (ptr && *ptr) {
463           stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
464           ptr = endPtr;
465         }
466       }
467     }
468     fclose(fp);
469   }
470   else
471   {
472      ERR ("unimplemented!\n");
473      return ERROR_NOT_SUPPORTED;
474   }
475
476   return NO_ERROR;
477 #endif
478 }
479
480 DWORD getIPStats(PMIB_IPSTATS stats)
481 {
482 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
483   int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
484 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
485   int ip_ttl, ip_forwarding;
486   struct ipstat ip_stat;
487   size_t needed;
488
489   if (!stats)
490       return ERROR_INVALID_PARAMETER;
491
492   needed = sizeof(ip_stat);
493   if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
494   {
495       ERR ("failed to get ipstat\n");
496       return ERROR_NOT_SUPPORTED;
497   }
498
499   needed = sizeof(ip_ttl);
500   if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
501   {
502       ERR ("failed to get ip Default TTL\n");
503       return ERROR_NOT_SUPPORTED;
504   }
505
506   needed = sizeof(ip_forwarding);
507   if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
508   {
509       ERR ("failed to get ip forwarding\n");
510       return ERROR_NOT_SUPPORTED;
511   }
512
513   stats->dwForwarding = ip_forwarding;
514   stats->dwDefaultTTL = ip_ttl;
515   stats->dwInDelivers = ip_stat.ips_delivered;
516   stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
517   stats->dwInAddrErrors = ip_stat.ips_cantforward;
518   stats->dwInReceives = ip_stat.ips_total;
519   stats->dwForwDatagrams = ip_stat.ips_forward;
520   stats->dwInUnknownProtos = ip_stat.ips_noproto;
521   stats->dwInDiscards = ip_stat.ips_fragdropped;
522   stats->dwOutDiscards = ip_stat.ips_odropped;
523   stats->dwReasmOks = ip_stat.ips_reassembled;
524   stats->dwFragOks = ip_stat.ips_fragmented;
525   stats->dwFragFails = ip_stat.ips_cantfrag;
526   stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
527   stats->dwOutNoRoutes = ip_stat.ips_noroute;
528   stats->dwOutRequests = ip_stat.ips_localout;
529   stats->dwReasmReqds = ip_stat.ips_fragments;
530
531   return NO_ERROR;
532 #else
533   FILE *fp;
534
535   if (!stats)
536     return ERROR_INVALID_PARAMETER;
537
538   memset(stats, 0, sizeof(MIB_IPSTATS));
539   stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
540   stats->dwNumRoutes = getNumRoutes();
541
542   /* get most of these stats from /proc/net/snmp, no error if can't */
543   fp = fopen("/proc/net/snmp", "r");
544   if (fp) {
545     static const char hdr[] = "Ip:";
546     char buf[512] = { 0 }, *ptr;
547
548     do {
549       ptr = fgets(buf, sizeof(buf), fp);
550     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
551     if (ptr) {
552       /* last line was a header, get another */
553       ptr = fgets(buf, sizeof(buf), fp);
554       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
555         char *endPtr;
556
557         ptr += sizeof(hdr);
558         if (ptr && *ptr) {
559           stats->dwForwarding = strtoul(ptr, &endPtr, 10);
560           ptr = endPtr;
561         }
562         if (ptr && *ptr) {
563           stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
564           ptr = endPtr;
565         }
566         if (ptr && *ptr) {
567           stats->dwInReceives = strtoul(ptr, &endPtr, 10);
568           ptr = endPtr;
569         }
570         if (ptr && *ptr) {
571           stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
572           ptr = endPtr;
573         }
574         if (ptr && *ptr) {
575           stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
576           ptr = endPtr;
577         }
578         if (ptr && *ptr) {
579           stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
580           ptr = endPtr;
581         }
582         if (ptr && *ptr) {
583           stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
584           ptr = endPtr;
585         }
586         if (ptr && *ptr) {
587           stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
588           ptr = endPtr;
589         }
590         if (ptr && *ptr) {
591           stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
592           ptr = endPtr;
593         }
594         if (ptr && *ptr) {
595           stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
596           ptr = endPtr;
597         }
598         if (ptr && *ptr) {
599           stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
600           ptr = endPtr;
601         }
602         if (ptr && *ptr) {
603           stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
604           ptr = endPtr;
605         }
606         if (ptr && *ptr) {
607           stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
608           ptr = endPtr;
609         }
610         if (ptr && *ptr) {
611           stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
612           ptr = endPtr;
613         }
614         if (ptr && *ptr) {
615           stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
616           ptr = endPtr;
617         }
618         if (ptr && *ptr) {
619           stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
620           ptr = endPtr;
621         }
622         if (ptr && *ptr) {
623           stats->dwFragOks = strtoul(ptr, &endPtr, 10);
624           ptr = endPtr;
625         }
626         if (ptr && *ptr) {
627           stats->dwFragFails = strtoul(ptr, &endPtr, 10);
628           ptr = endPtr;
629         }
630         if (ptr && *ptr) {
631           stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
632           ptr = endPtr;
633         }
634         /* hmm, no routingDiscards */
635       }
636     }
637     fclose(fp);
638   }
639   else
640   {
641      ERR ("unimplemented!\n");
642      return ERROR_NOT_SUPPORTED;
643   }
644
645   return NO_ERROR;
646 #endif
647 }
648
649 DWORD getTCPStats(MIB_TCPSTATS *stats)
650 {
651 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
652 #ifndef TCPTV_MIN  /* got removed in Mac OS X for some reason */
653 #define TCPTV_MIN 2
654 #define TCPTV_REXMTMAX 128
655 #endif
656   int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
657 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
658 #define hz 1000
659   struct tcpstat tcp_stat;
660   size_t needed;
661
662   if (!stats)
663     return ERROR_INVALID_PARAMETER;
664   needed = sizeof(tcp_stat);
665
666   if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
667   {
668       ERR ("failed to get tcpstat\n");
669       return ERROR_NOT_SUPPORTED;
670   }
671
672   stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
673   stats->dwRtoMin = TCPTV_MIN;
674   stats->dwRtoMax = TCPTV_REXMTMAX;
675   stats->dwMaxConn = -1;
676   stats->dwActiveOpens = tcp_stat.tcps_connattempt;
677   stats->dwPassiveOpens = tcp_stat.tcps_accepts;
678   stats->dwAttemptFails = tcp_stat.tcps_conndrops;
679   stats->dwEstabResets = tcp_stat.tcps_drops;
680   stats->dwCurrEstab = 0;
681   stats->dwInSegs = tcp_stat.tcps_rcvtotal;
682   stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
683   stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
684   stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
685   stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
686   stats->dwNumConns = tcp_stat.tcps_connects;
687
688   return NO_ERROR;
689
690 #else
691   FILE *fp;
692
693   if (!stats)
694     return ERROR_INVALID_PARAMETER;
695
696   memset(stats, 0, sizeof(MIB_TCPSTATS));
697
698   /* get from /proc/net/snmp, no error if can't */
699   fp = fopen("/proc/net/snmp", "r");
700   if (fp) {
701     static const char hdr[] = "Tcp:";
702     char buf[512] = { 0 }, *ptr;
703
704
705     do {
706       ptr = fgets(buf, sizeof(buf), fp);
707     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
708     if (ptr) {
709       /* last line was a header, get another */
710       ptr = fgets(buf, sizeof(buf), fp);
711       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
712         char *endPtr;
713
714         ptr += sizeof(hdr);
715         if (ptr && *ptr) {
716           stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
717           ptr = endPtr;
718         }
719         if (ptr && *ptr) {
720           stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
721           ptr = endPtr;
722         }
723         if (ptr && *ptr) {
724           stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
725           ptr = endPtr;
726         }
727         if (ptr && *ptr) {
728           stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
729           ptr = endPtr;
730         }
731         if (ptr && *ptr) {
732           stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
733           ptr = endPtr;
734         }
735         if (ptr && *ptr) {
736           stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
737           ptr = endPtr;
738         }
739         if (ptr && *ptr) {
740           stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
741           ptr = endPtr;
742         }
743         if (ptr && *ptr) {
744           stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
745           ptr = endPtr;
746         }
747         if (ptr && *ptr) {
748           stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
749           ptr = endPtr;
750         }
751         if (ptr && *ptr) {
752           stats->dwInSegs = strtoul(ptr, &endPtr, 10);
753           ptr = endPtr;
754         }
755         if (ptr && *ptr) {
756           stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
757           ptr = endPtr;
758         }
759         if (ptr && *ptr) {
760           stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
761           ptr = endPtr;
762         }
763         if (ptr && *ptr) {
764           stats->dwInErrs = strtoul(ptr, &endPtr, 10);
765           ptr = endPtr;
766         }
767         if (ptr && *ptr) {
768           stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
769           ptr = endPtr;
770         }
771         stats->dwNumConns = getNumTcpEntries();
772       }
773     }
774     fclose(fp);
775   }
776   else
777   {
778      ERR ("unimplemented!\n");
779      return ERROR_NOT_SUPPORTED;
780   }
781
782   return NO_ERROR;
783 #endif
784 }
785
786 DWORD getUDPStats(MIB_UDPSTATS *stats)
787 {
788 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
789   int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
790 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
791   struct udpstat udp_stat;
792   size_t needed;
793   if (!stats)
794       return ERROR_INVALID_PARAMETER;
795
796   needed = sizeof(udp_stat);
797
798   if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
799   {
800       ERR ("failed to get udpstat\n");
801       return ERROR_NOT_SUPPORTED;
802   }
803
804   stats->dwInDatagrams = udp_stat.udps_ipackets;
805   stats->dwOutDatagrams = udp_stat.udps_opackets;
806   stats->dwNoPorts = udp_stat.udps_noport;
807   stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
808   stats->dwNumAddrs = getNumUdpEntries();
809
810   return NO_ERROR;
811 #else
812   FILE *fp;
813
814   if (!stats)
815     return ERROR_INVALID_PARAMETER;
816
817   memset(stats, 0, sizeof(MIB_UDPSTATS));
818
819   /* get from /proc/net/snmp, no error if can't */
820   fp = fopen("/proc/net/snmp", "r");
821   if (fp) {
822     static const char hdr[] = "Udp:";
823     char buf[512] = { 0 }, *ptr;
824
825
826     do {
827       ptr = fgets(buf, sizeof(buf), fp);
828     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
829     if (ptr) {
830       /* last line was a header, get another */
831       ptr = fgets(buf, sizeof(buf), fp);
832       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
833         char *endPtr;
834
835         ptr += sizeof(hdr);
836         if (ptr && *ptr) {
837           stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
838           ptr = endPtr;
839         }
840         if (ptr && *ptr) {
841           stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
842           ptr = endPtr;
843         }
844         if (ptr && *ptr) {
845           stats->dwInErrors = strtoul(ptr, &endPtr, 10);
846           ptr = endPtr;
847         }
848         if (ptr && *ptr) {
849           stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
850           ptr = endPtr;
851         }
852         if (ptr && *ptr) {
853           stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
854           ptr = endPtr;
855         }
856       }
857     }
858     fclose(fp);
859   }
860   else
861   {
862      ERR ("unimplemented!\n");
863      return ERROR_NOT_SUPPORTED;
864   }
865
866   return NO_ERROR;
867 #endif
868 }
869
870 static DWORD getNumWithOneHeader(const char *filename)
871 {
872 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
873    size_t Len = 0;
874    char *Buf;
875    struct xinpgen *pXIG, *pOrigXIG;
876    int Protocol;
877    DWORD NumEntries = 0;
878
879    if (!strcmp (filename, "net.inet.tcp.pcblist"))
880       Protocol = IPPROTO_TCP;
881    else if (!strcmp (filename, "net.inet.udp.pcblist"))
882       Protocol = IPPROTO_UDP;
883    else
884    {
885       ERR ("Unsupported mib '%s', needs protocol mapping\n",
886            filename);
887       return 0;
888    }
889
890    if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
891    {
892       WARN ("Unable to read '%s' via sysctlbyname\n", filename);
893       return 0;
894    }
895
896    Buf = HeapAlloc (GetProcessHeap (), 0, Len);
897    if (!Buf)
898    {
899       ERR ("Out of memory!\n");
900       return 0;
901    }
902
903    if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
904    {
905       ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
906       HeapFree (GetProcessHeap (), 0, Buf);
907       return 0;
908    }
909
910    /* Might be nothing here; first entry is just a header it seems */
911    if (Len <= sizeof (struct xinpgen))
912    {
913       HeapFree (GetProcessHeap (), 0, Buf);
914       return 0;
915    }
916
917    pOrigXIG = (struct xinpgen *)Buf;
918    pXIG = pOrigXIG;
919
920    for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
921         pXIG->xig_len > sizeof (struct xinpgen);
922         pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
923    {
924       struct tcpcb *pTCPData = NULL;
925       struct inpcb *pINData;
926       struct xsocket *pSockData;
927
928       if (Protocol == IPPROTO_TCP)
929       {
930          pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
931          pINData = &((struct xtcpcb *)pXIG)->xt_inp;
932          pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
933       }
934       else
935       {
936          pINData = &((struct xinpcb *)pXIG)->xi_inp;
937          pSockData = &((struct xinpcb *)pXIG)->xi_socket;
938       }
939
940       /* Ignore sockets for other protocols */
941       if (pSockData->xso_protocol != Protocol)
942          continue;
943
944       /* Ignore PCBs that were freed while generating the data */
945       if (pINData->inp_gencnt > pOrigXIG->xig_gen)
946          continue;
947
948       /* we're only interested in IPv4 addresses */
949       if (!(pINData->inp_vflag & INP_IPV4) ||
950           (pINData->inp_vflag & INP_IPV6))
951          continue;
952
953       /* If all 0's, skip it */
954       if (!pINData->inp_laddr.s_addr &&
955           !pINData->inp_lport &&
956           !pINData->inp_faddr.s_addr &&
957           !pINData->inp_fport)
958          continue;
959
960       NumEntries++;
961    }
962
963    HeapFree (GetProcessHeap (), 0, Buf);
964    return NumEntries;
965 #else
966   FILE *fp;
967   int ret = 0;
968
969   fp = fopen(filename, "r");
970   if (fp) {
971     char buf[512] = { 0 }, *ptr;
972
973
974     ptr = fgets(buf, sizeof(buf), fp);
975     if (ptr) {
976       do {
977         ptr = fgets(buf, sizeof(buf), fp);
978         if (ptr)
979           ret++;
980       } while (ptr);
981     }
982     fclose(fp);
983   }
984   else
985      ERR ("Unable to open '%s' to count entries!\n", filename);
986
987   return ret;
988 #endif
989 }
990
991 DWORD getNumRoutes(void)
992 {
993 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
994    int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
995    size_t needed;
996    char *buf, *lim, *next;
997    struct rt_msghdr *rtm;
998    DWORD RouteCount = 0;
999
1000    if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1001    {
1002       ERR ("sysctl 1 failed!\n");
1003       return 0;
1004    }
1005
1006    buf = HeapAlloc (GetProcessHeap (), 0, needed);
1007    if (!buf) return 0;
1008
1009    if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1010    {
1011       ERR ("sysctl 2 failed!\n");
1012       HeapFree (GetProcessHeap (), 0, buf);
1013       return 0;
1014    }
1015
1016    lim = buf + needed;
1017    for (next = buf; next < lim; next += rtm->rtm_msglen)
1018    {
1019       rtm = (struct rt_msghdr *)next;
1020
1021       if (rtm->rtm_type != RTM_GET)
1022       {
1023          WARN ("Got unexpected message type 0x%x!\n",
1024                rtm->rtm_type);
1025          continue;
1026       }
1027
1028       /* Ignore all entries except for gateway routes which aren't
1029          multicast */
1030       if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1031          continue;
1032
1033       RouteCount++;
1034    }
1035
1036    HeapFree (GetProcessHeap (), 0, buf);
1037    return RouteCount;
1038 #else
1039    return getNumWithOneHeader("/proc/net/route");
1040 #endif
1041 }
1042
1043 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1044  DWORD flags)
1045 {
1046   DWORD ret;
1047
1048   if (!ppIpForwardTable)
1049     ret = ERROR_INVALID_PARAMETER;
1050   else {
1051     DWORD numRoutes = getNumRoutes();
1052     DWORD size = sizeof(MIB_IPFORWARDTABLE);
1053     PMIB_IPFORWARDTABLE table;
1054
1055     if (numRoutes > 1)
1056       size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1057     table = HeapAlloc(heap, flags, size);
1058     if (table) {
1059 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1060        int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1061        size_t needed;
1062        char *buf, *lim, *next, *addrPtr;
1063        struct rt_msghdr *rtm;
1064
1065        if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1066        {
1067           ERR ("sysctl 1 failed!\n");
1068           HeapFree (GetProcessHeap (), 0, table);
1069           return NO_ERROR;
1070        }
1071
1072        buf = HeapAlloc (GetProcessHeap (), 0, needed);
1073        if (!buf)
1074        {
1075           HeapFree (GetProcessHeap (), 0, table);
1076           return ERROR_OUTOFMEMORY;
1077        }
1078
1079        if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1080        {
1081           ERR ("sysctl 2 failed!\n");
1082           HeapFree (GetProcessHeap (), 0, table);
1083           HeapFree (GetProcessHeap (), 0, buf);
1084           return NO_ERROR;
1085        }
1086
1087        *ppIpForwardTable = table;
1088        table->dwNumEntries = 0;
1089
1090        lim = buf + needed;
1091        for (next = buf; next < lim; next += rtm->rtm_msglen)
1092        {
1093           int i;
1094
1095           rtm = (struct rt_msghdr *)next;
1096
1097           if (rtm->rtm_type != RTM_GET)
1098           {
1099              WARN ("Got unexpected message type 0x%x!\n",
1100                    rtm->rtm_type);
1101              continue;
1102           }
1103
1104           /* Ignore all entries except for gateway routes which aren't
1105              multicast */
1106           if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1107               (rtm->rtm_flags & RTF_MULTICAST))
1108              continue;
1109
1110           memset (&table->table[table->dwNumEntries], 0,
1111                   sizeof (MIB_IPFORWARDROW));
1112           table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1113           table->table[table->dwNumEntries].dwForwardType =
1114              MIB_IPROUTE_TYPE_INDIRECT;
1115           table->table[table->dwNumEntries].dwForwardMetric1 =
1116              rtm->rtm_rmx.rmx_hopcount;
1117           table->table[table->dwNumEntries].dwForwardProto =
1118              MIB_IPPROTO_LOCAL;
1119
1120           addrPtr = (char *)(rtm + 1);
1121
1122           for (i = 1; i; i <<= 1)
1123           {
1124              struct sockaddr *sa;
1125              DWORD addr;
1126
1127              if (!(i & rtm->rtm_addrs))
1128                 continue;
1129
1130              sa = (struct sockaddr *)addrPtr;
1131              ADVANCE (addrPtr, sa);
1132
1133              /* default routes are encoded by length-zero sockaddr */
1134              if (sa->sa_len == 0)
1135                 addr = 0;
1136              else if (sa->sa_family != AF_INET)
1137              {
1138                 WARN ("Received unsupported sockaddr family 0x%x\n",
1139                      sa->sa_family);
1140                 addr = 0;
1141              }
1142              else
1143              {
1144                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1145
1146                 addr = sin->sin_addr.s_addr;
1147              }
1148
1149              switch (i)
1150              {
1151                 case RTA_DST:
1152                    table->table[table->dwNumEntries].dwForwardDest = addr;
1153                    break;
1154
1155                 case RTA_GATEWAY:
1156                    table->table[table->dwNumEntries].dwForwardNextHop = addr;
1157                    break;
1158
1159                 case RTA_NETMASK:
1160                    table->table[table->dwNumEntries].dwForwardMask = addr;
1161                    break;
1162
1163                 default:
1164                    WARN ("Unexpected address type 0x%x\n", i);
1165              }
1166           }
1167
1168           table->dwNumEntries++;
1169        }
1170
1171        HeapFree (GetProcessHeap (), 0, buf);
1172        ret = NO_ERROR;
1173 #else
1174       FILE *fp;
1175
1176       ret = NO_ERROR;
1177       *ppIpForwardTable = table;
1178       table->dwNumEntries = 0;
1179       /* get from /proc/net/route, no error if can't */
1180       fp = fopen("/proc/net/route", "r");
1181       if (fp) {
1182         char buf[512] = { 0 }, *ptr;
1183
1184         /* skip header line */
1185         ptr = fgets(buf, sizeof(buf), fp);
1186         while (ptr && table->dwNumEntries < numRoutes) {
1187           memset(&table->table[table->dwNumEntries], 0,
1188            sizeof(MIB_IPFORWARDROW));
1189           ptr = fgets(buf, sizeof(buf), fp);
1190           if (ptr) {
1191             DWORD index;
1192
1193             while (!isspace(*ptr))
1194               ptr++;
1195             *ptr = '\0';
1196             ptr++;
1197             if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1198               char *endPtr;
1199
1200               table->table[table->dwNumEntries].dwForwardIfIndex = index;
1201               if (*ptr) {
1202                 table->table[table->dwNumEntries].dwForwardDest =
1203                  strtoul(ptr, &endPtr, 16);
1204                 ptr = endPtr;
1205               }
1206               if (ptr && *ptr) {
1207                 table->table[table->dwNumEntries].dwForwardNextHop =
1208                  strtoul(ptr, &endPtr, 16);
1209                 ptr = endPtr;
1210               }
1211               if (ptr && *ptr) {
1212                 DWORD flags = strtoul(ptr, &endPtr, 16);
1213
1214                 if (!(flags & RTF_UP))
1215                   table->table[table->dwNumEntries].dwForwardType =
1216                    MIB_IPROUTE_TYPE_INVALID;
1217                 else if (flags & RTF_GATEWAY)
1218                   table->table[table->dwNumEntries].dwForwardType =
1219                    MIB_IPROUTE_TYPE_INDIRECT;
1220                 else
1221                   table->table[table->dwNumEntries].dwForwardType =
1222                    MIB_IPROUTE_TYPE_DIRECT;
1223                 ptr = endPtr;
1224               }
1225               if (ptr && *ptr) {
1226                 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1227                 ptr = endPtr;
1228               }
1229               if (ptr && *ptr) {
1230                 strtoul(ptr, &endPtr, 16); /* use, skip */
1231                 ptr = endPtr;
1232               }
1233               if (ptr && *ptr) {
1234                 table->table[table->dwNumEntries].dwForwardMetric1 =
1235                  strtoul(ptr, &endPtr, 16);
1236                 ptr = endPtr;
1237               }
1238               if (ptr && *ptr) {
1239                 table->table[table->dwNumEntries].dwForwardMask =
1240                  strtoul(ptr, &endPtr, 16);
1241                 ptr = endPtr;
1242               }
1243               /* FIXME: other protos might be appropriate, e.g. the default
1244                * route is typically set with MIB_IPPROTO_NETMGMT instead */
1245               table->table[table->dwNumEntries].dwForwardProto =
1246                MIB_IPPROTO_LOCAL;
1247               table->dwNumEntries++;
1248             }
1249           }
1250         }
1251         fclose(fp);
1252       }
1253       else
1254       {
1255         ERR ("unimplemented!\n");
1256         return ERROR_NOT_SUPPORTED;
1257       }
1258 #endif
1259     }
1260     else
1261       ret = ERROR_OUTOFMEMORY;
1262   }
1263   return ret;
1264 }
1265
1266 DWORD getNumArpEntries(void)
1267 {
1268 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1269   int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1270 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1271   DWORD arpEntries = 0;
1272   size_t needed;
1273   char *buf, *lim, *next;
1274   struct rt_msghdr *rtm;
1275   struct sockaddr_inarp *sinarp;
1276   struct sockaddr_dl *sdl;
1277
1278   if (sysctl (mib, MIB_LEN,  NULL, &needed, NULL, 0) == -1)
1279   {
1280      ERR ("failed to get size of arp table\n");
1281      return 0;
1282   }
1283
1284   buf = HeapAlloc (GetProcessHeap (), 0, needed);
1285   if (!buf) return 0;
1286
1287   if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1288   {
1289      ERR ("failed to get arp table\n");
1290      HeapFree (GetProcessHeap (), 0, buf);
1291      return 0;
1292   }
1293
1294   lim = buf + needed;
1295   next = buf;
1296   while(next < lim)
1297   {
1298       rtm = (struct rt_msghdr *)next;
1299       sinarp=(struct sockaddr_inarp *)(rtm + 1);
1300       sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1301       if(sdl->sdl_alen) /* arp entry */
1302       arpEntries++;
1303       next += rtm->rtm_msglen;
1304   }
1305   HeapFree (GetProcessHeap (), 0, buf);
1306   return arpEntries;
1307 #endif
1308   return getNumWithOneHeader("/proc/net/arp");
1309 }
1310
1311 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1312 {
1313   DWORD ret = NO_ERROR;
1314   if (!ppIpNetTable)
1315     ret = ERROR_INVALID_PARAMETER;
1316   else {
1317     DWORD numEntries = getNumArpEntries();
1318     DWORD size = sizeof(MIB_IPNETTABLE);
1319     PMIB_IPNETTABLE table;
1320
1321     if (numEntries > 1)
1322       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1323     table = HeapAlloc(heap, flags, size);
1324 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1325     if (table)
1326     {
1327       int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1328 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1329       size_t needed;
1330       char *buf, *lim, *next;
1331       struct rt_msghdr *rtm;
1332       struct sockaddr_inarp *sinarp;
1333       struct sockaddr_dl *sdl;
1334
1335       *ppIpNetTable = table;
1336       table->dwNumEntries = 0;
1337
1338       if (sysctl (mib, MIB_LEN,  NULL, &needed, NULL, 0) == -1)
1339       {
1340          ERR ("failed to get size of arp table\n");
1341          return ERROR_NOT_SUPPORTED;
1342       }
1343
1344       buf = HeapAlloc (GetProcessHeap (), 0, needed);
1345       if (!buf) return ERROR_OUTOFMEMORY;
1346
1347       if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1348       {
1349          ERR ("failed to get arp table\n");
1350          HeapFree (GetProcessHeap (), 0, buf);
1351          return ERROR_NOT_SUPPORTED;
1352       }
1353
1354       lim = buf + needed;
1355       next = buf;
1356       while(next < lim)
1357       {
1358           rtm = (struct rt_msghdr *)next;
1359           sinarp=(struct sockaddr_inarp *)(rtm + 1);
1360           sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1361           if(sdl->sdl_alen) /* arp entry */
1362           {
1363               DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1364               memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1365               table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1366               table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1367               table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1368
1369               table->table[table->dwNumEntries].bPhysAddr[
1370                   table->table[table->dwNumEntries].dwPhysAddrLen++] =
1371                   byte & 0x0ff;
1372               if(rtm->rtm_rmx.rmx_expire == 0)
1373                   table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1374               else if(sinarp->sin_other & SIN_PROXY)
1375                   table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1376               else if(rtm->rtm_rmx.rmx_expire != 0)
1377                   table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1378               else
1379                   table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1380
1381               table->dwNumEntries++;
1382           }
1383           next += rtm->rtm_msglen;
1384       }
1385       HeapFree (GetProcessHeap (), 0, buf);
1386     }
1387     else
1388         ret = ERROR_OUTOFMEMORY;
1389   return ret;
1390 #endif
1391
1392     if (table) {
1393       FILE *fp;
1394       *ppIpNetTable = table;
1395       table->dwNumEntries = 0;
1396       /* get from /proc/net/arp, no error if can't */
1397       fp = fopen("/proc/net/arp", "r");
1398       if (fp) {
1399         char buf[512] = { 0 }, *ptr;
1400
1401         /* skip header line */
1402         ptr = fgets(buf, sizeof(buf), fp);
1403         while (ptr && table->dwNumEntries < numEntries) {
1404           ptr = fgets(buf, sizeof(buf), fp);
1405           if (ptr) {
1406             char *endPtr;
1407
1408             memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1409             table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1410             while (ptr && *ptr && !isspace(*ptr))
1411               ptr++;
1412
1413             if (ptr && *ptr) {
1414               strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1415               ptr = endPtr;
1416             }
1417             if (ptr && *ptr) {
1418               DWORD flags = strtoul(ptr, &endPtr, 16);
1419
1420 #ifdef ATF_COM
1421               if (flags & ATF_COM)
1422                 table->table[table->dwNumEntries].dwType =
1423                  MIB_IPNET_TYPE_DYNAMIC;
1424               else
1425 #endif
1426 #ifdef ATF_PERM
1427               if (flags & ATF_PERM)
1428                 table->table[table->dwNumEntries].dwType =
1429                  MIB_IPNET_TYPE_STATIC;
1430               else
1431 #endif
1432                 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1433
1434               ptr = endPtr;
1435             }
1436             while (ptr && *ptr && isspace(*ptr))
1437               ptr++;
1438             while (ptr && *ptr && !isspace(*ptr)) {
1439               DWORD byte = strtoul(ptr, &endPtr, 16);
1440
1441               if (endPtr && *endPtr) {
1442                 endPtr++;
1443                 table->table[table->dwNumEntries].bPhysAddr[
1444                  table->table[table->dwNumEntries].dwPhysAddrLen++] =
1445                  byte & 0x0ff;
1446               }
1447               ptr = endPtr;
1448             }
1449             if (ptr && *ptr) {
1450               strtoul(ptr, &endPtr, 16); /* mask (skip) */
1451               ptr = endPtr;
1452             }
1453             getInterfaceIndexByName(ptr,
1454              &table->table[table->dwNumEntries].dwIndex);
1455             table->dwNumEntries++;
1456           }
1457         }
1458         fclose(fp);
1459       }
1460       else
1461         ret = ERROR_NOT_SUPPORTED;
1462     }
1463     else
1464       ret = ERROR_OUTOFMEMORY;
1465   }
1466   return ret;
1467 }
1468
1469 DWORD getNumUdpEntries(void)
1470 {
1471 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1472    return getNumWithOneHeader ("net.inet.udp.pcblist");
1473 #else
1474   return getNumWithOneHeader("/proc/net/udp");
1475 #endif
1476 }
1477
1478 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1479 {
1480   DWORD ret;
1481
1482 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1483   ERR ("unimplemented!\n");
1484   return ERROR_NOT_SUPPORTED;
1485 #endif
1486
1487   if (!ppUdpTable)
1488     ret = ERROR_INVALID_PARAMETER;
1489   else {
1490     DWORD numEntries = getNumUdpEntries();
1491     DWORD size = sizeof(MIB_UDPTABLE);
1492     PMIB_UDPTABLE table;
1493
1494     if (numEntries > 1)
1495       size += (numEntries - 1) * sizeof(MIB_UDPROW);
1496     table = HeapAlloc(heap, flags, size);
1497     if (table) {
1498       FILE *fp;
1499
1500       ret = NO_ERROR;
1501       *ppUdpTable = table;
1502       table->dwNumEntries = 0;
1503       /* get from /proc/net/udp, no error if can't */
1504       fp = fopen("/proc/net/udp", "r");
1505       if (fp) {
1506         char buf[512] = { 0 }, *ptr;
1507
1508         /* skip header line */
1509         ptr = fgets(buf, sizeof(buf), fp);
1510         while (ptr && table->dwNumEntries < numEntries) {
1511           memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1512           ptr = fgets(buf, sizeof(buf), fp);
1513           if (ptr) {
1514             char *endPtr;
1515
1516             if (ptr && *ptr) {
1517               strtoul(ptr, &endPtr, 16); /* skip */
1518               ptr = endPtr;
1519             }
1520             if (ptr && *ptr) {
1521               ptr++;
1522               table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1523                &endPtr, 16);
1524               ptr = endPtr;
1525             }
1526             if (ptr && *ptr) {
1527               ptr++;
1528               table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1529                &endPtr, 16);
1530               ptr = endPtr;
1531             }
1532             table->dwNumEntries++;
1533           }
1534         }
1535         fclose(fp);
1536       }
1537       else
1538         ret = ERROR_NOT_SUPPORTED;
1539     }
1540     else
1541       ret = ERROR_OUTOFMEMORY;
1542   }
1543   return ret;
1544 }
1545
1546
1547 DWORD getNumTcpEntries(void)
1548 {
1549 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1550    return getNumWithOneHeader ("net.inet.tcp.pcblist");
1551 #else
1552    return getNumWithOneHeader ("/proc/net/tcp");
1553 #endif
1554 }
1555
1556
1557 /* Why not a lookup table? Because the TCPS_* constants are different
1558    on different platforms */
1559 static DWORD TCPStateToMIBState (int state)
1560 {
1561    switch (state)
1562    {
1563       case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1564       case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1565       case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1566       case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1567       case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1568       case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1569       case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1570       case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1571       case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1572       case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1573       default:
1574       case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1575    }
1576 }
1577
1578
1579 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1580                   DWORD flags)
1581 {
1582    DWORD numEntries;
1583    PMIB_TCPTABLE table;
1584 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1585    size_t Len = 0;
1586    char *Buf;
1587    struct xinpgen *pXIG, *pOrigXIG;
1588 #else
1589    FILE *fp;
1590    char buf[512] = { 0 }, *ptr;
1591 #endif
1592
1593    if (!ppTcpTable)
1594       return ERROR_INVALID_PARAMETER;
1595
1596    numEntries = getNumTcpEntries ();
1597
1598    if (!*ppTcpTable)
1599    {
1600       DWORD size = sizeof(MIB_TCPTABLE);
1601
1602       if (numEntries > 1)
1603          size += (numEntries - 1) * sizeof (MIB_TCPROW);
1604       *ppTcpTable = HeapAlloc (heap, flags, size);
1605       if (!*ppTcpTable)
1606       {
1607          ERR ("Out of memory!\n");
1608          return ERROR_OUTOFMEMORY;
1609       }
1610       maxEntries = numEntries;
1611    }
1612
1613    table = *ppTcpTable;
1614    table->dwNumEntries = 0;
1615    if (!numEntries)
1616       return NO_ERROR;
1617
1618 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1619
1620    if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1621    {
1622       ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1623       return ERROR_OUTOFMEMORY;
1624    }
1625
1626    Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1627    if (!Buf)
1628    {
1629       ERR ("Out of memory!\n");
1630       return ERROR_OUTOFMEMORY;
1631    }
1632
1633    if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1634    {
1635       ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1636       HeapFree (GetProcessHeap (), 0, Buf);
1637       return ERROR_OUTOFMEMORY;
1638    }
1639
1640    /* Might be nothing here; first entry is just a header it seems */
1641    if (Len <= sizeof (struct xinpgen))
1642    {
1643       HeapFree (GetProcessHeap (), 0, Buf);
1644       return NO_ERROR;
1645    }
1646
1647    pOrigXIG = (struct xinpgen *)Buf;
1648    pXIG = pOrigXIG;
1649
1650    for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1651         (pXIG->xig_len > sizeof (struct xinpgen)) &&
1652            (table->dwNumEntries < maxEntries);
1653         pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1654    {
1655       struct tcpcb *pTCPData = NULL;
1656       struct inpcb *pINData;
1657       struct xsocket *pSockData;
1658
1659       pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1660       pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1661       pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1662
1663       /* Ignore sockets for other protocols */
1664       if (pSockData->xso_protocol != IPPROTO_TCP)
1665          continue;
1666
1667       /* Ignore PCBs that were freed while generating the data */
1668       if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1669          continue;
1670
1671       /* we're only interested in IPv4 addresses */
1672       if (!(pINData->inp_vflag & INP_IPV4) ||
1673           (pINData->inp_vflag & INP_IPV6))
1674          continue;
1675
1676       /* If all 0's, skip it */
1677       if (!pINData->inp_laddr.s_addr &&
1678           !pINData->inp_lport &&
1679           !pINData->inp_faddr.s_addr &&
1680           !pINData->inp_fport)
1681          continue;
1682
1683       /* Fill in structure details */
1684       table->table[table->dwNumEntries].dwLocalAddr =
1685          pINData->inp_laddr.s_addr;
1686       table->table[table->dwNumEntries].dwLocalPort =
1687          pINData->inp_lport;
1688       table->table[table->dwNumEntries].dwRemoteAddr =
1689          pINData->inp_faddr.s_addr;
1690       table->table[table->dwNumEntries].dwRemotePort =
1691          pINData->inp_fport;
1692       table->table[table->dwNumEntries].dwState =
1693          TCPStateToMIBState (pTCPData->t_state);
1694
1695       table->dwNumEntries++;
1696    }
1697
1698    HeapFree (GetProcessHeap (), 0, Buf);
1699 #else
1700    /* get from /proc/net/tcp, no error if can't */
1701    fp = fopen("/proc/net/tcp", "r");
1702    if (!fp)
1703       return ERROR_NOT_SUPPORTED;
1704
1705    /* skip header line */
1706    ptr = fgets(buf, sizeof(buf), fp);
1707    while (ptr && table->dwNumEntries < maxEntries) {
1708       memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1709       ptr = fgets(buf, sizeof(buf), fp);
1710       if (ptr) {
1711          char *endPtr;
1712
1713          while (ptr && *ptr && *ptr != ':')
1714             ptr++;
1715          if (ptr && *ptr)
1716             ptr++;
1717          if (ptr && *ptr) {
1718             table->table[table->dwNumEntries].dwLocalAddr =
1719                strtoul(ptr, &endPtr, 16);
1720             ptr = endPtr;
1721          }
1722          if (ptr && *ptr) {
1723             ptr++;
1724             table->table[table->dwNumEntries].dwLocalPort =
1725                htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1726             ptr = endPtr;
1727          }
1728          if (ptr && *ptr) {
1729             table->table[table->dwNumEntries].dwRemoteAddr =
1730                strtoul(ptr, &endPtr, 16);
1731             ptr = endPtr;
1732          }
1733          if (ptr && *ptr) {
1734             ptr++;
1735             table->table[table->dwNumEntries].dwRemotePort =
1736                htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1737             ptr = endPtr;
1738          }
1739          if (ptr && *ptr) {
1740             DWORD state = strtoul(ptr, &endPtr, 16);
1741
1742             table->table[table->dwNumEntries].dwState =
1743                TCPStateToMIBState (state);
1744             ptr = endPtr;
1745          }
1746          table->dwNumEntries++;
1747       }
1748    }
1749    fclose(fp);
1750 #endif
1751
1752    return NO_ERROR;
1753 }