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