d3drm: Implement IDirect3DRMMesh_AddGroup.
[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)
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_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 /* 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)
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         struct ipstat ip_stat;
668         size_t needed;
669
670         needed = sizeof(ip_stat);
671         if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
672         {
673             ERR ("failed to get ipstat\n");
674             return ERROR_NOT_SUPPORTED;
675         }
676
677         needed = sizeof(ip_ttl);
678         if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
679         {
680             ERR ("failed to get ip Default TTL\n");
681             return ERROR_NOT_SUPPORTED;
682         }
683
684         needed = sizeof(ip_forwarding);
685         if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
686         {
687             ERR ("failed to get ip forwarding\n");
688             return ERROR_NOT_SUPPORTED;
689         }
690
691         stats->u.dwForwarding = ip_forwarding;
692         stats->dwDefaultTTL = ip_ttl;
693         stats->dwInDelivers = ip_stat.ips_delivered;
694         stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
695         stats->dwInAddrErrors = ip_stat.ips_cantforward;
696         stats->dwInReceives = ip_stat.ips_total;
697         stats->dwForwDatagrams = ip_stat.ips_forward;
698         stats->dwInUnknownProtos = ip_stat.ips_noproto;
699         stats->dwInDiscards = ip_stat.ips_fragdropped;
700         stats->dwOutDiscards = ip_stat.ips_odropped;
701         stats->dwReasmOks = ip_stat.ips_reassembled;
702         stats->dwFragOks = ip_stat.ips_fragmented;
703         stats->dwFragFails = ip_stat.ips_cantfrag;
704         stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
705         stats->dwOutNoRoutes = ip_stat.ips_noroute;
706         stats->dwOutRequests = ip_stat.ips_localout;
707         stats->dwReasmReqds = ip_stat.ips_fragments;
708         ret = NO_ERROR;
709     }
710 #else
711     FIXME( "unimplemented\n" );
712 #endif
713     return ret;
714 }
715
716
717 /******************************************************************
718  *    GetTcpStatistics (IPHLPAPI.@)
719  *
720  * Get the TCP statistics for the local computer.
721  *
722  * PARAMS
723  *  stats [Out] buffer for TCP statistics
724  *
725  * RETURNS
726  *  Success: NO_ERROR
727  *  Failure: error code from winerror.h
728  */
729 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
730 {
731     DWORD ret = ERROR_NOT_SUPPORTED;
732
733     if (!stats) return ERROR_INVALID_PARAMETER;
734     memset( stats, 0, sizeof(*stats) );
735
736 #ifdef __linux__
737     {
738         FILE *fp;
739
740         if ((fp = fopen("/proc/net/snmp", "r")))
741         {
742             static const char hdr[] = "Tcp:";
743             MIB_TCPTABLE *tcp_table;
744             char buf[512], *ptr;
745
746             while ((ptr = fgets(buf, sizeof(buf), fp)))
747             {
748                 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
749                 /* last line was a header, get another */
750                 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
751                 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
752                 {
753                     ptr += sizeof(hdr);
754                     sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
755                             &stats->u.dwRtoAlgorithm,
756                             &stats->dwRtoMin,
757                             &stats->dwRtoMax,
758                             &stats->dwMaxConn,
759                             &stats->dwActiveOpens,
760                             &stats->dwPassiveOpens,
761                             &stats->dwAttemptFails,
762                             &stats->dwEstabResets,
763                             &stats->dwCurrEstab,
764                             &stats->dwInSegs,
765                             &stats->dwOutSegs,
766                             &stats->dwRetransSegs,
767                             &stats->dwInErrs,
768                             &stats->dwOutRsts );
769                     break;
770                 }
771             }
772             if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
773             {
774                 stats->dwNumConns = tcp_table->dwNumEntries;
775                 HeapFree( GetProcessHeap(), 0, tcp_table );
776             }
777             fclose(fp);
778             ret = NO_ERROR;
779         }
780     }
781 #elif defined(HAVE_LIBKSTAT)
782     {
783         static char tcp[] = "tcp";
784         kstat_ctl_t *kc;
785         kstat_t *ksp;
786
787         if ((kc = kstat_open()) &&
788             (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
789             kstat_read( kc, ksp, NULL ) != -1 &&
790             ksp->ks_type == KSTAT_TYPE_NAMED)
791         {
792             stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
793             stats->dwRtoMin       = kstat_get_ui32( ksp, "rtoMin" );
794             stats->dwRtoMax       = kstat_get_ui32( ksp, "rtoMax" );
795             stats->dwMaxConn      = kstat_get_ui32( ksp, "maxConn" );
796             stats->dwActiveOpens  = kstat_get_ui32( ksp, "activeOpens" );
797             stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
798             stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
799             stats->dwEstabResets  = kstat_get_ui32( ksp, "estabResets" );
800             stats->dwCurrEstab    = kstat_get_ui32( ksp, "currEstab" );
801             stats->dwInSegs       = kstat_get_ui32( ksp, "inSegs" );
802             stats->dwOutSegs      = kstat_get_ui32( ksp, "outSegs" );
803             stats->dwRetransSegs  = kstat_get_ui32( ksp, "retransSegs" );
804             stats->dwInErrs       = kstat_get_ui32( ksp, "inErrs" );
805             stats->dwOutRsts      = kstat_get_ui32( ksp, "outRsts" );
806             stats->dwNumConns     = kstat_get_ui32( ksp, "connTableSize" );
807             ret = NO_ERROR;
808         }
809         if (kc) kstat_close( kc );
810     }
811 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
812     {
813 #ifndef TCPTV_MIN  /* got removed in Mac OS X for some reason */
814 #define TCPTV_MIN 2
815 #define TCPTV_REXMTMAX 128
816 #endif
817         int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
818 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
819 #define hz 1000
820         struct tcpstat tcp_stat;
821         size_t needed = sizeof(tcp_stat);
822
823         if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
824         {
825             stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
826             stats->dwRtoMin = TCPTV_MIN;
827             stats->dwRtoMax = TCPTV_REXMTMAX;
828             stats->dwMaxConn = -1;
829             stats->dwActiveOpens = tcp_stat.tcps_connattempt;
830             stats->dwPassiveOpens = tcp_stat.tcps_accepts;
831             stats->dwAttemptFails = tcp_stat.tcps_conndrops;
832             stats->dwEstabResets = tcp_stat.tcps_drops;
833             stats->dwCurrEstab = 0;
834             stats->dwInSegs = tcp_stat.tcps_rcvtotal;
835             stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
836             stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
837             stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
838             stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
839             stats->dwNumConns = tcp_stat.tcps_connects;
840             ret = NO_ERROR;
841         }
842         else ERR ("failed to get tcpstat\n");
843     }
844 #else
845     FIXME( "unimplemented\n" );
846 #endif
847     return ret;
848 }
849
850
851 /******************************************************************
852  *    GetUdpStatistics (IPHLPAPI.@)
853  *
854  * Get the UDP statistics for the local computer.
855  *
856  * PARAMS
857  *  stats [Out] buffer for UDP statistics
858  *
859  * RETURNS
860  *  Success: NO_ERROR
861  *  Failure: error code from winerror.h
862  */
863 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
864 {
865     DWORD ret = ERROR_NOT_SUPPORTED;
866
867     if (!stats) return ERROR_INVALID_PARAMETER;
868     memset( stats, 0, sizeof(*stats) );
869
870 #ifdef __linux__
871     {
872         FILE *fp;
873
874         if ((fp = fopen("/proc/net/snmp", "r")))
875         {
876             static const char hdr[] = "Udp:";
877             char buf[512], *ptr;
878
879             while ((ptr = fgets(buf, sizeof(buf), fp)))
880             {
881                 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
882                 /* last line was a header, get another */
883                 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
884                 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
885                 {
886                     ptr += sizeof(hdr);
887                     sscanf( ptr, "%u %u %u %u %u",
888                             &stats->dwInDatagrams, &stats->dwNoPorts,
889                             &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
890                     break;
891                 }
892             }
893             fclose(fp);
894             ret = NO_ERROR;
895         }
896     }
897 #elif defined(HAVE_LIBKSTAT)
898     {
899         static char udp[] = "udp";
900         kstat_ctl_t *kc;
901         kstat_t *ksp;
902         MIB_UDPTABLE *udp_table;
903
904         if ((kc = kstat_open()) &&
905             (ksp = kstat_lookup( kc, udp, 0, udp )) &&
906             kstat_read( kc, ksp, NULL ) != -1 &&
907             ksp->ks_type == KSTAT_TYPE_NAMED)
908         {
909             stats->dwInDatagrams  = kstat_get_ui32( ksp, "inDatagrams" );
910             stats->dwNoPorts      = 0;  /* FIXME */
911             stats->dwInErrors     = kstat_get_ui32( ksp, "inErrors" );
912             stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
913             if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
914             {
915                 stats->dwNumAddrs = udp_table->dwNumEntries;
916                 HeapFree( GetProcessHeap(), 0, udp_table );
917             }
918             ret = NO_ERROR;
919         }
920         if (kc) kstat_close( kc );
921     }
922 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
923     {
924         int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
925 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
926         struct udpstat udp_stat;
927         MIB_UDPTABLE *udp_table;
928         size_t needed = sizeof(udp_stat);
929
930         if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
931         {
932             stats->dwInDatagrams = udp_stat.udps_ipackets;
933             stats->dwOutDatagrams = udp_stat.udps_opackets;
934             stats->dwNoPorts = udp_stat.udps_noport;
935             stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
936             if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
937             {
938                 stats->dwNumAddrs = udp_table->dwNumEntries;
939                 HeapFree( GetProcessHeap(), 0, udp_table );
940             }
941             ret = NO_ERROR;
942         }
943         else ERR ("failed to get udpstat\n");
944     }
945 #else
946     FIXME( "unimplemented\n" );
947 #endif
948     return ret;
949 }
950
951
952 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
953                                                  DWORD *count, const MIB_IPFORWARDROW *row )
954 {
955     if (table->dwNumEntries >= *count)
956     {
957         MIB_IPFORWARDTABLE *new_table;
958         DWORD new_count = table->dwNumEntries * 2;
959
960         if (!(new_table = HeapReAlloc( heap, flags, table,
961                                        FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
962         {
963             HeapFree( heap, 0, table );
964             return NULL;
965         }
966         *count = new_count;
967         table = new_table;
968     }
969     memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
970     return table;
971 }
972
973 static int compare_ipforward_rows(const void *a, const void *b)
974 {
975     const MIB_IPFORWARDROW *rowA = a;
976     const MIB_IPFORWARDROW *rowB = b;
977     int ret;
978
979     if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
980     if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
981     if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
982     return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
983 }
984
985 /******************************************************************
986  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
987  *
988  * Get the route table.
989  * Like GetIpForwardTable(), but allocate the returned table from heap.
990  *
991  * PARAMS
992  *  ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
993  *                         allocated and returned.
994  *  bOrder           [In]  whether to sort the table
995  *  heap             [In]  heap from which the table is allocated
996  *  flags            [In]  flags to HeapAlloc
997  *
998  * RETURNS
999  *  ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1000  *  on failure, NO_ERROR on success.
1001  */
1002 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
1003                                                    HANDLE heap, DWORD flags)
1004 {
1005     MIB_IPFORWARDTABLE *table;
1006     MIB_IPFORWARDROW row;
1007     DWORD ret = NO_ERROR, count = 16;
1008
1009     TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1010
1011     if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1012
1013     if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1014         return ERROR_OUTOFMEMORY;
1015
1016     table->dwNumEntries = 0;
1017
1018 #ifdef __linux__
1019     {
1020         FILE *fp;
1021
1022         if ((fp = fopen("/proc/net/route", "r")))
1023         {
1024             char buf[512], *ptr;
1025             DWORD flags;
1026
1027             /* skip header line */
1028             ptr = fgets(buf, sizeof(buf), fp);
1029             while ((ptr = fgets(buf, sizeof(buf), fp)))
1030             {
1031                 memset( &row, 0, sizeof(row) );
1032
1033                 while (!isspace(*ptr)) ptr++;
1034                 *ptr++ = 0;
1035                 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1036                     continue;
1037
1038                 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1039                 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1040                 flags = strtoul(ptr + 1, &ptr, 16);
1041
1042                 if (!(flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID;
1043                 else if (flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1044                 else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT;
1045
1046                 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1047                 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1048                 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1049                 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1050                 /* FIXME: other protos might be appropriate, e.g. the default
1051                  * route is typically set with MIB_IPPROTO_NETMGMT instead */
1052                 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1053
1054                 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1055                     break;
1056             }
1057             fclose(fp);
1058         }
1059         else ret = ERROR_NOT_SUPPORTED;
1060     }
1061 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1062     {
1063         void *data;
1064         int fd, len, namelen;
1065         mib2_ipRouteEntry_t *entry;
1066         char name[64];
1067
1068         if ((fd = open_streams_mib( NULL )) != -1)
1069         {
1070             if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1071             {
1072                 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1073                 {
1074                     row.dwForwardDest      = entry->ipRouteDest;
1075                     row.dwForwardMask      = entry->ipRouteMask;
1076                     row.dwForwardPolicy    = 0;
1077                     row.dwForwardNextHop   = entry->ipRouteNextHop;
1078                     row.u1.dwForwardType   = entry->ipRouteType;
1079                     row.u2.dwForwardProto  = entry->ipRouteProto;
1080                     row.dwForwardAge       = entry->ipRouteAge;
1081                     row.dwForwardNextHopAS = 0;
1082                     row.dwForwardMetric1   = entry->ipRouteMetric1;
1083                     row.dwForwardMetric2   = entry->ipRouteMetric2;
1084                     row.dwForwardMetric3   = entry->ipRouteMetric3;
1085                     row.dwForwardMetric4   = entry->ipRouteMetric4;
1086                     row.dwForwardMetric5   = entry->ipRouteMetric5;
1087                     namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1088                     memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1089                     name[namelen] = 0;
1090                     getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1091                     if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1092                 }
1093                 HeapFree( GetProcessHeap(), 0, data );
1094             }
1095             close( fd );
1096         }
1097         else ret = ERROR_NOT_SUPPORTED;
1098     }
1099 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1100     {
1101        int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1102        size_t needed;
1103        char *buf = NULL, *lim, *next, *addrPtr;
1104        struct rt_msghdr *rtm;
1105
1106        if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1107        {
1108           ERR ("sysctl 1 failed!\n");
1109           ret = ERROR_NOT_SUPPORTED;
1110           goto done;
1111        }
1112
1113        buf = HeapAlloc (GetProcessHeap (), 0, needed);
1114        if (!buf)
1115        {
1116           ret = ERROR_OUTOFMEMORY;
1117           goto done;
1118        }
1119
1120        if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1121        {
1122           ret = ERROR_NOT_SUPPORTED;
1123           goto done;
1124        }
1125
1126        lim = buf + needed;
1127        for (next = buf; next < lim; next += rtm->rtm_msglen)
1128        {
1129           int i;
1130
1131           rtm = (struct rt_msghdr *)next;
1132
1133           if (rtm->rtm_type != RTM_GET)
1134           {
1135              WARN ("Got unexpected message type 0x%x!\n",
1136                    rtm->rtm_type);
1137              continue;
1138           }
1139
1140           /* Ignore all entries except for gateway routes which aren't
1141              multicast */
1142           if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1143               (rtm->rtm_flags & RTF_MULTICAST))
1144              continue;
1145
1146           memset( &row, 0, sizeof(row) );
1147           row.dwForwardIfIndex = rtm->rtm_index;
1148           row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1149           row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1150           row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1151
1152           addrPtr = (char *)(rtm + 1);
1153
1154           for (i = 1; i; i <<= 1)
1155           {
1156              struct sockaddr *sa;
1157              DWORD addr;
1158
1159              if (!(i & rtm->rtm_addrs))
1160                 continue;
1161
1162              sa = (struct sockaddr *)addrPtr;
1163              ADVANCE (addrPtr, sa);
1164
1165              /* default routes are encoded by length-zero sockaddr */
1166              if (sa->sa_len == 0)
1167                 addr = 0;
1168              else if (sa->sa_family != AF_INET)
1169              {
1170                 WARN ("Received unsupported sockaddr family 0x%x\n",
1171                      sa->sa_family);
1172                 addr = 0;
1173              }
1174              else
1175              {
1176                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1177
1178                 addr = sin->sin_addr.s_addr;
1179              }
1180
1181              switch (i)
1182              {
1183                 case RTA_DST:     row.dwForwardDest = addr; break;
1184                 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1185                 case RTA_NETMASK: row.dwForwardMask = addr; break;
1186                 default:
1187                    WARN ("Unexpected address type 0x%x\n", i);
1188              }
1189           }
1190
1191           if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1192               break;
1193        }
1194 done:
1195       HeapFree( GetProcessHeap (), 0, buf );
1196     }
1197 #else
1198     FIXME( "not implemented\n" );
1199     ret = ERROR_NOT_SUPPORTED;
1200 #endif
1201
1202     if (!table) return ERROR_OUTOFMEMORY;
1203     if (!ret)
1204     {
1205         if (bOrder && table->dwNumEntries)
1206             qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1207         *ppIpForwardTable = table;
1208     }
1209     else HeapFree( heap, flags, table );
1210     TRACE( "returning ret %u table %p\n", ret, table );
1211     return ret;
1212 }
1213
1214 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1215                                          DWORD *count, const MIB_IPNETROW *row )
1216 {
1217     if (table->dwNumEntries >= *count)
1218     {
1219         MIB_IPNETTABLE *new_table;
1220         DWORD new_count = table->dwNumEntries * 2;
1221
1222         if (!(new_table = HeapReAlloc( heap, flags, table,
1223                                        FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1224         {
1225             HeapFree( heap, 0, table );
1226             return NULL;
1227         }
1228         *count = new_count;
1229         table = new_table;
1230     }
1231     memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1232     return table;
1233 }
1234
1235 static int compare_ipnet_rows(const void *a, const void *b)
1236 {
1237     const MIB_IPNETROW *rowA = a;
1238     const MIB_IPNETROW *rowB = b;
1239
1240     return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1241 }
1242
1243
1244 /******************************************************************
1245  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1246  *
1247  * Get the IP-to-physical address mapping table.
1248  * Like GetIpNetTable(), but allocate the returned table from heap.
1249  *
1250  * PARAMS
1251  *  ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1252  *                     allocated and returned.
1253  *  bOrder       [In]  whether to sort the table
1254  *  heap         [In]  heap from which the table is allocated
1255  *  flags        [In]  flags to HeapAlloc
1256  *
1257  * RETURNS
1258  *  ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1259  *  on failure, NO_ERROR on success.
1260  */
1261 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1262                                                HANDLE heap, DWORD flags)
1263 {
1264     MIB_IPNETTABLE *table;
1265     MIB_IPNETROW row;
1266     DWORD ret = NO_ERROR, count = 16;
1267
1268     TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1269
1270     if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1271
1272     if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1273         return ERROR_OUTOFMEMORY;
1274
1275     table->dwNumEntries = 0;
1276
1277 #ifdef __linux__
1278     {
1279         FILE *fp;
1280
1281         if ((fp = fopen("/proc/net/arp", "r")))
1282         {
1283             char buf[512], *ptr;
1284             DWORD flags;
1285
1286             /* skip header line */
1287             ptr = fgets(buf, sizeof(buf), fp);
1288             while ((ptr = fgets(buf, sizeof(buf), fp)))
1289             {
1290                 memset( &row, 0, sizeof(row) );
1291
1292                 row.dwAddr = inet_addr(ptr);
1293                 while (*ptr && !isspace(*ptr)) ptr++;
1294                 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1295                 flags = strtoul(ptr + 1, &ptr, 16);
1296
1297 #ifdef ATF_COM
1298                 if (flags & ATF_COM) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1299                 else
1300 #endif
1301 #ifdef ATF_PERM
1302                 if (flags & ATF_PERM) row.u.Type = MIB_IPNET_TYPE_STATIC;
1303                 else
1304 #endif
1305                     row.u.Type = MIB_IPNET_TYPE_OTHER;
1306
1307                 while (*ptr && isspace(*ptr)) ptr++;
1308                 while (*ptr && !isspace(*ptr))
1309                 {
1310                     row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1311                     if (*ptr) ptr++;
1312                 }
1313                 while (*ptr && isspace(*ptr)) ptr++;
1314                 while (*ptr && !isspace(*ptr)) ptr++;   /* mask (skip) */
1315                 while (*ptr && isspace(*ptr)) ptr++;
1316                 getInterfaceIndexByName(ptr, &row.dwIndex);
1317
1318                 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1319                     break;
1320             }
1321             fclose(fp);
1322         }
1323         else ret = ERROR_NOT_SUPPORTED;
1324     }
1325 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1326     {
1327         void *data;
1328         int fd, len, namelen;
1329         mib2_ipNetToMediaEntry_t *entry;
1330         char name[64];
1331
1332         if ((fd = open_streams_mib( NULL )) != -1)
1333         {
1334             if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1335             {
1336                 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1337                 {
1338                     row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1339                     memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1340                     row.dwAddr = entry->ipNetToMediaNetAddress;
1341                     row.u.Type = entry->ipNetToMediaType;
1342                     namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1343                     memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1344                     name[namelen] = 0;
1345                     getInterfaceIndexByName( name, &row.dwIndex );
1346                     if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1347                 }
1348                 HeapFree( GetProcessHeap(), 0, data );
1349             }
1350             close( fd );
1351         }
1352         else ret = ERROR_NOT_SUPPORTED;
1353     }
1354 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1355     {
1356       int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1357 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1358       size_t needed;
1359       char *buf = NULL, *lim, *next;
1360       struct rt_msghdr *rtm;
1361       struct sockaddr_inarp *sinarp;
1362       struct sockaddr_dl *sdl;
1363
1364       if (sysctl (mib, MIB_LEN,  NULL, &needed, NULL, 0) == -1)
1365       {
1366          ERR ("failed to get arp table\n");
1367          ret = ERROR_NOT_SUPPORTED;
1368          goto done;
1369       }
1370
1371       buf = HeapAlloc (GetProcessHeap (), 0, needed);
1372       if (!buf)
1373       {
1374           ret = ERROR_OUTOFMEMORY;
1375           goto done;
1376       }
1377
1378       if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1379       {
1380          ret = ERROR_NOT_SUPPORTED;
1381          goto done;
1382       }
1383
1384       lim = buf + needed;
1385       next = buf;
1386       while(next < lim)
1387       {
1388           rtm = (struct rt_msghdr *)next;
1389           sinarp=(struct sockaddr_inarp *)(rtm + 1);
1390           sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1391           if(sdl->sdl_alen) /* arp entry */
1392           {
1393               memset( &row, 0, sizeof(row) );
1394               row.dwAddr = sinarp->sin_addr.s_addr;
1395               row.dwIndex = sdl->sdl_index;
1396               row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1397               memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1398               if(rtm->rtm_rmx.rmx_expire == 0) row.u.Type = MIB_IPNET_TYPE_STATIC;
1399               else if(sinarp->sin_other & SIN_PROXY) row.u.Type = MIB_IPNET_TYPE_OTHER;
1400               else if(rtm->rtm_rmx.rmx_expire != 0) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1401               else row.u.Type = MIB_IPNET_TYPE_INVALID;
1402
1403               if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1404                   break;
1405           }
1406           next += rtm->rtm_msglen;
1407       }
1408 done:
1409       HeapFree( GetProcessHeap (), 0, buf );
1410     }
1411 #else
1412     FIXME( "not implemented\n" );
1413     ret = ERROR_NOT_SUPPORTED;
1414 #endif
1415
1416     if (!table) return ERROR_OUTOFMEMORY;
1417     if (!ret)
1418     {
1419         if (bOrder && table->dwNumEntries)
1420             qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1421         *ppIpNetTable = table;
1422     }
1423     else HeapFree( heap, flags, table );
1424     TRACE( "returning ret %u table %p\n", ret, table );
1425     return ret;
1426 }
1427
1428
1429 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1430                                      DWORD *count, const MIB_UDPROW *row )
1431 {
1432     if (table->dwNumEntries >= *count)
1433     {
1434         MIB_UDPTABLE *new_table;
1435         DWORD new_count = table->dwNumEntries * 2;
1436
1437         if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1438         {
1439             HeapFree( heap, 0, table );
1440             return NULL;
1441         }
1442         *count = new_count;
1443         table = new_table;
1444     }
1445     memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1446     return table;
1447 }
1448
1449 static int compare_udp_rows(const void *a, const void *b)
1450 {
1451     const MIB_UDPROW *rowA = a;
1452     const MIB_UDPROW *rowB = b;
1453     int ret;
1454
1455     if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1456     return rowA->dwLocalPort - rowB->dwLocalPort;
1457 }
1458
1459
1460 /******************************************************************
1461  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1462  *
1463  * Get the UDP listener table.
1464  * Like GetUdpTable(), but allocate the returned table from heap.
1465  *
1466  * PARAMS
1467  *  ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1468  *                   allocated and returned.
1469  *  bOrder     [In]  whether to sort the table
1470  *  heap       [In]  heap from which the table is allocated
1471  *  flags      [In]  flags to HeapAlloc
1472  *
1473  * RETURNS
1474  *  ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1475  *  returns otherwise.
1476  */
1477 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1478                                              HANDLE heap, DWORD flags)
1479 {
1480     MIB_UDPTABLE *table;
1481     MIB_UDPROW row;
1482     DWORD ret = NO_ERROR, count = 16;
1483
1484     TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1485
1486     if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1487
1488     if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1489         return ERROR_OUTOFMEMORY;
1490
1491     table->dwNumEntries = 0;
1492
1493 #ifdef __linux__
1494     {
1495         FILE *fp;
1496
1497         if ((fp = fopen("/proc/net/udp", "r")))
1498         {
1499             char buf[512], *ptr;
1500             DWORD dummy;
1501
1502             /* skip header line */
1503             ptr = fgets(buf, sizeof(buf), fp);
1504             while ((ptr = fgets(buf, sizeof(buf), fp)))
1505             {
1506                 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1507                     continue;
1508                 row.dwLocalPort = htons( row.dwLocalPort );
1509                 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1510                     break;
1511             }
1512             fclose(fp);
1513         }
1514         else ret = ERROR_NOT_SUPPORTED;
1515     }
1516 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1517     {
1518         void *data;
1519         int fd, len;
1520         mib2_udpEntry_t *entry;
1521
1522         if ((fd = open_streams_mib( "udp" )) != -1)
1523         {
1524             if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
1525             {
1526                 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1527                 {
1528                     row.dwLocalAddr = entry->udpLocalAddress;
1529                     row.dwLocalPort = htons( entry->udpLocalPort );
1530                     if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1531                 }
1532                 HeapFree( GetProcessHeap(), 0, data );
1533             }
1534             close( fd );
1535         }
1536         else ret = ERROR_NOT_SUPPORTED;
1537     }
1538 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1539     {
1540         size_t Len = 0;
1541         char *Buf = NULL;
1542         struct xinpgen *pXIG, *pOrigXIG;
1543
1544         if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
1545         {
1546             ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1547             ret = ERROR_NOT_SUPPORTED;
1548             goto done;
1549         }
1550
1551         Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1552         if (!Buf)
1553         {
1554             ret = ERROR_OUTOFMEMORY;
1555             goto done;
1556         }
1557
1558         if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
1559         {
1560             ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1561             ret = ERROR_NOT_SUPPORTED;
1562             goto done;
1563         }
1564
1565         /* Might be nothing here; first entry is just a header it seems */
1566         if (Len <= sizeof (struct xinpgen)) goto done;
1567
1568         pOrigXIG = (struct xinpgen *)Buf;
1569         pXIG = pOrigXIG;
1570
1571         for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1572              pXIG->xig_len > sizeof (struct xinpgen);
1573              pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1574         {
1575             struct inpcb *pINData;
1576             struct xsocket *pSockData;
1577
1578             pINData = &((struct xinpcb *)pXIG)->xi_inp;
1579             pSockData = &((struct xinpcb *)pXIG)->xi_socket;
1580
1581             /* Ignore sockets for other protocols */
1582             if (pSockData->xso_protocol != IPPROTO_UDP)
1583                 continue;
1584
1585             /* Ignore PCBs that were freed while generating the data */
1586             if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1587                 continue;
1588
1589             /* we're only interested in IPv4 addresses */
1590             if (!(pINData->inp_vflag & INP_IPV4) ||
1591                 (pINData->inp_vflag & INP_IPV6))
1592                 continue;
1593
1594             /* If all 0's, skip it */
1595             if (!pINData->inp_laddr.s_addr &&
1596                 !pINData->inp_lport)
1597                 continue;
1598
1599             /* Fill in structure details */
1600             row.dwLocalAddr = pINData->inp_laddr.s_addr;
1601             row.dwLocalPort = pINData->inp_lport;
1602             if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1603         }
1604
1605     done:
1606         HeapFree (GetProcessHeap (), 0, Buf);
1607     }
1608 #else
1609     FIXME( "not implemented\n" );
1610     ret = ERROR_NOT_SUPPORTED;
1611 #endif
1612
1613     if (!table) return ERROR_OUTOFMEMORY;
1614     if (!ret)
1615     {
1616         if (bOrder && table->dwNumEntries)
1617             qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1618         *ppUdpTable = table;
1619     }
1620     else HeapFree( heap, flags, table );
1621     TRACE( "returning ret %u table %p\n", ret, table );
1622     return ret;
1623 }
1624
1625 static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
1626 {
1627     DWORD table_size;
1628
1629     switch (class)
1630     {
1631     case TCP_TABLE_BASIC_LISTENER:
1632     case TCP_TABLE_BASIC_CONNECTIONS:
1633     case TCP_TABLE_BASIC_ALL:
1634     {
1635         table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
1636         if (row_size) *row_size = sizeof(MIB_TCPROW);
1637         break;
1638     }
1639     case TCP_TABLE_OWNER_PID_LISTENER:
1640     case TCP_TABLE_OWNER_PID_CONNECTIONS:
1641     case TCP_TABLE_OWNER_PID_ALL:
1642     {
1643         table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
1644         if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
1645         break;
1646     }
1647     default:
1648         ERR("unhandled class %u\n", class);
1649         return 0;
1650     }
1651     return table_size;
1652 }
1653
1654 static MIB_TCPTABLE *append_tcp_row( TCP_TABLE_CLASS class, HANDLE heap, DWORD flags,
1655                                      MIB_TCPTABLE *table, DWORD *count,
1656                                      const MIB_TCPROW_OWNER_PID *row, DWORD row_size )
1657 {
1658     if (table->dwNumEntries >= *count)
1659     {
1660         MIB_TCPTABLE *new_table;
1661         DWORD new_count = table->dwNumEntries * 2, new_table_size;
1662
1663         new_table_size = get_tcp_table_sizes( class, new_count, NULL );
1664         if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
1665         {
1666             HeapFree( heap, 0, table );
1667             return NULL;
1668         }
1669         *count = new_count;
1670         table = new_table;
1671     }
1672     memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
1673     table->dwNumEntries++;
1674     return table;
1675 }
1676
1677
1678 /* Why not a lookup table? Because the TCPS_* constants are different
1679    on different platforms */
1680 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1681 {
1682    switch (state)
1683    {
1684       case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1685       case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1686       case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1687       case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1688       case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1689       case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1690       case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1691       case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1692       case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1693       case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1694       default:
1695       case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1696    }
1697 }
1698
1699 static int compare_tcp_rows(const void *a, const void *b)
1700 {
1701     const MIB_TCPROW *rowA = a;
1702     const MIB_TCPROW *rowB = b;
1703     int ret;
1704
1705     if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1706     if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1707                ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1708     if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1709     return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1710 }
1711
1712 struct pid_map
1713 {
1714     unsigned int pid;
1715     unsigned int unix_pid;
1716 };
1717
1718 static struct pid_map *get_pid_map( unsigned int *num_entries )
1719 {
1720     HANDLE snapshot = NULL;
1721     struct pid_map *map;
1722     unsigned int i = 0, count = 16, size = count * sizeof(*map);
1723     NTSTATUS ret;
1724
1725     if (!(map = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
1726
1727     SERVER_START_REQ( create_snapshot )
1728     {
1729         req->flags      = SNAP_PROCESS;
1730         req->attributes = 0;
1731         if (!(ret = wine_server_call( req )))
1732             snapshot = wine_server_ptr_handle( reply->handle );
1733     }
1734     SERVER_END_REQ;
1735
1736     *num_entries = 0;
1737     while (ret == STATUS_SUCCESS)
1738     {
1739         SERVER_START_REQ( next_process )
1740         {
1741             req->handle = wine_server_obj_handle( snapshot );
1742             req->reset = (i == 0);
1743             if (!(ret = wine_server_call( req )))
1744             {
1745                 if (i >= count)
1746                 {
1747                     struct pid_map *new_map;
1748                     count *= 2;
1749                     size = count * sizeof(*new_map);
1750
1751                     if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, size )))
1752                     {
1753                         HeapFree( GetProcessHeap(), 0, map );
1754                         map = NULL;
1755                         goto done;
1756                     }
1757                     map = new_map;
1758                 }
1759                 map[i].pid = reply->pid;
1760                 map[i].unix_pid = reply->unix_pid;
1761                 (*num_entries)++;
1762                 i++;
1763             }
1764         }
1765         SERVER_END_REQ;
1766     }
1767
1768 done:
1769     NtClose( snapshot );
1770     return map;
1771 }
1772
1773 static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, int inode )
1774 {
1775 #ifdef __linux__
1776     unsigned int i, len_socket;
1777     char socket[32];
1778
1779     sprintf( socket, "socket:[%d]", inode );
1780     len_socket = strlen( socket );
1781     for (i = 0; i < num_entries; i++)
1782     {
1783         char dir[32];
1784         struct dirent *dirent;
1785         DIR *dirfd;
1786
1787         sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
1788         if ((dirfd = opendir( dir )))
1789         {
1790             while ((dirent = readdir( dirfd )))
1791             {
1792                 char link[sizeof(dirent->d_name) + 32], name[32];
1793                 int len;
1794
1795                 sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
1796                 if ((len = readlink( link, name, 32 )) > 0) name[len] = 0;
1797                 if (len == len_socket && !strcmp( socket, name ))
1798                 {
1799                     closedir( dirfd );
1800                     return map[i].pid;
1801                 }
1802             }
1803             closedir( dirfd );
1804         }
1805     }
1806     return 0;
1807 #else
1808     FIXME( "not implemented\n" );
1809     return 0;
1810 #endif
1811 }
1812
1813 DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
1814                        DWORD *size )
1815 {
1816     MIB_TCPTABLE *table;
1817     MIB_TCPROW_OWNER_PID row;
1818     DWORD ret = NO_ERROR, count = 16, table_size, row_size;
1819
1820     if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
1821         return ERROR_INVALID_PARAMETER;
1822
1823     if (!(table = HeapAlloc( heap, flags, table_size )))
1824         return ERROR_OUTOFMEMORY;
1825
1826     table->dwNumEntries = 0;
1827
1828 #ifdef __linux__
1829     {
1830         FILE *fp;
1831
1832         if ((fp = fopen("/proc/net/tcp", "r")))
1833         {
1834             char buf[512], *ptr;
1835             struct pid_map *map = NULL;
1836             unsigned int dummy, num_entries = 0;
1837             int inode;
1838
1839             if (class == TCP_TABLE_OWNER_PID_ALL) map = get_pid_map( &num_entries );
1840
1841             /* skip header line */
1842             ptr = fgets(buf, sizeof(buf), fp);
1843             while ((ptr = fgets(buf, sizeof(buf), fp)))
1844             {
1845                 if (sscanf( ptr, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy,
1846                             &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
1847                             &row.dwRemotePort, &row.dwState, &inode ) != 7)
1848                     continue;
1849                 row.dwLocalPort = htons( row.dwLocalPort );
1850                 row.dwRemotePort = htons( row.dwRemotePort );
1851                 row.dwState = TCPStateToMIBState( row.dwState );
1852                 if (class == TCP_TABLE_OWNER_PID_ALL)
1853                     row.dwOwningPid = find_owning_pid( map, num_entries, inode );
1854
1855                 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
1856                     break;
1857             }
1858             HeapFree( GetProcessHeap(), 0, map );
1859             fclose( fp );
1860         }
1861         else ret = ERROR_NOT_SUPPORTED;
1862     }
1863 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1864     {
1865         void *data;
1866         int fd, len;
1867         mib2_tcpConnEntry_t *entry;
1868
1869         if ((fd = open_streams_mib( "tcp" )) != -1)
1870         {
1871             if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
1872             {
1873                 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1874                 {
1875                     row.dwLocalAddr = entry->tcpConnLocalAddress;
1876                     row.dwLocalPort = htons( entry->tcpConnLocalPort );
1877                     row.dwRemoteAddr = entry->tcpConnRemAddress;
1878                     row.dwRemotePort = htons( entry->tcpConnRemPort );
1879                     row.dwState = entry->tcpConnState;
1880                     if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
1881                         break;
1882                 }
1883                 HeapFree( GetProcessHeap(), 0, data );
1884             }
1885             close( fd );
1886         }
1887         else ret = ERROR_NOT_SUPPORTED;
1888     }
1889 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1890     {
1891         size_t Len = 0;
1892         char *Buf = NULL;
1893         struct xinpgen *pXIG, *pOrigXIG;
1894
1895         if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1896         {
1897             ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1898             ret = ERROR_NOT_SUPPORTED;
1899             goto done;
1900         }
1901
1902         Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1903         if (!Buf)
1904         {
1905             ret = ERROR_OUTOFMEMORY;
1906             goto done;
1907         }
1908
1909         if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1910         {
1911             ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1912             ret = ERROR_NOT_SUPPORTED;
1913             goto done;
1914         }
1915
1916         /* Might be nothing here; first entry is just a header it seems */
1917         if (Len <= sizeof (struct xinpgen)) goto done;
1918
1919         pOrigXIG = (struct xinpgen *)Buf;
1920         pXIG = pOrigXIG;
1921
1922         for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1923              pXIG->xig_len > sizeof (struct xinpgen);
1924              pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1925         {
1926             struct tcpcb *pTCPData = NULL;
1927             struct inpcb *pINData;
1928             struct xsocket *pSockData;
1929
1930             pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1931             pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1932             pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1933
1934             /* Ignore sockets for other protocols */
1935             if (pSockData->xso_protocol != IPPROTO_TCP)
1936                 continue;
1937
1938             /* Ignore PCBs that were freed while generating the data */
1939             if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1940                 continue;
1941
1942             /* we're only interested in IPv4 addresses */
1943             if (!(pINData->inp_vflag & INP_IPV4) ||
1944                 (pINData->inp_vflag & INP_IPV6))
1945                 continue;
1946
1947             /* If all 0's, skip it */
1948             if (!pINData->inp_laddr.s_addr &&
1949                 !pINData->inp_lport &&
1950                 !pINData->inp_faddr.s_addr &&
1951                 !pINData->inp_fport)
1952                 continue;
1953
1954             /* Fill in structure details */
1955             row.dwLocalAddr = pINData->inp_laddr.s_addr;
1956             row.dwLocalPort = pINData->inp_lport;
1957             row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1958             row.dwRemotePort = pINData->inp_fport;
1959             row.dwState = TCPStateToMIBState (pTCPData->t_state);
1960             if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
1961                 break;
1962         }
1963
1964     done:
1965         HeapFree (GetProcessHeap (), 0, Buf);
1966     }
1967 #else
1968     FIXME( "not implemented\n" );
1969     ret = ERROR_NOT_SUPPORTED;
1970 #endif
1971
1972     if (!table) return ERROR_OUTOFMEMORY;
1973     if (!ret)
1974     {
1975         if (order && table->dwNumEntries)
1976             qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
1977         *tablep = table;
1978     }
1979     else HeapFree( heap, flags, table );
1980     if (size) *size = get_tcp_table_sizes( class, count, NULL );
1981     TRACE( "returning ret %u table %p\n", ret, table );
1982     return ret;
1983 }
1984
1985 /******************************************************************
1986  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1987  *
1988  * Get the TCP connection table.
1989  * Like GetTcpTable(), but allocate the returned table from heap.
1990  *
1991  * PARAMS
1992  *  ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1993  *                   allocated and returned.
1994  *  bOrder     [In]  whether to sort the table
1995  *  heap       [In]  heap from which the table is allocated
1996  *  flags      [In]  flags to HeapAlloc
1997  *
1998  * RETURNS
1999  *  ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2000  *  returns otherwise.
2001  */
2002 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
2003                                               HANDLE heap, DWORD flags )
2004 {
2005     TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
2006
2007     if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
2008     return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
2009 }