wbemprox: Store the class name in the class object.
[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
1437 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1438                                      DWORD *count, const MIB_UDPROW *row )
1439 {
1440     if (table->dwNumEntries >= *count)
1441     {
1442         MIB_UDPTABLE *new_table;
1443         DWORD new_count = table->dwNumEntries * 2;
1444
1445         if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1446         {
1447             HeapFree( heap, 0, table );
1448             return NULL;
1449         }
1450         *count = new_count;
1451         table = new_table;
1452     }
1453     memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1454     return table;
1455 }
1456
1457 static int compare_udp_rows(const void *a, const void *b)
1458 {
1459     const MIB_UDPROW *rowA = a;
1460     const MIB_UDPROW *rowB = b;
1461     int ret;
1462
1463     if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1464     return rowA->dwLocalPort - rowB->dwLocalPort;
1465 }
1466
1467
1468 /******************************************************************
1469  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1470  *
1471  * Get the UDP listener table.
1472  * Like GetUdpTable(), but allocate the returned table from heap.
1473  *
1474  * PARAMS
1475  *  ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1476  *                   allocated and returned.
1477  *  bOrder     [In]  whether to sort the table
1478  *  heap       [In]  heap from which the table is allocated
1479  *  flags      [In]  flags to HeapAlloc
1480  *
1481  * RETURNS
1482  *  ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1483  *  returns otherwise.
1484  */
1485 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1486                                              HANDLE heap, DWORD flags)
1487 {
1488     MIB_UDPTABLE *table;
1489     MIB_UDPROW row;
1490     DWORD ret = NO_ERROR, count = 16;
1491
1492     TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1493
1494     if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1495
1496     if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1497         return ERROR_OUTOFMEMORY;
1498
1499     table->dwNumEntries = 0;
1500
1501 #ifdef __linux__
1502     {
1503         FILE *fp;
1504
1505         if ((fp = fopen("/proc/net/udp", "r")))
1506         {
1507             char buf[512], *ptr;
1508             DWORD dummy;
1509
1510             /* skip header line */
1511             ptr = fgets(buf, sizeof(buf), fp);
1512             while ((ptr = fgets(buf, sizeof(buf), fp)))
1513             {
1514                 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1515                     continue;
1516                 row.dwLocalPort = htons( row.dwLocalPort );
1517                 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1518                     break;
1519             }
1520             fclose(fp);
1521         }
1522         else ret = ERROR_NOT_SUPPORTED;
1523     }
1524 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1525     {
1526         void *data;
1527         int fd, len;
1528         mib2_udpEntry_t *entry;
1529
1530         if ((fd = open_streams_mib( "udp" )) != -1)
1531         {
1532             if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
1533             {
1534                 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1535                 {
1536                     row.dwLocalAddr = entry->udpLocalAddress;
1537                     row.dwLocalPort = htons( entry->udpLocalPort );
1538                     if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1539                 }
1540                 HeapFree( GetProcessHeap(), 0, data );
1541             }
1542             close( fd );
1543         }
1544         else ret = ERROR_NOT_SUPPORTED;
1545     }
1546 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1547     {
1548         size_t Len = 0;
1549         char *Buf = NULL;
1550         struct xinpgen *pXIG, *pOrigXIG;
1551
1552         if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
1553         {
1554             ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1555             ret = ERROR_NOT_SUPPORTED;
1556             goto done;
1557         }
1558
1559         Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1560         if (!Buf)
1561         {
1562             ret = ERROR_OUTOFMEMORY;
1563             goto done;
1564         }
1565
1566         if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
1567         {
1568             ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1569             ret = ERROR_NOT_SUPPORTED;
1570             goto done;
1571         }
1572
1573         /* Might be nothing here; first entry is just a header it seems */
1574         if (Len <= sizeof (struct xinpgen)) goto done;
1575
1576         pOrigXIG = (struct xinpgen *)Buf;
1577         pXIG = pOrigXIG;
1578
1579         for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1580              pXIG->xig_len > sizeof (struct xinpgen);
1581              pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1582         {
1583             struct inpcb *pINData;
1584             struct xsocket *pSockData;
1585
1586             pINData = &((struct xinpcb *)pXIG)->xi_inp;
1587             pSockData = &((struct xinpcb *)pXIG)->xi_socket;
1588
1589             /* Ignore sockets for other protocols */
1590             if (pSockData->xso_protocol != IPPROTO_UDP)
1591                 continue;
1592
1593             /* Ignore PCBs that were freed while generating the data */
1594             if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1595                 continue;
1596
1597             /* we're only interested in IPv4 addresses */
1598             if (!(pINData->inp_vflag & INP_IPV4) ||
1599                 (pINData->inp_vflag & INP_IPV6))
1600                 continue;
1601
1602             /* If all 0's, skip it */
1603             if (!pINData->inp_laddr.s_addr &&
1604                 !pINData->inp_lport)
1605                 continue;
1606
1607             /* Fill in structure details */
1608             row.dwLocalAddr = pINData->inp_laddr.s_addr;
1609             row.dwLocalPort = pINData->inp_lport;
1610             if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1611         }
1612
1613     done:
1614         HeapFree (GetProcessHeap (), 0, Buf);
1615     }
1616 #else
1617     FIXME( "not implemented\n" );
1618     ret = ERROR_NOT_SUPPORTED;
1619 #endif
1620
1621     if (!table) return ERROR_OUTOFMEMORY;
1622     if (!ret)
1623     {
1624         if (bOrder && table->dwNumEntries)
1625             qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1626         *ppUdpTable = table;
1627     }
1628     else HeapFree( heap, flags, table );
1629     TRACE( "returning ret %u table %p\n", ret, table );
1630     return ret;
1631 }
1632
1633 static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
1634 {
1635     DWORD table_size;
1636
1637     switch (class)
1638     {
1639     case TCP_TABLE_BASIC_LISTENER:
1640     case TCP_TABLE_BASIC_CONNECTIONS:
1641     case TCP_TABLE_BASIC_ALL:
1642     {
1643         table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
1644         if (row_size) *row_size = sizeof(MIB_TCPROW);
1645         break;
1646     }
1647     case TCP_TABLE_OWNER_PID_LISTENER:
1648     case TCP_TABLE_OWNER_PID_CONNECTIONS:
1649     case TCP_TABLE_OWNER_PID_ALL:
1650     {
1651         table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
1652         if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
1653         break;
1654     }
1655     default:
1656         ERR("unhandled class %u\n", class);
1657         return 0;
1658     }
1659     return table_size;
1660 }
1661
1662 static MIB_TCPTABLE *append_tcp_row( TCP_TABLE_CLASS class, HANDLE heap, DWORD flags,
1663                                      MIB_TCPTABLE *table, DWORD *count,
1664                                      const MIB_TCPROW_OWNER_PID *row, DWORD row_size )
1665 {
1666     if (table->dwNumEntries >= *count)
1667     {
1668         MIB_TCPTABLE *new_table;
1669         DWORD new_count = table->dwNumEntries * 2, new_table_size;
1670
1671         new_table_size = get_tcp_table_sizes( class, new_count, NULL );
1672         if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
1673         {
1674             HeapFree( heap, 0, table );
1675             return NULL;
1676         }
1677         *count = new_count;
1678         table = new_table;
1679     }
1680     memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
1681     table->dwNumEntries++;
1682     return table;
1683 }
1684
1685
1686 /* Why not a lookup table? Because the TCPS_* constants are different
1687    on different platforms */
1688 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1689 {
1690    switch (state)
1691    {
1692       case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1693       case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1694       case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1695       case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1696       case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1697       case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1698       case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1699       case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1700       case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1701       case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1702       default:
1703       case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1704    }
1705 }
1706
1707 static int compare_tcp_rows(const void *a, const void *b)
1708 {
1709     const MIB_TCPROW *rowA = a;
1710     const MIB_TCPROW *rowB = b;
1711     int ret;
1712
1713     if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1714     if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1715                ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1716     if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1717     return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1718 }
1719
1720 struct pid_map
1721 {
1722     unsigned int pid;
1723     unsigned int unix_pid;
1724 };
1725
1726 static struct pid_map *get_pid_map( unsigned int *num_entries )
1727 {
1728     HANDLE snapshot = NULL;
1729     struct pid_map *map;
1730     unsigned int i = 0, count = 16, size = count * sizeof(*map);
1731     NTSTATUS ret;
1732
1733     if (!(map = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
1734
1735     SERVER_START_REQ( create_snapshot )
1736     {
1737         req->flags      = SNAP_PROCESS;
1738         req->attributes = 0;
1739         if (!(ret = wine_server_call( req )))
1740             snapshot = wine_server_ptr_handle( reply->handle );
1741     }
1742     SERVER_END_REQ;
1743
1744     *num_entries = 0;
1745     while (ret == STATUS_SUCCESS)
1746     {
1747         SERVER_START_REQ( next_process )
1748         {
1749             req->handle = wine_server_obj_handle( snapshot );
1750             req->reset = (i == 0);
1751             if (!(ret = wine_server_call( req )))
1752             {
1753                 if (i >= count)
1754                 {
1755                     struct pid_map *new_map;
1756                     count *= 2;
1757                     size = count * sizeof(*new_map);
1758
1759                     if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, size )))
1760                     {
1761                         HeapFree( GetProcessHeap(), 0, map );
1762                         map = NULL;
1763                         goto done;
1764                     }
1765                     map = new_map;
1766                 }
1767                 map[i].pid = reply->pid;
1768                 map[i].unix_pid = reply->unix_pid;
1769                 (*num_entries)++;
1770                 i++;
1771             }
1772         }
1773         SERVER_END_REQ;
1774     }
1775
1776 done:
1777     NtClose( snapshot );
1778     return map;
1779 }
1780
1781 static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, int inode )
1782 {
1783 #ifdef __linux__
1784     unsigned int i, len_socket;
1785     char socket[32];
1786
1787     sprintf( socket, "socket:[%d]", inode );
1788     len_socket = strlen( socket );
1789     for (i = 0; i < num_entries; i++)
1790     {
1791         char dir[32];
1792         struct dirent *dirent;
1793         DIR *dirfd;
1794
1795         sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
1796         if ((dirfd = opendir( dir )))
1797         {
1798             while ((dirent = readdir( dirfd )))
1799             {
1800                 char link[sizeof(dirent->d_name) + 32], name[32];
1801                 int len;
1802
1803                 sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
1804                 if ((len = readlink( link, name, 32 )) > 0) name[len] = 0;
1805                 if (len == len_socket && !strcmp( socket, name ))
1806                 {
1807                     closedir( dirfd );
1808                     return map[i].pid;
1809                 }
1810             }
1811             closedir( dirfd );
1812         }
1813     }
1814     return 0;
1815 #else
1816     FIXME( "not implemented\n" );
1817     return 0;
1818 #endif
1819 }
1820
1821 DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
1822                        DWORD *size )
1823 {
1824     MIB_TCPTABLE *table;
1825     MIB_TCPROW_OWNER_PID row;
1826     DWORD ret = NO_ERROR, count = 16, table_size, row_size;
1827
1828     if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
1829         return ERROR_INVALID_PARAMETER;
1830
1831     if (!(table = HeapAlloc( heap, flags, table_size )))
1832         return ERROR_OUTOFMEMORY;
1833
1834     table->dwNumEntries = 0;
1835
1836 #ifdef __linux__
1837     {
1838         FILE *fp;
1839
1840         if ((fp = fopen("/proc/net/tcp", "r")))
1841         {
1842             char buf[512], *ptr;
1843             struct pid_map *map = NULL;
1844             unsigned int dummy, num_entries = 0;
1845             int inode;
1846
1847             if (class == TCP_TABLE_OWNER_PID_ALL) map = get_pid_map( &num_entries );
1848
1849             /* skip header line */
1850             ptr = fgets(buf, sizeof(buf), fp);
1851             while ((ptr = fgets(buf, sizeof(buf), fp)))
1852             {
1853                 if (sscanf( ptr, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy,
1854                             &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
1855                             &row.dwRemotePort, &row.dwState, &inode ) != 7)
1856                     continue;
1857                 row.dwLocalPort = htons( row.dwLocalPort );
1858                 row.dwRemotePort = htons( row.dwRemotePort );
1859                 row.dwState = TCPStateToMIBState( row.dwState );
1860                 if (class == TCP_TABLE_OWNER_PID_ALL)
1861                     row.dwOwningPid = find_owning_pid( map, num_entries, inode );
1862
1863                 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
1864                     break;
1865             }
1866             HeapFree( GetProcessHeap(), 0, map );
1867             fclose( fp );
1868         }
1869         else ret = ERROR_NOT_SUPPORTED;
1870     }
1871 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1872     {
1873         void *data;
1874         int fd, len;
1875         mib2_tcpConnEntry_t *entry;
1876
1877         if ((fd = open_streams_mib( "tcp" )) != -1)
1878         {
1879             if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
1880             {
1881                 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1882                 {
1883                     row.dwLocalAddr = entry->tcpConnLocalAddress;
1884                     row.dwLocalPort = htons( entry->tcpConnLocalPort );
1885                     row.dwRemoteAddr = entry->tcpConnRemAddress;
1886                     row.dwRemotePort = htons( entry->tcpConnRemPort );
1887                     row.dwState = entry->tcpConnState;
1888                     if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
1889                         break;
1890                 }
1891                 HeapFree( GetProcessHeap(), 0, data );
1892             }
1893             close( fd );
1894         }
1895         else ret = ERROR_NOT_SUPPORTED;
1896     }
1897 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1898     {
1899         size_t Len = 0;
1900         char *Buf = NULL;
1901         struct xinpgen *pXIG, *pOrigXIG;
1902
1903         if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1904         {
1905             ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1906             ret = ERROR_NOT_SUPPORTED;
1907             goto done;
1908         }
1909
1910         Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1911         if (!Buf)
1912         {
1913             ret = ERROR_OUTOFMEMORY;
1914             goto done;
1915         }
1916
1917         if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1918         {
1919             ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1920             ret = ERROR_NOT_SUPPORTED;
1921             goto done;
1922         }
1923
1924         /* Might be nothing here; first entry is just a header it seems */
1925         if (Len <= sizeof (struct xinpgen)) goto done;
1926
1927         pOrigXIG = (struct xinpgen *)Buf;
1928         pXIG = pOrigXIG;
1929
1930         for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1931              pXIG->xig_len > sizeof (struct xinpgen);
1932              pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1933         {
1934             struct tcpcb *pTCPData = NULL;
1935             struct inpcb *pINData;
1936             struct xsocket *pSockData;
1937
1938             pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1939             pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1940             pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1941
1942             /* Ignore sockets for other protocols */
1943             if (pSockData->xso_protocol != IPPROTO_TCP)
1944                 continue;
1945
1946             /* Ignore PCBs that were freed while generating the data */
1947             if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1948                 continue;
1949
1950             /* we're only interested in IPv4 addresses */
1951             if (!(pINData->inp_vflag & INP_IPV4) ||
1952                 (pINData->inp_vflag & INP_IPV6))
1953                 continue;
1954
1955             /* If all 0's, skip it */
1956             if (!pINData->inp_laddr.s_addr &&
1957                 !pINData->inp_lport &&
1958                 !pINData->inp_faddr.s_addr &&
1959                 !pINData->inp_fport)
1960                 continue;
1961
1962             /* Fill in structure details */
1963             row.dwLocalAddr = pINData->inp_laddr.s_addr;
1964             row.dwLocalPort = pINData->inp_lport;
1965             row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1966             row.dwRemotePort = pINData->inp_fport;
1967             row.dwState = TCPStateToMIBState (pTCPData->t_state);
1968             if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
1969                 break;
1970         }
1971
1972     done:
1973         HeapFree (GetProcessHeap (), 0, Buf);
1974     }
1975 #else
1976     FIXME( "not implemented\n" );
1977     ret = ERROR_NOT_SUPPORTED;
1978 #endif
1979
1980     if (!table) return ERROR_OUTOFMEMORY;
1981     if (!ret)
1982     {
1983         if (order && table->dwNumEntries)
1984             qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
1985         *tablep = table;
1986     }
1987     else HeapFree( heap, flags, table );
1988     if (size) *size = get_tcp_table_sizes( class, count, NULL );
1989     TRACE( "returning ret %u table %p\n", ret, table );
1990     return ret;
1991 }
1992
1993 /******************************************************************
1994  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1995  *
1996  * Get the TCP connection table.
1997  * Like GetTcpTable(), but allocate the returned table from heap.
1998  *
1999  * PARAMS
2000  *  ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2001  *                   allocated and returned.
2002  *  bOrder     [In]  whether to sort the table
2003  *  heap       [In]  heap from which the table is allocated
2004  *  flags      [In]  flags to HeapAlloc
2005  *
2006  * RETURNS
2007  *  ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2008  *  returns otherwise.
2009  */
2010 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
2011                                               HANDLE heap, DWORD flags )
2012 {
2013     TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
2014
2015     if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
2016     return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
2017 }