iphlpapi: Fix HRESULT/win32 error code confusion.
[wine.git] / dlls / iphlpapi / ipstats.c
blob1f52fcc4723f387108e356800d98542add99611b
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
127 #ifndef ROUNDUP
128 #define ROUNDUP(a) \
129 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
130 #endif
131 #ifndef ADVANCE
132 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
133 #endif
135 #include "ntstatus.h"
136 #define WIN32_NO_STATUS
137 #define NONAMELESSUNION
138 #include "ifenum.h"
139 #include "ipstats.h"
141 #include "wine/debug.h"
142 #include "wine/server.h"
144 #ifndef HAVE_NETINET_TCP_FSM_H
145 #define TCPS_ESTABLISHED 1
146 #define TCPS_SYN_SENT 2
147 #define TCPS_SYN_RECEIVED 3
148 #define TCPS_FIN_WAIT_1 4
149 #define TCPS_FIN_WAIT_2 5
150 #define TCPS_TIME_WAIT 6
151 #define TCPS_CLOSED 7
152 #define TCPS_CLOSE_WAIT 8
153 #define TCPS_LAST_ACK 9
154 #define TCPS_LISTEN 10
155 #define TCPS_CLOSING 11
156 #endif
158 #ifndef RTF_MULTICAST
159 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
160 #endif
162 #ifndef RTF_LLINFO
163 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
164 #endif
166 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
168 #ifdef HAVE_LIBKSTAT
169 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
171 unsigned int i;
172 kstat_named_t *data = ksp->ks_data;
174 for (i = 0; i < ksp->ks_ndata; i++)
175 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
176 return 0;
179 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
181 unsigned int i;
182 kstat_named_t *data = ksp->ks_data;
184 for (i = 0; i < ksp->ks_ndata; i++)
185 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
186 return 0;
188 #endif
190 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
191 static int open_streams_mib( const char *proto )
193 int fd;
194 struct strbuf buf;
195 struct request
197 struct T_optmgmt_req req_header;
198 struct opthdr opt_header;
199 } request;
201 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
203 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
204 return -1;
206 if (proto) ioctl( fd, I_PUSH, proto );
208 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
209 request.req_header.OPT_length = sizeof(request.opt_header);
210 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
211 request.req_header.MGMT_flags = T_CURRENT;
212 request.opt_header.level = MIB2_IP;
213 request.opt_header.name = 0;
214 request.opt_header.len = 0;
216 buf.len = sizeof(request);
217 buf.buf = (caddr_t)&request;
218 if (putmsg( fd, &buf, NULL, 0 ) == -1)
220 WARN( "putmsg: %s\n", strerror(errno) );
221 close( fd );
222 fd = -1;
224 return fd;
227 static void *read_mib_entry( int fd, int level, int name, int *len )
229 struct strbuf buf;
230 void *data;
231 int ret, flags = 0;
233 struct reply
235 struct T_optmgmt_ack ack_header;
236 struct opthdr opt_header;
237 } reply;
239 for (;;)
241 buf.maxlen = sizeof(reply);
242 buf.buf = (caddr_t)&reply;
243 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
244 if (!(ret & MOREDATA)) return NULL;
245 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
246 if (buf.len < sizeof(reply.ack_header)) return NULL;
247 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
249 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
250 buf.maxlen = reply.opt_header.len;
251 buf.buf = (caddr_t)data;
252 flags = 0;
253 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
254 reply.opt_header.level == level &&
255 reply.opt_header.name == name)
257 *len = buf.len;
258 return data;
260 HeapFree( GetProcessHeap(), 0, data );
263 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
265 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
267 DWORD ret = ERROR_NOT_SUPPORTED;
269 if (!name || !entry) return ERROR_INVALID_PARAMETER;
271 #ifdef __linux__
273 FILE *fp;
275 if ((fp = fopen("/proc/net/dev", "r")))
277 DWORD skip;
278 char buf[512], *ptr;
279 int nameLen = strlen(name);
281 while ((ptr = fgets(buf, sizeof(buf), fp)))
283 while (*ptr && isspace(*ptr)) ptr++;
284 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
286 ptr += nameLen + 1;
287 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
288 &entry->dwInOctets, &entry->dwInUcastPkts,
289 &entry->dwInErrors, &entry->dwInDiscards,
290 &skip, &skip, &skip,
291 &entry->dwInNUcastPkts, &entry->dwOutOctets,
292 &entry->dwOutUcastPkts, &entry->dwOutErrors,
293 &entry->dwOutDiscards );
294 break;
297 fclose(fp);
298 ret = NO_ERROR;
301 #elif defined(HAVE_LIBKSTAT)
303 kstat_ctl_t *kc;
304 kstat_t *ksp;
306 if ((kc = kstat_open()) &&
307 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
308 kstat_read( kc, ksp, NULL ) != -1 &&
309 ksp->ks_type == KSTAT_TYPE_NAMED)
311 entry->dwMtu = 1500; /* FIXME */
312 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
313 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
314 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
315 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
316 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
317 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
318 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
319 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
320 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
321 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
322 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
323 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
324 entry->dwOutDiscards = 0; /* FIXME */
325 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
326 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
327 ret = NO_ERROR;
329 if (kc) kstat_close( kc );
331 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
333 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
334 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
336 size_t needed;
337 char *buf = NULL, *end;
338 struct if_msghdr *ifm;
339 struct if_data ifdata;
341 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
343 ERR ("failed to get size of iflist\n");
344 goto done;
346 buf = HeapAlloc (GetProcessHeap (), 0, needed);
347 if (!buf)
349 ret = ERROR_OUTOFMEMORY;
350 goto done;
352 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
354 ERR ("failed to get iflist\n");
355 goto done;
357 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
359 ifm = (struct if_msghdr *) buf;
360 if(ifm->ifm_type == RTM_IFINFO)
362 ifdata = ifm->ifm_data;
363 entry->dwMtu = ifdata.ifi_mtu;
364 entry->dwSpeed = ifdata.ifi_baudrate;
365 entry->dwInOctets = ifdata.ifi_ibytes;
366 entry->dwInErrors = ifdata.ifi_ierrors;
367 entry->dwInDiscards = ifdata.ifi_iqdrops;
368 entry->dwInUcastPkts = ifdata.ifi_ipackets;
369 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
370 entry->dwOutOctets = ifdata.ifi_obytes;
371 entry->dwOutUcastPkts = ifdata.ifi_opackets;
372 entry->dwOutErrors = ifdata.ifi_oerrors;
373 ret = NO_ERROR;
374 break;
377 done:
378 HeapFree (GetProcessHeap (), 0, buf);
380 #else
381 FIXME( "unimplemented\n" );
382 #endif
383 return ret;
387 /******************************************************************
388 * GetIcmpStatistics (IPHLPAPI.@)
390 * Get the ICMP statistics for the local computer.
392 * PARAMS
393 * stats [Out] buffer for ICMP statistics
395 * RETURNS
396 * Success: NO_ERROR
397 * Failure: error code from winerror.h
399 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
401 DWORD ret = ERROR_NOT_SUPPORTED;
403 if (!stats) return ERROR_INVALID_PARAMETER;
404 memset( stats, 0, sizeof(MIB_ICMP) );
406 #ifdef __linux__
408 FILE *fp;
410 if ((fp = fopen("/proc/net/snmp", "r")))
412 static const char hdr[] = "Icmp:";
413 char buf[512], *ptr;
415 while ((ptr = fgets(buf, sizeof(buf), fp)))
417 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
418 /* last line was a header, get another */
419 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
420 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
422 ptr += sizeof(hdr);
423 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
424 &stats->stats.icmpInStats.dwMsgs,
425 &stats->stats.icmpInStats.dwErrors,
426 &stats->stats.icmpInStats.dwDestUnreachs,
427 &stats->stats.icmpInStats.dwTimeExcds,
428 &stats->stats.icmpInStats.dwParmProbs,
429 &stats->stats.icmpInStats.dwSrcQuenchs,
430 &stats->stats.icmpInStats.dwRedirects,
431 &stats->stats.icmpInStats.dwEchoReps,
432 &stats->stats.icmpInStats.dwTimestamps,
433 &stats->stats.icmpInStats.dwTimestampReps,
434 &stats->stats.icmpInStats.dwAddrMasks,
435 &stats->stats.icmpInStats.dwAddrMaskReps,
436 &stats->stats.icmpOutStats.dwMsgs,
437 &stats->stats.icmpOutStats.dwErrors,
438 &stats->stats.icmpOutStats.dwDestUnreachs,
439 &stats->stats.icmpOutStats.dwTimeExcds,
440 &stats->stats.icmpOutStats.dwParmProbs,
441 &stats->stats.icmpOutStats.dwSrcQuenchs,
442 &stats->stats.icmpOutStats.dwRedirects,
443 &stats->stats.icmpOutStats.dwEchoReps,
444 &stats->stats.icmpOutStats.dwTimestamps,
445 &stats->stats.icmpOutStats.dwTimestampReps,
446 &stats->stats.icmpOutStats.dwAddrMasks,
447 &stats->stats.icmpOutStats.dwAddrMaskReps );
448 break;
451 fclose(fp);
452 ret = NO_ERROR;
455 #elif defined(HAVE_LIBKSTAT)
457 static char ip[] = "ip", icmp[] = "icmp";
458 kstat_ctl_t *kc;
459 kstat_t *ksp;
461 if ((kc = kstat_open()) &&
462 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
463 kstat_read( kc, ksp, NULL ) != -1 &&
464 ksp->ks_type == KSTAT_TYPE_NAMED)
466 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
467 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
468 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
469 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
470 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
471 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
472 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
473 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
474 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
475 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
476 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
477 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
478 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
479 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
480 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
481 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
482 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
483 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
484 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
485 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
486 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
487 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
488 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
489 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
490 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
491 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
492 ret = NO_ERROR;
494 if (kc) kstat_close( kc );
496 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && defined(HAVE_STRUCT_ICMPSTAT_ICPS_INHIST)
498 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
499 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
500 struct icmpstat icmp_stat;
501 size_t needed = sizeof(icmp_stat);
502 int i;
504 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
506 /*in stats */
507 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
508 for(i = 0; i <= ICMP_MAXTYPE; i++)
509 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
511 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
513 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
514 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
515 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
516 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
517 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
518 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
519 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
520 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
521 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
522 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
523 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
525 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST
526 /* out stats */
527 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
528 for(i = 0; i <= ICMP_MAXTYPE; i++)
529 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
531 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
533 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
534 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
535 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
536 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
537 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
538 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
539 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
540 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
541 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
542 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
543 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
544 #endif /* HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST */
545 ret = NO_ERROR;
548 #else /* ICMPCTL_STATS */
549 FIXME( "unimplemented\n" );
550 #endif
551 return ret;
554 /******************************************************************
555 * GetIcmpStatisticsEx (IPHLPAPI.@)
557 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
559 * PARAMS
560 * stats [Out] buffer for ICMP statistics
561 * family [In] specifies whether IPv4 or IPv6 statistics are returned
563 * RETURNS
564 * Success: NO_ERROR
565 * Failure: error code from winerror.h
567 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX stats, DWORD family)
569 DWORD ret = ERROR_NOT_SUPPORTED;
570 MIB_ICMP ipv4stats;
572 if (!stats) return ERROR_INVALID_PARAMETER;
573 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
574 memset( stats, 0, sizeof(MIB_ICMP_EX) );
576 if (family == WS_AF_INET6)
578 #ifdef __linux__
580 FILE *fp;
582 if ((fp = fopen("/proc/net/snmp6", "r")))
584 struct icmpstatstruct{
585 const char *name;
586 DWORD pos;
588 static const struct icmpstatstruct icmpinstatlist[] = {
589 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
590 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
591 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
592 { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
593 { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
594 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
595 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
596 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
597 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
598 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
599 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
600 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
601 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
602 { "Icmp6InRedirects", ND_REDIRECT },
603 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
605 static const struct icmpstatstruct icmpoutstatlist[] = {
606 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
607 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
608 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
609 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
610 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
611 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
612 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
613 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
614 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
615 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
616 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
617 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
618 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
619 { "Icmp6OutRedirects", ND_REDIRECT },
620 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
622 char buf[512], *ptr, *value;
623 DWORD res, i;
625 while ((ptr = fgets(buf, sizeof(buf), fp)))
627 if (!(value = strchr(buf, ' ')))
628 continue;
630 /* terminate the valuename */
631 ptr = value - 1;
632 *(ptr + 1) = '\0';
634 /* and strip leading spaces from value */
635 value += 1;
636 while (*value==' ') value++;
637 if ((ptr = strchr(value, '\n')))
638 *ptr='\0';
640 if (!strcasecmp(buf, "Icmp6InMsgs"))
642 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwMsgs = res;
643 continue;
646 if (!strcasecmp(buf, "Icmp6InErrors"))
648 if (sscanf(value, "%d", &res)) stats->icmpInStats.dwErrors = res;
649 continue;
652 for (i = 0; i < sizeof(icmpinstatlist)/sizeof(icmpinstatlist[0]); i++)
654 if (!strcasecmp(buf, icmpinstatlist[i].name))
656 if (sscanf(value, "%d", &res))
657 stats->icmpInStats.rgdwTypeCount[icmpinstatlist[i].pos] = res;
658 break;
662 if (!strcasecmp(buf, "Icmp6OutMsgs"))
664 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwMsgs = res;
665 continue;
668 if (!strcasecmp(buf, "Icmp6OutErrors"))
670 if (sscanf(value, "%d", &res)) stats->icmpOutStats.dwErrors = res;
671 continue;
674 for (i = 0; i < sizeof(icmpoutstatlist)/sizeof(icmpoutstatlist[0]); i++)
676 if (!strcasecmp(buf, icmpoutstatlist[i].name))
678 if (sscanf(value, "%d", &res))
679 stats->icmpOutStats.rgdwTypeCount[icmpoutstatlist[i].pos] = res;
680 break;
685 fclose(fp);
686 ret = NO_ERROR;
689 #else
690 FIXME( "unimplemented for IPv6\n" );
691 #endif
692 return ret;
695 ret = GetIcmpStatistics(&ipv4stats);
696 if (!ret)
698 stats->icmpInStats.dwMsgs = ipv4stats.stats.icmpInStats.dwMsgs;
699 stats->icmpInStats.dwErrors = ipv4stats.stats.icmpInStats.dwErrors;
700 stats->icmpInStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpInStats.dwDestUnreachs;
701 stats->icmpInStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpInStats.dwSrcQuenchs;
702 stats->icmpInStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpInStats.dwRedirects;
703 stats->icmpInStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpInStats.dwEchos;
704 stats->icmpInStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpInStats.dwTimeExcds;
705 stats->icmpInStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpInStats.dwParmProbs;
706 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpInStats.dwTimestamps;
707 stats->icmpInStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpInStats.dwTimestampReps;
708 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpInStats.dwAddrMasks;
709 stats->icmpInStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpInStats.dwAddrMaskReps;
711 stats->icmpOutStats.dwMsgs = ipv4stats.stats.icmpOutStats.dwMsgs;
712 stats->icmpOutStats.dwErrors = ipv4stats.stats.icmpOutStats.dwErrors;
713 stats->icmpOutStats.rgdwTypeCount[ICMP4_DST_UNREACH] = ipv4stats.stats.icmpOutStats.dwDestUnreachs;
714 stats->icmpOutStats.rgdwTypeCount[ICMP4_SOURCE_QUENCH] = ipv4stats.stats.icmpOutStats.dwSrcQuenchs;
715 stats->icmpOutStats.rgdwTypeCount[ICMP4_REDIRECT] = ipv4stats.stats.icmpOutStats.dwRedirects;
716 stats->icmpOutStats.rgdwTypeCount[ICMP4_ECHO_REQUEST] = ipv4stats.stats.icmpOutStats.dwEchos;
717 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIME_EXCEEDED] = ipv4stats.stats.icmpOutStats.dwTimeExcds;
718 stats->icmpOutStats.rgdwTypeCount[ICMP4_PARAM_PROB] = ipv4stats.stats.icmpOutStats.dwParmProbs;
719 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REQUEST] = ipv4stats.stats.icmpOutStats.dwTimestamps;
720 stats->icmpOutStats.rgdwTypeCount[ICMP4_TIMESTAMP_REPLY] = ipv4stats.stats.icmpOutStats.dwTimestampReps;
721 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REQUEST] = ipv4stats.stats.icmpOutStats.dwAddrMasks;
722 stats->icmpOutStats.rgdwTypeCount[ICMP4_MASK_REPLY] = ipv4stats.stats.icmpOutStats.dwAddrMaskReps;
724 return ret;
727 /******************************************************************
728 * GetIpStatisticsEx (IPHLPAPI.@)
730 * Get the IPv4 and IPv6 statistics for the local computer.
732 * PARAMS
733 * stats [Out] buffer for IP statistics
734 * family [In] specifies whether IPv4 or IPv6 statistics are returned
736 * RETURNS
737 * Success: NO_ERROR
738 * Failure: error code from winerror.h
740 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS stats, DWORD family)
742 DWORD ret = ERROR_NOT_SUPPORTED;
743 MIB_IPFORWARDTABLE *fwd_table;
745 if (!stats) return ERROR_INVALID_PARAMETER;
746 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
747 memset( stats, 0, sizeof(*stats) );
749 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
750 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
752 stats->dwNumRoutes = fwd_table->dwNumEntries;
753 HeapFree( GetProcessHeap(), 0, fwd_table );
756 if (family == WS_AF_INET6)
758 #ifdef __linux__
760 FILE *fp;
762 if ((fp = fopen("/proc/net/snmp6", "r")))
764 struct {
765 const char *name;
766 DWORD *elem;
767 } ipstatlist[] = {
768 { "Ip6InReceives", &stats->dwInReceives },
769 { "Ip6InHdrErrors", &stats->dwInHdrErrors },
770 { "Ip6InAddrErrors", &stats->dwInAddrErrors },
771 { "Ip6OutForwDatagrams", &stats->dwForwDatagrams },
772 { "Ip6InUnknownProtos", &stats->dwInUnknownProtos },
773 { "Ip6InDiscards", &stats->dwInDiscards },
774 { "Ip6InDelivers", &stats->dwInDelivers },
775 { "Ip6OutRequests", &stats->dwOutRequests },
776 { "Ip6OutDiscards", &stats->dwOutDiscards },
777 { "Ip6OutNoRoutes", &stats->dwOutNoRoutes },
778 { "Ip6ReasmTimeout", &stats->dwReasmTimeout },
779 { "Ip6ReasmReqds", &stats->dwReasmReqds },
780 { "Ip6ReasmOKs", &stats->dwReasmOks },
781 { "Ip6ReasmFails", &stats->dwReasmFails },
782 { "Ip6FragOKs", &stats->dwFragOks },
783 { "Ip6FragFails", &stats->dwFragFails },
784 { "Ip6FragCreates", &stats->dwFragCreates },
785 /* hmm, no routingDiscards, defaultTTL and forwarding? */
787 char buf[512], *ptr, *value;
788 DWORD res, i;
790 while ((ptr = fgets(buf, sizeof(buf), fp)))
792 if (!(value = strchr(buf, ' ')))
793 continue;
795 /* terminate the valuename */
796 ptr = value - 1;
797 *(ptr + 1) = '\0';
799 /* and strip leading spaces from value */
800 value += 1;
801 while (*value==' ') value++;
802 if ((ptr = strchr(value, '\n')))
803 *ptr='\0';
805 for (i = 0; i < sizeof(ipstatlist)/sizeof(ipstatlist[0]); i++)
806 if (!strcasecmp(buf, ipstatlist[i].name))
808 if (sscanf(value, "%d", &res)) *ipstatlist[i].elem = res;
809 continue;
812 fclose(fp);
813 ret = NO_ERROR;
816 #else
817 FIXME( "unimplemented for IPv6\n" );
818 #endif
819 return ret;
822 #ifdef __linux__
824 FILE *fp;
826 if ((fp = fopen("/proc/net/snmp", "r")))
828 static const char hdr[] = "Ip:";
829 char buf[512], *ptr;
831 while ((ptr = fgets(buf, sizeof(buf), fp)))
833 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
834 /* last line was a header, get another */
835 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
836 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
838 ptr += sizeof(hdr);
839 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
840 &stats->u.dwForwarding,
841 &stats->dwDefaultTTL,
842 &stats->dwInReceives,
843 &stats->dwInHdrErrors,
844 &stats->dwInAddrErrors,
845 &stats->dwForwDatagrams,
846 &stats->dwInUnknownProtos,
847 &stats->dwInDiscards,
848 &stats->dwInDelivers,
849 &stats->dwOutRequests,
850 &stats->dwOutDiscards,
851 &stats->dwOutNoRoutes,
852 &stats->dwReasmTimeout,
853 &stats->dwReasmReqds,
854 &stats->dwReasmOks,
855 &stats->dwReasmFails,
856 &stats->dwFragOks,
857 &stats->dwFragFails,
858 &stats->dwFragCreates );
859 /* hmm, no routingDiscards */
860 break;
863 fclose(fp);
864 ret = NO_ERROR;
867 #elif defined(HAVE_LIBKSTAT)
869 static char ip[] = "ip";
870 kstat_ctl_t *kc;
871 kstat_t *ksp;
873 if ((kc = kstat_open()) &&
874 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
875 kstat_read( kc, ksp, NULL ) != -1 &&
876 ksp->ks_type == KSTAT_TYPE_NAMED)
878 stats->u.dwForwarding = kstat_get_ui32( ksp, "forwarding" );
879 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
880 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
881 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
882 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
883 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
884 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
885 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
886 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
887 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
888 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
889 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
890 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
891 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
892 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
893 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
894 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
895 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
896 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
897 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
898 ret = NO_ERROR;
900 if (kc) kstat_close( kc );
902 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
904 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
905 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
906 int ip_ttl, ip_forwarding;
907 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
908 struct ipstat ip_stat;
909 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
910 struct ip_stats ip_stat;
911 #endif
912 size_t needed;
914 needed = sizeof(ip_stat);
915 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
917 ERR ("failed to get ipstat\n");
918 return ERROR_NOT_SUPPORTED;
921 needed = sizeof(ip_ttl);
922 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
924 ERR ("failed to get ip Default TTL\n");
925 return ERROR_NOT_SUPPORTED;
928 needed = sizeof(ip_forwarding);
929 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
931 ERR ("failed to get ip forwarding\n");
932 return ERROR_NOT_SUPPORTED;
935 stats->u.dwForwarding = ip_forwarding;
936 stats->dwDefaultTTL = ip_ttl;
937 stats->dwInDelivers = ip_stat.ips_delivered;
938 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
939 stats->dwInAddrErrors = ip_stat.ips_cantforward;
940 stats->dwInReceives = ip_stat.ips_total;
941 stats->dwForwDatagrams = ip_stat.ips_forward;
942 stats->dwInUnknownProtos = ip_stat.ips_noproto;
943 stats->dwInDiscards = ip_stat.ips_fragdropped;
944 stats->dwOutDiscards = ip_stat.ips_odropped;
945 stats->dwReasmOks = ip_stat.ips_reassembled;
946 stats->dwFragOks = ip_stat.ips_fragmented;
947 stats->dwFragFails = ip_stat.ips_cantfrag;
948 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
949 stats->dwOutNoRoutes = ip_stat.ips_noroute;
950 stats->dwOutRequests = ip_stat.ips_localout;
951 stats->dwReasmReqds = ip_stat.ips_fragments;
952 ret = NO_ERROR;
954 #else
955 FIXME( "unimplemented for IPv4\n" );
956 #endif
957 return ret;
960 /******************************************************************
961 * GetIpStatistics (IPHLPAPI.@)
963 * Get the IP statistics for the local computer.
965 * PARAMS
966 * stats [Out] buffer for IP statistics
968 * RETURNS
969 * Success: NO_ERROR
970 * Failure: error code from winerror.h
972 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
974 return GetIpStatisticsEx(stats, WS_AF_INET);
977 /******************************************************************
978 * GetTcpStatisticsEx (IPHLPAPI.@)
980 * Get the IPv4 and IPv6 TCP statistics for the local computer.
982 * PARAMS
983 * stats [Out] buffer for TCP statistics
984 * family [In] specifies whether IPv4 or IPv6 statistics are returned
986 * RETURNS
987 * Success: NO_ERROR
988 * Failure: error code from winerror.h
990 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS stats, DWORD family)
992 DWORD ret = ERROR_NOT_SUPPORTED;
994 if (!stats) return ERROR_INVALID_PARAMETER;
995 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
996 memset( stats, 0, sizeof(*stats) );
998 if (family == WS_AF_INET6)
1000 FIXME( "unimplemented for IPv6\n" );
1001 return ret;
1004 #ifdef __linux__
1006 FILE *fp;
1008 if ((fp = fopen("/proc/net/snmp", "r")))
1010 static const char hdr[] = "Tcp:";
1011 MIB_TCPTABLE *tcp_table;
1012 char buf[512], *ptr;
1014 while ((ptr = fgets(buf, sizeof(buf), fp)))
1016 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
1017 /* last line was a header, get another */
1018 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1019 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
1021 ptr += sizeof(hdr);
1022 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
1023 &stats->u.dwRtoAlgorithm,
1024 &stats->dwRtoMin,
1025 &stats->dwRtoMax,
1026 &stats->dwMaxConn,
1027 &stats->dwActiveOpens,
1028 &stats->dwPassiveOpens,
1029 &stats->dwAttemptFails,
1030 &stats->dwEstabResets,
1031 &stats->dwCurrEstab,
1032 &stats->dwInSegs,
1033 &stats->dwOutSegs,
1034 &stats->dwRetransSegs,
1035 &stats->dwInErrs,
1036 &stats->dwOutRsts );
1037 break;
1040 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
1042 stats->dwNumConns = tcp_table->dwNumEntries;
1043 HeapFree( GetProcessHeap(), 0, tcp_table );
1045 fclose(fp);
1046 ret = NO_ERROR;
1049 #elif defined(HAVE_LIBKSTAT)
1051 static char tcp[] = "tcp";
1052 kstat_ctl_t *kc;
1053 kstat_t *ksp;
1055 if ((kc = kstat_open()) &&
1056 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
1057 kstat_read( kc, ksp, NULL ) != -1 &&
1058 ksp->ks_type == KSTAT_TYPE_NAMED)
1060 stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
1061 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
1062 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
1063 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
1064 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
1065 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
1066 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
1067 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
1068 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
1069 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
1070 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
1071 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
1072 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
1073 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
1074 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
1075 ret = NO_ERROR;
1077 if (kc) kstat_close( kc );
1079 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
1081 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
1082 #define TCPTV_MIN 2
1083 #define TCPTV_REXMTMAX 128
1084 #endif
1085 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
1086 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1087 #define hz 1000
1088 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
1089 struct tcpstat tcp_stat;
1090 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
1091 struct tcp_stats tcp_stat;
1092 #endif
1093 size_t needed = sizeof(tcp_stat);
1095 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
1097 stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
1098 stats->dwRtoMin = TCPTV_MIN;
1099 stats->dwRtoMax = TCPTV_REXMTMAX;
1100 stats->dwMaxConn = -1;
1101 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
1102 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
1103 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
1104 stats->dwEstabResets = tcp_stat.tcps_drops;
1105 stats->dwCurrEstab = 0;
1106 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
1107 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
1108 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
1109 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
1110 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
1111 stats->dwNumConns = tcp_stat.tcps_connects;
1112 ret = NO_ERROR;
1114 else ERR ("failed to get tcpstat\n");
1116 #else
1117 FIXME( "unimplemented\n" );
1118 #endif
1119 return ret;
1122 /******************************************************************
1123 * GetTcpStatistics (IPHLPAPI.@)
1125 * Get the TCP statistics for the local computer.
1127 * PARAMS
1128 * stats [Out] buffer for TCP statistics
1130 * RETURNS
1131 * Success: NO_ERROR
1132 * Failure: error code from winerror.h
1134 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
1136 return GetTcpStatisticsEx(stats, WS_AF_INET);
1139 /******************************************************************
1140 * GetUdpStatistics (IPHLPAPI.@)
1142 * Get the IPv4 and IPv6 UDP statistics for the local computer.
1144 * PARAMS
1145 * stats [Out] buffer for UDP statistics
1146 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1148 * RETURNS
1149 * Success: NO_ERROR
1150 * Failure: error code from winerror.h
1152 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS stats, DWORD family)
1154 DWORD ret = ERROR_NOT_SUPPORTED;
1156 if (!stats) return ERROR_INVALID_PARAMETER;
1157 if (family != WS_AF_INET && family != WS_AF_INET6) return ERROR_INVALID_PARAMETER;
1158 memset( stats, 0, sizeof(*stats) );
1160 stats->dwNumAddrs = getNumInterfaces();
1162 if (family == WS_AF_INET6)
1164 #ifdef __linux__
1166 FILE *fp;
1168 if ((fp = fopen("/proc/net/snmp6", "r")))
1170 struct {
1171 const char *name;
1172 DWORD *elem;
1173 } udpstatlist[] = {
1174 { "Udp6InDatagrams", &stats->dwInDatagrams },
1175 { "Udp6NoPorts", &stats->dwNoPorts },
1176 { "Udp6InErrors", &stats->dwInErrors },
1177 { "Udp6OutDatagrams", &stats->dwOutDatagrams },
1179 char buf[512], *ptr, *value;
1180 DWORD res, i;
1182 while ((ptr = fgets(buf, sizeof(buf), fp)))
1184 if (!(value = strchr(buf, ' ')))
1185 continue;
1187 /* terminate the valuename */
1188 ptr = value - 1;
1189 *(ptr + 1) = '\0';
1191 /* and strip leading spaces from value */
1192 value += 1;
1193 while (*value==' ') value++;
1194 if ((ptr = strchr(value, '\n')))
1195 *ptr='\0';
1197 for (i = 0; i < sizeof(udpstatlist)/sizeof(udpstatlist[0]); i++)
1198 if (!strcasecmp(buf, udpstatlist[i].name))
1200 if (sscanf(value, "%d", &res)) *udpstatlist[i].elem = res;
1201 continue;
1204 fclose(fp);
1205 ret = NO_ERROR;
1208 #else
1209 FIXME( "unimplemented for IPv6\n" );
1210 #endif
1211 return ret;
1214 #ifdef __linux__
1216 FILE *fp;
1218 if ((fp = fopen("/proc/net/snmp", "r")))
1220 static const char hdr[] = "Udp:";
1221 char buf[512], *ptr;
1223 while ((ptr = fgets(buf, sizeof(buf), fp)))
1225 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
1226 /* last line was a header, get another */
1227 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
1228 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
1230 ptr += sizeof(hdr);
1231 sscanf( ptr, "%u %u %u %u %u",
1232 &stats->dwInDatagrams, &stats->dwNoPorts,
1233 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
1234 break;
1237 fclose(fp);
1238 ret = NO_ERROR;
1241 #elif defined(HAVE_LIBKSTAT)
1243 static char udp[] = "udp";
1244 kstat_ctl_t *kc;
1245 kstat_t *ksp;
1246 MIB_UDPTABLE *udp_table;
1248 if ((kc = kstat_open()) &&
1249 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
1250 kstat_read( kc, ksp, NULL ) != -1 &&
1251 ksp->ks_type == KSTAT_TYPE_NAMED)
1253 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
1254 stats->dwNoPorts = 0; /* FIXME */
1255 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
1256 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
1257 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1259 stats->dwNumAddrs = udp_table->dwNumEntries;
1260 HeapFree( GetProcessHeap(), 0, udp_table );
1262 ret = NO_ERROR;
1264 if (kc) kstat_close( kc );
1266 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
1268 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
1269 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1270 struct udpstat udp_stat;
1271 MIB_UDPTABLE *udp_table;
1272 size_t needed = sizeof(udp_stat);
1274 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
1276 stats->dwInDatagrams = udp_stat.udps_ipackets;
1277 stats->dwOutDatagrams = udp_stat.udps_opackets;
1278 stats->dwNoPorts = udp_stat.udps_noport;
1279 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
1280 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
1282 stats->dwNumAddrs = udp_table->dwNumEntries;
1283 HeapFree( GetProcessHeap(), 0, udp_table );
1285 ret = NO_ERROR;
1287 else ERR ("failed to get udpstat\n");
1289 #else
1290 FIXME( "unimplemented for IPv4\n" );
1291 #endif
1292 return ret;
1295 /******************************************************************
1296 * GetUdpStatistics (IPHLPAPI.@)
1298 * Get the UDP statistics for the local computer.
1300 * PARAMS
1301 * stats [Out] buffer for UDP statistics
1303 * RETURNS
1304 * Success: NO_ERROR
1305 * Failure: error code from winerror.h
1307 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
1309 return GetUdpStatisticsEx(stats, WS_AF_INET);
1312 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
1313 DWORD *count, const MIB_IPFORWARDROW *row )
1315 if (table->dwNumEntries >= *count)
1317 MIB_IPFORWARDTABLE *new_table;
1318 DWORD new_count = table->dwNumEntries * 2;
1320 if (!(new_table = HeapReAlloc( heap, flags, table,
1321 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
1323 HeapFree( heap, 0, table );
1324 return NULL;
1326 *count = new_count;
1327 table = new_table;
1329 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1330 return table;
1333 static int compare_ipforward_rows(const void *a, const void *b)
1335 const MIB_IPFORWARDROW *rowA = a;
1336 const MIB_IPFORWARDROW *rowB = b;
1337 int ret;
1339 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
1340 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
1341 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
1342 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1345 /******************************************************************
1346 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1348 * Get the route table.
1349 * Like GetIpForwardTable(), but allocate the returned table from heap.
1351 * PARAMS
1352 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1353 * allocated and returned.
1354 * bOrder [In] whether to sort the table
1355 * heap [In] heap from which the table is allocated
1356 * flags [In] flags to HeapAlloc
1358 * RETURNS
1359 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1360 * on failure, NO_ERROR on success.
1362 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
1363 HANDLE heap, DWORD flags)
1365 MIB_IPFORWARDTABLE *table;
1366 MIB_IPFORWARDROW row;
1367 DWORD ret = NO_ERROR, count = 16;
1369 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1371 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1373 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1374 return ERROR_OUTOFMEMORY;
1376 table->dwNumEntries = 0;
1378 #ifdef __linux__
1380 FILE *fp;
1382 if ((fp = fopen("/proc/net/route", "r")))
1384 char buf[512], *ptr;
1385 DWORD flags;
1387 /* skip header line */
1388 ptr = fgets(buf, sizeof(buf), fp);
1389 while ((ptr = fgets(buf, sizeof(buf), fp)))
1391 memset( &row, 0, sizeof(row) );
1393 while (!isspace(*ptr)) ptr++;
1394 *ptr++ = 0;
1395 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1396 continue;
1398 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1399 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1400 flags = strtoul(ptr + 1, &ptr, 16);
1402 if (!(flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID;
1403 else if (flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1404 else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT;
1406 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1407 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1408 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1409 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1410 /* FIXME: other protos might be appropriate, e.g. the default
1411 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1412 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1414 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1415 break;
1417 fclose(fp);
1419 else ret = ERROR_NOT_SUPPORTED;
1421 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1423 void *data;
1424 int fd, len, namelen;
1425 mib2_ipRouteEntry_t *entry;
1426 char name[64];
1428 if ((fd = open_streams_mib( NULL )) != -1)
1430 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1432 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1434 row.dwForwardDest = entry->ipRouteDest;
1435 row.dwForwardMask = entry->ipRouteMask;
1436 row.dwForwardPolicy = 0;
1437 row.dwForwardNextHop = entry->ipRouteNextHop;
1438 row.u1.dwForwardType = entry->ipRouteType;
1439 row.u2.dwForwardProto = entry->ipRouteProto;
1440 row.dwForwardAge = entry->ipRouteAge;
1441 row.dwForwardNextHopAS = 0;
1442 row.dwForwardMetric1 = entry->ipRouteMetric1;
1443 row.dwForwardMetric2 = entry->ipRouteMetric2;
1444 row.dwForwardMetric3 = entry->ipRouteMetric3;
1445 row.dwForwardMetric4 = entry->ipRouteMetric4;
1446 row.dwForwardMetric5 = entry->ipRouteMetric5;
1447 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1448 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1449 name[namelen] = 0;
1450 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1451 if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1453 HeapFree( GetProcessHeap(), 0, data );
1455 close( fd );
1457 else ret = ERROR_NOT_SUPPORTED;
1459 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1461 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1462 size_t needed;
1463 char *buf = NULL, *lim, *next, *addrPtr;
1464 struct rt_msghdr *rtm;
1466 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1468 ERR ("sysctl 1 failed!\n");
1469 ret = ERROR_NOT_SUPPORTED;
1470 goto done;
1473 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1474 if (!buf)
1476 ret = ERROR_OUTOFMEMORY;
1477 goto done;
1480 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1482 ret = ERROR_NOT_SUPPORTED;
1483 goto done;
1486 lim = buf + needed;
1487 for (next = buf; next < lim; next += rtm->rtm_msglen)
1489 int i;
1491 rtm = (struct rt_msghdr *)next;
1493 if (rtm->rtm_type != RTM_GET)
1495 WARN ("Got unexpected message type 0x%x!\n",
1496 rtm->rtm_type);
1497 continue;
1500 /* Ignore gateway routes which are multicast */
1501 if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST))
1502 continue;
1504 memset( &row, 0, sizeof(row) );
1505 row.dwForwardIfIndex = rtm->rtm_index;
1506 row.u1.ForwardType = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPROUTE_TYPE_INDIRECT : MIB_IPROUTE_TYPE_DIRECT;
1507 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1508 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1510 addrPtr = (char *)(rtm + 1);
1512 for (i = 1; i; i <<= 1)
1514 struct sockaddr *sa;
1515 DWORD addr;
1517 if (!(i & rtm->rtm_addrs))
1518 continue;
1520 sa = (struct sockaddr *)addrPtr;
1521 ADVANCE (addrPtr, sa);
1523 /* default routes are encoded by length-zero sockaddr */
1524 if (sa->sa_len == 0) {
1525 addr = 0;
1526 }else {
1527 switch(sa->sa_family) {
1528 case AF_INET: {
1529 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1530 addr = sin->sin_addr.s_addr;
1531 break;
1533 #ifdef AF_LINK
1534 case AF_LINK:
1535 if(i == RTA_GATEWAY && row.u1.ForwardType == MIB_IPROUTE_TYPE_DIRECT) {
1536 /* For direct route we may simply use dest addr as next hop */
1537 C_ASSERT(RTA_DST < RTA_GATEWAY);
1538 addr = row.dwForwardDest;
1539 break;
1541 /* fallthrough */
1542 #endif
1543 default:
1544 WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family);
1545 addr = 0;
1549 switch (i)
1551 case RTA_DST: row.dwForwardDest = addr; break;
1552 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1553 case RTA_NETMASK: row.dwForwardMask = addr; break;
1554 default:
1555 WARN ("Unexpected address type 0x%x\n", i);
1559 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1560 break;
1562 done:
1563 HeapFree( GetProcessHeap (), 0, buf );
1565 #else
1566 FIXME( "not implemented\n" );
1567 ret = ERROR_NOT_SUPPORTED;
1568 #endif
1570 if (!table) return ERROR_OUTOFMEMORY;
1571 if (!ret)
1573 if (bOrder && table->dwNumEntries)
1574 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1575 *ppIpForwardTable = table;
1577 else HeapFree( heap, flags, table );
1578 TRACE( "returning ret %u table %p\n", ret, table );
1579 return ret;
1582 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1583 DWORD *count, const MIB_IPNETROW *row )
1585 if (table->dwNumEntries >= *count)
1587 MIB_IPNETTABLE *new_table;
1588 DWORD new_count = table->dwNumEntries * 2;
1590 if (!(new_table = HeapReAlloc( heap, flags, table,
1591 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1593 HeapFree( heap, 0, table );
1594 return NULL;
1596 *count = new_count;
1597 table = new_table;
1599 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1600 return table;
1603 static int compare_ipnet_rows(const void *a, const void *b)
1605 const MIB_IPNETROW *rowA = a;
1606 const MIB_IPNETROW *rowB = b;
1608 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1612 /******************************************************************
1613 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1615 * Get the IP-to-physical address mapping table.
1616 * Like GetIpNetTable(), but allocate the returned table from heap.
1618 * PARAMS
1619 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1620 * allocated and returned.
1621 * bOrder [In] whether to sort the table
1622 * heap [In] heap from which the table is allocated
1623 * flags [In] flags to HeapAlloc
1625 * RETURNS
1626 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1627 * on failure, NO_ERROR on success.
1629 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1630 HANDLE heap, DWORD flags)
1632 MIB_IPNETTABLE *table;
1633 MIB_IPNETROW row;
1634 DWORD ret = NO_ERROR, count = 16;
1636 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1638 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1640 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1641 return ERROR_OUTOFMEMORY;
1643 table->dwNumEntries = 0;
1645 #ifdef __linux__
1647 FILE *fp;
1649 if ((fp = fopen("/proc/net/arp", "r")))
1651 char buf[512], *ptr;
1652 DWORD flags;
1654 /* skip header line */
1655 ptr = fgets(buf, sizeof(buf), fp);
1656 while ((ptr = fgets(buf, sizeof(buf), fp)))
1658 memset( &row, 0, sizeof(row) );
1660 row.dwAddr = inet_addr(ptr);
1661 while (*ptr && !isspace(*ptr)) ptr++;
1662 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1663 flags = strtoul(ptr + 1, &ptr, 16);
1665 #ifdef ATF_COM
1666 if (flags & ATF_COM) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1667 else
1668 #endif
1669 #ifdef ATF_PERM
1670 if (flags & ATF_PERM) row.u.Type = MIB_IPNET_TYPE_STATIC;
1671 else
1672 #endif
1673 row.u.Type = MIB_IPNET_TYPE_OTHER;
1675 while (*ptr && isspace(*ptr)) ptr++;
1676 while (*ptr && !isspace(*ptr))
1678 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1679 if (*ptr) ptr++;
1681 while (*ptr && isspace(*ptr)) ptr++;
1682 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1683 while (*ptr && isspace(*ptr)) ptr++;
1684 getInterfaceIndexByName(ptr, &row.dwIndex);
1686 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1687 break;
1689 fclose(fp);
1691 else ret = ERROR_NOT_SUPPORTED;
1693 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1695 void *data;
1696 int fd, len, namelen;
1697 mib2_ipNetToMediaEntry_t *entry;
1698 char name[64];
1700 if ((fd = open_streams_mib( NULL )) != -1)
1702 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1704 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1706 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1707 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1708 row.dwAddr = entry->ipNetToMediaNetAddress;
1709 row.u.Type = entry->ipNetToMediaType;
1710 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1711 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1712 name[namelen] = 0;
1713 getInterfaceIndexByName( name, &row.dwIndex );
1714 if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1716 HeapFree( GetProcessHeap(), 0, data );
1718 close( fd );
1720 else ret = ERROR_NOT_SUPPORTED;
1722 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1724 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1725 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1726 size_t needed;
1727 char *buf = NULL, *lim, *next;
1728 struct rt_msghdr *rtm;
1729 struct sockaddr_inarp *sinarp;
1730 struct sockaddr_dl *sdl;
1732 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1734 ERR ("failed to get arp table\n");
1735 ret = ERROR_NOT_SUPPORTED;
1736 goto done;
1739 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1740 if (!buf)
1742 ret = ERROR_OUTOFMEMORY;
1743 goto done;
1746 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1748 ret = ERROR_NOT_SUPPORTED;
1749 goto done;
1752 lim = buf + needed;
1753 next = buf;
1754 while(next < lim)
1756 rtm = (struct rt_msghdr *)next;
1757 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1758 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1759 if(sdl->sdl_alen) /* arp entry */
1761 memset( &row, 0, sizeof(row) );
1762 row.dwAddr = sinarp->sin_addr.s_addr;
1763 row.dwIndex = sdl->sdl_index;
1764 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1765 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1766 if(rtm->rtm_rmx.rmx_expire == 0) row.u.Type = MIB_IPNET_TYPE_STATIC;
1767 else if(sinarp->sin_other & SIN_PROXY) row.u.Type = MIB_IPNET_TYPE_OTHER;
1768 else if(rtm->rtm_rmx.rmx_expire != 0) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1769 else row.u.Type = MIB_IPNET_TYPE_INVALID;
1771 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1772 break;
1774 next += rtm->rtm_msglen;
1776 done:
1777 HeapFree( GetProcessHeap (), 0, buf );
1779 #else
1780 FIXME( "not implemented\n" );
1781 ret = ERROR_NOT_SUPPORTED;
1782 #endif
1784 if (!table) return ERROR_OUTOFMEMORY;
1785 if (!ret)
1787 if (bOrder && table->dwNumEntries)
1788 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1789 *ppIpNetTable = table;
1791 else HeapFree( heap, flags, table );
1792 TRACE( "returning ret %u table %p\n", ret, table );
1793 return ret;
1796 static DWORD get_tcp_table_sizes( TCP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
1798 DWORD table_size;
1800 switch (class)
1802 case TCP_TABLE_BASIC_LISTENER:
1803 case TCP_TABLE_BASIC_CONNECTIONS:
1804 case TCP_TABLE_BASIC_ALL:
1806 table_size = FIELD_OFFSET(MIB_TCPTABLE, table[row_count]);
1807 if (row_size) *row_size = sizeof(MIB_TCPROW);
1808 break;
1810 case TCP_TABLE_OWNER_PID_LISTENER:
1811 case TCP_TABLE_OWNER_PID_CONNECTIONS:
1812 case TCP_TABLE_OWNER_PID_ALL:
1814 table_size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table[row_count]);
1815 if (row_size) *row_size = sizeof(MIB_TCPROW_OWNER_PID);
1816 break;
1818 default:
1819 ERR("unhandled class %u\n", class);
1820 return 0;
1822 return table_size;
1825 static MIB_TCPTABLE *append_tcp_row( TCP_TABLE_CLASS class, HANDLE heap, DWORD flags,
1826 MIB_TCPTABLE *table, DWORD *count,
1827 const MIB_TCPROW_OWNER_PID *row, DWORD row_size )
1829 if (table->dwNumEntries >= *count)
1831 MIB_TCPTABLE *new_table;
1832 DWORD new_count = table->dwNumEntries * 2, new_table_size;
1834 new_table_size = get_tcp_table_sizes( class, new_count, NULL );
1835 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
1837 HeapFree( heap, 0, table );
1838 return NULL;
1840 *count = new_count;
1841 table = new_table;
1843 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
1844 table->dwNumEntries++;
1845 return table;
1849 /* Why not a lookup table? Because the TCPS_* constants are different
1850 on different platforms */
1851 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1853 switch (state)
1855 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1856 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1857 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1858 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1859 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1860 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1861 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1862 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1863 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1864 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1865 default:
1866 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1870 static int compare_tcp_rows(const void *a, const void *b)
1872 const MIB_TCPROW *rowA = a;
1873 const MIB_TCPROW *rowB = b;
1874 int ret;
1876 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1877 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1878 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1879 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1880 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1883 struct pid_map
1885 unsigned int pid;
1886 unsigned int unix_pid;
1889 static struct pid_map *get_pid_map( unsigned int *num_entries )
1891 HANDLE snapshot = NULL;
1892 struct pid_map *map;
1893 unsigned int i = 0, count = 16, size = count * sizeof(*map);
1894 NTSTATUS ret;
1896 if (!(map = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
1898 SERVER_START_REQ( create_snapshot )
1900 req->flags = SNAP_PROCESS;
1901 req->attributes = 0;
1902 if (!(ret = wine_server_call( req )))
1903 snapshot = wine_server_ptr_handle( reply->handle );
1905 SERVER_END_REQ;
1907 *num_entries = 0;
1908 while (ret == STATUS_SUCCESS)
1910 SERVER_START_REQ( next_process )
1912 req->handle = wine_server_obj_handle( snapshot );
1913 req->reset = (i == 0);
1914 if (!(ret = wine_server_call( req )))
1916 if (i >= count)
1918 struct pid_map *new_map;
1919 count *= 2;
1920 size = count * sizeof(*new_map);
1922 if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, size )))
1924 HeapFree( GetProcessHeap(), 0, map );
1925 map = NULL;
1926 goto done;
1928 map = new_map;
1930 map[i].pid = reply->pid;
1931 map[i].unix_pid = reply->unix_pid;
1932 (*num_entries)++;
1933 i++;
1936 SERVER_END_REQ;
1939 done:
1940 NtClose( snapshot );
1941 return map;
1944 static unsigned int find_owning_pid( struct pid_map *map, unsigned int num_entries, int inode )
1946 #ifdef __linux__
1947 unsigned int i, len_socket;
1948 char socket[32];
1950 sprintf( socket, "socket:[%d]", inode );
1951 len_socket = strlen( socket );
1952 for (i = 0; i < num_entries; i++)
1954 char dir[32];
1955 struct dirent *dirent;
1956 DIR *dirfd;
1958 sprintf( dir, "/proc/%u/fd", map[i].unix_pid );
1959 if ((dirfd = opendir( dir )))
1961 while ((dirent = readdir( dirfd )))
1963 char link[sizeof(dirent->d_name) + 32], name[32];
1964 int len;
1966 sprintf( link, "/proc/%u/fd/%s", map[i].unix_pid, dirent->d_name );
1967 if ((len = readlink( link, name, 32 )) > 0) name[len] = 0;
1968 if (len == len_socket && !strcmp( socket, name ))
1970 closedir( dirfd );
1971 return map[i].pid;
1974 closedir( dirfd );
1977 return 0;
1978 #else
1979 FIXME( "not implemented\n" );
1980 return 0;
1981 #endif
1984 DWORD build_tcp_table( TCP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
1985 DWORD *size )
1987 MIB_TCPTABLE *table;
1988 MIB_TCPROW_OWNER_PID row;
1989 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
1991 if (!(table_size = get_tcp_table_sizes( class, count, &row_size )))
1992 return ERROR_INVALID_PARAMETER;
1994 if (!(table = HeapAlloc( heap, flags, table_size )))
1995 return ERROR_OUTOFMEMORY;
1997 table->dwNumEntries = 0;
1999 #ifdef __linux__
2001 FILE *fp;
2003 if ((fp = fopen("/proc/net/tcp", "r")))
2005 char buf[512], *ptr;
2006 struct pid_map *map = NULL;
2007 unsigned int dummy, num_entries = 0;
2008 int inode;
2010 if (class == TCP_TABLE_OWNER_PID_ALL) map = get_pid_map( &num_entries );
2012 /* skip header line */
2013 ptr = fgets(buf, sizeof(buf), fp);
2014 while ((ptr = fgets(buf, sizeof(buf), fp)))
2016 if (sscanf( ptr, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy,
2017 &row.dwLocalAddr, &row.dwLocalPort, &row.dwRemoteAddr,
2018 &row.dwRemotePort, &row.dwState, &inode ) != 7)
2019 continue;
2020 row.dwLocalPort = htons( row.dwLocalPort );
2021 row.dwRemotePort = htons( row.dwRemotePort );
2022 row.dwState = TCPStateToMIBState( row.dwState );
2023 if (class == TCP_TABLE_OWNER_PID_ALL)
2024 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2026 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2027 break;
2029 HeapFree( GetProcessHeap(), 0, map );
2030 fclose( fp );
2032 else ret = ERROR_NOT_SUPPORTED;
2034 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2036 void *data;
2037 int fd, len;
2038 mib2_tcpConnEntry_t *entry;
2040 if ((fd = open_streams_mib( "tcp" )) != -1)
2042 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
2044 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2046 row.dwLocalAddr = entry->tcpConnLocalAddress;
2047 row.dwLocalPort = htons( entry->tcpConnLocalPort );
2048 row.dwRemoteAddr = entry->tcpConnRemAddress;
2049 row.dwRemotePort = htons( entry->tcpConnRemPort );
2050 row.dwState = entry->tcpConnState;
2051 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2052 break;
2054 HeapFree( GetProcessHeap(), 0, data );
2056 close( fd );
2058 else ret = ERROR_NOT_SUPPORTED;
2060 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2062 size_t Len = 0;
2063 char *Buf = NULL;
2064 struct xinpgen *pXIG, *pOrigXIG;
2066 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
2068 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2069 ret = ERROR_NOT_SUPPORTED;
2070 goto done;
2073 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2074 if (!Buf)
2076 ret = ERROR_OUTOFMEMORY;
2077 goto done;
2080 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
2082 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2083 ret = ERROR_NOT_SUPPORTED;
2084 goto done;
2087 /* Might be nothing here; first entry is just a header it seems */
2088 if (Len <= sizeof (struct xinpgen)) goto done;
2090 pOrigXIG = (struct xinpgen *)Buf;
2091 pXIG = pOrigXIG;
2093 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2094 pXIG->xig_len > sizeof (struct xinpgen);
2095 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2097 struct tcpcb *pTCPData = NULL;
2098 struct inpcb *pINData;
2099 struct xsocket *pSockData;
2101 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
2102 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
2103 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
2105 /* Ignore sockets for other protocols */
2106 if (pSockData->xso_protocol != IPPROTO_TCP)
2107 continue;
2109 /* Ignore PCBs that were freed while generating the data */
2110 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2111 continue;
2113 /* we're only interested in IPv4 addresses */
2114 if (!(pINData->inp_vflag & INP_IPV4) ||
2115 (pINData->inp_vflag & INP_IPV6))
2116 continue;
2118 /* If all 0's, skip it */
2119 if (!pINData->inp_laddr.s_addr &&
2120 !pINData->inp_lport &&
2121 !pINData->inp_faddr.s_addr &&
2122 !pINData->inp_fport)
2123 continue;
2125 /* Fill in structure details */
2126 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2127 row.dwLocalPort = pINData->inp_lport;
2128 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
2129 row.dwRemotePort = pINData->inp_fport;
2130 row.dwState = TCPStateToMIBState (pTCPData->t_state);
2131 if (!(table = append_tcp_row( class, heap, flags, table, &count, &row, row_size )))
2132 break;
2135 done:
2136 HeapFree (GetProcessHeap (), 0, Buf);
2138 #else
2139 FIXME( "not implemented\n" );
2140 ret = ERROR_NOT_SUPPORTED;
2141 #endif
2143 if (!table) return ERROR_OUTOFMEMORY;
2144 if (!ret)
2146 if (order && table->dwNumEntries)
2147 qsort( table->table, table->dwNumEntries, row_size, compare_tcp_rows );
2148 *tablep = table;
2150 else HeapFree( heap, flags, table );
2151 if (size) *size = get_tcp_table_sizes( class, count, NULL );
2152 TRACE( "returning ret %u table %p\n", ret, table );
2153 return ret;
2156 /******************************************************************
2157 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
2159 * Get the TCP connection table.
2160 * Like GetTcpTable(), but allocate the returned table from heap.
2162 * PARAMS
2163 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2164 * allocated and returned.
2165 * bOrder [In] whether to sort the table
2166 * heap [In] heap from which the table is allocated
2167 * flags [In] flags to HeapAlloc
2169 * RETURNS
2170 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2171 * returns otherwise.
2173 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
2174 HANDLE heap, DWORD flags )
2176 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
2178 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
2179 return build_tcp_table( TCP_TABLE_BASIC_ALL, (void **)ppTcpTable, bOrder, heap, flags, NULL );
2182 static DWORD get_udp_table_sizes( UDP_TABLE_CLASS class, DWORD row_count, DWORD *row_size )
2184 DWORD table_size;
2186 switch (class)
2188 case UDP_TABLE_BASIC:
2190 table_size = FIELD_OFFSET(MIB_UDPTABLE, table[row_count]);
2191 if (row_size) *row_size = sizeof(MIB_UDPROW);
2192 break;
2194 case UDP_TABLE_OWNER_PID:
2196 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table[row_count]);
2197 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_PID);
2198 break;
2200 case UDP_TABLE_OWNER_MODULE:
2202 table_size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table[row_count]);
2203 if (row_size) *row_size = sizeof(MIB_UDPROW_OWNER_MODULE);
2204 break;
2206 default:
2207 ERR("unhandled class %u\n", class);
2208 return 0;
2210 return table_size;
2213 static MIB_UDPTABLE *append_udp_row( UDP_TABLE_CLASS class, HANDLE heap, DWORD flags,
2214 MIB_UDPTABLE *table, DWORD *count,
2215 const MIB_UDPROW_OWNER_MODULE *row, DWORD row_size )
2217 if (table->dwNumEntries >= *count)
2219 MIB_UDPTABLE *new_table;
2220 DWORD new_count = table->dwNumEntries * 2, new_table_size;
2222 new_table_size = get_udp_table_sizes( class, new_count, NULL );
2223 if (!(new_table = HeapReAlloc( heap, flags, table, new_table_size )))
2225 HeapFree( heap, 0, table );
2226 return NULL;
2228 *count = new_count;
2229 table = new_table;
2231 memcpy( (char *)table->table + (table->dwNumEntries * row_size), row, row_size );
2232 table->dwNumEntries++;
2233 return table;
2236 static int compare_udp_rows(const void *a, const void *b)
2238 const MIB_UDPROW *rowA = a;
2239 const MIB_UDPROW *rowB = b;
2240 int ret;
2242 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
2243 return rowA->dwLocalPort - rowB->dwLocalPort;
2246 DWORD build_udp_table( UDP_TABLE_CLASS class, void **tablep, BOOL order, HANDLE heap, DWORD flags,
2247 DWORD *size )
2249 MIB_UDPTABLE *table;
2250 MIB_UDPROW_OWNER_MODULE row;
2251 DWORD ret = NO_ERROR, count = 16, table_size, row_size;
2253 if (!(table_size = get_udp_table_sizes( class, count, &row_size )))
2254 return ERROR_INVALID_PARAMETER;
2256 if (!(table = HeapAlloc( heap, flags, table_size )))
2257 return ERROR_OUTOFMEMORY;
2259 table->dwNumEntries = 0;
2260 memset( &row, 0, sizeof(row) );
2262 #ifdef __linux__
2264 FILE *fp;
2266 if ((fp = fopen( "/proc/net/udp", "r" )))
2268 char buf[512], *ptr;
2269 struct pid_map *map = NULL;
2270 unsigned int dummy, num_entries = 0;
2271 int inode;
2273 if (class == UDP_TABLE_OWNER_PID || class == UDP_TABLE_OWNER_MODULE)
2274 map = get_pid_map( &num_entries );
2276 /* skip header line */
2277 ptr = fgets( buf, sizeof(buf), fp );
2278 while ((ptr = fgets( buf, sizeof(buf), fp )))
2280 if (sscanf( ptr, "%u: %x:%x %*s %*s %*s %*s %*s %*s %*s %d", &dummy,
2281 &row.dwLocalAddr, &row.dwLocalPort, &inode ) != 4)
2282 continue;
2283 row.dwLocalPort = htons( row.dwLocalPort );
2284 if (class == UDP_TABLE_OWNER_PID || class == UDP_TABLE_OWNER_MODULE)
2285 row.dwOwningPid = find_owning_pid( map, num_entries, inode );
2286 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size )))
2287 break;
2289 HeapFree( GetProcessHeap(), 0, map );
2290 fclose( fp );
2292 else ret = ERROR_NOT_SUPPORTED;
2294 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2296 void *data;
2297 int fd, len;
2298 mib2_udpEntry_t *entry;
2300 if ((fd = open_streams_mib( "udp" )) != -1)
2302 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
2304 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
2306 row.dwLocalAddr = entry->udpLocalAddress;
2307 row.dwLocalPort = htons( entry->udpLocalPort );
2308 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size ))) break;
2310 HeapFree( GetProcessHeap(), 0, data );
2312 close( fd );
2314 else ret = ERROR_NOT_SUPPORTED;
2316 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2318 size_t Len = 0;
2319 char *Buf = NULL;
2320 struct xinpgen *pXIG, *pOrigXIG;
2322 if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
2324 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2325 ret = ERROR_NOT_SUPPORTED;
2326 goto done;
2329 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
2330 if (!Buf)
2332 ret = ERROR_OUTOFMEMORY;
2333 goto done;
2336 if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
2338 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2339 ret = ERROR_NOT_SUPPORTED;
2340 goto done;
2343 /* Might be nothing here; first entry is just a header it seems */
2344 if (Len <= sizeof (struct xinpgen)) goto done;
2346 pOrigXIG = (struct xinpgen *)Buf;
2347 pXIG = pOrigXIG;
2349 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
2350 pXIG->xig_len > sizeof (struct xinpgen);
2351 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
2353 struct inpcb *pINData;
2354 struct xsocket *pSockData;
2356 pINData = &((struct xinpcb *)pXIG)->xi_inp;
2357 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
2359 /* Ignore sockets for other protocols */
2360 if (pSockData->xso_protocol != IPPROTO_UDP)
2361 continue;
2363 /* Ignore PCBs that were freed while generating the data */
2364 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
2365 continue;
2367 /* we're only interested in IPv4 addresses */
2368 if (!(pINData->inp_vflag & INP_IPV4) ||
2369 (pINData->inp_vflag & INP_IPV6))
2370 continue;
2372 /* If all 0's, skip it */
2373 if (!pINData->inp_laddr.s_addr &&
2374 !pINData->inp_lport)
2375 continue;
2377 /* Fill in structure details */
2378 row.dwLocalAddr = pINData->inp_laddr.s_addr;
2379 row.dwLocalPort = pINData->inp_lport;
2380 if (!(table = append_udp_row( class, heap, flags, table, &count, &row, row_size ))) break;
2383 done:
2384 HeapFree (GetProcessHeap (), 0, Buf);
2386 #else
2387 FIXME( "not implemented\n" );
2388 ret = ERROR_NOT_SUPPORTED;
2389 #endif
2391 if (!table) return ERROR_OUTOFMEMORY;
2392 if (!ret)
2394 if (order && table->dwNumEntries)
2395 qsort( table->table, table->dwNumEntries, row_size, compare_udp_rows );
2396 *tablep = table;
2398 else HeapFree( heap, flags, table );
2399 if (size) *size = get_udp_table_sizes( class, count, NULL );
2400 TRACE( "returning ret %u table %p\n", ret, table );
2401 return ret;
2404 /******************************************************************
2405 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
2407 * Get the UDP listener table.
2408 * Like GetUdpTable(), but allocate the returned table from heap.
2410 * PARAMS
2411 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
2412 * allocated and returned.
2413 * bOrder [In] whether to sort the table
2414 * heap [In] heap from which the table is allocated
2415 * flags [In] flags to HeapAlloc
2417 * RETURNS
2418 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
2419 * returns otherwise.
2421 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
2422 HANDLE heap, DWORD flags)
2424 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
2426 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
2427 return build_udp_table( UDP_TABLE_BASIC, (void **)ppUdpTable, bOrder, heap, flags, NULL );