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