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