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