iphlpapi: Implement AllocateAndGetTcpExTableFromStack.
[wine.git] / dlls / iphlpapi / ipstats.c
blob0b762ebc8e16e6def923974b16042e6a4c73e34d
1 /*
2 * Copyright (C) 2003,2006 Juan Lang
3 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * Copyright (C) 2009 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
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 #ifdef HAVE_SYS_PARAM_H
127 #include <sys/param.h>
128 #endif
129 #ifdef HAVE_SYS_QUEUE_H
130 #include <sys/queue.h>
131 #endif
132 #ifdef HAVE_SYS_USER_H
133 /* Make sure the definitions of struct kinfo_proc are the same. */
134 #include <sys/user.h>
135 #endif
136 #ifdef HAVE_LIBPROCSTAT_H
137 #include <libprocstat.h>
138 #endif
139 #ifdef HAVE_LIBPROC_H
140 #include <libproc.h>
141 #endif
143 #ifndef ROUNDUP
144 #define ROUNDUP(a) \
145 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
146 #endif
147 #ifndef ADVANCE
148 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
149 #endif
151 #include "ntstatus.h"
152 #define WIN32_NO_STATUS
153 #define NONAMELESSUNION
154 #define USE_WS_PREFIX
155 #include "winsock2.h"
156 #include "ws2ipdef.h"
157 #include "ifenum.h"
158 #include "ipstats.h"
159 #include "iphlpapi.h"
161 #include "wine/debug.h"
162 #include "wine/server.h"
163 #include "wine/unicode.h"
165 #ifndef HAVE_NETINET_TCP_FSM_H
166 #define TCPS_ESTABLISHED 1
167 #define TCPS_SYN_SENT 2
168 #define TCPS_SYN_RECEIVED 3
169 #define TCPS_FIN_WAIT_1 4
170 #define TCPS_FIN_WAIT_2 5
171 #define TCPS_TIME_WAIT 6
172 #define TCPS_CLOSED 7
173 #define TCPS_CLOSE_WAIT 8
174 #define TCPS_LAST_ACK 9
175 #define TCPS_LISTEN 10
176 #define TCPS_CLOSING 11
177 #endif
179 #ifndef RTF_MULTICAST
180 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
181 #endif
183 #ifndef RTF_LLINFO
184 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
185 #endif
187 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
189 #ifdef HAVE_LIBKSTAT
190 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
192 unsigned int i;
193 kstat_named_t *data = ksp->ks_data;
195 for (i = 0; i < ksp->ks_ndata; i++)
196 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
197 return 0;
200 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
202 unsigned int i;
203 kstat_named_t *data = ksp->ks_data;
205 for (i = 0; i < ksp->ks_ndata; i++)
206 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
207 return 0;
209 #endif
211 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
212 static int open_streams_mib( const char *proto )
214 int fd;
215 struct strbuf buf;
216 struct request
218 struct T_optmgmt_req req_header;
219 struct opthdr opt_header;
220 } request;
222 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
224 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
225 return -1;
227 if (proto) ioctl( fd, I_PUSH, proto );
229 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
230 request.req_header.OPT_length = sizeof(request.opt_header);
231 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
232 request.req_header.MGMT_flags = T_CURRENT;
233 request.opt_header.level = MIB2_IP;
234 request.opt_header.name = 0;
235 request.opt_header.len = 0;
237 buf.len = sizeof(request);
238 buf.buf = (caddr_t)&request;
239 if (putmsg( fd, &buf, NULL, 0 ) == -1)
241 WARN( "putmsg: %s\n", strerror(errno) );
242 close( fd );
243 fd = -1;
245 return fd;
248 static void *read_mib_entry( int fd, int level, int name, int *len )
250 struct strbuf buf;
251 void *data;
252 int ret, flags = 0;
254 struct reply
256 struct T_optmgmt_ack ack_header;
257 struct opthdr opt_header;
258 } reply;
260 for (;;)
262 buf.maxlen = sizeof(reply);
263 buf.buf = (caddr_t)&reply;
264 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
265 if (!(ret & MOREDATA)) return NULL;
266 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
267 if (buf.len < sizeof(reply.ack_header)) return NULL;
268 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
270 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
271 buf.maxlen = reply.opt_header.len;
272 buf.buf = (caddr_t)data;
273 flags = 0;
274 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
275 reply.opt_header.level == level &&
276 reply.opt_header.name == name)
278 *len = buf.len;
279 return data;
281 HeapFree( GetProcessHeap(), 0, data );
284 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
286 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
288 DWORD ret = ERROR_NOT_SUPPORTED;
290 if (!name || !entry) return ERROR_INVALID_PARAMETER;
292 #ifdef __linux__
294 FILE *fp;
296 if ((fp = fopen("/proc/net/dev", "r")))
298 DWORD skip;
299 char buf[512], *ptr;
300 int nameLen = strlen(name);
302 while ((ptr = fgets(buf, sizeof(buf), fp)))
304 while (*ptr && isspace(*ptr)) ptr++;
305 if (_strnicmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
307 ptr += nameLen + 1;
308 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
309 &entry->dwInOctets, &entry->dwInUcastPkts,
310 &entry->dwInErrors, &entry->dwInDiscards,
311 &skip, &skip, &skip,
312 &entry->dwInNUcastPkts, &entry->dwOutOctets,
313 &entry->dwOutUcastPkts, &entry->dwOutErrors,
314 &entry->dwOutDiscards );
315 break;
318 fclose(fp);
319 ret = NO_ERROR;
322 #elif defined(HAVE_LIBKSTAT)
324 kstat_ctl_t *kc;
325 kstat_t *ksp;
327 if ((kc = kstat_open()) &&
328 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
329 kstat_read( kc, ksp, NULL ) != -1 &&
330 ksp->ks_type == KSTAT_TYPE_NAMED)
332 entry->dwMtu = 1500; /* FIXME */
333 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
334 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
335 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
336 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
337 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
338 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
339 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
340 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
341 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
342 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
343 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
344 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
345 entry->dwOutDiscards = 0; /* FIXME */
346 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
347 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
348 ret = NO_ERROR;
350 if (kc) kstat_close( kc );
352 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
354 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
355 size_t needed;
356 char *buf = NULL, *end;
357 struct if_msghdr *ifm;
358 struct if_data ifdata;
360 if(sysctl(mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0) == -1)
362 ERR ("failed to get size of iflist\n");
363 goto done;
365 buf = HeapAlloc (GetProcessHeap (), 0, needed);
366 if (!buf)
368 ret = ERROR_OUTOFMEMORY;
369 goto done;
371 if(sysctl(mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0) == -1)
373 ERR ("failed to get iflist\n");
374 goto done;
376 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
378 ifm = (struct if_msghdr *) buf;
379 if(ifm->ifm_type == RTM_IFINFO)
381 ifdata = ifm->ifm_data;
382 entry->dwMtu = ifdata.ifi_mtu;
383 entry->dwSpeed = ifdata.ifi_baudrate;
384 entry->dwInOctets = ifdata.ifi_ibytes;
385 entry->dwInErrors = ifdata.ifi_ierrors;
386 entry->dwInDiscards = ifdata.ifi_iqdrops;
387 entry->dwInUcastPkts = ifdata.ifi_ipackets;
388 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
389 entry->dwOutOctets = ifdata.ifi_obytes;
390 entry->dwOutUcastPkts = ifdata.ifi_opackets;
391 entry->dwOutErrors = ifdata.ifi_oerrors;
392 ret = NO_ERROR;
393 break;
396 done:
397 HeapFree (GetProcessHeap (), 0, buf);
399 #else
400 FIXME( "unimplemented\n" );
401 #endif
402 return ret;
406 /******************************************************************
407 * GetIcmpStatistics (IPHLPAPI.@)
409 * Get the ICMP statistics for the local computer.
411 * PARAMS
412 * stats [Out] buffer for ICMP statistics
414 * RETURNS
415 * Success: NO_ERROR
416 * Failure: error code from winerror.h
418 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
420 DWORD ret = ERROR_NOT_SUPPORTED;
422 if (!stats) return ERROR_INVALID_PARAMETER;
423 memset( stats, 0, sizeof(MIB_ICMP) );
425 #ifdef __linux__
427 FILE *fp;
429 if ((fp = fopen("/proc/net/snmp", "r")))
431 static const char hdr[] = "Icmp:";
432 char buf[512], *ptr;
434 while ((ptr = fgets(buf, sizeof(buf), fp)))
436 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
437 /* last line was a header, get another */
438 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
439 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
441 ptr += sizeof(hdr);
442 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",
443 &stats->stats.icmpInStats.dwMsgs,
444 &stats->stats.icmpInStats.dwErrors,
445 &stats->stats.icmpInStats.dwDestUnreachs,
446 &stats->stats.icmpInStats.dwTimeExcds,
447 &stats->stats.icmpInStats.dwParmProbs,
448 &stats->stats.icmpInStats.dwSrcQuenchs,
449 &stats->stats.icmpInStats.dwRedirects,
450 &stats->stats.icmpInStats.dwEchoReps,
451 &stats->stats.icmpInStats.dwTimestamps,
452 &stats->stats.icmpInStats.dwTimestampReps,
453 &stats->stats.icmpInStats.dwAddrMasks,
454 &stats->stats.icmpInStats.dwAddrMaskReps,
455 &stats->stats.icmpOutStats.dwMsgs,
456 &stats->stats.icmpOutStats.dwErrors,
457 &stats->stats.icmpOutStats.dwDestUnreachs,
458 &stats->stats.icmpOutStats.dwTimeExcds,
459 &stats->stats.icmpOutStats.dwParmProbs,
460 &stats->stats.icmpOutStats.dwSrcQuenchs,
461 &stats->stats.icmpOutStats.dwRedirects,
462 &stats->stats.icmpOutStats.dwEchoReps,
463 &stats->stats.icmpOutStats.dwTimestamps,
464 &stats->stats.icmpOutStats.dwTimestampReps,
465 &stats->stats.icmpOutStats.dwAddrMasks,
466 &stats->stats.icmpOutStats.dwAddrMaskReps );
467 break;
470 fclose(fp);
471 ret = NO_ERROR;
474 #elif defined(HAVE_LIBKSTAT)
476 static char ip[] = "ip", icmp[] = "icmp";
477 kstat_ctl_t *kc;
478 kstat_t *ksp;
480 if ((kc = kstat_open()) &&
481 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
482 kstat_read( kc, ksp, NULL ) != -1 &&
483 ksp->ks_type == KSTAT_TYPE_NAMED)
485 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
486 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
487 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
488 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
489 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
490 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
491 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
492 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
493 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
494 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
495 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
496 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
497 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
498 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
499 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
500 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
501 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
502 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
503 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
504 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
505 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
506 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
507 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
508 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
509 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
510 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
511 ret = NO_ERROR;
513 if (kc) kstat_close( kc );
515 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && (defined(HAVE_STRUCT_ICMPSTAT_ICPS_INHIST) || defined(HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST))
517 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
518 struct icmpstat icmp_stat;
519 size_t needed = sizeof(icmp_stat);
520 int i;
522 if(sysctl(mib, ARRAY_SIZE(mib), &icmp_stat, &needed, NULL, 0) != -1)
524 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_INHIST
525 /*in stats */
526 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
527 for(i = 0; i <= ICMP_MAXTYPE; i++)
528 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
530 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
532 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
533 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
534 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
535 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
536 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
537 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
538 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
539 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
540 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
541 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
542 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
543 #endif
545 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST
546 /* out stats */
547 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
548 for(i = 0; i <= ICMP_MAXTYPE; i++)
549 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
551 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
553 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
554 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
555 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
556 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
557 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
558 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
559 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
560 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
561 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
562 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
563 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
564 #endif /* HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST */
565 ret = NO_ERROR;
568 #else /* ICMPCTL_STATS */
569 FIXME( "unimplemented\n" );
570 #endif
571 return ret;
574 /******************************************************************
575 * GetIcmpStatisticsEx (IPHLPAPI.@)
577 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
579 * PARAMS
580 * stats [Out] buffer for ICMP statistics
581 * family [In] specifies whether IPv4 or IPv6 statistics are returned
583 * RETURNS
584 * Success: NO_ERROR
585 * Failure: error code from winerror.h
587 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX stats, DWORD family)
589 DWORD ret = ERROR_NOT_SUPPORTED;
590 MIB_ICMP ipv4stats;
592 if (!stats) return ERROR_INVALID_PARAMETER;
593 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
594 memset( stats, 0, sizeof(MIB_ICMP_EX) );
596 if (family == WS_AF_INET6)
598 #ifdef __linux__
600 FILE *fp;
602 if ((fp = fopen("/proc/net/snmp6", "r")))
604 struct icmpstatstruct{
605 const char *name;
606 DWORD pos;
608 static const struct icmpstatstruct icmpinstatlist[] = {
609 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
610 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
611 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
612 { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
613 { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
614 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
615 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
616 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
617 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
618 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
619 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
620 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
621 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
622 { "Icmp6InRedirects", ND_REDIRECT },
623 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
625 static const struct icmpstatstruct icmpoutstatlist[] = {
626 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
627 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
628 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
629 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
630 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
631 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
632 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
633 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
634 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
635 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
636 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
637 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
638 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
639 { "Icmp6OutRedirects", ND_REDIRECT },
640 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
642 char buf[512], *ptr, *value;
643 DWORD res, i;
645 while ((ptr = fgets(buf, sizeof(buf), fp)))
647 if (!(value = strchr(buf, ' ')))
648 continue;
650 /* terminate the valuename */
651 ptr = value - 1;
652 *(ptr + 1) = '\0';
654 /* and strip leading spaces from value */
655 value += 1;
656 while (*value==' ') value++;
657 if ((ptr = strchr(value, '\n')))
658 *ptr='\0';
660 if (!_strnicmp(buf, "Icmp6InMsgs", -1))
662 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwMsgs = res;
663 continue;
666 if (!_strnicmp(buf, "Icmp6InErrors", -1))
668 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwErrors = res;
669 continue;
672 for (i = 0; i < ARRAY_SIZE(icmpinstatlist); i++)
674 if (!_strnicmp(buf, icmpinstatlist[i].name, -1))
676 if (sscanf(value, "%d", &res))
677 stats->icmpInStats.rgdwTypeCount[icmpinstatlist[i].pos] = res;
678 break;
682 if (!_strnicmp(buf, "Icmp6OutMsgs", -1))
684 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwMsgs = res;
685 continue;
688 if (!_strnicmp(buf, "Icmp6OutErrors", -1))
690 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwErrors = res;
691 continue;
694 for (i = 0; i < ARRAY_SIZE(icmpoutstatlist); i++)
696 if (!_strnicmp(buf, icmpoutstatlist[i].name, -1))
698 if (sscanf(value, "%d", &res))
699 stats->icmpOutStats.rgdwTypeCount[icmpoutstatlist[i].pos] = res;
700 break;
705 fclose(fp);
706 ret = NO_ERROR;
709 #else
710 FIXME( "unimplemented for IPv6\n" );
711 #endif
712 return ret;
715 ret = GetIcmpStatistics(&ipv4stats);
716 if (!ret)
718 stats->icmpInStats.dwMsgs = ipv4stats.stats.icmpInStats.dwMsgs;
719 stats->icmpInStats.dwErrors = ipv4stats.stats.icmpInStats.dwErrors;
720 stats->icmpInStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpInStats.dwDestUnreachs;
721 stats->icmpInStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpInStats.dwSrcQuenchs;
722 stats->icmpInStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpInStats.dwRedirects;
723 stats->icmpInStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpInStats.dwEchos;
724 stats->icmpInStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpInStats.dwTimeExcds;
725 stats->icmpInStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpInStats.dwParmProbs;
726 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpInStats.dwTimestamps;
727 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpInStats.dwTimestampReps;
728 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpInStats.dwAddrMasks;
729 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpInStats.dwAddrMaskReps;
731 stats->icmpOutStats.dwMsgs = ipv4stats.stats.icmpOutStats.dwMsgs;
732 stats->icmpOutStats.dwErrors = ipv4stats.stats.icmpOutStats.dwErrors;
733 stats->icmpOutStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpOutStats.dwDestUnreachs;
734 stats->icmpOutStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpOutStats.dwSrcQuenchs;
735 stats->icmpOutStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpOutStats.dwRedirects;
736 stats->icmpOutStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpOutStats.dwEchos;
737 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpOutStats.dwTimeExcds;
738 stats->icmpOutStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpOutStats.dwParmProbs;
739 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpOutStats.dwTimestamps;
740 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpOutStats.dwTimestampReps;
741 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpOutStats.dwAddrMasks;
742 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpOutStats.dwAddrMaskReps;
744 return ret;
747 /******************************************************************
748 * GetIpStatisticsEx (IPHLPAPI.@)
750 * Get the IPv4 and IPv6 statistics for the local computer.
752 * PARAMS
753 * stats [Out] buffer for IP statistics
754 * family [In] specifies whether IPv4 or IPv6 statistics are returned
756 * RETURNS
757 * Success: NO_ERROR
758 * Failure: error code from winerror.h
760 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS stats, DWORD family)
762 DWORD ret = ERROR_NOT_SUPPORTED;
763 MIB_IPFORWARDTABLE *fwd_table;
765 if (!stats) return ERROR_INVALID_PARAMETER;
766 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
767 memset( stats, 0, sizeof(*stats) );
769 stats->dwNumIf = stats->dwNumAddr = get_interface_indices( FALSE, NULL );
770 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
772 stats->dwNumRoutes = fwd_table->dwNumEntries;
773 HeapFree( GetProcessHeap(), 0, fwd_table );
776 if (family == WS_AF_INET6)
778 #ifdef __linux__
780 FILE *fp;
782 if ((fp = fopen("/proc/net/snmp6", "r")))
784 struct {
785 const char *name;
786 DWORD *elem;
787 } ipstatlist[] = {
788 { "Ip6InReceives", &stats->dwInReceives },
789 { "Ip6InHdrErrors", &stats->dwInHdrErrors },
790 { "Ip6InAddrErrors", &stats->dwInAddrErrors },
791 { "Ip6OutForwDatagrams", &stats->dwForwDatagrams },
792 { "Ip6InUnknownProtos", &stats->dwInUnknownProtos },
793 { "Ip6InDiscards", &stats->dwInDiscards },
794 { "Ip6InDelivers", &stats->dwInDelivers },
795 { "Ip6OutRequests", &stats->dwOutRequests },
796 { "Ip6OutDiscards", &stats->dwOutDiscards },
797 { "Ip6OutNoRoutes", &stats->dwOutNoRoutes },
798 { "Ip6ReasmTimeout", &stats->dwReasmTimeout },
799 { "Ip6ReasmReqds", &stats->dwReasmReqds },
800 { "Ip6ReasmOKs", &stats->dwReasmOks },
801 { "Ip6ReasmFails", &stats->dwReasmFails },
802 { "Ip6FragOKs", &stats->dwFragOks },
803 { "Ip6FragFails", &stats->dwFragFails },
804 { "Ip6FragCreates", &stats->dwFragCreates },
805 /* hmm, no routingDiscards, defaultTTL and forwarding? */
807 char buf[512], *ptr, *value;
808 DWORD res, i;
810 while ((ptr = fgets(buf, sizeof(buf), fp)))
812 if (!(value = strchr(buf, ' ')))
813 continue;
815 /* terminate the valuename */
816 ptr = value - 1;
817 *(ptr + 1) = '\0';
819 /* and strip leading spaces from value */
820 value += 1;
821 while (*value==' ') value++;
822 if ((ptr = strchr(value, '\n')))
823 *ptr='\0';
825 for (i = 0; i < ARRAY_SIZE(ipstatlist); i++)
826 if (!_strnicmp(buf, ipstatlist[i].name, -1) && sscanf(value, "%d", &res))
827 *ipstatlist[i].elem = res;
829 fclose(fp);
830 ret = NO_ERROR;
833 #else
834 FIXME( "unimplemented for IPv6\n" );
835 #endif
836 return ret;
839 #ifdef __linux__
841 FILE *fp;
843 if ((fp = fopen("/proc/net/snmp", "r")))
845 static const char hdr[] = "Ip:";
846 char buf[512], *ptr;
848 while ((ptr = fgets(buf, sizeof(buf), fp)))
850 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
851 /* last line was a header, get another */
852 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
853 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
855 ptr += sizeof(hdr);
856 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
857 &stats->u.dwForwarding,
858 &stats->dwDefaultTTL,
859 &stats->dwInReceives,
860 &stats->dwInHdrErrors,
861 &stats->dwInAddrErrors,
862 &stats->dwForwDatagrams,
863 &stats->dwInUnknownProtos,
864 &stats->dwInDiscards,
865 &stats->dwInDelivers,
866 &stats->dwOutRequests,
867 &stats->dwOutDiscards,
868 &stats->dwOutNoRoutes,
869 &stats->dwReasmTimeout,
870 &stats->dwReasmReqds,
871 &stats->dwReasmOks,
872 &stats->dwReasmFails,
873 &stats->dwFragOks,
874 &stats->dwFragFails,
875 &stats->dwFragCreates );
876 /* hmm, no routingDiscards */
877 break;
880 fclose(fp);
881 ret = NO_ERROR;
884 #elif defined(HAVE_LIBKSTAT)
886 static char ip[] = "ip";
887 kstat_ctl_t *kc;
888 kstat_t *ksp;
890 if ((kc = kstat_open()) &&
891 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
892 kstat_read( kc, ksp, NULL ) != -1 &&
893 ksp->ks_type == KSTAT_TYPE_NAMED)
895 stats->u.dwForwarding = kstat_get_ui32( ksp, "forwarding" );
896 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
897 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
898 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
899 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
900 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
901 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
902 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
903 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
904 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
905 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
906 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
907 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
908 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
909 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
910 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
911 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
912 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
913 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
914 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
915 ret = NO_ERROR;
917 if (kc) kstat_close( kc );
919 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
921 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
922 int ip_ttl, ip_forwarding;
923 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
924 struct ipstat ip_stat;
925 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
926 struct ip_stats ip_stat;
927 #endif
928 size_t needed;
930 needed = sizeof(ip_stat);
931 if(sysctl(mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0) == -1)
933 ERR ("failed to get ipstat\n");
934 return ERROR_NOT_SUPPORTED;
937 needed = sizeof(ip_ttl);
938 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
940 ERR ("failed to get ip Default TTL\n");
941 return ERROR_NOT_SUPPORTED;
944 needed = sizeof(ip_forwarding);
945 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
947 ERR ("failed to get ip forwarding\n");
948 return ERROR_NOT_SUPPORTED;
951 stats->u.dwForwarding = ip_forwarding;
952 stats->dwDefaultTTL = ip_ttl;
953 stats->dwInDelivers = ip_stat.ips_delivered;
954 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
955 stats->dwInAddrErrors = ip_stat.ips_cantforward;
956 stats->dwInReceives = ip_stat.ips_total;
957 stats->dwForwDatagrams = ip_stat.ips_forward;
958 stats->dwInUnknownProtos = ip_stat.ips_noproto;
959 stats->dwInDiscards = ip_stat.ips_fragdropped;
960 stats->dwOutDiscards = ip_stat.ips_odropped;
961 stats->dwReasmOks = ip_stat.ips_reassembled;
962 stats->dwFragOks = ip_stat.ips_fragmented;
963 stats->dwFragFails = ip_stat.ips_cantfrag;
964 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
965 stats->dwOutNoRoutes = ip_stat.ips_noroute;
966 stats->dwOutRequests = ip_stat.ips_localout;
967 stats->dwReasmReqds = ip_stat.ips_fragments;
968 ret = NO_ERROR;
970 #else
971 FIXME( "unimplemented for IPv4\n" );
972 #endif
973 return ret;
976 /******************************************************************
977 * GetIpStatistics (IPHLPAPI.@)
979 * Get the IP statistics for the local computer.
981 * PARAMS
982 * stats [Out] buffer for IP statistics
984 * RETURNS
985 * Success: NO_ERROR
986 * Failure: error code from winerror.h
988 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
990 return GetIpStatisticsEx(stats, WS_AF_INET);
993 /******************************************************************
994 * GetTcpStatisticsEx (IPHLPAPI.@)
996 * Get the IPv4 and IPv6 TCP statistics for the local computer.
998 * PARAMS
999 * stats [Out] buffer for TCP statistics
1000 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1002 * RETURNS
1003 * Success: NO_ERROR
1004 * Failure: error code from winerror.h
1006 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS stats, DWORD family)
1008 DWORD ret = ERROR_NOT_SUPPORTED;
1010 if (!stats) return ERROR_INVALID_PARAMETER;
1011 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1012 memset( stats, 0, sizeof(*stats) );
1014 if (family == WS_AF_INET6)
1016 FIXME( "unimplemented for IPv6\n" );
1017 return ret;
1020 #ifdef __linux__
1022 FILE *fp;
1024 if ((fp = fopen("/proc/net/snmp", "r")))
1026 static const char hdr[] = "Tcp:";
1027 MIB_TCPTABLE *tcp_table;
1028 char buf[512], *ptr;
1030 while ((ptr = fgets(buf, sizeof(buf), fp)))
1032 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
1033 /* last line was a header, get another */
1034 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1035 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
1037 ptr += sizeof(hdr);
1038 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
1039 &stats->u.dwRtoAlgorithm,
1040 &stats->dwRtoMin,
1041 &stats->dwRtoMax,
1042 &stats->dwMaxConn,
1043 &stats->dwActiveOpens,
1044 &stats->dwPassiveOpens,
1045 &stats->dwAttemptFails,
1046 &stats->dwEstabResets,
1047 &stats->dwCurrEstab,
1048 &stats->dwInSegs,
1049 &stats->dwOutSegs,
1050 &stats->dwRetransSegs,
1051 &stats->dwInErrs,
1052 &stats->dwOutRsts );
1053 break;
1056 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
1058 stats->dwNumConns = tcp_table->dwNumEntries;
1059 HeapFree( GetProcessHeap(), 0, tcp_table );
1061 fclose(fp);
1062 ret = NO_ERROR;
1065 #elif defined(HAVE_LIBKSTAT)
1067 static char tcp[] = "tcp";
1068 kstat_ctl_t *kc;
1069 kstat_t *ksp;
1071 if ((kc = kstat_open()) &&
1072 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
1073 kstat_read( kc, ksp, NULL ) != -1 &&
1074 ksp->ks_type == KSTAT_TYPE_NAMED)
1076 stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
1077 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
1078 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
1079 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
1080 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
1081 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
1082 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
1083 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
1084 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
1085 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
1086 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
1087 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
1088 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
1089 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
1090 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
1091 ret = NO_ERROR;
1093 if (kc) kstat_close( kc );
1095 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
1097 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
1098 #define TCPTV_MIN 2
1099 #define TCPTV_REXMTMAX 128
1100 #endif
1101 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
1102 #define hz 1000
1103 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
1104 struct tcpstat tcp_stat;
1105 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
1106 struct tcp_stats tcp_stat;
1107 #endif
1108 size_t needed = sizeof(tcp_stat);
1110 if(sysctl(mib, ARRAY_SIZE(mib), &tcp_stat, &needed, NULL, 0) != -1)
1112 stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
1113 stats->dwRtoMin = TCPTV_MIN;
1114 stats->dwRtoMax = TCPTV_REXMTMAX;
1115 stats->dwMaxConn = -1;
1116 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
1117 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
1118 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
1119 stats->dwEstabResets = tcp_stat.tcps_drops;
1120 stats->dwCurrEstab = 0;
1121 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
1122 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
1123 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
1124 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
1125 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
1126 stats->dwNumConns = tcp_stat.tcps_connects;
1127 ret = NO_ERROR;
1129 else ERR ("failed to get tcpstat\n");
1131 #else
1132 FIXME( "unimplemented\n" );
1133 #endif
1134 return ret;
1137 /******************************************************************
1138 * GetTcpStatistics (IPHLPAPI.@)
1140 * Get the TCP statistics for the local computer.
1142 * PARAMS
1143 * stats [Out] buffer for TCP statistics
1145 * RETURNS
1146 * Success: NO_ERROR
1147 * Failure: error code from winerror.h
1149 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
1151 return GetTcpStatisticsEx(stats, WS_AF_INET);
1154 /******************************************************************
1155 * GetUdpStatistics (IPHLPAPI.@)
1157 * Get the IPv4 and IPv6 UDP statistics for the local computer.
1159 * PARAMS
1160 * stats [Out] buffer for UDP statistics
1161 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1163 * RETURNS
1164 * Success: NO_ERROR
1165 * Failure: error code from winerror.h
1167 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS stats, DWORD family)
1169 DWORD ret = ERROR_NOT_SUPPORTED;
1171 if (!stats) return ERROR_INVALID_PARAMETER;
1172 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1173 memset( stats, 0, sizeof(*stats) );
1175 stats->dwNumAddrs = get_interface_indices( FALSE, NULL );
1177 if (family == WS_AF_INET6)
1179 #ifdef __linux__
1181 FILE *fp;
1183 if ((fp = fopen("/proc/net/snmp6", "r")))
1185 struct {
1186 const char *name;
1187 DWORD *elem;
1188 } udpstatlist[] = {
1189 { "Udp6InDatagrams", &stats->dwInDatagrams },
1190 { "Udp6NoPorts", &stats->dwNoPorts },
1191 { "Udp6InErrors", &stats->dwInErrors },
1192 { "Udp6OutDatagrams", &stats->dwOutDatagrams },
1194 char buf[512], *ptr, *value;
1195 DWORD res, i;
1197 while ((ptr = fgets(buf, sizeof(buf), fp)))
1199 if (!(value = strchr(buf, ' ')))
1200 continue;
1202 /* terminate the valuename */
1203 ptr = value - 1;
1204 *(ptr + 1) = '\0';
1206 /* and strip leading spaces from value */
1207 value += 1;
1208 while (*value==' ') value++;
1209 if ((ptr = strchr(value, '\n')))
1210 *ptr='\0';
1212 for (i = 0; i < ARRAY_SIZE(udpstatlist); i++)
1213 if (!_strnicmp(buf, udpstatlist[i].name, -1) && sscanf(value, "%d", &res))
1214 *udpstatlist[i].elem = res;
1216 fclose(fp);
1217 ret = NO_ERROR;
1220 #else
1221 FIXME( "unimplemented for IPv6\n" );
1222 #endif
1223 return ret;
1226 #ifdef __linux__
1228 FILE *fp;
1230 if ((fp = fopen("/proc/net/snmp", "r")))
1232 static const char hdr[] = "Udp:";
1233 char buf[512], *ptr;
1235 while ((ptr = fgets(buf, sizeof(buf), fp)))
1237 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
1238 /* last line was a header, get another */
1239 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1240 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
1242 ptr += sizeof(hdr);
1243 sscanf( ptr, "%u %u %u %u %u",
1244 &stats->dwInDatagrams, &stats->dwNoPorts,
1245 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
1246 break;
1249 fclose(fp);
1250 ret = NO_ERROR;
1253 #elif defined(HAVE_LIBKSTAT)
1255 static char udp[] = "udp";
1256 kstat_ctl_t *kc;
1257 kstat_t *ksp;
1258 MIB_UDPTABLE *udp_table;
1260 if ((kc = kstat_open()) &&
1261 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
1262 kstat_read( kc, ksp, NULL ) != -1 &&
1263 ksp->ks_type == KSTAT_TYPE_NAMED)
1265 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
1266 stats->dwNoPorts = 0; /* FIXME */
1267 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
1268 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
1269 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1271 stats->dwNumAddrs = udp_table->dwNumEntries;
1272 HeapFree( GetProcessHeap(), 0, udp_table );
1274 ret = NO_ERROR;
1276 if (kc) kstat_close( kc );
1278 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
1280 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
1281 struct udpstat udp_stat;
1282 MIB_UDPTABLE *udp_table;
1283 size_t needed = sizeof(udp_stat);
1285 if(sysctl(mib, ARRAY_SIZE(mib), &udp_stat, &needed, NULL, 0) != -1)
1287 stats->dwInDatagrams = udp_stat.udps_ipackets;
1288 stats->dwOutDatagrams = udp_stat.udps_opackets;
1289 stats->dwNoPorts = udp_stat.udps_noport;
1290 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
1291 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1293 stats->dwNumAddrs = udp_table->dwNumEntries;
1294 HeapFree( GetProcessHeap(), 0, udp_table );
1296 ret = NO_ERROR;
1298 else ERR ("failed to get udpstat\n");
1300 #else
1301 FIXME( "unimplemented for IPv4\n" );
1302 #endif
1303 return ret;
1306 /******************************************************************
1307 * GetUdpStatistics (IPHLPAPI.@)
1309 * Get the UDP statistics for the local computer.
1311 * PARAMS
1312 * stats [Out] buffer for UDP statistics
1314 * RETURNS
1315 * Success: NO_ERROR
1316 * Failure: error code from winerror.h
1318 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
1320 return GetUdpStatisticsEx(stats, WS_AF_INET);
1323 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
1324 DWORD *count, const MIB_IPFORWARDROW *row )
1326 if (table->dwNumEntries >= *count)
1328 MIB_IPFORWARDTABLE *new_table;
1329 DWORD new_count = table->dwNumEntries * 2;
1331 if (!(new_table = HeapReAlloc( heap, flags, table,
1332 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
1334 HeapFree( heap, 0, table );
1335 return NULL;
1337 *count = new_count;
1338 table = new_table;
1340 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1341 return table;
1344 static int compare_ipforward_rows(const void *a, const void *b)
1346 const MIB_IPFORWARDROW *rowA = a;
1347 const MIB_IPFORWARDROW *rowB = b;
1348 int ret;
1350 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
1351 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
1352 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
1353 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1356 /******************************************************************
1357 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1359 * Get the route table.
1360 * Like GetIpForwardTable(), but allocate the returned table from heap.
1362 * PARAMS
1363 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1364 * allocated and returned.
1365 * bOrder [In] whether to sort the table
1366 * heap [In] heap from which the table is allocated
1367 * flags [In] flags to HeapAlloc
1369 * RETURNS
1370 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1371 * on failure, NO_ERROR on success.
1373 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
1374 HANDLE heap, DWORD flags)
1376 MIB_IPFORWARDTABLE *table;
1377 MIB_IPFORWARDROW row;
1378 DWORD ret = NO_ERROR, count = 16;
1380 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1382 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1384 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1385 return ERROR_OUTOFMEMORY;
1387 table->dwNumEntries = 0;
1389 #ifdef __linux__
1391 FILE *fp;
1393 if ((fp = fopen("/proc/net/route", "r")))
1395 char buf[512], *ptr;
1396 DWORD flags;
1398 /* skip header line */
1399 ptr = fgets(buf, sizeof(buf), fp);
1400 while ((ptr = fgets(buf, sizeof(buf), fp)))
1402 memset( &row, 0, sizeof(row) );
1404 while (!isspace(*ptr)) ptr++;
1405 *ptr++ = 0;
1406 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1407 continue;
1409 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1410 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1411 flags = strtoul(ptr + 1, &ptr, 16);
1413 if (!(flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID;
1414 else if (flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1415 else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT;
1417 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1418 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1419 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1420 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1421 /* FIXME: other protos might be appropriate, e.g. the default
1422 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1423 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1425 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1426 break;
1428 fclose(fp);
1430 else ret = ERROR_NOT_SUPPORTED;
1432 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1434 void *data;
1435 int fd, len, namelen;
1436 mib2_ipRouteEntry_t *entry;
1437 char name[64];
1439 if ((fd = open_streams_mib( NULL )) != -1)
1441 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1443 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1445 row.dwForwardDest = entry->ipRouteDest;
1446 row.dwForwardMask = entry->ipRouteMask;
1447 row.dwForwardPolicy = 0;
1448 row.dwForwardNextHop = entry->ipRouteNextHop;
1449 row.u1.dwForwardType = entry->ipRouteType;
1450 row.u2.dwForwardProto = entry->ipRouteProto;
1451 row.dwForwardAge = entry->ipRouteAge;
1452 row.dwForwardNextHopAS = 0;
1453 row.dwForwardMetric1 = entry->ipRouteMetric1;
1454 row.dwForwardMetric2 = entry->ipRouteMetric2;
1455 row.dwForwardMetric3 = entry->ipRouteMetric3;
1456 row.dwForwardMetric4 = entry->ipRouteMetric4;
1457 row.dwForwardMetric5 = entry->ipRouteMetric5;
1458 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1459 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1460 name[namelen] = 0;
1461 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1462 if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1464 HeapFree( GetProcessHeap(), 0, data );
1466 close( fd );
1468 else ret = ERROR_NOT_SUPPORTED;
1470 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1472 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1473 size_t needed;
1474 char *buf = NULL, *lim, *next, *addrPtr;
1475 struct rt_msghdr *rtm;
1477 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1479 ERR ("sysctl 1 failed!\n");
1480 ret = ERROR_NOT_SUPPORTED;
1481 goto done;
1484 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1485 if (!buf)
1487 ret = ERROR_OUTOFMEMORY;
1488 goto done;
1491 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1493 ret = ERROR_NOT_SUPPORTED;
1494 goto done;
1497 lim = buf + needed;
1498 for (next = buf; next < lim; next += rtm->rtm_msglen)
1500 int i;
1502 rtm = (struct rt_msghdr *)next;
1504 if (rtm->rtm_type != RTM_GET)
1506 WARN ("Got unexpected message type 0x%x!\n",
1507 rtm->rtm_type);
1508 continue;
1511 /* Ignore gateway routes which are multicast */
1512 if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST))
1513 continue;
1515 memset( &row, 0, sizeof(row) );
1516 row.dwForwardIfIndex = rtm->rtm_index;
1517 row.u1.ForwardType = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
1518 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1519 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1521 addrPtr = (char *)(rtm + 1);
1523 for (i = 1; i; i <<= 1)
1525 struct sockaddr *sa;
1526 DWORD addr;
1528 if (!(i & rtm->rtm_addrs))
1529 continue;
1531 sa = (struct sockaddr *)addrPtr;
1532 ADVANCE (addrPtr, sa);
1534 /* default routes are encoded by length-zero sockaddr */
1535 if (sa->sa_len == 0) {
1536 addr = 0;
1537 }else {
1538 switch(sa->sa_family) {
1539 case AF_INET: {
1540 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1541 addr = sin->sin_addr.s_addr;
1542 break;
1544 #ifdef AF_LINK
1545 case AF_LINK:
1546 if(i == RTA_GATEWAY && row.u1.ForwardType == MIB_IPROUTE_TYPE_DIRECT) {
1547 /* For direct route we may simply use dest addr as next hop */
1548 C_ASSERT(RTA_DST < RTA_GATEWAY);
1549 addr = row.dwForwardDest;
1550 break;
1552 /* fallthrough */
1553 #endif
1554 default:
1555 WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family);
1556 addr = 0;
1560 switch (i)
1562 case RTA_DST: row.dwForwardDest = addr; break;
1563 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1564 case RTA_NETMASK: row.dwForwardMask = addr; break;
1565 default:
1566 WARN ("Unexpected address type 0x%x\n", i);
1570 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1571 break;
1573 done:
1574 HeapFree( GetProcessHeap (), 0, buf );
1576 #else
1577 FIXME( "not implemented\n" );
1578 ret = ERROR_NOT_SUPPORTED;
1579 #endif
1581 if (!table) return ERROR_OUTOFMEMORY;
1582 if (!ret)
1584 if (bOrder && table->dwNumEntries)
1585 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1586 *ppIpForwardTable = table;
1588 else HeapFree( heap, flags, table );
1589 TRACE( "returning ret %u table %p\n", ret, table );
1590 return ret;
1593 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1594 DWORD *count, const MIB_IPNETROW *row )
1596 if (table->dwNumEntries >= *count)
1598 MIB_IPNETTABLE *new_table;
1599 DWORD new_count = table->dwNumEntries * 2;
1601 if (!(new_table = HeapReAlloc( heap, flags, table,
1602 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1604 HeapFree( heap, 0, table );
1605 return NULL;
1607 *count = new_count;
1608 table = new_table;
1610 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1611 return table;
1614 static int compare_ipnet_rows(const void *a, const void *b)
1616 const MIB_IPNETROW *rowA = a;
1617 const MIB_IPNETROW *rowB = b;
1619 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1623 /******************************************************************
1624 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1626 * Get the IP-to-physical address mapping table.
1627 * Like GetIpNetTable(), but allocate the returned table from heap.
1629 * PARAMS
1630 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1631 * allocated and returned.
1632 * bOrder [In] whether to sort the table
1633 * heap [In] heap from which the table is allocated
1634 * flags [In] flags to HeapAlloc
1636 * RETURNS
1637 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1638 * on failure, NO_ERROR on success.
1640 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1641 HANDLE heap, DWORD flags)
1643 MIB_IPNETTABLE *table;
1644 MIB_IPNETROW row;
1645 DWORD ret = NO_ERROR, count = 16;
1647 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1649 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1651 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1652 return ERROR_OUTOFMEMORY;
1654 table->dwNumEntries = 0;
1656 #ifdef __linux__
1658 FILE *fp;
1660 if ((fp = fopen("/proc/net/arp", "r")))
1662 char buf[512], *ptr;
1663 DWORD flags;
1665 /* skip header line */
1666 ptr = fgets(buf, sizeof(buf), fp);
1667 while ((ptr = fgets(buf, sizeof(buf), fp)))
1669 memset( &row, 0, sizeof(row) );
1671 row.dwAddr = inet_addr(ptr);
1672 while (*ptr && !isspace(*ptr)) ptr++;
1673 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1674 flags = strtoul(ptr + 1, &ptr, 16);
1676 #ifdef ATF_COM
1677 if (flags & ATF_COM) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1678 else
1679 #endif
1680 #ifdef ATF_PERM
1681 if (flags & ATF_PERM) row.u.Type = MIB_IPNET_TYPE_STATIC;
1682 else
1683 #endif
1684 row.u.Type = MIB_IPNET_TYPE_OTHER;
1686 while (*ptr && isspace(*ptr)) ptr++;
1687 while (*ptr && !isspace(*ptr))
1689 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1690 if (*ptr) ptr++;
1692 while (*ptr && isspace(*ptr)) ptr++;
1693 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1694 while (*ptr && isspace(*ptr)) ptr++;
1695 getInterfaceIndexByName(ptr, &row.dwIndex);
1697 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1698 break;
1700 fclose(fp);
1702 else ret = ERROR_NOT_SUPPORTED;
1704 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1706 void *data;
1707 int fd, len, namelen;
1708 mib2_ipNetToMediaEntry_t *entry;
1709 char name[64];
1711 if ((fd = open_streams_mib( NULL )) != -1)
1713 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1715 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1717 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1718 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1719 row.dwAddr = entry->ipNetToMediaNetAddress;
1720 row.u.Type = entry->ipNetToMediaType;
1721 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1722 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1723 name[namelen] = 0;
1724 getInterfaceIndexByName( name, &row.dwIndex );
1725 if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1727 HeapFree( GetProcessHeap(), 0, data );
1729 close( fd );
1731 else ret = ERROR_NOT_SUPPORTED;
1733 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1735 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1736 size_t needed;
1737 char *buf = NULL, *lim, *next;
1738 struct rt_msghdr *rtm;
1739 struct sockaddr_inarp *sinarp;
1740 struct sockaddr_dl *sdl;
1742 if (sysctl (mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0) == -1)
1744 ERR ("failed to get arp table\n");
1745 ret = ERROR_NOT_SUPPORTED;
1746 goto done;
1749 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1750 if (!buf)
1752 ret = ERROR_OUTOFMEMORY;
1753 goto done;
1756 if (sysctl (mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0) == -1)
1758 ret = ERROR_NOT_SUPPORTED;
1759 goto done;
1762 lim = buf + needed;
1763 next = buf;
1764 while(next < lim)
1766 rtm = (struct rt_msghdr *)next;
1767 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1768 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1769 if(sdl->sdl_alen) /* arp entry */
1771 memset( &row, 0, sizeof(row) );
1772 row.dwAddr = sinarp->sin_addr.s_addr;
1773 row.dwIndex = sdl->sdl_index;
1774 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1775 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1776 if(rtm->rtm_rmx.rmx_expire == 0) row.u.Type = MIB_IPNET_TYPE_STATIC;
1777 else if(sinarp->sin_other & SIN_PROXY) row.u.Type = MIB_IPNET_TYPE_OTHER;
1778 else if(rtm->rtm_rmx.rmx_expire != 0) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1779 else row.u.Type = MIB_IPNET_TYPE_INVALID;
1781 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1782 break;
1784 next += rtm->rtm_msglen;
1786 done:
1787 HeapFree( GetProcessHeap (), 0, buf );
1789 #else
1790 FIXME( "not implemented\n" );
1791 ret = ERROR_NOT_SUPPORTED;
1792 #endif
1794 if (!table) return ERROR_OUTOFMEMORY;
1795 if (!ret)
1797 if (bOrder && table->dwNumEntries)
1798 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1799 *ppIpNetTable = table;
1801 else HeapFree( heap, flags, table );
1802 TRACE( "returning ret %u table %p\n", ret, table );
1803 return ret;
1806 static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
1808 DWORD table_size;
1810 switch (class)
1812 case TCP_TABLE_BASIC_LISTENER:
1813 case TCP_TABLE_BASIC_CONNECTIONS:
1814 case TCP_TABLE_BASIC_ALL:
1816 table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
1817 if (row_size) *row_size = sizeof(MIB_TCPROW);
1818 break;
1820 case TCP_TABLE_OWNER_PID_LISTENER:
1821 case TCP_TABLE_OWNER_PID_CONNECTIONS:
1822 case TCP_TABLE_OWNER_PID_ALL:
1824 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
1825 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
1826 break;
1828 case TCP_TABLE_OWNER_MODULE_LISTENER:
1829 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1830 case TCP_TABLE_OWNER_MODULE_ALL:
1832 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]);
1833 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_MODULE);
1834 break;
1836 default:
1837 ERR("unhandled class %u\n", class);
1838 return 0;
1840 return table_size;
1843 static MIB_TCPTABLE *append_tcp_row( TCP_TABLE_CLASS class, HANDLE heap, DWORD flags,
1844 MIB_TCPTABLE *table, DWORD *count,
1845 const MIB_TCPROW_OWNER_MODULE *row, DWORD row_size )
1847 if (table->dwNumEntries >= *count)
1849 MIB_TCPTABLE *new_table;
1850 DWORD new_count = table->dwNumEntries * 2, new_table_size;
1852 new_table_size = get_tcp_table_sizes( class, new_count, NULL );
1853 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
1855 HeapFree( heap, 0, table );
1856 return NULL;
1858 *count = new_count;
1859 table = new_table;
1861 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
1862 table->dwNumEntries++;
1863 return table;
1867 /* Why not a lookup table? Because the TCPS_* constants are different
1868 on different platforms */
1869 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1871 switch (state)
1873 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1874 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1875 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1876 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1877 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1878 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1879 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1880 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1881 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1882 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1883 default:
1884 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1888 static int compare_tcp_rows(const void *a, const void *b)
1890 const MIB_TCPROW *rowA = a;
1891 const MIB_TCPROW *rowB = b;
1892 int ret;
1894 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1895 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1896 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1897 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1898 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1901 struct pid_map
1903 unsigned int pid;
1904 unsigned int unix_pid;
1907 static struct pid_map *get_pid_map( unsigned int *num_entries )
1909 HANDLE snapshot = NULL;
1910 struct pid_map *map;
1911 unsigned int i = 0, count = 16, size = count * sizeof(*map);
1912 NTSTATUS ret;
1914 if (!(map = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
1916 SERVER_START_REQ( create_snapshot )
1918 req->flags = SNAP_PROCESS;
1919 req->attributes = 0;
1920 if (!(ret = wine_server_call( req )))
1921 snapshot = wine_server_ptr_handle( reply->handle );
1923 SERVER_END_REQ;
1925 *num_entries = 0;
1926 while (ret == STATUS_SUCCESS)
1928 SERVER_START_REQ( next_process )
1930 req->handle = wine_server_obj_handle( snapshot );
1931 req->reset = (i == 0);
1932 if (!(ret = wine_server_call( req )))
1934 if (i >= count)
1936 struct pid_map *new_map;
1937 count *= 2;
1938 size = count * sizeof(*new_map);
1940 if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, size )))
1942 HeapFree( GetProcessHeap(), 0, map );
1943 map = NULL;
1944 goto done;
1946 map = new_map;
1948 map[i].pid = reply->pid;
1949 map[i].unix_pid = reply->unix_pid;
1950 (*num_entries)++;
1951 i++;
1954 SERVER_END_REQ;
1957 done:
1958 NtClose( snapshot );
1959 return map;
1962 static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, UINT_PTR inode )
1964 #ifdef __linux__
1965 unsigned int i, len_socket;
1966 char socket[32];
1968 sprintf( socket, "socket:[%lu]", inode );
1969 len_socket = strlen( socket );
1970 for (i = 0; i < num_entries; i++)
1972 char dir[32];
1973 struct dirent *dirent;
1974 DIR *dirfd;
1976 sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
1977 if ((dirfd = opendir( dir )))
1979 while ((dirent = readdir( dirfd )))
1981 char link[sizeof(dirent->d_name) + 32], name[32];
1982 int len;
1984 sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
1985 if ((len = readlink( link, name, sizeof(name) - 1 )) > 0) name[len] = 0;
1986 if (len == len_socket && !strcmp( socket, name ))
1988 closedir( dirfd );
1989 return map[i].pid;
1992 closedir( dirfd );
1995 return 0;
1996 #elif defined(HAVE_LIBPROCSTAT)
1997 struct procstat *pstat;
1998 struct kinfo_proc *proc;
1999 struct filestat_list *fds;
2000 struct filestat *fd;
2001 struct sockstat sock;
2002 unsigned int i, proc_count;
2004 pstat = procstat_open_sysctl();
2005 if (!pstat) return 0;
2007 for (i = 0; i < num_entries; i++)
2009 proc = procstat_getprocs( pstat, KERN_PROC_PID, map[i].unix_pid, &proc_count );
2010 if (!proc || proc_count < 1) continue;
2012 fds = procstat_getfiles( pstat, proc, 0 );
2013 if (!fds)
2015 procstat_freeprocs( pstat, proc );
2016 continue;
2019 STAILQ_FOREACH( fd, fds, next )
2021 char errbuf[_POSIX2_LINE_MAX];
2023 if (fd->fs_type != PS_FST_TYPE_SOCKET) continue;
2025 procstat_get_socket_info( pstat, fd, &sock, errbuf );
2027 if (sock.so_pcb == inode)
2029 procstat_freefiles( pstat, fds );
2030 procstat_freeprocs( pstat, proc );
2031 procstat_close( pstat );
2032 return map[i].pid;
2036 procstat_freefiles( pstat, fds );
2037 procstat_freeprocs( pstat, proc );
2040 procstat_close( pstat );
2041 return 0;
2042 #elif defined(HAVE_PROC_PIDINFO)
2043 struct proc_fdinfo *fds;
2044 struct socket_fdinfo sock;
2045 unsigned int i, j, n;
2047 for (i = 0; i < num_entries; i++)
2049 int fd_len = proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, NULL, 0 );
2050 if (fd_len <= 0) continue;
2052 fds = HeapAlloc( GetProcessHeap(), 0, fd_len );
2053 if (!fds) continue;
2055 proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, fds, fd_len );
2056 n = fd_len / sizeof(struct proc_fdinfo);
2057 for (j = 0; j < n; j++)
2059 if (fds[j].proc_fdtype != PROX_FDTYPE_SOCKET) continue;
2061 proc_pidfdinfo( map[i].unix_pid, fds[j].proc_fd, PROC_PIDFDSOCKETINFO, &sock, sizeof(sock) );
2062 if (sock.psi.soi_pcb == inode)
2064 HeapFree( GetProcessHeap(), 0, fds );
2065 return map[i].pid;
2069 HeapFree( GetProcessHeap(), 0, fds );
2071 return 0;
2072 #else
2073 FIXME( "not implemented\n" );
2074 return 0;
2075 #endif
2078 static BOOL match_class( TCP_TABLE_CLASS class, MIB_TCP_STATE state )
2080 switch (class)
2082 case TCP_TABLE_BASIC_ALL:
2083 case TCP_TABLE_OWNER_PID_ALL:
2084 case TCP_TABLE_OWNER_MODULE_ALL:
2085 return TRUE;
2087 case TCP_TABLE_BASIC_LISTENER:
2088 case TCP_TABLE_OWNER_PID_LISTENER:
2089 case TCP_TABLE_OWNER_MODULE_LISTENER:
2090 if (state == MIB_TCP_STATE_LISTEN) return TRUE;
2091 return FALSE;
2093 case TCP_TABLE_BASIC_CONNECTIONS:
2094 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2095 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2096 if (state == MIB_TCP_STATE_ESTAB) return TRUE;
2097 return FALSE;
2099 default:
2100 ERR( "unhandled class %u\n", class );
2101 return FALSE;
2105 DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2106 DWORD *size )
2108 MIB_TCPTABLE *table;
2109 MIB_TCPROW_OWNER_MODULE row;
2110 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2112 if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
2113 return ERROR_INVALID_PARAMETER;
2115 if (!(table = HeapAlloc( heap, flags, table_size )))
2116 return ERROR_OUTOFMEMORY;
2118 table->dwNumEntries = 0;
2120 #ifdef __linux__
2122 FILE *fp;
2124 if ((fp = fopen("/proc/net/tcp", "r")))
2126 char buf[512], *ptr;
2127 struct pid_map *map = NULL;
2128 unsigned int dummy, num_entries = 0;
2129 int inode;
2131 if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
2133 /* skip header line */
2134 ptr = fgets(buf, sizeof(buf), fp);
2135 while ((ptr = fgets(buf, sizeof(buf), fp)))
2137 if (sscanf( ptr, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy,
2138 &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
2139 &row.dwRemotePort, &row.dwState, &inode ) != 7)
2140 continue;
2141 row.dwLocalPort = htons( row.dwLocalPort );
2142 row.dwRemotePort = htons( row.dwRemotePort );
2143 row.dwState = TCPStateToMIBState( row.dwState );
2144 if (!match_class( class, row.dwState )) continue;
2146 if (class >= TCP_TABLE_OWNER_PID_LISTENER)
2147 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2148 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2150 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2151 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2153 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2154 break;
2156 HeapFree( GetProcessHeap(), 0, map );
2157 fclose( fp );
2159 else ret = ERROR_NOT_SUPPORTED;
2161 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2163 void *data;
2164 int fd, len;
2165 mib2_tcpConnEntry_t *entry;
2167 if ((fd = open_streams_mib( "tcp" )) != -1)
2169 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
2171 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2173 row.dwLocalAddr = entry->tcpConnLocalAddress;
2174 row.dwLocalPort = htons( entry->tcpConnLocalPort );
2175 row.dwRemoteAddr = entry->tcpConnRemAddress;
2176 row.dwRemotePort = htons( entry->tcpConnRemPort );
2177 row.dwState = entry->tcpConnState;
2178 if (!match_class( class, row.dwState )) continue;
2179 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2180 break;
2182 HeapFree( GetProcessHeap(), 0, data );
2184 close( fd );
2186 else ret = ERROR_NOT_SUPPORTED;
2188 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2190 size_t Len = 0;
2191 char *Buf = NULL;
2192 struct xinpgen *pXIG, *pOrigXIG;
2193 struct pid_map *pMap = NULL;
2194 unsigned NumEntries;
2196 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
2198 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2199 ret = ERROR_NOT_SUPPORTED;
2200 goto done;
2203 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2204 if (!Buf)
2206 ret = ERROR_OUTOFMEMORY;
2207 goto done;
2210 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
2212 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2213 ret = ERROR_NOT_SUPPORTED;
2214 goto done;
2217 if (class >= TCP_TABLE_OWNER_PID_LISTENER) pMap = get_pid_map( &NumEntries );
2219 /* Might be nothing here; first entry is just a header it seems */
2220 if (Len <= sizeof (struct xinpgen)) goto done;
2222 pOrigXIG = (struct xinpgen *)Buf;
2223 pXIG = pOrigXIG;
2225 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2226 pXIG->xig_len > sizeof (struct xinpgen);
2227 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2229 struct tcpcb *pTCPData = NULL;
2230 struct inpcb *pINData;
2231 struct xsocket *pSockData;
2233 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
2234 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
2235 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
2237 /* Ignore sockets for other protocols */
2238 if (pSockData->xso_protocol != IPPROTO_TCP)
2239 continue;
2241 /* Ignore PCBs that were freed while generating the data */
2242 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2243 continue;
2245 /* we're only interested in IPv4 addresses */
2246 if (!(pINData->inp_vflag & INP_IPV4) ||
2247 (pINData->inp_vflag & INP_IPV6))
2248 continue;
2250 /* If all 0's, skip it */
2251 if (!pINData->inp_laddr.s_addr &&
2252 !pINData->inp_lport &&
2253 !pINData->inp_faddr.s_addr &&
2254 !pINData->inp_fport)
2255 continue;
2257 /* Fill in structure details */
2258 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2259 row.dwLocalPort = pINData->inp_lport;
2260 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
2261 row.dwRemotePort = pINData->inp_fport;
2262 row.dwState = TCPStateToMIBState (pTCPData->t_state);
2263 if (!match_class( class, row.dwState )) continue;
2264 if (class >= TCP_TABLE_OWNER_PID_LISTENER)
2265 row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
2266 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2268 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2269 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2271 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2272 break;
2275 done:
2276 HeapFree( GetProcessHeap(), 0, pMap );
2277 HeapFree (GetProcessHeap (), 0, Buf);
2279 #else
2280 FIXME( "not implemented\n" );
2281 ret = ERROR_NOT_SUPPORTED;
2282 #endif
2284 if (!table) return ERROR_OUTOFMEMORY;
2285 if (!ret)
2287 if (order && table->dwNumEntries)
2288 qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
2289 *tablep = table;
2291 else HeapFree( heap, flags, table );
2292 if (size) *size = get_tcp_table_sizes( class, count, NULL );
2293 TRACE( "returning ret %u table %p\n", ret, table );
2294 return ret;
2297 /******************************************************************
2298 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
2300 * Get the TCP connection table.
2301 * Like GetTcpTable(), but allocate the returned table from heap.
2303 * PARAMS
2304 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2305 * allocated and returned.
2306 * bOrder [In] whether to sort the table
2307 * heap [In] heap from which the table is allocated
2308 * flags [In] flags to HeapAlloc
2310 * RETURNS
2311 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2312 * returns otherwise.
2314 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
2315 HANDLE heap, DWORD flags )
2317 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
2319 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
2320 return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
2323 /******************************************************************
2324 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
2326 * Get the TCP connection table.
2327 * Like GetTcpTable(), but allocate the returned table from heap.
2329 * PARAMS
2330 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE_EX is
2331 * allocated and returned.
2332 * bOrder [In] whether to sort the table
2333 * heap [In] heap from which the table is allocated
2334 * flags [In] flags to HeapAlloc
2335 * family [In] address family [AF_INET|AF_INET6]
2337 * RETURNS
2338 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2339 * returns otherwise.
2341 DWORD WINAPI AllocateAndGetTcpExTableFromStack( VOID **ppTcpTable, BOOL bOrder,
2342 HANDLE heap, DWORD flags, DWORD family )
2344 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x, family %u\n",
2345 ppTcpTable, bOrder, heap, flags, family);
2347 if (!ppTcpTable || !family)
2348 return ERROR_INVALID_PARAMETER;
2350 if (family != WS_AF_INET)
2352 FIXME( "family = %u not supported\n", family );
2353 return ERROR_NOT_SUPPORTED;
2356 return build_tcp_table( TCP_TABLE_OWNER_PID_ALL, ppTcpTable, bOrder, heap, flags, NULL );
2359 static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2361 DWORD table_size;
2363 switch (class)
2365 case UDP_TABLE_BASIC:
2367 table_size = FIELD_OFFSET(MIB_UDPTABLE, table[row_count]);
2368 if (row_size) *row_size = sizeof(MIB_UDPROW);
2369 break;
2371 case UDP_TABLE_OWNER_PID:
2373 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table[row_count]);
2374 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_PID);
2375 break;
2377 case UDP_TABLE_OWNER_MODULE:
2379 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table[row_count]);
2380 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_MODULE);
2381 break;
2383 default:
2384 ERR("unhandled class %u\n", class);
2385 return 0;
2387 return table_size;
2390 static MIB_UDPTABLE *append_udp_row( UDP_TABLE_CLASS class, HANDLE heap, DWORD flags,
2391 MIB_UDPTABLE *table, DWORD *count,
2392 const MIB_UDPROW_OWNER_MODULE *row, DWORD row_size )
2394 if (table->dwNumEntries >= *count)
2396 MIB_UDPTABLE *new_table;
2397 DWORD new_count = table->dwNumEntries * 2, new_table_size;
2399 new_table_size = get_udp_table_sizes( class, new_count, NULL );
2400 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
2402 HeapFree( heap, 0, table );
2403 return NULL;
2405 *count = new_count;
2406 table = new_table;
2408 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
2409 table->dwNumEntries++;
2410 return table;
2413 static int compare_udp_rows(const void *a, const void *b)
2415 const MIB_UDPROW *rowA = a;
2416 const MIB_UDPROW *rowB = b;
2417 int ret;
2419 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
2420 return rowA->dwLocalPort - rowB->dwLocalPort;
2423 DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2424 DWORD *size )
2426 MIB_UDPTABLE *table;
2427 MIB_UDPROW_OWNER_MODULE row;
2428 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2430 if (!(table_size = get_udp_table_sizes( class, count, &row_size )))
2431 return ERROR_INVALID_PARAMETER;
2433 if (!(table = HeapAlloc( heap, flags, table_size )))
2434 return ERROR_OUTOFMEMORY;
2436 table->dwNumEntries = 0;
2437 memset( &row, 0, sizeof(row) );
2439 #ifdef __linux__
2441 FILE *fp;
2443 if ((fp = fopen( "/proc/net/udp", "r" )))
2445 char buf[512], *ptr;
2446 struct pid_map *map = NULL;
2447 unsigned int dummy, num_entries = 0;
2448 int inode;
2450 if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
2452 /* skip header line */
2453 ptr = fgets( buf, sizeof(buf), fp );
2454 while ((ptr = fgets( buf, sizeof(buf), fp )))
2456 if (sscanf( ptr, "%u: %x:%x %*s %*s %*s %*s %*s %*s %*s %d", &dummy,
2457 &row.dwLocalAddr, &row.dwLocalPort, &inode ) != 4)
2458 continue;
2459 row.dwLocalPort = htons( row.dwLocalPort );
2461 if (class >= UDP_TABLE_OWNER_PID)
2462 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2463 if (class >= UDP_TABLE_OWNER_MODULE)
2465 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2466 row.u.dwFlags = 0;
2467 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2469 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size )))
2470 break;
2472 HeapFree( GetProcessHeap(), 0, map );
2473 fclose( fp );
2475 else ret = ERROR_NOT_SUPPORTED;
2477 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2479 void *data;
2480 int fd, len;
2481 mib2_udpEntry_t *entry;
2483 if ((fd = open_streams_mib( "udp" )) != -1)
2485 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
2487 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2489 row.dwLocalAddr = entry->udpLocalAddress;
2490 row.dwLocalPort = htons( entry->udpLocalPort );
2491 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size ))) break;
2493 HeapFree( GetProcessHeap(), 0, data );
2495 close( fd );
2497 else ret = ERROR_NOT_SUPPORTED;
2499 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2501 size_t Len = 0;
2502 char *Buf = NULL;
2503 struct xinpgen *pXIG, *pOrigXIG;
2504 struct pid_map *pMap = NULL;
2505 unsigned NumEntries;
2507 if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
2509 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2510 ret = ERROR_NOT_SUPPORTED;
2511 goto done;
2514 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2515 if (!Buf)
2517 ret = ERROR_OUTOFMEMORY;
2518 goto done;
2521 if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
2523 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2524 ret = ERROR_NOT_SUPPORTED;
2525 goto done;
2528 if (class >= UDP_TABLE_OWNER_PID)
2529 pMap = get_pid_map( &NumEntries );
2531 /* Might be nothing here; first entry is just a header it seems */
2532 if (Len <= sizeof (struct xinpgen)) goto done;
2534 pOrigXIG = (struct xinpgen *)Buf;
2535 pXIG = pOrigXIG;
2537 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2538 pXIG->xig_len > sizeof (struct xinpgen);
2539 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2541 struct inpcb *pINData;
2542 struct xsocket *pSockData;
2544 pINData = &((struct xinpcb *)pXIG)->xi_inp;
2545 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
2547 /* Ignore sockets for other protocols */
2548 if (pSockData->xso_protocol != IPPROTO_UDP)
2549 continue;
2551 /* Ignore PCBs that were freed while generating the data */
2552 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2553 continue;
2555 /* we're only interested in IPv4 addresses */
2556 if (!(pINData->inp_vflag & INP_IPV4) ||
2557 (pINData->inp_vflag & INP_IPV6))
2558 continue;
2560 /* If all 0's, skip it */
2561 if (!pINData->inp_laddr.s_addr &&
2562 !pINData->inp_lport)
2563 continue;
2565 /* Fill in structure details */
2566 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2567 row.dwLocalPort = pINData->inp_lport;
2568 if (class >= UDP_TABLE_OWNER_PID)
2569 row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
2570 if (class >= UDP_TABLE_OWNER_MODULE)
2572 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2573 row.u.dwFlags = 0;
2574 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2576 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size ))) break;
2579 done:
2580 HeapFree( GetProcessHeap(), 0, pMap );
2581 HeapFree (GetProcessHeap (), 0, Buf);
2583 #else
2584 FIXME( "not implemented\n" );
2585 ret = ERROR_NOT_SUPPORTED;
2586 #endif
2588 if (!table) return ERROR_OUTOFMEMORY;
2589 if (!ret)
2591 if (order && table->dwNumEntries)
2592 qsort( table->table, table->dwNumEntries, row_size, compare_udp_rows );
2593 *tablep = table;
2595 else HeapFree( heap, flags, table );
2596 if (size) *size = get_udp_table_sizes( class, count, NULL );
2597 TRACE( "returning ret %u table %p\n", ret, table );
2598 return ret;
2601 static DWORD get_udp6_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2603 DWORD table_size;
2605 switch (class)
2607 case UDP_TABLE_BASIC:
2609 table_size = FIELD_OFFSET(MIB_UDP6TABLE, table[row_count]);
2610 if (row_size) *row_size = sizeof(MIB_UDP6ROW);
2611 break;
2613 case UDP_TABLE_OWNER_PID:
2615 table_size = FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID, table[row_count]);
2616 if (row_size) *row_size = sizeof(MIB_UDP6ROW_OWNER_PID);
2617 break;
2619 case UDP_TABLE_OWNER_MODULE:
2621 table_size = FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE, table[row_count]);
2622 if (row_size) *row_size = sizeof(MIB_UDP6ROW_OWNER_MODULE);
2623 break;
2625 default:
2626 ERR("unhandled class %u\n", class);
2627 return 0;
2629 return table_size;
2632 static MIB_UDP6TABLE *append_udp6_row( UDP_TABLE_CLASS class, HANDLE heap, DWORD flags,
2633 MIB_UDP6TABLE *table, DWORD *count,
2634 const MIB_UDP6ROW_OWNER_MODULE *row, DWORD row_size )
2636 if (table->dwNumEntries >= *count)
2638 MIB_UDP6TABLE *new_table;
2639 DWORD new_count = table->dwNumEntries * 2, new_table_size;
2641 new_table_size = get_udp6_table_sizes( class, new_count, NULL );
2642 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
2644 HeapFree( heap, 0, table );
2645 return NULL;
2647 *count = new_count;
2648 table = new_table;
2650 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
2651 table->dwNumEntries++;
2652 return table;
2655 static int compare_udp6_rows(const void *a, const void *b)
2657 const MIB_UDP6ROW *rowA = a;
2658 const MIB_UDP6ROW *rowB = b;
2659 int ret;
2661 if ((ret = memcmp(&rowA->dwLocalAddr, &rowB->dwLocalAddr, sizeof(rowA->dwLocalAddr)) != 0)) return ret;
2662 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
2663 return rowA->dwLocalPort - rowB->dwLocalPort;
2666 struct ipv6_addr_scope
2668 IN6_ADDR addr;
2669 DWORD scope;
2672 static struct ipv6_addr_scope *get_ipv6_addr_scope_table(unsigned int *size)
2674 struct ipv6_addr_scope *table = NULL;
2675 unsigned int table_size = 0;
2677 if (!(table = HeapAlloc( GetProcessHeap(), 0, sizeof(table[0]) )))
2678 return NULL;
2680 #ifdef __linux__
2682 FILE *fp;
2683 char buf[512], *ptr;
2685 if (!(fp = fopen( "/proc/net/if_inet6", "r" )))
2686 goto failed;
2688 while ((ptr = fgets( buf, sizeof(buf), fp )))
2690 WORD a[8];
2691 DWORD scope;
2692 struct ipv6_addr_scope *new_table;
2693 struct ipv6_addr_scope *entry;
2694 unsigned int i;
2696 if (sscanf( ptr, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*s %*s %x",
2697 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &scope ) != 9)
2698 continue;
2700 table_size++;
2701 if (!(new_table = HeapReAlloc( GetProcessHeap(), 0, table, table_size * sizeof(table[0]) )))
2703 fclose(fp);
2704 goto failed;
2707 table = new_table;
2708 entry = &table[table_size - 1];
2710 i = 0;
2711 while (i < 8)
2713 entry->addr.u.Word[i] = htons(a[i]);
2714 i++;
2717 entry->scope = htons(scope);
2720 fclose(fp);
2722 #else
2723 FIXME( "not implemented\n" );
2724 goto failed;
2725 #endif
2727 *size = table_size;
2728 return table;
2730 failed:
2731 HeapFree( GetProcessHeap(), 0, table );
2732 return NULL;
2735 static DWORD find_ipv6_addr_scope(const IN6_ADDR *addr, const struct ipv6_addr_scope *table, unsigned int size)
2737 const BYTE multicast_scope_mask = 0x0F;
2738 const BYTE multicast_scope_shift = 0;
2739 unsigned int i = 0;
2741 if (WS_IN6_IS_ADDR_UNSPECIFIED(addr))
2742 return 0;
2744 if (WS_IN6_IS_ADDR_MULTICAST(addr))
2745 return htons((addr->u.Byte[1] & multicast_scope_mask) >> multicast_scope_shift);
2747 if (!table)
2748 return -1;
2750 while (i < size)
2752 if (memcmp(&table[i].addr, addr, sizeof(table[i].addr)) == 0)
2753 return table[i].scope;
2754 i++;
2757 return -1;
2760 DWORD build_udp6_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2761 DWORD *size )
2763 MIB_UDP6TABLE *table;
2764 MIB_UDP6ROW_OWNER_MODULE row;
2765 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2767 if (!(table_size = get_udp6_table_sizes( class, count, &row_size )))
2768 return ERROR_INVALID_PARAMETER;
2770 if (!(table = HeapAlloc( heap, flags, table_size )))
2771 return ERROR_OUTOFMEMORY;
2773 table->dwNumEntries = 0;
2774 memset( &row, 0, sizeof(row) );
2776 #ifdef __linux__
2778 FILE *fp;
2780 if ((fp = fopen( "/proc/net/udp6", "r" )))
2782 char buf[512], *ptr;
2783 struct pid_map *map = NULL;
2784 unsigned int num_entries = 0;
2785 struct ipv6_addr_scope *addr_scopes;
2786 unsigned int addr_scopes_size = 0;
2787 unsigned int dummy;
2788 int inode;
2790 addr_scopes = get_ipv6_addr_scope_table(&addr_scopes_size);
2792 if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
2794 /* skip header line */
2795 ptr = fgets( buf, sizeof(buf), fp );
2796 while ((ptr = fgets( buf, sizeof(buf), fp )))
2798 DWORD in6_addr32[4];
2800 if (sscanf( ptr, "%u: %8x%8x%8x%8x:%x %*s %*s %*s %*s %*s %*s %*s %d", &dummy,
2801 &in6_addr32[0], &in6_addr32[1], &in6_addr32[2], &in6_addr32[3],
2802 &row.dwLocalPort, &inode ) != 7)
2803 continue;
2804 memcpy(&row.ucLocalAddr, in6_addr32, sizeof(row.ucLocalAddr));
2805 row.dwLocalScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size);
2806 row.dwLocalPort = htons( row.dwLocalPort );
2808 if (class >= UDP_TABLE_OWNER_PID)
2809 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2810 if (class >= UDP_TABLE_OWNER_MODULE)
2812 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2813 row.u.dwFlags = 0;
2814 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2816 if (!(table = append_udp6_row( class, heap, flags, table, &count, &row, row_size )))
2817 break;
2819 HeapFree( GetProcessHeap(), 0, map );
2820 HeapFree( GetProcessHeap(), 0, addr_scopes );
2821 fclose( fp );
2823 else ret = ERROR_NOT_SUPPORTED;
2825 #else
2826 FIXME( "not implemented\n" );
2827 ret = ERROR_NOT_SUPPORTED;
2828 #endif
2830 if (!table) return ERROR_OUTOFMEMORY;
2831 if (!ret)
2833 if (order && table->dwNumEntries)
2834 qsort( table->table, table->dwNumEntries, row_size, compare_udp6_rows );
2835 *tablep = table;
2837 else HeapFree( heap, flags, table );
2838 if (size) *size = get_udp6_table_sizes( class, count, NULL );
2839 TRACE( "returning ret %u table %p\n", ret, table );
2840 return ret;
2843 /******************************************************************
2844 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
2846 * Get the UDP listener table.
2847 * Like GetUdpTable(), but allocate the returned table from heap.
2849 * PARAMS
2850 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
2851 * allocated and returned.
2852 * bOrder [In] whether to sort the table
2853 * heap [In] heap from which the table is allocated
2854 * flags [In] flags to HeapAlloc
2856 * RETURNS
2857 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
2858 * returns otherwise.
2860 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
2861 HANDLE heap, DWORD flags)
2863 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
2865 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
2866 return build_udp_table( UDP_TABLE_BASIC, (void **)ppUdpTable, bOrder, heap, flags, NULL );