ncrypt: Add NCryptIsKeyHandle stub.
[wine.git] / dlls / iphlpapi / ipstats.c
blob0fa446c21a5ac27d3cf967d214c120d801dd393e
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
142 #ifdef HAVE_IFADDRS_H
143 #include <ifaddrs.h>
144 #endif
146 #ifndef ROUNDUP
147 #define ROUNDUP(a) \
148 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int))
149 #endif
150 #ifndef ADVANCE
151 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
152 #endif
154 #include "ntstatus.h"
155 #define WIN32_NO_STATUS
156 #define NONAMELESSUNION
157 #define USE_WS_PREFIX
158 #include "winsock2.h"
159 #include "ws2ipdef.h"
160 #include "ifenum.h"
161 #include "ipstats.h"
162 #include "iphlpapi.h"
164 #include "wine/debug.h"
165 #include "wine/server.h"
166 #include "wine/unicode.h"
168 #ifndef HAVE_NETINET_TCP_FSM_H
169 #define TCPS_ESTABLISHED 1
170 #define TCPS_SYN_SENT 2
171 #define TCPS_SYN_RECEIVED 3
172 #define TCPS_FIN_WAIT_1 4
173 #define TCPS_FIN_WAIT_2 5
174 #define TCPS_TIME_WAIT 6
175 #define TCPS_CLOSED 7
176 #define TCPS_CLOSE_WAIT 8
177 #define TCPS_LAST_ACK 9
178 #define TCPS_LISTEN 10
179 #define TCPS_CLOSING 11
180 #endif
182 #ifndef RTF_MULTICAST
183 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
184 #endif
186 #ifndef RTF_LLINFO
187 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
188 #endif
190 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
192 #ifdef HAVE_LIBKSTAT
193 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
195 unsigned int i;
196 kstat_named_t *data = ksp->ks_data;
198 for (i = 0; i < ksp->ks_ndata; i++)
199 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
200 return 0;
203 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
205 unsigned int i;
206 kstat_named_t *data = ksp->ks_data;
208 for (i = 0; i < ksp->ks_ndata; i++)
209 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
210 return 0;
212 #endif
214 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
215 static int open_streams_mib( const char *proto )
217 int fd;
218 struct strbuf buf;
219 struct request
221 struct T_optmgmt_req req_header;
222 struct opthdr opt_header;
223 } request;
225 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
227 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
228 return -1;
230 if (proto) ioctl( fd, I_PUSH, proto );
232 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
233 request.req_header.OPT_length = sizeof(request.opt_header);
234 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
235 request.req_header.MGMT_flags = T_CURRENT;
236 request.opt_header.level = MIB2_IP;
237 request.opt_header.name = 0;
238 request.opt_header.len = 0;
240 buf.len = sizeof(request);
241 buf.buf = (caddr_t)&request;
242 if (putmsg( fd, &buf, NULL, 0 ) == -1)
244 WARN( "putmsg: %s\n", strerror(errno) );
245 close( fd );
246 fd = -1;
248 return fd;
251 static void *read_mib_entry( int fd, int level, int name, int *len )
253 struct strbuf buf;
254 void *data;
255 int ret, flags = 0;
257 struct reply
259 struct T_optmgmt_ack ack_header;
260 struct opthdr opt_header;
261 } reply;
263 for (;;)
265 buf.maxlen = sizeof(reply);
266 buf.buf = (caddr_t)&reply;
267 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
268 if (!(ret & MOREDATA)) return NULL;
269 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
270 if (buf.len < sizeof(reply.ack_header)) return NULL;
271 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
273 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
274 buf.maxlen = reply.opt_header.len;
275 buf.buf = (caddr_t)data;
276 flags = 0;
277 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
278 reply.opt_header.level == level &&
279 reply.opt_header.name == name)
281 *len = buf.len;
282 return data;
284 HeapFree( GetProcessHeap(), 0, data );
287 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
289 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
291 DWORD ret = ERROR_NOT_SUPPORTED;
293 if (!name || !entry) return ERROR_INVALID_PARAMETER;
295 #ifdef __linux__
297 FILE *fp;
299 if ((fp = fopen("/proc/net/dev", "r")))
301 DWORD skip;
302 char buf[512], *ptr;
303 int nameLen = strlen(name);
305 while ((ptr = fgets(buf, sizeof(buf), fp)))
307 while (*ptr && isspace(*ptr)) ptr++;
308 if (_strnicmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
310 ptr += nameLen + 1;
311 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
312 &entry->dwInOctets, &entry->dwInUcastPkts,
313 &entry->dwInErrors, &entry->dwInDiscards,
314 &skip, &skip, &skip,
315 &entry->dwInNUcastPkts, &entry->dwOutOctets,
316 &entry->dwOutUcastPkts, &entry->dwOutErrors,
317 &entry->dwOutDiscards );
318 break;
321 fclose(fp);
322 ret = NO_ERROR;
325 #elif defined(HAVE_LIBKSTAT)
327 kstat_ctl_t *kc;
328 kstat_t *ksp;
330 if ((kc = kstat_open()) &&
331 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
332 kstat_read( kc, ksp, NULL ) != -1 &&
333 ksp->ks_type == KSTAT_TYPE_NAMED)
335 entry->dwMtu = 1500; /* FIXME */
336 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
337 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
338 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
339 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
340 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
341 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
342 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
343 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
344 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
345 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
346 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
347 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
348 entry->dwOutDiscards = 0; /* FIXME */
349 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
350 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
351 ret = NO_ERROR;
353 if (kc) kstat_close( kc );
355 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
357 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
358 size_t needed;
359 char *buf = NULL, *end;
360 struct if_msghdr *ifm;
361 struct if_data ifdata;
363 if(sysctl(mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0) == -1)
365 ERR ("failed to get size of iflist\n");
366 goto done;
368 buf = HeapAlloc (GetProcessHeap (), 0, needed);
369 if (!buf)
371 ret = ERROR_OUTOFMEMORY;
372 goto done;
374 if(sysctl(mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0) == -1)
376 ERR ("failed to get iflist\n");
377 goto done;
379 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
381 ifm = (struct if_msghdr *) buf;
382 if(ifm->ifm_type == RTM_IFINFO)
384 ifdata = ifm->ifm_data;
385 entry->dwMtu = ifdata.ifi_mtu;
386 entry->dwSpeed = ifdata.ifi_baudrate;
387 entry->dwInOctets = ifdata.ifi_ibytes;
388 entry->dwInErrors = ifdata.ifi_ierrors;
389 entry->dwInDiscards = ifdata.ifi_iqdrops;
390 entry->dwInUcastPkts = ifdata.ifi_ipackets;
391 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
392 entry->dwOutOctets = ifdata.ifi_obytes;
393 entry->dwOutUcastPkts = ifdata.ifi_opackets;
394 entry->dwOutErrors = ifdata.ifi_oerrors;
395 ret = NO_ERROR;
396 break;
399 done:
400 HeapFree (GetProcessHeap (), 0, buf);
402 #else
403 FIXME( "unimplemented\n" );
404 #endif
405 return ret;
409 /******************************************************************
410 * GetIcmpStatistics (IPHLPAPI.@)
412 * Get the ICMP statistics for the local computer.
414 * PARAMS
415 * stats [Out] buffer for ICMP statistics
417 * RETURNS
418 * Success: NO_ERROR
419 * Failure: error code from winerror.h
421 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
423 DWORD ret = ERROR_NOT_SUPPORTED;
425 if (!stats) return ERROR_INVALID_PARAMETER;
426 memset( stats, 0, sizeof(MIB_ICMP) );
428 #ifdef __linux__
430 FILE *fp;
432 if ((fp = fopen("/proc/net/snmp", "r")))
434 static const char hdr[] = "Icmp:";
435 char buf[512], *ptr;
437 while ((ptr = fgets(buf, sizeof(buf), fp)))
439 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
440 /* last line was a header, get another */
441 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
442 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
444 ptr += sizeof(hdr);
445 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",
446 &stats->stats.icmpInStats.dwMsgs,
447 &stats->stats.icmpInStats.dwErrors,
448 &stats->stats.icmpInStats.dwDestUnreachs,
449 &stats->stats.icmpInStats.dwTimeExcds,
450 &stats->stats.icmpInStats.dwParmProbs,
451 &stats->stats.icmpInStats.dwSrcQuenchs,
452 &stats->stats.icmpInStats.dwRedirects,
453 &stats->stats.icmpInStats.dwEchoReps,
454 &stats->stats.icmpInStats.dwTimestamps,
455 &stats->stats.icmpInStats.dwTimestampReps,
456 &stats->stats.icmpInStats.dwAddrMasks,
457 &stats->stats.icmpInStats.dwAddrMaskReps,
458 &stats->stats.icmpOutStats.dwMsgs,
459 &stats->stats.icmpOutStats.dwErrors,
460 &stats->stats.icmpOutStats.dwDestUnreachs,
461 &stats->stats.icmpOutStats.dwTimeExcds,
462 &stats->stats.icmpOutStats.dwParmProbs,
463 &stats->stats.icmpOutStats.dwSrcQuenchs,
464 &stats->stats.icmpOutStats.dwRedirects,
465 &stats->stats.icmpOutStats.dwEchoReps,
466 &stats->stats.icmpOutStats.dwTimestamps,
467 &stats->stats.icmpOutStats.dwTimestampReps,
468 &stats->stats.icmpOutStats.dwAddrMasks,
469 &stats->stats.icmpOutStats.dwAddrMaskReps );
470 break;
473 fclose(fp);
474 ret = NO_ERROR;
477 #elif defined(HAVE_LIBKSTAT)
479 static char ip[] = "ip", icmp[] = "icmp";
480 kstat_ctl_t *kc;
481 kstat_t *ksp;
483 if ((kc = kstat_open()) &&
484 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
485 kstat_read( kc, ksp, NULL ) != -1 &&
486 ksp->ks_type == KSTAT_TYPE_NAMED)
488 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
489 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
490 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
491 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
492 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
493 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
494 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
495 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
496 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
497 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
498 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
499 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
500 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
501 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
502 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
503 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
504 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
505 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
506 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
507 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
508 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
509 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
510 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
511 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
512 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
513 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
514 ret = NO_ERROR;
516 if (kc) kstat_close( kc );
518 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && (defined(HAVE_STRUCT_ICMPSTAT_ICPS_INHIST) || defined(HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST))
520 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
521 struct icmpstat icmp_stat;
522 size_t needed = sizeof(icmp_stat);
523 int i;
525 if(sysctl(mib, ARRAY_SIZE(mib), &icmp_stat, &needed, NULL, 0) != -1)
527 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_INHIST
528 /*in stats */
529 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
530 for(i = 0; i <= ICMP_MAXTYPE; i++)
531 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
533 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
535 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
536 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
537 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
538 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
539 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
540 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
541 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
542 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
543 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
544 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
545 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
546 #endif
548 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST
549 /* out stats */
550 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
551 for(i = 0; i <= ICMP_MAXTYPE; i++)
552 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
554 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
556 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
557 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
558 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
559 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
560 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
561 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
562 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
563 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
564 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
565 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
566 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
567 #endif /* HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST */
568 ret = NO_ERROR;
571 #else /* ICMPCTL_STATS */
572 FIXME( "unimplemented\n" );
573 #endif
574 return ret;
577 /******************************************************************
578 * GetIcmpStatisticsEx (IPHLPAPI.@)
580 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
582 * PARAMS
583 * stats [Out] buffer for ICMP statistics
584 * family [In] specifies whether IPv4 or IPv6 statistics are returned
586 * RETURNS
587 * Success: NO_ERROR
588 * Failure: error code from winerror.h
590 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX stats, DWORD family)
592 DWORD ret = ERROR_NOT_SUPPORTED;
593 MIB_ICMP ipv4stats;
595 if (!stats) return ERROR_INVALID_PARAMETER;
596 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
597 memset( stats, 0, sizeof(MIB_ICMP_EX) );
599 if (family == WS_AF_INET6)
601 #ifdef __linux__
603 FILE *fp;
605 if ((fp = fopen("/proc/net/snmp6", "r")))
607 struct icmpstatstruct{
608 const char *name;
609 DWORD pos;
611 static const struct icmpstatstruct icmpinstatlist[] = {
612 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
613 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
614 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
615 { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
616 { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
617 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
618 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
619 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
620 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
621 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
622 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
623 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
624 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
625 { "Icmp6InRedirects", ND_REDIRECT },
626 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
628 static const struct icmpstatstruct icmpoutstatlist[] = {
629 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
630 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
631 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
632 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
633 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
634 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
635 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
636 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
637 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
638 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
639 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
640 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
641 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
642 { "Icmp6OutRedirects", ND_REDIRECT },
643 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
645 char buf[512], *ptr, *value;
646 DWORD res, i;
648 while ((ptr = fgets(buf, sizeof(buf), fp)))
650 if (!(value = strchr(buf, ' ')))
651 continue;
653 /* terminate the valuename */
654 ptr = value - 1;
655 *(ptr + 1) = '\0';
657 /* and strip leading spaces from value */
658 value += 1;
659 while (*value==' ') value++;
660 if ((ptr = strchr(value, '\n')))
661 *ptr='\0';
663 if (!_strnicmp(buf, "Icmp6InMsgs", -1))
665 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwMsgs = res;
666 continue;
669 if (!_strnicmp(buf, "Icmp6InErrors", -1))
671 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwErrors = res;
672 continue;
675 for (i = 0; i < ARRAY_SIZE(icmpinstatlist); i++)
677 if (!_strnicmp(buf, icmpinstatlist[i].name, -1))
679 if (sscanf(value, "%d", &res))
680 stats->icmpInStats.rgdwTypeCount[icmpinstatlist[i].pos] = res;
681 break;
685 if (!_strnicmp(buf, "Icmp6OutMsgs", -1))
687 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwMsgs = res;
688 continue;
691 if (!_strnicmp(buf, "Icmp6OutErrors", -1))
693 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwErrors = res;
694 continue;
697 for (i = 0; i < ARRAY_SIZE(icmpoutstatlist); i++)
699 if (!_strnicmp(buf, icmpoutstatlist[i].name, -1))
701 if (sscanf(value, "%d", &res))
702 stats->icmpOutStats.rgdwTypeCount[icmpoutstatlist[i].pos] = res;
703 break;
708 fclose(fp);
709 ret = NO_ERROR;
712 #else
713 FIXME( "unimplemented for IPv6\n" );
714 #endif
715 return ret;
718 ret = GetIcmpStatistics(&ipv4stats);
719 if (!ret)
721 stats->icmpInStats.dwMsgs = ipv4stats.stats.icmpInStats.dwMsgs;
722 stats->icmpInStats.dwErrors = ipv4stats.stats.icmpInStats.dwErrors;
723 stats->icmpInStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpInStats.dwDestUnreachs;
724 stats->icmpInStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpInStats.dwSrcQuenchs;
725 stats->icmpInStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpInStats.dwRedirects;
726 stats->icmpInStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpInStats.dwEchos;
727 stats->icmpInStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpInStats.dwTimeExcds;
728 stats->icmpInStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpInStats.dwParmProbs;
729 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpInStats.dwTimestamps;
730 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpInStats.dwTimestampReps;
731 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpInStats.dwAddrMasks;
732 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpInStats.dwAddrMaskReps;
734 stats->icmpOutStats.dwMsgs = ipv4stats.stats.icmpOutStats.dwMsgs;
735 stats->icmpOutStats.dwErrors = ipv4stats.stats.icmpOutStats.dwErrors;
736 stats->icmpOutStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpOutStats.dwDestUnreachs;
737 stats->icmpOutStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpOutStats.dwSrcQuenchs;
738 stats->icmpOutStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpOutStats.dwRedirects;
739 stats->icmpOutStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpOutStats.dwEchos;
740 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpOutStats.dwTimeExcds;
741 stats->icmpOutStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpOutStats.dwParmProbs;
742 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpOutStats.dwTimestamps;
743 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpOutStats.dwTimestampReps;
744 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpOutStats.dwAddrMasks;
745 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpOutStats.dwAddrMaskReps;
747 return ret;
750 /******************************************************************
751 * GetIpStatisticsEx (IPHLPAPI.@)
753 * Get the IPv4 and IPv6 statistics for the local computer.
755 * PARAMS
756 * stats [Out] buffer for IP statistics
757 * family [In] specifies whether IPv4 or IPv6 statistics are returned
759 * RETURNS
760 * Success: NO_ERROR
761 * Failure: error code from winerror.h
763 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS stats, DWORD family)
765 DWORD ret = ERROR_NOT_SUPPORTED;
766 MIB_IPFORWARDTABLE *fwd_table;
768 if (!stats) return ERROR_INVALID_PARAMETER;
769 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
770 memset( stats, 0, sizeof(*stats) );
772 stats->dwNumIf = stats->dwNumAddr = get_interface_indices( FALSE, NULL );
773 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
775 stats->dwNumRoutes = fwd_table->dwNumEntries;
776 HeapFree( GetProcessHeap(), 0, fwd_table );
779 if (family == WS_AF_INET6)
781 #ifdef __linux__
783 FILE *fp;
785 if ((fp = fopen("/proc/net/snmp6", "r")))
787 struct {
788 const char *name;
789 DWORD *elem;
790 } ipstatlist[] = {
791 { "Ip6InReceives", &stats->dwInReceives },
792 { "Ip6InHdrErrors", &stats->dwInHdrErrors },
793 { "Ip6InAddrErrors", &stats->dwInAddrErrors },
794 { "Ip6OutForwDatagrams", &stats->dwForwDatagrams },
795 { "Ip6InUnknownProtos", &stats->dwInUnknownProtos },
796 { "Ip6InDiscards", &stats->dwInDiscards },
797 { "Ip6InDelivers", &stats->dwInDelivers },
798 { "Ip6OutRequests", &stats->dwOutRequests },
799 { "Ip6OutDiscards", &stats->dwOutDiscards },
800 { "Ip6OutNoRoutes", &stats->dwOutNoRoutes },
801 { "Ip6ReasmTimeout", &stats->dwReasmTimeout },
802 { "Ip6ReasmReqds", &stats->dwReasmReqds },
803 { "Ip6ReasmOKs", &stats->dwReasmOks },
804 { "Ip6ReasmFails", &stats->dwReasmFails },
805 { "Ip6FragOKs", &stats->dwFragOks },
806 { "Ip6FragFails", &stats->dwFragFails },
807 { "Ip6FragCreates", &stats->dwFragCreates },
808 /* hmm, no routingDiscards, defaultTTL and forwarding? */
810 char buf[512], *ptr, *value;
811 DWORD res, i;
813 while ((ptr = fgets(buf, sizeof(buf), fp)))
815 if (!(value = strchr(buf, ' ')))
816 continue;
818 /* terminate the valuename */
819 ptr = value - 1;
820 *(ptr + 1) = '\0';
822 /* and strip leading spaces from value */
823 value += 1;
824 while (*value==' ') value++;
825 if ((ptr = strchr(value, '\n')))
826 *ptr='\0';
828 for (i = 0; i < ARRAY_SIZE(ipstatlist); i++)
829 if (!_strnicmp(buf, ipstatlist[i].name, -1) && sscanf(value, "%d", &res))
830 *ipstatlist[i].elem = res;
832 fclose(fp);
833 ret = NO_ERROR;
836 #else
837 FIXME( "unimplemented for IPv6\n" );
838 #endif
839 return ret;
842 #ifdef __linux__
844 FILE *fp;
846 if ((fp = fopen("/proc/net/snmp", "r")))
848 static const char hdr[] = "Ip:";
849 char buf[512], *ptr;
851 while ((ptr = fgets(buf, sizeof(buf), fp)))
853 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
854 /* last line was a header, get another */
855 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
856 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
858 ptr += sizeof(hdr);
859 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
860 &stats->u.dwForwarding,
861 &stats->dwDefaultTTL,
862 &stats->dwInReceives,
863 &stats->dwInHdrErrors,
864 &stats->dwInAddrErrors,
865 &stats->dwForwDatagrams,
866 &stats->dwInUnknownProtos,
867 &stats->dwInDiscards,
868 &stats->dwInDelivers,
869 &stats->dwOutRequests,
870 &stats->dwOutDiscards,
871 &stats->dwOutNoRoutes,
872 &stats->dwReasmTimeout,
873 &stats->dwReasmReqds,
874 &stats->dwReasmOks,
875 &stats->dwReasmFails,
876 &stats->dwFragOks,
877 &stats->dwFragFails,
878 &stats->dwFragCreates );
879 /* hmm, no routingDiscards */
880 break;
883 fclose(fp);
884 ret = NO_ERROR;
887 #elif defined(HAVE_LIBKSTAT)
889 static char ip[] = "ip";
890 kstat_ctl_t *kc;
891 kstat_t *ksp;
893 if ((kc = kstat_open()) &&
894 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
895 kstat_read( kc, ksp, NULL ) != -1 &&
896 ksp->ks_type == KSTAT_TYPE_NAMED)
898 stats->u.dwForwarding = kstat_get_ui32( ksp, "forwarding" );
899 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
900 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
901 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
902 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
903 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
904 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
905 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
906 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
907 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
908 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
909 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
910 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
911 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
912 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
913 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
914 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
915 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
916 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
917 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
918 ret = NO_ERROR;
920 if (kc) kstat_close( kc );
922 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
924 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
925 int ip_ttl, ip_forwarding;
926 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
927 struct ipstat ip_stat;
928 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
929 struct ip_stats ip_stat;
930 #endif
931 size_t needed;
933 needed = sizeof(ip_stat);
934 if(sysctl(mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0) == -1)
936 ERR ("failed to get ipstat\n");
937 return ERROR_NOT_SUPPORTED;
940 needed = sizeof(ip_ttl);
941 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
943 ERR ("failed to get ip Default TTL\n");
944 return ERROR_NOT_SUPPORTED;
947 needed = sizeof(ip_forwarding);
948 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
950 ERR ("failed to get ip forwarding\n");
951 return ERROR_NOT_SUPPORTED;
954 /* ip.forwarding is 0 or 1 on BSD */
955 stats->u.dwForwarding = ip_forwarding+1;
956 stats->dwDefaultTTL = ip_ttl;
957 stats->dwInReceives = ip_stat.ips_total;
958 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen +
959 ip_stat.ips_badvers + ip_stat.ips_badoptions;
960 /* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
961 stats->dwInAddrErrors = ip_stat.ips_cantforward + ip_stat.ips_badaddr + ip_stat.ips_notmember;
962 stats->dwForwDatagrams = ip_stat.ips_forward;
963 stats->dwInUnknownProtos = ip_stat.ips_noproto;
964 stats->dwInDiscards = ip_stat.ips_fragdropped;
965 stats->dwInDelivers = ip_stat.ips_delivered;
966 stats->dwOutRequests = ip_stat.ips_localout;
967 /*stats->dwRoutingDiscards = 0;*/ /* FIXME */
968 stats->dwOutDiscards = ip_stat.ips_odropped;
969 stats->dwOutNoRoutes = ip_stat.ips_noroute;
970 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
971 stats->dwReasmReqds = ip_stat.ips_fragments;
972 stats->dwReasmOks = ip_stat.ips_reassembled;
973 stats->dwReasmFails = ip_stat.ips_fragments - ip_stat.ips_reassembled;
974 stats->dwFragOks = ip_stat.ips_fragmented;
975 stats->dwFragFails = ip_stat.ips_cantfrag;
976 stats->dwFragCreates = ip_stat.ips_ofragments;
977 ret = NO_ERROR;
979 #else
980 FIXME( "unimplemented for IPv4\n" );
981 #endif
982 return ret;
985 /******************************************************************
986 * GetIpStatistics (IPHLPAPI.@)
988 * Get the IP statistics for the local computer.
990 * PARAMS
991 * stats [Out] buffer for IP statistics
993 * RETURNS
994 * Success: NO_ERROR
995 * Failure: error code from winerror.h
997 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
999 return GetIpStatisticsEx(stats, WS_AF_INET);
1002 /******************************************************************
1003 * GetTcpStatisticsEx (IPHLPAPI.@)
1005 * Get the IPv4 and IPv6 TCP statistics for the local computer.
1007 * PARAMS
1008 * stats [Out] buffer for TCP statistics
1009 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1011 * RETURNS
1012 * Success: NO_ERROR
1013 * Failure: error code from winerror.h
1015 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS stats, DWORD family)
1017 DWORD ret = ERROR_NOT_SUPPORTED;
1019 if (!stats) return ERROR_INVALID_PARAMETER;
1020 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1021 memset( stats, 0, sizeof(*stats) );
1023 if (family == WS_AF_INET6)
1025 FIXME( "unimplemented for IPv6\n" );
1026 return ret;
1029 #ifdef __linux__
1031 FILE *fp;
1033 if ((fp = fopen("/proc/net/snmp", "r")))
1035 static const char hdr[] = "Tcp:";
1036 MIB_TCPTABLE *tcp_table;
1037 char buf[512], *ptr;
1039 while ((ptr = fgets(buf, sizeof(buf), fp)))
1041 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
1042 /* last line was a header, get another */
1043 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1044 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
1046 ptr += sizeof(hdr);
1047 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
1048 &stats->u.dwRtoAlgorithm,
1049 &stats->dwRtoMin,
1050 &stats->dwRtoMax,
1051 &stats->dwMaxConn,
1052 &stats->dwActiveOpens,
1053 &stats->dwPassiveOpens,
1054 &stats->dwAttemptFails,
1055 &stats->dwEstabResets,
1056 &stats->dwCurrEstab,
1057 &stats->dwInSegs,
1058 &stats->dwOutSegs,
1059 &stats->dwRetransSegs,
1060 &stats->dwInErrs,
1061 &stats->dwOutRsts );
1062 break;
1065 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
1067 stats->dwNumConns = tcp_table->dwNumEntries;
1068 HeapFree( GetProcessHeap(), 0, tcp_table );
1070 fclose(fp);
1071 ret = NO_ERROR;
1074 #elif defined(HAVE_LIBKSTAT)
1076 static char tcp[] = "tcp";
1077 kstat_ctl_t *kc;
1078 kstat_t *ksp;
1080 if ((kc = kstat_open()) &&
1081 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
1082 kstat_read( kc, ksp, NULL ) != -1 &&
1083 ksp->ks_type == KSTAT_TYPE_NAMED)
1085 stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
1086 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
1087 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
1088 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
1089 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
1090 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
1091 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
1092 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
1093 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
1094 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
1095 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
1096 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
1097 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
1098 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
1099 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
1100 ret = NO_ERROR;
1102 if (kc) kstat_close( kc );
1104 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
1106 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
1107 #define TCPTV_MIN 2
1108 #define TCPTV_REXMTMAX 128
1109 #endif
1110 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
1111 #define hz 1000
1112 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
1113 struct tcpstat tcp_stat;
1114 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
1115 struct tcp_stats tcp_stat;
1116 #endif
1117 size_t needed = sizeof(tcp_stat);
1119 if(sysctl(mib, ARRAY_SIZE(mib), &tcp_stat, &needed, NULL, 0) != -1)
1121 stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
1122 stats->dwRtoMin = TCPTV_MIN;
1123 stats->dwRtoMax = TCPTV_REXMTMAX;
1124 stats->dwMaxConn = -1;
1125 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
1126 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
1127 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
1128 stats->dwEstabResets = tcp_stat.tcps_drops;
1129 stats->dwCurrEstab = 0;
1130 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
1131 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
1132 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
1133 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
1134 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
1135 stats->dwNumConns = tcp_stat.tcps_connects;
1136 ret = NO_ERROR;
1138 else ERR ("failed to get tcpstat\n");
1140 #else
1141 FIXME( "unimplemented\n" );
1142 #endif
1143 return ret;
1146 /******************************************************************
1147 * GetTcpStatistics (IPHLPAPI.@)
1149 * Get the TCP statistics for the local computer.
1151 * PARAMS
1152 * stats [Out] buffer for TCP statistics
1154 * RETURNS
1155 * Success: NO_ERROR
1156 * Failure: error code from winerror.h
1158 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
1160 return GetTcpStatisticsEx(stats, WS_AF_INET);
1163 /******************************************************************
1164 * GetUdpStatistics (IPHLPAPI.@)
1166 * Get the IPv4 and IPv6 UDP statistics for the local computer.
1168 * PARAMS
1169 * stats [Out] buffer for UDP statistics
1170 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1172 * RETURNS
1173 * Success: NO_ERROR
1174 * Failure: error code from winerror.h
1176 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS stats, DWORD family)
1178 DWORD ret = ERROR_NOT_SUPPORTED;
1180 if (!stats) return ERROR_INVALID_PARAMETER;
1181 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1182 memset( stats, 0, sizeof(*stats) );
1184 stats->dwNumAddrs = get_interface_indices( FALSE, NULL );
1186 if (family == WS_AF_INET6)
1188 #ifdef __linux__
1190 FILE *fp;
1192 if ((fp = fopen("/proc/net/snmp6", "r")))
1194 struct {
1195 const char *name;
1196 DWORD *elem;
1197 } udpstatlist[] = {
1198 { "Udp6InDatagrams", &stats->dwInDatagrams },
1199 { "Udp6NoPorts", &stats->dwNoPorts },
1200 { "Udp6InErrors", &stats->dwInErrors },
1201 { "Udp6OutDatagrams", &stats->dwOutDatagrams },
1203 char buf[512], *ptr, *value;
1204 DWORD res, i;
1206 while ((ptr = fgets(buf, sizeof(buf), fp)))
1208 if (!(value = strchr(buf, ' ')))
1209 continue;
1211 /* terminate the valuename */
1212 ptr = value - 1;
1213 *(ptr + 1) = '\0';
1215 /* and strip leading spaces from value */
1216 value += 1;
1217 while (*value==' ') value++;
1218 if ((ptr = strchr(value, '\n')))
1219 *ptr='\0';
1221 for (i = 0; i < ARRAY_SIZE(udpstatlist); i++)
1222 if (!_strnicmp(buf, udpstatlist[i].name, -1) && sscanf(value, "%d", &res))
1223 *udpstatlist[i].elem = res;
1225 fclose(fp);
1226 ret = NO_ERROR;
1229 #else
1230 FIXME( "unimplemented for IPv6\n" );
1231 #endif
1232 return ret;
1235 #ifdef __linux__
1237 FILE *fp;
1239 if ((fp = fopen("/proc/net/snmp", "r")))
1241 static const char hdr[] = "Udp:";
1242 char buf[512], *ptr;
1244 while ((ptr = fgets(buf, sizeof(buf), fp)))
1246 if (_strnicmp(buf, hdr, sizeof(hdr) - 1)) continue;
1247 /* last line was a header, get another */
1248 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1249 if (!_strnicmp(buf, hdr, sizeof(hdr) - 1))
1251 ptr += sizeof(hdr);
1252 sscanf( ptr, "%u %u %u %u %u",
1253 &stats->dwInDatagrams, &stats->dwNoPorts,
1254 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
1255 break;
1258 fclose(fp);
1259 ret = NO_ERROR;
1262 #elif defined(HAVE_LIBKSTAT)
1264 static char udp[] = "udp";
1265 kstat_ctl_t *kc;
1266 kstat_t *ksp;
1267 MIB_UDPTABLE *udp_table;
1269 if ((kc = kstat_open()) &&
1270 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
1271 kstat_read( kc, ksp, NULL ) != -1 &&
1272 ksp->ks_type == KSTAT_TYPE_NAMED)
1274 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
1275 stats->dwNoPorts = 0; /* FIXME */
1276 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
1277 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
1278 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1280 stats->dwNumAddrs = udp_table->dwNumEntries;
1281 HeapFree( GetProcessHeap(), 0, udp_table );
1283 ret = NO_ERROR;
1285 if (kc) kstat_close( kc );
1287 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
1289 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
1290 struct udpstat udp_stat;
1291 MIB_UDPTABLE *udp_table;
1292 size_t needed = sizeof(udp_stat);
1294 if(sysctl(mib, ARRAY_SIZE(mib), &udp_stat, &needed, NULL, 0) != -1)
1296 stats->dwInDatagrams = udp_stat.udps_ipackets;
1297 stats->dwOutDatagrams = udp_stat.udps_opackets;
1298 stats->dwNoPorts = udp_stat.udps_noport;
1299 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
1300 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1302 stats->dwNumAddrs = udp_table->dwNumEntries;
1303 HeapFree( GetProcessHeap(), 0, udp_table );
1305 ret = NO_ERROR;
1307 else ERR ("failed to get udpstat\n");
1309 #else
1310 FIXME( "unimplemented for IPv4\n" );
1311 #endif
1312 return ret;
1315 /******************************************************************
1316 * GetUdpStatistics (IPHLPAPI.@)
1318 * Get the UDP statistics for the local computer.
1320 * PARAMS
1321 * stats [Out] buffer for UDP statistics
1323 * RETURNS
1324 * Success: NO_ERROR
1325 * Failure: error code from winerror.h
1327 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
1329 return GetUdpStatisticsEx(stats, WS_AF_INET);
1332 static void *append_table_row( HANDLE heap, DWORD flags, void *table, DWORD *table_size, DWORD *table_capacity,
1333 const void *row, DWORD row_size )
1335 DWORD *num_entries = table; /* this must be the first field */
1336 if (*num_entries == *table_capacity)
1338 void *new_table;
1339 *table_size += *table_capacity * row_size;
1340 if (!(new_table = HeapReAlloc( heap, flags, table, *table_size )))
1342 HeapFree( heap, 0, table );
1343 return NULL;
1345 num_entries = table = new_table;
1346 *table_capacity *= 2;
1348 memcpy( (char *)table + *table_size - (*table_capacity - *num_entries) * row_size, row, row_size );
1349 (*num_entries)++;
1350 return table;
1353 static int compare_ipforward_rows(const void *a, const void *b)
1355 const MIB_IPFORWARDROW *rowA = a;
1356 const MIB_IPFORWARDROW *rowB = b;
1357 int ret;
1359 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
1360 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
1361 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
1362 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1365 /******************************************************************
1366 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1368 * Get the route table.
1369 * Like GetIpForwardTable(), but allocate the returned table from heap.
1371 * PARAMS
1372 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1373 * allocated and returned.
1374 * bOrder [In] whether to sort the table
1375 * heap [In] heap from which the table is allocated
1376 * flags [In] flags to HeapAlloc
1378 * RETURNS
1379 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1380 * on failure, NO_ERROR on success.
1382 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
1383 HANDLE heap, DWORD flags)
1385 MIB_IPFORWARDTABLE *table;
1386 MIB_IPFORWARDROW row;
1387 DWORD ret = NO_ERROR, count = 16, table_size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[count] );
1389 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1391 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1393 if (!(table = HeapAlloc( heap, flags, table_size )))
1394 return ERROR_OUTOFMEMORY;
1396 table->dwNumEntries = 0;
1398 #ifdef __linux__
1400 FILE *fp;
1402 if ((fp = fopen("/proc/net/route", "r")))
1404 char buf[512], *ptr;
1405 DWORD rtf_flags;
1407 /* skip header line */
1408 ptr = fgets(buf, sizeof(buf), fp);
1409 while ((ptr = fgets(buf, sizeof(buf), fp)))
1411 memset( &row, 0, sizeof(row) );
1413 while (!isspace(*ptr)) ptr++;
1414 *ptr++ = 0;
1415 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1416 continue;
1418 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1419 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1420 rtf_flags = strtoul(ptr + 1, &ptr, 16);
1422 if (!(rtf_flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID;
1423 else if (rtf_flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1424 else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT;
1426 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1427 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1428 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1429 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1430 /* FIXME: other protos might be appropriate, e.g. the default
1431 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1432 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1434 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) )))
1435 break;
1437 fclose(fp);
1439 else ret = ERROR_NOT_SUPPORTED;
1441 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1443 void *data;
1444 int fd, len, namelen;
1445 mib2_ipRouteEntry_t *entry;
1446 char name[64];
1448 if ((fd = open_streams_mib( NULL )) != -1)
1450 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1452 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1454 row.dwForwardDest = entry->ipRouteDest;
1455 row.dwForwardMask = entry->ipRouteMask;
1456 row.dwForwardPolicy = 0;
1457 row.dwForwardNextHop = entry->ipRouteNextHop;
1458 row.u1.dwForwardType = entry->ipRouteType;
1459 row.u2.dwForwardProto = entry->ipRouteProto;
1460 row.dwForwardAge = entry->ipRouteAge;
1461 row.dwForwardNextHopAS = 0;
1462 row.dwForwardMetric1 = entry->ipRouteMetric1;
1463 row.dwForwardMetric2 = entry->ipRouteMetric2;
1464 row.dwForwardMetric3 = entry->ipRouteMetric3;
1465 row.dwForwardMetric4 = entry->ipRouteMetric4;
1466 row.dwForwardMetric5 = entry->ipRouteMetric5;
1467 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1468 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1469 name[namelen] = 0;
1470 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1471 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) )))
1472 break;
1474 HeapFree( GetProcessHeap(), 0, data );
1476 close( fd );
1478 else ret = ERROR_NOT_SUPPORTED;
1480 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1482 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1483 size_t needed;
1484 char *buf = NULL, *lim, *next, *addrPtr;
1485 struct rt_msghdr *rtm;
1487 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1489 ERR ("sysctl 1 failed!\n");
1490 ret = ERROR_NOT_SUPPORTED;
1491 goto done;
1494 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1495 if (!buf)
1497 ret = ERROR_OUTOFMEMORY;
1498 goto done;
1501 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1503 ret = ERROR_NOT_SUPPORTED;
1504 goto done;
1507 lim = buf + needed;
1508 for (next = buf; next < lim; next += rtm->rtm_msglen)
1510 int i;
1511 sa_family_t dst_family = AF_UNSPEC;
1513 rtm = (struct rt_msghdr *)next;
1515 if (rtm->rtm_type != RTM_GET)
1517 WARN ("Got unexpected message type 0x%x!\n",
1518 rtm->rtm_type);
1519 continue;
1522 /* Ignore gateway routes which are multicast */
1523 if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST))
1524 continue;
1526 memset( &row, 0, sizeof(row) );
1527 row.dwForwardIfIndex = rtm->rtm_index;
1528 row.u1.ForwardType = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
1529 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1530 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1532 addrPtr = (char *)(rtm + 1);
1534 for (i = 1; i; i <<= 1)
1536 struct sockaddr *sa;
1537 DWORD addr;
1539 if (!(i & rtm->rtm_addrs))
1540 continue;
1542 sa = (struct sockaddr *)addrPtr;
1543 if (addrPtr + sa->sa_len > next + rtm->rtm_msglen)
1545 ERR ("struct sockaddr extends beyond the route message, %p > %p\n",
1546 addrPtr + sa->sa_len, next + rtm->rtm_msglen );
1549 ADVANCE (addrPtr, sa);
1551 /* Apple's netstat prints the netmask together with the destination
1552 * and only looks at the destination's address family. The netmask's
1553 * sa_family sometimes contains the non-existent value 0xff. */
1554 switch(i == RTA_NETMASK ? dst_family : sa->sa_family) {
1555 case AF_INET: {
1556 /* Netmasks (and possibly other addresses) have only enough size
1557 * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has
1558 * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first
1559 * byte of sin_addr). Due to the alignment constraint we can de
1560 * facto read the full 4 bytes of sin_addr (except for the case of
1561 * netmask 0). Don't assume though that the extra bytes are zeroed. */
1562 struct sockaddr_in sin = {0};
1563 memcpy(&sin, sa, sa->sa_len);
1564 addr = sin.sin_addr.s_addr;
1565 break;
1567 #ifdef AF_LINK
1568 case AF_LINK:
1569 if(i == RTA_GATEWAY && row.u1.ForwardType == MIB_IPROUTE_TYPE_DIRECT) {
1570 /* For direct route we may simply use dest addr as next hop */
1571 C_ASSERT(RTA_DST < RTA_GATEWAY);
1572 addr = row.dwForwardDest;
1573 break;
1575 /* fallthrough */
1576 #endif
1577 default:
1578 WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family);
1579 addr = 0;
1582 switch (i)
1584 case RTA_DST:
1585 row.dwForwardDest = addr;
1586 dst_family = sa->sa_family;
1587 break;
1588 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1589 case RTA_NETMASK: row.dwForwardMask = addr; break;
1590 default:
1591 WARN ("Unexpected address type 0x%x\n", i);
1595 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) )))
1596 break;
1598 done:
1599 HeapFree( GetProcessHeap (), 0, buf );
1601 #else
1602 FIXME( "not implemented\n" );
1603 ret = ERROR_NOT_SUPPORTED;
1604 #endif
1606 if (!table) return ERROR_OUTOFMEMORY;
1607 if (!ret)
1609 if (bOrder && table->dwNumEntries)
1610 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1611 *ppIpForwardTable = table;
1613 else HeapFree( heap, flags, table );
1614 TRACE( "returning ret %u table %p\n", ret, table );
1615 return ret;
1618 static int compare_ipnet_rows(const void *a, const void *b)
1620 const MIB_IPNETROW *rowA = a;
1621 const MIB_IPNETROW *rowB = b;
1623 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1627 /******************************************************************
1628 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1630 * Get the IP-to-physical address mapping table.
1631 * Like GetIpNetTable(), but allocate the returned table from heap.
1633 * PARAMS
1634 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1635 * allocated and returned.
1636 * bOrder [In] whether to sort the table
1637 * heap [In] heap from which the table is allocated
1638 * flags [In] flags to HeapAlloc
1640 * RETURNS
1641 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1642 * on failure, NO_ERROR on success.
1644 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1645 HANDLE heap, DWORD flags)
1647 MIB_IPNETTABLE *table;
1648 MIB_IPNETROW row;
1649 DWORD ret = NO_ERROR, count = 16, table_size = FIELD_OFFSET( MIB_IPNETTABLE, table[count] );
1651 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1653 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1655 if (!(table = HeapAlloc( heap, flags, table_size )))
1656 return ERROR_OUTOFMEMORY;
1658 table->dwNumEntries = 0;
1660 #ifdef __linux__
1662 FILE *fp;
1664 if ((fp = fopen("/proc/net/arp", "r")))
1666 char buf[512], *ptr;
1667 DWORD atf_flags;
1669 /* skip header line */
1670 ptr = fgets(buf, sizeof(buf), fp);
1671 while ((ptr = fgets(buf, sizeof(buf), fp)))
1673 memset( &row, 0, sizeof(row) );
1675 row.dwAddr = inet_addr(ptr);
1676 while (*ptr && !isspace(*ptr)) ptr++;
1677 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1678 atf_flags = strtoul(ptr + 1, &ptr, 16);
1680 #ifdef ATF_COM
1681 if (atf_flags & ATF_COM) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1682 else
1683 #endif
1684 #ifdef ATF_PERM
1685 if (atf_flags & ATF_PERM) row.u.Type = MIB_IPNET_TYPE_STATIC;
1686 else
1687 #endif
1688 row.u.Type = MIB_IPNET_TYPE_OTHER;
1690 while (*ptr && isspace(*ptr)) ptr++;
1691 while (*ptr && !isspace(*ptr))
1693 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1694 if (*ptr) ptr++;
1696 while (*ptr && isspace(*ptr)) ptr++;
1697 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1698 while (*ptr && isspace(*ptr)) ptr++;
1699 getInterfaceIndexByName(ptr, &row.dwIndex);
1701 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) )))
1702 break;
1704 fclose(fp);
1706 else ret = ERROR_NOT_SUPPORTED;
1708 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1710 void *data;
1711 int fd, len, namelen;
1712 mib2_ipNetToMediaEntry_t *entry;
1713 char name[64];
1715 if ((fd = open_streams_mib( NULL )) != -1)
1717 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1719 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1721 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1722 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1723 row.dwAddr = entry->ipNetToMediaNetAddress;
1724 row.u.Type = entry->ipNetToMediaType;
1725 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1726 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1727 name[namelen] = 0;
1728 getInterfaceIndexByName( name, &row.dwIndex );
1729 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) )))
1730 break;
1732 HeapFree( GetProcessHeap(), 0, data );
1734 close( fd );
1736 else ret = ERROR_NOT_SUPPORTED;
1738 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1740 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1741 size_t needed;
1742 char *buf = NULL, *lim, *next;
1743 struct rt_msghdr *rtm;
1744 struct sockaddr_inarp *sinarp;
1745 struct sockaddr_dl *sdl;
1747 if (sysctl (mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0) == -1)
1749 ERR ("failed to get arp table\n");
1750 ret = ERROR_NOT_SUPPORTED;
1751 goto done;
1754 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1755 if (!buf)
1757 ret = ERROR_OUTOFMEMORY;
1758 goto done;
1761 if (sysctl (mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0) == -1)
1763 ret = ERROR_NOT_SUPPORTED;
1764 goto done;
1767 lim = buf + needed;
1768 next = buf;
1769 while(next < lim)
1771 rtm = (struct rt_msghdr *)next;
1772 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1773 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1774 if(sdl->sdl_alen) /* arp entry */
1776 memset( &row, 0, sizeof(row) );
1777 row.dwAddr = sinarp->sin_addr.s_addr;
1778 row.dwIndex = sdl->sdl_index;
1779 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1780 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1781 if(rtm->rtm_rmx.rmx_expire == 0) row.u.Type = MIB_IPNET_TYPE_STATIC;
1782 else if(sinarp->sin_other & SIN_PROXY) row.u.Type = MIB_IPNET_TYPE_OTHER;
1783 else if(rtm->rtm_rmx.rmx_expire != 0) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1784 else row.u.Type = MIB_IPNET_TYPE_INVALID;
1786 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, sizeof(row) )))
1787 break;
1789 next += rtm->rtm_msglen;
1791 done:
1792 HeapFree( GetProcessHeap (), 0, buf );
1794 #else
1795 FIXME( "not implemented\n" );
1796 ret = ERROR_NOT_SUPPORTED;
1797 #endif
1799 if (!table) return ERROR_OUTOFMEMORY;
1800 if (!ret)
1802 if (bOrder && table->dwNumEntries)
1803 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1804 *ppIpNetTable = table;
1806 else HeapFree( heap, flags, table );
1807 TRACE( "returning ret %u table %p\n", ret, table );
1808 return ret;
1811 static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
1813 DWORD table_size;
1815 switch (class)
1817 case TCP_TABLE_BASIC_LISTENER:
1818 case TCP_TABLE_BASIC_CONNECTIONS:
1819 case TCP_TABLE_BASIC_ALL:
1821 table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
1822 if (row_size) *row_size = sizeof(MIB_TCPROW);
1823 break;
1825 case TCP_TABLE_OWNER_PID_LISTENER:
1826 case TCP_TABLE_OWNER_PID_CONNECTIONS:
1827 case TCP_TABLE_OWNER_PID_ALL:
1829 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
1830 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
1831 break;
1833 case TCP_TABLE_OWNER_MODULE_LISTENER:
1834 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1835 case TCP_TABLE_OWNER_MODULE_ALL:
1837 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table[row_count]);
1838 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_MODULE);
1839 break;
1841 default:
1842 ERR("unhandled class %u\n", class);
1843 return 0;
1845 return table_size;
1848 /* Why not a lookup table? Because the TCPS_* constants are different
1849 on different platforms */
1850 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1852 switch (state)
1854 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1855 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1856 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1857 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1858 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1859 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1860 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1861 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1862 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1863 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1864 default:
1865 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1869 static int compare_tcp_rows(const void *a, const void *b)
1871 const MIB_TCPROW *rowA = a;
1872 const MIB_TCPROW *rowB = b;
1873 int ret;
1875 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1876 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1877 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1878 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1879 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1882 struct pid_map
1884 unsigned int pid;
1885 unsigned int unix_pid;
1888 static struct pid_map *get_pid_map( unsigned int *num_entries )
1890 struct pid_map *map;
1891 unsigned int i = 0, map_count = 16, buffer_len = 4096, process_count, pos = 0;
1892 NTSTATUS ret;
1893 char *buffer = NULL, *new_buffer;
1895 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_len ))) return NULL;
1897 for (;;)
1899 SERVER_START_REQ( list_processes )
1901 wine_server_set_reply( req, buffer, buffer_len );
1902 ret = wine_server_call( req );
1903 buffer_len = reply->info_size;
1904 process_count = reply->process_count;
1906 SERVER_END_REQ;
1908 if (ret != STATUS_INFO_LENGTH_MISMATCH) break;
1910 if (!(new_buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, buffer_len )))
1912 HeapFree( GetProcessHeap(), 0, buffer );
1913 return NULL;
1915 buffer = new_buffer;
1918 if (!(map = HeapAlloc( GetProcessHeap(), 0, map_count * sizeof(*map) )))
1920 HeapFree( GetProcessHeap(), 0, buffer );
1921 return NULL;
1924 for (i = 0; i < process_count; ++i)
1926 const struct process_info *process;
1928 pos = (pos + 7) & ~7;
1929 process = (const struct process_info *)(buffer + pos);
1931 if (i >= map_count)
1933 struct pid_map *new_map;
1934 map_count *= 2;
1935 if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, map_count * sizeof(*map))))
1937 HeapFree( GetProcessHeap(), 0, map );
1938 HeapFree( GetProcessHeap(), 0, buffer );
1939 return NULL;
1941 map = new_map;
1944 map[i].pid = process->pid;
1945 map[i].unix_pid = process->unix_pid;
1947 pos += sizeof(struct process_info) + process->name_len;
1948 pos = (pos + 7) & ~7;
1949 pos += process->thread_count * sizeof(struct thread_info);
1952 HeapFree( GetProcessHeap(), 0, buffer );
1953 *num_entries = process_count;
1954 return map;
1957 static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, UINT_PTR inode )
1959 #ifdef __linux__
1960 unsigned int i, len_socket;
1961 char socket[32];
1963 sprintf( socket, "socket:[%lu]", inode );
1964 len_socket = strlen( socket );
1965 for (i = 0; i < num_entries; i++)
1967 char dir[32];
1968 struct dirent *dirent;
1969 DIR *dirfd;
1971 sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
1972 if ((dirfd = opendir( dir )))
1974 while ((dirent = readdir( dirfd )))
1976 char link[sizeof(dirent->d_name) + 32], name[32];
1977 int len;
1979 sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
1980 if ((len = readlink( link, name, sizeof(name) - 1 )) > 0) name[len] = 0;
1981 if (len == len_socket && !strcmp( socket, name ))
1983 closedir( dirfd );
1984 return map[i].pid;
1987 closedir( dirfd );
1990 return 0;
1991 #elif defined(HAVE_LIBPROCSTAT)
1992 struct procstat *pstat;
1993 struct kinfo_proc *proc;
1994 struct filestat_list *fds;
1995 struct filestat *fd;
1996 struct sockstat sock;
1997 unsigned int i, proc_count;
1999 pstat = procstat_open_sysctl();
2000 if (!pstat) return 0;
2002 for (i = 0; i < num_entries; i++)
2004 proc = procstat_getprocs( pstat, KERN_PROC_PID, map[i].unix_pid, &proc_count );
2005 if (!proc || proc_count < 1) continue;
2007 fds = procstat_getfiles( pstat, proc, 0 );
2008 if (!fds)
2010 procstat_freeprocs( pstat, proc );
2011 continue;
2014 STAILQ_FOREACH( fd, fds, next )
2016 char errbuf[_POSIX2_LINE_MAX];
2018 if (fd->fs_type != PS_FST_TYPE_SOCKET) continue;
2020 procstat_get_socket_info( pstat, fd, &sock, errbuf );
2022 if (sock.so_pcb == inode)
2024 procstat_freefiles( pstat, fds );
2025 procstat_freeprocs( pstat, proc );
2026 procstat_close( pstat );
2027 return map[i].pid;
2031 procstat_freefiles( pstat, fds );
2032 procstat_freeprocs( pstat, proc );
2035 procstat_close( pstat );
2036 return 0;
2037 #elif defined(HAVE_PROC_PIDINFO)
2038 struct proc_fdinfo *fds;
2039 struct socket_fdinfo sock;
2040 unsigned int i, j, n;
2042 for (i = 0; i < num_entries; i++)
2044 int fd_len = proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, NULL, 0 );
2045 if (fd_len <= 0) continue;
2047 fds = HeapAlloc( GetProcessHeap(), 0, fd_len );
2048 if (!fds) continue;
2050 proc_pidinfo( map[i].unix_pid, PROC_PIDLISTFDS, 0, fds, fd_len );
2051 n = fd_len / sizeof(struct proc_fdinfo);
2052 for (j = 0; j < n; j++)
2054 if (fds[j].proc_fdtype != PROX_FDTYPE_SOCKET) continue;
2056 proc_pidfdinfo( map[i].unix_pid, fds[j].proc_fd, PROC_PIDFDSOCKETINFO, &sock, sizeof(sock) );
2057 if (sock.psi.soi_pcb == inode)
2059 HeapFree( GetProcessHeap(), 0, fds );
2060 return map[i].pid;
2064 HeapFree( GetProcessHeap(), 0, fds );
2066 return 0;
2067 #else
2068 FIXME( "not implemented\n" );
2069 return 0;
2070 #endif
2073 static BOOL match_class( TCP_TABLE_CLASS class, MIB_TCP_STATE state )
2075 switch (class)
2077 case TCP_TABLE_BASIC_ALL:
2078 case TCP_TABLE_OWNER_PID_ALL:
2079 case TCP_TABLE_OWNER_MODULE_ALL:
2080 return TRUE;
2082 case TCP_TABLE_BASIC_LISTENER:
2083 case TCP_TABLE_OWNER_PID_LISTENER:
2084 case TCP_TABLE_OWNER_MODULE_LISTENER:
2085 if (state == MIB_TCP_STATE_LISTEN) return TRUE;
2086 return FALSE;
2088 case TCP_TABLE_BASIC_CONNECTIONS:
2089 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2090 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2091 if (state == MIB_TCP_STATE_ESTAB) return TRUE;
2092 return FALSE;
2094 default:
2095 ERR( "unhandled class %u\n", class );
2096 return FALSE;
2100 DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2101 DWORD *size )
2103 MIB_TCPTABLE *table;
2104 MIB_TCPROW_OWNER_MODULE row;
2105 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2107 if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
2108 return ERROR_INVALID_PARAMETER;
2110 if (!(table = HeapAlloc( heap, flags, table_size )))
2111 return ERROR_OUTOFMEMORY;
2113 table->dwNumEntries = 0;
2115 #ifdef __linux__
2117 FILE *fp;
2119 if ((fp = fopen("/proc/net/tcp", "r")))
2121 char buf[512], *ptr;
2122 struct pid_map *map = NULL;
2123 unsigned int num_entries = 0;
2124 int inode;
2126 if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
2128 /* skip header line */
2129 ptr = fgets(buf, sizeof(buf), fp);
2130 while ((ptr = fgets(buf, sizeof(buf), fp)))
2132 if (sscanf( ptr, "%*x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d",
2133 &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
2134 &row.dwRemotePort, &row.dwState, &inode ) != 6)
2135 continue;
2136 row.dwLocalPort = htons( row.dwLocalPort );
2137 row.dwRemotePort = htons( row.dwRemotePort );
2138 row.dwState = TCPStateToMIBState( row.dwState );
2139 if (!match_class( class, row.dwState )) continue;
2141 if (class >= TCP_TABLE_OWNER_PID_LISTENER)
2142 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2143 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2145 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2146 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2148 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2149 break;
2151 HeapFree( GetProcessHeap(), 0, map );
2152 fclose( fp );
2154 else ret = ERROR_NOT_SUPPORTED;
2156 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2158 void *data;
2159 int fd, len;
2160 mib2_tcpConnEntry_t *entry;
2162 if ((fd = open_streams_mib( "tcp" )) != -1)
2164 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
2166 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2168 row.dwLocalAddr = entry->tcpConnLocalAddress;
2169 row.dwLocalPort = htons( entry->tcpConnLocalPort );
2170 row.dwRemoteAddr = entry->tcpConnRemAddress;
2171 row.dwRemotePort = htons( entry->tcpConnRemPort );
2172 row.dwState = entry->tcpConnState;
2173 if (!match_class( class, row.dwState )) continue;
2174 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2175 break;
2177 HeapFree( GetProcessHeap(), 0, data );
2179 close( fd );
2181 else ret = ERROR_NOT_SUPPORTED;
2183 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2185 size_t Len = 0;
2186 char *Buf = NULL;
2187 struct xinpgen *pXIG, *pOrigXIG;
2188 struct pid_map *pMap = NULL;
2189 unsigned NumEntries;
2191 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
2193 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2194 ret = ERROR_NOT_SUPPORTED;
2195 goto done;
2198 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2199 if (!Buf)
2201 ret = ERROR_OUTOFMEMORY;
2202 goto done;
2205 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
2207 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2208 ret = ERROR_NOT_SUPPORTED;
2209 goto done;
2212 if (class >= TCP_TABLE_OWNER_PID_LISTENER) pMap = get_pid_map( &NumEntries );
2214 /* Might be nothing here; first entry is just a header it seems */
2215 if (Len <= sizeof (struct xinpgen)) goto done;
2217 pOrigXIG = (struct xinpgen *)Buf;
2218 pXIG = pOrigXIG;
2220 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2221 pXIG->xig_len > sizeof (struct xinpgen);
2222 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2224 #if __FreeBSD_version >= 1200026
2225 struct xtcpcb *pTCPData = (struct xtcpcb *)pXIG;
2226 struct xinpcb *pINData = &pTCPData->xt_inp;
2227 struct xsocket *pSockData = &pINData->xi_socket;
2228 #else
2229 struct tcpcb *pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
2230 struct inpcb *pINData = &((struct xtcpcb *)pXIG)->xt_inp;
2231 struct xsocket *pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
2232 #endif
2234 /* Ignore sockets for other protocols */
2235 if (pSockData->xso_protocol != IPPROTO_TCP)
2236 continue;
2238 /* Ignore PCBs that were freed while generating the data */
2239 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2240 continue;
2242 /* we're only interested in IPv4 addresses */
2243 if (!(pINData->inp_vflag & INP_IPV4) ||
2244 (pINData->inp_vflag & INP_IPV6))
2245 continue;
2247 /* If all 0's, skip it */
2248 if (!pINData->inp_laddr.s_addr &&
2249 !pINData->inp_lport &&
2250 !pINData->inp_faddr.s_addr &&
2251 !pINData->inp_fport)
2252 continue;
2254 /* Fill in structure details */
2255 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2256 row.dwLocalPort = pINData->inp_lport;
2257 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
2258 row.dwRemotePort = pINData->inp_fport;
2259 row.dwState = TCPStateToMIBState (pTCPData->t_state);
2260 if (!match_class( class, row.dwState )) continue;
2261 if (class >= TCP_TABLE_OWNER_PID_LISTENER)
2262 row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
2263 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2265 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2266 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2268 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2269 break;
2272 done:
2273 HeapFree( GetProcessHeap(), 0, pMap );
2274 HeapFree (GetProcessHeap (), 0, Buf);
2276 #else
2277 FIXME( "not implemented\n" );
2278 ret = ERROR_NOT_SUPPORTED;
2279 #endif
2281 if (!table) return ERROR_OUTOFMEMORY;
2282 if (!ret)
2284 if (order && table->dwNumEntries)
2285 qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
2286 *tablep = table;
2288 else HeapFree( heap, flags, table );
2289 if (size) *size = get_tcp_table_sizes( class, count, NULL );
2290 TRACE( "returning ret %u table %p\n", ret, table );
2291 return ret;
2294 /******************************************************************
2295 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
2297 * Get the TCP connection table.
2298 * Like GetTcpTable(), but allocate the returned table from heap.
2300 * PARAMS
2301 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2302 * allocated and returned.
2303 * bOrder [In] whether to sort the table
2304 * heap [In] heap from which the table is allocated
2305 * flags [In] flags to HeapAlloc
2307 * RETURNS
2308 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2309 * returns otherwise.
2311 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
2312 HANDLE heap, DWORD flags )
2314 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
2316 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
2317 return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
2320 /******************************************************************
2321 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
2323 * Get the TCP connection table.
2324 * Like GetTcpTable(), but allocate the returned table from heap.
2326 * PARAMS
2327 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE_EX is
2328 * allocated and returned.
2329 * bOrder [In] whether to sort the table
2330 * heap [In] heap from which the table is allocated
2331 * flags [In] flags to HeapAlloc
2332 * family [In] address family [AF_INET|AF_INET6]
2334 * RETURNS
2335 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2336 * returns otherwise.
2338 DWORD WINAPI AllocateAndGetTcpExTableFromStack( VOID **ppTcpTable, BOOL bOrder,
2339 HANDLE heap, DWORD flags, DWORD family )
2341 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x, family %u\n",
2342 ppTcpTable, bOrder, heap, flags, family);
2344 if (!ppTcpTable || !family)
2345 return ERROR_INVALID_PARAMETER;
2347 if (family != WS_AF_INET)
2349 FIXME( "family = %u not supported\n", family );
2350 return ERROR_NOT_SUPPORTED;
2353 return build_tcp_table( TCP_TABLE_OWNER_PID_ALL, ppTcpTable, bOrder, heap, flags, NULL );
2356 static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2358 DWORD table_size;
2360 switch (class)
2362 case UDP_TABLE_BASIC:
2364 table_size = FIELD_OFFSET(MIB_UDPTABLE, table[row_count]);
2365 if (row_size) *row_size = sizeof(MIB_UDPROW);
2366 break;
2368 case UDP_TABLE_OWNER_PID:
2370 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table[row_count]);
2371 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_PID);
2372 break;
2374 case UDP_TABLE_OWNER_MODULE:
2376 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table[row_count]);
2377 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_MODULE);
2378 break;
2380 default:
2381 ERR("unhandled class %u\n", class);
2382 return 0;
2384 return table_size;
2387 static int compare_udp_rows(const void *a, const void *b)
2389 const MIB_UDPROW *rowA = a;
2390 const MIB_UDPROW *rowB = b;
2391 int ret;
2393 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
2394 return rowA->dwLocalPort - rowB->dwLocalPort;
2397 DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2398 DWORD *size )
2400 MIB_UDPTABLE *table;
2401 MIB_UDPROW_OWNER_MODULE row;
2402 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2404 if (!(table_size = get_udp_table_sizes( class, count, &row_size )))
2405 return ERROR_INVALID_PARAMETER;
2407 if (!(table = HeapAlloc( heap, flags, table_size )))
2408 return ERROR_OUTOFMEMORY;
2410 table->dwNumEntries = 0;
2411 memset( &row, 0, sizeof(row) );
2413 #ifdef __linux__
2415 FILE *fp;
2417 if ((fp = fopen( "/proc/net/udp", "r" )))
2419 char buf[512], *ptr;
2420 struct pid_map *map = NULL;
2421 unsigned int num_entries = 0;
2422 int inode;
2424 if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
2426 /* skip header line */
2427 ptr = fgets( buf, sizeof(buf), fp );
2428 while ((ptr = fgets( buf, sizeof(buf), fp )))
2430 if (sscanf( ptr, "%*u: %x:%x %*s %*s %*s %*s %*s %*s %*s %d",
2431 &row.dwLocalAddr, &row.dwLocalPort, &inode ) != 3)
2432 continue;
2433 row.dwLocalPort = htons( row.dwLocalPort );
2435 if (class >= UDP_TABLE_OWNER_PID)
2436 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2437 if (class >= UDP_TABLE_OWNER_MODULE)
2439 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2440 row.u.dwFlags = 0;
2441 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2443 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2444 break;
2446 HeapFree( GetProcessHeap(), 0, map );
2447 fclose( fp );
2449 else ret = ERROR_NOT_SUPPORTED;
2451 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2453 void *data;
2454 int fd, len;
2455 mib2_udpEntry_t *entry;
2457 if ((fd = open_streams_mib( "udp" )) != -1)
2459 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
2461 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2463 row.dwLocalAddr = entry->udpLocalAddress;
2464 row.dwLocalPort = htons( entry->udpLocalPort );
2465 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2466 break;
2468 HeapFree( GetProcessHeap(), 0, data );
2470 close( fd );
2472 else ret = ERROR_NOT_SUPPORTED;
2474 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2476 size_t Len = 0;
2477 char *Buf = NULL;
2478 struct xinpgen *pXIG, *pOrigXIG;
2479 struct pid_map *pMap = NULL;
2480 unsigned NumEntries;
2482 if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
2484 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2485 ret = ERROR_NOT_SUPPORTED;
2486 goto done;
2489 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2490 if (!Buf)
2492 ret = ERROR_OUTOFMEMORY;
2493 goto done;
2496 if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
2498 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2499 ret = ERROR_NOT_SUPPORTED;
2500 goto done;
2503 if (class >= UDP_TABLE_OWNER_PID)
2504 pMap = get_pid_map( &NumEntries );
2506 /* Might be nothing here; first entry is just a header it seems */
2507 if (Len <= sizeof (struct xinpgen)) goto done;
2509 pOrigXIG = (struct xinpgen *)Buf;
2510 pXIG = pOrigXIG;
2512 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2513 pXIG->xig_len > sizeof (struct xinpgen);
2514 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2516 #if __FreeBSD_version >= 1200026
2517 struct xinpcb *pINData = (struct xinpcb *)pXIG;
2518 struct xsocket *pSockData = &pINData->xi_socket;
2519 #else
2520 struct inpcb *pINData = &((struct xinpcb *)pXIG)->xi_inp;
2521 struct xsocket *pSockData = &((struct xinpcb *)pXIG)->xi_socket;
2522 #endif
2524 /* Ignore sockets for other protocols */
2525 if (pSockData->xso_protocol != IPPROTO_UDP)
2526 continue;
2528 /* Ignore PCBs that were freed while generating the data */
2529 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2530 continue;
2532 /* we're only interested in IPv4 addresses */
2533 if (!(pINData->inp_vflag & INP_IPV4) ||
2534 (pINData->inp_vflag & INP_IPV6))
2535 continue;
2537 /* If all 0's, skip it */
2538 if (!pINData->inp_laddr.s_addr &&
2539 !pINData->inp_lport)
2540 continue;
2542 /* Fill in structure details */
2543 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2544 row.dwLocalPort = pINData->inp_lport;
2545 if (class >= UDP_TABLE_OWNER_PID)
2546 row.dwOwningPid = find_owning_pid( pMap, NumEntries, (UINT_PTR)pSockData->so_pcb );
2547 if (class >= UDP_TABLE_OWNER_MODULE)
2549 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2550 row.u.dwFlags = 0;
2551 row.u.SpecificPortBind = !(pINData->inp_flags & INP_ANONPORT);
2552 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2554 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2555 break;
2558 done:
2559 HeapFree( GetProcessHeap(), 0, pMap );
2560 HeapFree (GetProcessHeap (), 0, Buf);
2562 #else
2563 FIXME( "not implemented\n" );
2564 ret = ERROR_NOT_SUPPORTED;
2565 #endif
2567 if (!table) return ERROR_OUTOFMEMORY;
2568 if (!ret)
2570 if (order && table->dwNumEntries)
2571 qsort( table->table, table->dwNumEntries, row_size, compare_udp_rows );
2572 *tablep = table;
2574 else HeapFree( heap, flags, table );
2575 if (size) *size = get_udp_table_sizes( class, count, NULL );
2576 TRACE( "returning ret %u table %p\n", ret, table );
2577 return ret;
2580 static DWORD get_tcp6_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2582 DWORD table_size;
2584 switch (class)
2586 case TCP_TABLE_BASIC_LISTENER:
2587 case TCP_TABLE_BASIC_CONNECTIONS:
2588 case TCP_TABLE_BASIC_ALL:
2590 table_size = FIELD_OFFSET(MIB_TCP6TABLE, table[row_count]);
2591 if (row_size) *row_size = sizeof(MIB_TCP6ROW);
2592 break;
2594 case TCP_TABLE_OWNER_PID_LISTENER:
2595 case TCP_TABLE_OWNER_PID_CONNECTIONS:
2596 case TCP_TABLE_OWNER_PID_ALL:
2598 table_size = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID, table[row_count]);
2599 if (row_size) *row_size = sizeof(MIB_TCP6ROW_OWNER_PID);
2600 break;
2602 case TCP_TABLE_OWNER_MODULE_LISTENER:
2603 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
2604 case TCP_TABLE_OWNER_MODULE_ALL:
2606 table_size = FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE, table[row_count]);
2607 if (row_size) *row_size = sizeof(MIB_TCP6ROW_OWNER_MODULE);
2608 break;
2610 default:
2611 ERR("unhandled class %u\n", class);
2612 return 0;
2614 return table_size;
2617 static int compare_tcp6_basic_rows(const void *a, const void *b)
2619 const MIB_TCP6ROW *rowA = a;
2620 const MIB_TCP6ROW *rowB = b;
2621 int ret;
2623 if ((ret = memcmp(&rowA->LocalAddr, &rowB->LocalAddr, sizeof(rowA->LocalAddr)) != 0)) return ret;
2624 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
2625 if ((ret = rowA->dwLocalPort - rowB->dwLocalPort) != 0) return ret;
2626 if ((ret = memcmp(&rowA->RemoteAddr, &rowB->RemoteAddr, sizeof(rowA->RemoteAddr)) != 0)) return ret;
2627 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
2628 return rowA->dwRemotePort - rowB->dwRemotePort;
2631 static int compare_tcp6_owner_rows(const void *a, const void *b)
2633 const MIB_TCP6ROW_OWNER_PID *rowA = a;
2634 const MIB_TCP6ROW_OWNER_PID *rowB = b;
2635 int ret;
2637 if ((ret = memcmp(&rowA->ucLocalAddr, &rowB->ucLocalAddr, sizeof(rowA->ucLocalAddr)) != 0)) return ret;
2638 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
2639 if ((ret = rowA->dwLocalPort - rowB->dwLocalPort) != 0) return ret;
2640 if ((ret = memcmp(&rowA->ucRemoteAddr, &rowB->ucRemoteAddr, sizeof(rowA->ucRemoteAddr)) != 0)) return ret;
2641 if ((ret = rowA->dwRemoteScopeId - rowB->dwRemoteScopeId) != 0) return ret;
2642 return rowA->dwRemotePort - rowB->dwRemotePort;
2645 static DWORD get_udp6_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2647 DWORD table_size;
2649 switch (class)
2651 case UDP_TABLE_BASIC:
2653 table_size = FIELD_OFFSET(MIB_UDP6TABLE, table[row_count]);
2654 if (row_size) *row_size = sizeof(MIB_UDP6ROW);
2655 break;
2657 case UDP_TABLE_OWNER_PID:
2659 table_size = FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID, table[row_count]);
2660 if (row_size) *row_size = sizeof(MIB_UDP6ROW_OWNER_PID);
2661 break;
2663 case UDP_TABLE_OWNER_MODULE:
2665 table_size = FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE, table[row_count]);
2666 if (row_size) *row_size = sizeof(MIB_UDP6ROW_OWNER_MODULE);
2667 break;
2669 default:
2670 ERR("unhandled class %u\n", class);
2671 return 0;
2673 return table_size;
2676 static int compare_udp6_rows(const void *a, const void *b)
2678 const MIB_UDP6ROW *rowA = a;
2679 const MIB_UDP6ROW *rowB = b;
2680 int ret;
2682 if ((ret = memcmp(&rowA->dwLocalAddr, &rowB->dwLocalAddr, sizeof(rowA->dwLocalAddr)) != 0)) return ret;
2683 if ((ret = rowA->dwLocalScopeId - rowB->dwLocalScopeId) != 0) return ret;
2684 return rowA->dwLocalPort - rowB->dwLocalPort;
2687 #if defined(__linux__) || (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN))
2688 struct ipv6_addr_scope
2690 IN6_ADDR addr;
2691 DWORD scope;
2694 static struct ipv6_addr_scope *get_ipv6_addr_scope_table(unsigned int *size)
2696 struct ipv6_addr_scope *table = NULL;
2697 unsigned int table_size = 0;
2698 #ifdef __linux__
2699 char buf[512], *ptr;
2700 FILE *fp;
2701 #elif defined(HAVE_GETIFADDRS)
2702 struct ifaddrs *addrs, *cur;
2703 #endif
2705 if (!(table = HeapAlloc( GetProcessHeap(), 0, sizeof(table[0]) )))
2706 return NULL;
2708 #ifdef __linux__
2709 if (!(fp = fopen( "/proc/net/if_inet6", "r" )))
2710 goto failed;
2712 while ((ptr = fgets( buf, sizeof(buf), fp )))
2714 WORD a[8];
2715 DWORD scope;
2716 struct ipv6_addr_scope *new_table;
2717 struct ipv6_addr_scope *entry;
2718 unsigned int i;
2720 if (sscanf( ptr, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*s %*s %x",
2721 &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7], &scope ) != 9)
2722 continue;
2724 table_size++;
2725 if (!(new_table = HeapReAlloc( GetProcessHeap(), 0, table, table_size * sizeof(table[0]) )))
2727 fclose(fp);
2728 goto failed;
2731 table = new_table;
2732 entry = &table[table_size - 1];
2734 i = 0;
2735 while (i < 8)
2737 entry->addr.u.Word[i] = htons(a[i]);
2738 i++;
2741 entry->scope = htons(scope);
2744 fclose(fp);
2745 #elif defined(HAVE_GETIFADDRS)
2746 if (getifaddrs(&addrs) == -1)
2747 goto failed;
2749 for (cur = addrs; cur; cur = cur->ifa_next)
2751 struct sockaddr_in6 *sin6;
2752 struct ipv6_addr_scope *new_table;
2753 struct ipv6_addr_scope *entry;
2755 if (cur->ifa_addr->sa_family != AF_INET6)
2756 continue;
2758 sin6 = (struct sockaddr_in6 *)cur->ifa_addr;
2760 table_size++;
2761 if (!(new_table = HeapReAlloc( GetProcessHeap(), 0, table, table_size * sizeof(table[0]) )))
2763 freeifaddrs(addrs);
2764 goto failed;
2767 table = new_table;
2768 entry = &table[table_size - 1];
2770 memcpy(&entry->addr, &sin6->sin6_addr, sizeof(entry->addr));
2771 entry->scope = sin6->sin6_scope_id;
2774 freeifaddrs(addrs);
2775 #else
2776 FIXME( "not implemented\n" );
2777 goto failed;
2778 #endif
2780 *size = table_size;
2781 return table;
2783 failed:
2784 HeapFree( GetProcessHeap(), 0, table );
2785 return NULL;
2788 static DWORD find_ipv6_addr_scope(const IN6_ADDR *addr, const struct ipv6_addr_scope *table, unsigned int size)
2790 const BYTE multicast_scope_mask = 0x0F;
2791 const BYTE multicast_scope_shift = 0;
2792 unsigned int i = 0;
2794 if (WS_IN6_IS_ADDR_UNSPECIFIED(addr))
2795 return 0;
2797 if (WS_IN6_IS_ADDR_MULTICAST(addr))
2798 return htons((addr->u.Byte[1] & multicast_scope_mask) >> multicast_scope_shift);
2800 if (!table)
2801 return -1;
2803 while (i < size)
2805 if (memcmp(&table[i].addr, addr, sizeof(table[i].addr)) == 0)
2806 return table[i].scope;
2807 i++;
2810 return -1;
2812 #endif
2814 DWORD build_tcp6_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2815 DWORD *size )
2817 MIB_TCP6TABLE *table;
2818 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2820 if (!(table_size = get_tcp6_table_sizes( class, count, &row_size )))
2821 return ERROR_INVALID_PARAMETER;
2823 if (!(table = HeapAlloc( heap, flags, table_size )))
2824 return ERROR_OUTOFMEMORY;
2826 table->dwNumEntries = 0;
2828 #ifdef __linux__
2830 MIB_TCP6ROW_OWNER_MODULE row;
2831 FILE *fp;
2833 if ((fp = fopen( "/proc/net/tcp6", "r" )))
2835 char buf[512], *ptr;
2836 struct pid_map *map = NULL;
2837 unsigned int num_entries = 0;
2838 struct ipv6_addr_scope *addr_scopes;
2839 unsigned int addr_scopes_size = 0;
2840 int inode;
2842 addr_scopes = get_ipv6_addr_scope_table(&addr_scopes_size);
2844 if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
2846 /* skip header line */
2847 ptr = fgets( buf, sizeof(buf), fp );
2848 while ((ptr = fgets( buf, sizeof(buf), fp )))
2850 DWORD *local_addr = (DWORD *)&row.ucLocalAddr;
2851 DWORD *remote_addr = (DWORD *)&row.ucRemoteAddr;
2853 if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %*s %*s %*s %*s %*s %*s %*s %d",
2854 &local_addr[0], &local_addr[1], &local_addr[2], &local_addr[3], &row.dwLocalPort,
2855 &remote_addr[0], &remote_addr[1], &remote_addr[2], &remote_addr[3], &row.dwRemotePort,
2856 &row.dwState, &inode ) != 12)
2857 continue;
2858 row.dwState = TCPStateToMIBState( row.dwState );
2859 if (!match_class( class, row.dwState )) continue;
2860 row.dwLocalScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size);
2861 row.dwLocalPort = htons( row.dwLocalPort );
2862 row.dwRemoteScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucRemoteAddr, addr_scopes, addr_scopes_size);
2863 row.dwRemotePort = htons( row.dwRemotePort );
2865 if (class <= TCP_TABLE_BASIC_ALL)
2867 /* MIB_TCP6ROW has a different field order */
2868 MIB_TCP6ROW basic_row;
2869 basic_row.State = row.dwState;
2870 memcpy( &basic_row.LocalAddr, &row.ucLocalAddr, sizeof(row.ucLocalAddr) );
2871 basic_row.dwLocalScopeId = row.dwLocalScopeId;
2872 basic_row.dwLocalPort = row.dwLocalPort;
2873 memcpy( &basic_row.RemoteAddr, &row.ucRemoteAddr, sizeof(row.ucRemoteAddr) );
2874 basic_row.dwRemoteScopeId = row.dwRemoteScopeId;
2875 basic_row.dwRemotePort = row.dwRemotePort;
2876 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &basic_row, row_size )))
2877 break;
2878 continue;
2881 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2882 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
2884 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
2885 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
2887 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
2888 break;
2890 HeapFree( GetProcessHeap(), 0, map );
2891 HeapFree( GetProcessHeap(), 0, addr_scopes );
2892 fclose( fp );
2894 else ret = ERROR_NOT_SUPPORTED;
2896 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2898 static const char zero[sizeof(IN6_ADDR)] = {0};
2900 MIB_TCP6ROW_OWNER_MODULE row;
2901 size_t len = 0;
2902 char *buf = NULL;
2903 struct xinpgen *xig, *orig_xig;
2904 struct pid_map *map = NULL;
2905 unsigned num_entries;
2906 struct ipv6_addr_scope *addr_scopes = NULL;
2907 unsigned int addr_scopes_size = 0;
2909 if (sysctlbyname( "net.inet.tcp.pcblist", NULL, &len, NULL, 0 ) < 0)
2911 ERR( "Failure to read net.inet.tcp.pcblist via sysctlbyname!\n" );
2912 ret = ERROR_NOT_SUPPORTED;
2913 goto done;
2916 buf = HeapAlloc( GetProcessHeap(), 0, len );
2917 if (!buf)
2919 ret = ERROR_OUTOFMEMORY;
2920 goto done;
2923 if (sysctlbyname( "net.inet.tcp.pcblist", buf, &len, NULL, 0 ) < 0)
2925 ERR( "Failure to read net.inet.tcp.pcblist via sysctlbyname!\n" );
2926 ret = ERROR_NOT_SUPPORTED;
2927 goto done;
2930 addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
2931 if (!addr_scopes)
2933 ret = ERROR_OUTOFMEMORY;
2934 goto done;
2937 if (class >= TCP_TABLE_OWNER_PID_LISTENER) map = get_pid_map( &num_entries );
2939 /* Might be nothing here; first entry is just a header it seems */
2940 if (len <= sizeof (struct xinpgen)) goto done;
2942 orig_xig = (struct xinpgen *)buf;
2943 xig = orig_xig;
2945 for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
2946 xig->xig_len > sizeof (struct xinpgen);
2947 xig = (struct xinpgen *)((char *)xig + xig->xig_len))
2949 #if __FreeBSD_version >= 1200026
2950 struct xtcpcb *tcp = (struct xtcpcb *)xig;
2951 struct xinpcb *in = &tcp->xt_inp;
2952 struct xsocket *sock = &in->xi_socket;
2953 #else
2954 struct tcpcb *tcp = &((struct xtcpcb *)xig)->xt_tp;
2955 struct inpcb *in = &((struct xtcpcb *)xig)->xt_inp;
2956 struct xsocket *sock = &((struct xtcpcb *)xig)->xt_socket;
2957 #endif
2959 /* Ignore sockets for other protocols */
2960 if (sock->xso_protocol != IPPROTO_TCP)
2961 continue;
2963 /* Ignore PCBs that were freed while generating the data */
2964 if (in->inp_gencnt > orig_xig->xig_gen)
2965 continue;
2967 /* we're only interested in IPv6 addresses */
2968 if (!(in->inp_vflag & INP_IPV6) ||
2969 (in->inp_vflag & INP_IPV4))
2970 continue;
2972 /* If all 0's, skip it */
2973 if (!memcmp( &in->in6p_laddr, zero, sizeof(zero) ) && !in->inp_lport &&
2974 !memcmp( &in->in6p_faddr, zero, sizeof(zero) ) && !in->inp_fport)
2975 continue;
2977 /* Fill in structure details */
2978 memcpy( &row.ucLocalAddr, &in->in6p_laddr.s6_addr, sizeof(row.ucLocalAddr) );
2979 row.dwLocalPort = in->inp_lport;
2980 row.dwLocalScopeId = find_ipv6_addr_scope( (const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size );
2981 memcpy( &row.ucRemoteAddr, &in->in6p_faddr.s6_addr, sizeof(row.ucRemoteAddr) );
2982 row.dwRemotePort = in->inp_fport;
2983 row.dwLocalScopeId = find_ipv6_addr_scope( (const IN6_ADDR *)&row.ucRemoteAddr, addr_scopes, addr_scopes_size );
2984 row.dwState = TCPStateToMIBState( tcp->t_state );
2985 if (!match_class( class, row.dwState )) continue;
2987 if (class <= TCP_TABLE_BASIC_ALL)
2989 /* MIB_TCP6ROW has a different field order */
2990 MIB_TCP6ROW basic_row;
2991 basic_row.State = row.dwState;
2992 memcpy( &basic_row.LocalAddr, &row.ucLocalAddr, sizeof(row.ucLocalAddr) );
2993 basic_row.dwLocalScopeId = row.dwLocalScopeId;
2994 basic_row.dwLocalPort = row.dwLocalPort;
2995 memcpy( &basic_row.RemoteAddr, &row.ucRemoteAddr, sizeof(row.ucRemoteAddr) );
2996 basic_row.dwRemoteScopeId = row.dwRemoteScopeId;
2997 basic_row.dwRemotePort = row.dwRemotePort;
2998 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &basic_row, row_size )))
2999 break;
3000 continue;
3003 row.dwOwningPid = find_owning_pid( map, num_entries, (UINT_PTR)sock->so_pcb );
3004 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER)
3006 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
3007 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
3009 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
3010 break;
3013 done:
3014 HeapFree( GetProcessHeap(), 0, map );
3015 HeapFree( GetProcessHeap(), 0, buf );
3016 HeapFree( GetProcessHeap(), 0, addr_scopes );
3018 #else
3019 FIXME( "not implemented\n" );
3020 ret = ERROR_NOT_SUPPORTED;
3021 #endif
3023 if (!table) return ERROR_OUTOFMEMORY;
3024 if (!ret)
3026 if (order && table->dwNumEntries)
3028 qsort( table->table, table->dwNumEntries, row_size,
3029 class <= TCP_TABLE_BASIC_ALL ? compare_tcp6_basic_rows : compare_tcp6_owner_rows );
3031 *tablep = table;
3033 else HeapFree( heap, flags, table );
3034 if (size) *size = get_tcp6_table_sizes( class, count, NULL );
3035 TRACE( "returning ret %u table %p\n", ret, table );
3036 return ret;
3039 DWORD build_udp6_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
3040 DWORD *size )
3042 MIB_UDP6TABLE *table;
3043 MIB_UDP6ROW_OWNER_MODULE row;
3044 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
3046 if (!(table_size = get_udp6_table_sizes( class, count, &row_size )))
3047 return ERROR_INVALID_PARAMETER;
3049 if (!(table = HeapAlloc( heap, flags, table_size )))
3050 return ERROR_OUTOFMEMORY;
3052 table->dwNumEntries = 0;
3053 memset( &row, 0, sizeof(row) );
3055 #ifdef __linux__
3057 FILE *fp;
3059 if ((fp = fopen( "/proc/net/udp6", "r" )))
3061 char buf[512], *ptr;
3062 struct pid_map *map = NULL;
3063 unsigned int num_entries = 0;
3064 struct ipv6_addr_scope *addr_scopes;
3065 unsigned int addr_scopes_size = 0;
3066 int inode;
3068 addr_scopes = get_ipv6_addr_scope_table(&addr_scopes_size);
3070 if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
3072 /* skip header line */
3073 ptr = fgets( buf, sizeof(buf), fp );
3074 while ((ptr = fgets( buf, sizeof(buf), fp )))
3076 DWORD *local_addr = (DWORD *)&row.ucLocalAddr;
3078 if (sscanf( ptr, "%*u: %8x%8x%8x%8x:%x %*s %*s %*s %*s %*s %*s %*s %d",
3079 &local_addr[0], &local_addr[1], &local_addr[2], &local_addr[3],
3080 &row.dwLocalPort, &inode ) != 6)
3081 continue;
3082 row.dwLocalScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size);
3083 row.dwLocalPort = htons( row.dwLocalPort );
3085 if (class >= UDP_TABLE_OWNER_PID)
3086 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
3087 if (class >= UDP_TABLE_OWNER_MODULE)
3089 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
3090 row.u.dwFlags = 0;
3091 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
3093 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
3094 break;
3096 HeapFree( GetProcessHeap(), 0, map );
3097 HeapFree( GetProcessHeap(), 0, addr_scopes );
3098 fclose( fp );
3100 else ret = ERROR_NOT_SUPPORTED;
3102 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
3104 static const char zero[sizeof(IN6_ADDR)] = {0};
3106 size_t len = 0;
3107 char *buf = NULL;
3108 struct xinpgen *xig, *orig_xig;
3109 struct pid_map *map = NULL;
3110 unsigned num_entries;
3111 struct ipv6_addr_scope *addr_scopes = NULL;
3112 unsigned int addr_scopes_size = 0;
3114 if (sysctlbyname( "net.inet.udp.pcblist", NULL, &len, NULL, 0 ) < 0)
3116 ERR( "Failure to read net.inet.udp.pcblist via sysctlbyname!\n" );
3117 ret = ERROR_NOT_SUPPORTED;
3118 goto done;
3121 buf = HeapAlloc( GetProcessHeap(), 0, len );
3122 if (!buf)
3124 ret = ERROR_OUTOFMEMORY;
3125 goto done;
3128 if (sysctlbyname( "net.inet.udp.pcblist", buf, &len, NULL, 0 ) < 0)
3130 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
3131 ret = ERROR_NOT_SUPPORTED;
3132 goto done;
3135 addr_scopes = get_ipv6_addr_scope_table( &addr_scopes_size );
3136 if (!addr_scopes)
3138 ret = ERROR_OUTOFMEMORY;
3139 goto done;
3142 if (class >= UDP_TABLE_OWNER_PID) map = get_pid_map( &num_entries );
3144 /* Might be nothing here; first entry is just a header it seems */
3145 if (len <= sizeof (struct xinpgen)) goto done;
3147 orig_xig = (struct xinpgen *)buf;
3148 xig = orig_xig;
3150 for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
3151 xig->xig_len > sizeof (struct xinpgen);
3152 xig = (struct xinpgen *)((char *)xig + xig->xig_len))
3154 #if __FreeBSD_version >= 1200026
3155 struct xinpcb *in = (struct xinpcb *)xig;
3156 struct xsocket *sock = &in->xi_socket;
3157 #else
3158 struct inpcb *in = &((struct xinpcb *)xig)->xi_inp;
3159 struct xsocket *sock = &((struct xinpcb *)xig)->xi_socket;
3160 #endif
3162 /* Ignore sockets for other protocols */
3163 if (sock->xso_protocol != IPPROTO_UDP)
3164 continue;
3166 /* Ignore PCBs that were freed while generating the data */
3167 if (in->inp_gencnt > orig_xig->xig_gen)
3168 continue;
3170 /* we're only interested in IPv6 addresses */
3171 if (!(in->inp_vflag & INP_IPV6) ||
3172 (in->inp_vflag & INP_IPV4))
3173 continue;
3175 /* If all 0's, skip it */
3176 if (!memcmp( &in->in6p_laddr.s6_addr, zero, sizeof(zero) ) && !in->inp_lport)
3177 continue;
3179 /* Fill in structure details */
3180 memcpy(row.ucLocalAddr, &in->in6p_laddr.s6_addr, sizeof(row.ucLocalAddr));
3181 row.dwLocalPort = in->inp_lport;
3182 row.dwLocalScopeId = find_ipv6_addr_scope((const IN6_ADDR *)&row.ucLocalAddr, addr_scopes, addr_scopes_size);
3183 if (class >= UDP_TABLE_OWNER_PID)
3184 row.dwOwningPid = find_owning_pid( map, num_entries, (UINT_PTR)sock->so_pcb );
3185 if (class >= UDP_TABLE_OWNER_MODULE)
3187 row.liCreateTimestamp.QuadPart = 0; /* FIXME */
3188 row.u.dwFlags = 0;
3189 row.u.SpecificPortBind = !(in->inp_flags & INP_ANONPORT);
3190 memset( &row.OwningModuleInfo, 0, sizeof(row.OwningModuleInfo) );
3192 if (!(table = append_table_row( heap, flags, table, &table_size, &count, &row, row_size )))
3193 break;
3196 done:
3197 HeapFree( GetProcessHeap(), 0, map );
3198 HeapFree( GetProcessHeap(), 0, buf );
3199 HeapFree( GetProcessHeap(), 0, addr_scopes );
3201 #else
3202 FIXME( "not implemented\n" );
3203 ret = ERROR_NOT_SUPPORTED;
3204 #endif
3206 if (!table) return ERROR_OUTOFMEMORY;
3207 if (!ret)
3209 if (order && table->dwNumEntries)
3210 qsort( table->table, table->dwNumEntries, row_size, compare_udp6_rows );
3211 *tablep = table;
3213 else HeapFree( heap, flags, table );
3214 if (size) *size = get_udp6_table_sizes( class, count, NULL );
3215 TRACE( "returning ret %u table %p\n", ret, table );
3216 return ret;
3219 /******************************************************************
3220 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
3222 * Get the UDP listener table.
3223 * Like GetUdpTable(), but allocate the returned table from heap.
3225 * PARAMS
3226 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
3227 * allocated and returned.
3228 * bOrder [In] whether to sort the table
3229 * heap [In] heap from which the table is allocated
3230 * flags [In] flags to HeapAlloc
3232 * RETURNS
3233 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
3234 * returns otherwise.
3236 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
3237 HANDLE heap, DWORD flags)
3239 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
3241 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
3242 return build_udp_table( UDP_TABLE_BASIC, (void **)ppUdpTable, bOrder, heap, flags, NULL );