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