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