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