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