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