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