regedit: An English (United States) spelling fix.
[wine/multimedia.git] / dlls / iphlpapi / ipstats.c
blobdb475fb45f6c33ae29ef52ac3a35b6b8b63cc6e6
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_ALIAS_H
31 #include <alias.h>
32 #endif
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
35 #endif
36 #ifdef HAVE_SYS_SOCKETVAR_H
37 #include <sys/socketvar.h>
38 #endif
39 #ifdef HAVE_SYS_TIMEOUT_H
40 #include <sys/timeout.h>
41 #endif
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
44 #endif
45 #ifdef HAVE_NETINET_IN_SYSTM_H
46 #include <netinet/in_systm.h>
47 #endif
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
50 #endif
51 #ifdef HAVE_NET_IF_H
52 #include <net/if.h>
53 #endif
54 #ifdef HAVE_NET_IF_DL_H
55 #include <net/if_dl.h>
56 #endif
57 #ifdef HAVE_NET_IF_TYPES_H
58 #include <net/if_types.h>
59 #endif
60 #ifdef HAVE_NET_ROUTE_H
61 #include <net/route.h>
62 #endif
63 #ifdef HAVE_NET_IF_ARP_H
64 #include <net/if_arp.h>
65 #endif
66 #ifdef HAVE_NETINET_IF_ETHER_H
67 #include <netinet/if_ether.h>
68 #endif
69 #ifdef HAVE_NETINET_IF_INARP_H
70 #include <netinet/if_inarp.h>
71 #endif
72 #ifdef HAVE_NETINET_IP_H
73 #include <netinet/ip.h>
74 #endif
75 #ifdef HAVE_NETINET_TCP_H
76 #include <netinet/tcp.h>
77 #endif
78 #ifdef HAVE_NETINET_IP_VAR_H
79 #include <netinet/ip_var.h>
80 #endif
81 #ifdef HAVE_NETINET_TCP_FSM_H
82 #include <netinet/tcp_fsm.h>
83 #endif
84 #ifdef HAVE_NETINET_IN_PCB_H
85 #include <netinet/in_pcb.h>
86 #endif
87 #ifdef HAVE_NETINET_TCP_TIMER_H
88 #include <netinet/tcp_timer.h>
89 #endif
90 #ifdef HAVE_NETINET_TCP_VAR_H
91 #include <netinet/tcp_var.h>
92 #endif
93 #ifdef HAVE_NETINET_IP_ICMP_H
94 #include <netinet/ip_icmp.h>
95 #endif
96 #ifdef HAVE_NETINET_ICMP_VAR_H
97 #include <netinet/icmp_var.h>
98 #endif
99 #ifdef HAVE_NETINET_UDP_H
100 #include <netinet/udp.h>
101 #endif
102 #ifdef HAVE_NETINET_UDP_VAR_H
103 #include <netinet/udp_var.h>
104 #endif
105 #ifdef HAVE_SYS_PROTOSW_H
106 #include <sys/protosw.h>
107 #endif
108 #ifdef HAVE_SYS_SYSCTL_H
109 #include <sys/sysctl.h>
110 #endif
111 #ifdef HAVE_KSTAT_H
112 #include <kstat.h>
113 #endif
114 #ifdef HAVE_INET_MIB2_H
115 #include <inet/mib2.h>
116 #endif
117 #ifdef HAVE_STROPTS_H
118 #include <stropts.h>
119 #endif
120 #ifdef HAVE_SYS_TIHDR_H
121 #include <sys/tihdr.h>
122 #endif
124 #ifndef ROUNDUP
125 #define ROUNDUP(a) \
126 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
127 #endif
128 #ifndef ADVANCE
129 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
130 #endif
132 #define NONAMELESSUNION
133 #include "ifenum.h"
134 #include "ipstats.h"
136 #include "wine/debug.h"
138 #ifndef HAVE_NETINET_TCP_FSM_H
139 #define TCPS_ESTABLISHED 1
140 #define TCPS_SYN_SENT 2
141 #define TCPS_SYN_RECEIVED 3
142 #define TCPS_FIN_WAIT_1 4
143 #define TCPS_FIN_WAIT_2 5
144 #define TCPS_TIME_WAIT 6
145 #define TCPS_CLOSED 7
146 #define TCPS_CLOSE_WAIT 8
147 #define TCPS_LAST_ACK 9
148 #define TCPS_LISTEN 10
149 #define TCPS_CLOSING 11
150 #endif
152 #ifndef RTF_MULTICAST
153 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
154 #endif
156 #ifndef RTF_LLINFO
157 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
158 #endif
160 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
162 #ifdef HAVE_LIBKSTAT
163 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
165 unsigned int i;
166 kstat_named_t *data = ksp->ks_data;
168 for (i = 0; i < ksp->ks_ndata; i++)
169 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
170 return 0;
173 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
175 unsigned int i;
176 kstat_named_t *data = ksp->ks_data;
178 for (i = 0; i < ksp->ks_ndata; i++)
179 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
180 return 0;
182 #endif
184 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
185 static int open_streams_mib( const char *proto )
187 int fd;
188 struct strbuf buf;
189 struct request
191 struct T_optmgmt_req req_header;
192 struct opthdr opt_header;
193 } request;
195 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
197 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
198 return -1;
200 if (proto) ioctl( fd, I_PUSH, proto );
202 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
203 request.req_header.OPT_length = sizeof(request.opt_header);
204 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
205 request.req_header.MGMT_flags = T_CURRENT;
206 request.opt_header.level = MIB2_IP;
207 request.opt_header.name = 0;
208 request.opt_header.len = 0;
210 buf.len = sizeof(request);
211 buf.buf = (caddr_t)&request;
212 if (putmsg( fd, &buf, NULL, 0 ) == -1)
214 WARN( "putmsg: %s\n", strerror(errno) );
215 close( fd );
216 fd = -1;
218 return fd;
221 static void *read_mib_entry( int fd, int level, int name, int *len )
223 struct strbuf buf;
224 void *data;
225 int ret, flags = 0;
227 struct reply
229 struct T_optmgmt_ack ack_header;
230 struct opthdr opt_header;
231 } reply;
233 for (;;)
235 buf.maxlen = sizeof(reply);
236 buf.buf = (caddr_t)&reply;
237 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
238 if (!(ret & MOREDATA)) return NULL;
239 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
240 if (buf.len < sizeof(reply.ack_header)) return NULL;
241 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
243 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
244 buf.maxlen = reply.opt_header.len;
245 buf.buf = (caddr_t)data;
246 flags = 0;
247 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
248 reply.opt_header.level == level &&
249 reply.opt_header.name == name)
251 *len = buf.len;
252 return data;
254 HeapFree( GetProcessHeap(), 0, data );
257 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
259 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
261 DWORD ret = ERROR_NOT_SUPPORTED;
263 if (!name || !entry) return ERROR_INVALID_PARAMETER;
265 #ifdef __linux__
267 FILE *fp;
269 if ((fp = fopen("/proc/net/dev", "r")))
271 DWORD skip;
272 char buf[512], *ptr;
273 int nameLen = strlen(name);
275 while ((ptr = fgets(buf, sizeof(buf), fp)))
277 while (*ptr && isspace(*ptr)) ptr++;
278 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
280 ptr += nameLen + 1;
281 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
282 &entry->dwInOctets, &entry->dwInUcastPkts,
283 &entry->dwInErrors, &entry->dwInDiscards,
284 &skip, &skip, &skip,
285 &entry->dwInNUcastPkts, &entry->dwOutOctets,
286 &entry->dwOutUcastPkts, &entry->dwOutErrors,
287 &entry->dwOutDiscards );
288 break;
291 fclose(fp);
292 ret = NO_ERROR;
295 #elif defined(HAVE_LIBKSTAT)
297 kstat_ctl_t *kc;
298 kstat_t *ksp;
300 if ((kc = kstat_open()) &&
301 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
302 kstat_read( kc, ksp, NULL ) != -1 &&
303 ksp->ks_type == KSTAT_TYPE_NAMED)
305 entry->dwMtu = 1500; /* FIXME */
306 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
307 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
308 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
309 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
310 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
311 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
312 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
313 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
314 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
315 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
316 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
317 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
318 entry->dwOutDiscards = 0; /* FIXME */
319 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
320 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
321 ret = NO_ERROR;
323 if (kc) kstat_close( kc );
325 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
327 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
328 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
330 size_t needed;
331 char *buf = NULL, *end;
332 struct if_msghdr *ifm;
333 struct if_data ifdata;
335 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
337 ERR ("failed to get size of iflist\n");
338 goto done;
340 buf = HeapAlloc (GetProcessHeap (), 0, needed);
341 if (!buf)
343 ret = ERROR_OUTOFMEMORY;
344 goto done;
346 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
348 ERR ("failed to get iflist\n");
349 goto done;
351 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
353 ifm = (struct if_msghdr *) buf;
354 if(ifm->ifm_type == RTM_IFINFO)
356 ifdata = ifm->ifm_data;
357 entry->dwMtu = ifdata.ifi_mtu;
358 entry->dwSpeed = ifdata.ifi_baudrate;
359 entry->dwInOctets = ifdata.ifi_ibytes;
360 entry->dwInErrors = ifdata.ifi_ierrors;
361 entry->dwInDiscards = ifdata.ifi_iqdrops;
362 entry->dwInUcastPkts = ifdata.ifi_ipackets;
363 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
364 entry->dwOutOctets = ifdata.ifi_obytes;
365 entry->dwOutUcastPkts = ifdata.ifi_opackets;
366 entry->dwOutErrors = ifdata.ifi_oerrors;
367 ret = NO_ERROR;
368 break;
371 done:
372 HeapFree (GetProcessHeap (), 0, buf);
374 #else
375 FIXME( "unimplemented\n" );
376 #endif
377 return ret;
381 /******************************************************************
382 * GetIcmpStatistics (IPHLPAPI.@)
384 * Get the ICMP statistics for the local computer.
386 * PARAMS
387 * stats [Out] buffer for ICMP statistics
389 * RETURNS
390 * Success: NO_ERROR
391 * Failure: error code from winerror.h
393 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
395 DWORD ret = ERROR_NOT_SUPPORTED;
397 if (!stats) return ERROR_INVALID_PARAMETER;
398 memset( stats, 0, sizeof(MIB_ICMP) );
400 #ifdef __linux__
402 FILE *fp;
404 if ((fp = fopen("/proc/net/snmp", "r")))
406 static const char hdr[] = "Icmp:";
407 char buf[512], *ptr;
409 while ((ptr = fgets(buf, sizeof(buf), fp)))
411 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
412 /* last line was a header, get another */
413 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
414 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
416 ptr += sizeof(hdr);
417 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",
418 &stats->stats.icmpInStats.dwMsgs,
419 &stats->stats.icmpInStats.dwErrors,
420 &stats->stats.icmpInStats.dwDestUnreachs,
421 &stats->stats.icmpInStats.dwTimeExcds,
422 &stats->stats.icmpInStats.dwParmProbs,
423 &stats->stats.icmpInStats.dwSrcQuenchs,
424 &stats->stats.icmpInStats.dwRedirects,
425 &stats->stats.icmpInStats.dwEchoReps,
426 &stats->stats.icmpInStats.dwTimestamps,
427 &stats->stats.icmpInStats.dwTimestampReps,
428 &stats->stats.icmpInStats.dwAddrMasks,
429 &stats->stats.icmpInStats.dwAddrMaskReps,
430 &stats->stats.icmpOutStats.dwMsgs,
431 &stats->stats.icmpOutStats.dwErrors,
432 &stats->stats.icmpOutStats.dwDestUnreachs,
433 &stats->stats.icmpOutStats.dwTimeExcds,
434 &stats->stats.icmpOutStats.dwParmProbs,
435 &stats->stats.icmpOutStats.dwSrcQuenchs,
436 &stats->stats.icmpOutStats.dwRedirects,
437 &stats->stats.icmpOutStats.dwEchoReps,
438 &stats->stats.icmpOutStats.dwTimestamps,
439 &stats->stats.icmpOutStats.dwTimestampReps,
440 &stats->stats.icmpOutStats.dwAddrMasks,
441 &stats->stats.icmpOutStats.dwAddrMaskReps );
442 break;
445 fclose(fp);
446 ret = NO_ERROR;
449 #elif defined(HAVE_LIBKSTAT)
451 static char ip[] = "ip", icmp[] = "icmp";
452 kstat_ctl_t *kc;
453 kstat_t *ksp;
455 if ((kc = kstat_open()) &&
456 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
457 kstat_read( kc, ksp, NULL ) != -1 &&
458 ksp->ks_type == KSTAT_TYPE_NAMED)
460 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
461 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
462 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
463 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
464 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
465 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
466 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
467 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
468 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
469 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
470 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
471 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
472 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
473 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
474 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
475 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
476 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
477 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
478 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
479 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
480 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
481 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
482 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
483 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
484 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
485 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
486 ret = NO_ERROR;
488 if (kc) kstat_close( kc );
490 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
492 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
493 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
494 struct icmpstat icmp_stat;
495 size_t needed = sizeof(icmp_stat);
496 int i;
498 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
500 /*in stats */
501 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
502 for(i = 0; i <= ICMP_MAXTYPE; i++)
503 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
505 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
507 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
508 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
509 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
510 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
511 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
512 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
513 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
514 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
515 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
516 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
517 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
519 #ifdef HAVE_ICPS_OUTHIST
520 /* out stats */
521 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
522 for(i = 0; i <= ICMP_MAXTYPE; i++)
523 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
525 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
527 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
528 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
529 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
530 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
531 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
532 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
533 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
534 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
535 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
536 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
537 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
538 #endif /* ICPS_OUTHIST */
539 ret = NO_ERROR;
542 #else /* ICMPCTL_STATS */
543 FIXME( "unimplemented\n" );
544 #endif
545 return ret;
549 /******************************************************************
550 * GetIpStatistics (IPHLPAPI.@)
552 * Get the IP statistics for the local computer.
554 * PARAMS
555 * stats [Out] buffer for IP statistics
557 * RETURNS
558 * Success: NO_ERROR
559 * Failure: error code from winerror.h
561 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
563 DWORD ret = ERROR_NOT_SUPPORTED;
564 MIB_IPFORWARDTABLE *fwd_table;
566 if (!stats) return ERROR_INVALID_PARAMETER;
567 memset( stats, 0, sizeof(*stats) );
569 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
570 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
572 stats->dwNumRoutes = fwd_table->dwNumEntries;
573 HeapFree( GetProcessHeap(), 0, fwd_table );
576 #ifdef __linux__
578 FILE *fp;
580 if ((fp = fopen("/proc/net/snmp", "r")))
582 static const char hdr[] = "Ip:";
583 char buf[512], *ptr;
585 while ((ptr = fgets(buf, sizeof(buf), fp)))
587 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
588 /* last line was a header, get another */
589 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
590 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
592 ptr += sizeof(hdr);
593 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
594 &stats->u.dwForwarding,
595 &stats->dwDefaultTTL,
596 &stats->dwInReceives,
597 &stats->dwInHdrErrors,
598 &stats->dwInAddrErrors,
599 &stats->dwForwDatagrams,
600 &stats->dwInUnknownProtos,
601 &stats->dwInDiscards,
602 &stats->dwInDelivers,
603 &stats->dwOutRequests,
604 &stats->dwOutDiscards,
605 &stats->dwOutNoRoutes,
606 &stats->dwReasmTimeout,
607 &stats->dwReasmReqds,
608 &stats->dwReasmOks,
609 &stats->dwReasmFails,
610 &stats->dwFragOks,
611 &stats->dwFragFails,
612 &stats->dwFragCreates );
613 /* hmm, no routingDiscards */
614 break;
617 fclose(fp);
618 ret = NO_ERROR;
621 #elif defined(HAVE_LIBKSTAT)
623 static char ip[] = "ip";
624 kstat_ctl_t *kc;
625 kstat_t *ksp;
627 if ((kc = kstat_open()) &&
628 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
629 kstat_read( kc, ksp, NULL ) != -1 &&
630 ksp->ks_type == KSTAT_TYPE_NAMED)
632 stats->u.dwForwarding = kstat_get_ui32( ksp, "forwarding" );
633 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
634 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
635 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
636 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
637 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
638 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
639 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
640 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
641 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
642 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
643 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
644 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
645 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
646 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
647 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
648 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
649 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
650 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
651 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
652 ret = NO_ERROR;
654 if (kc) kstat_close( kc );
656 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
658 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
659 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
660 int ip_ttl, ip_forwarding;
661 struct ipstat ip_stat;
662 size_t needed;
664 needed = sizeof(ip_stat);
665 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
667 ERR ("failed to get ipstat\n");
668 return ERROR_NOT_SUPPORTED;
671 needed = sizeof(ip_ttl);
672 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
674 ERR ("failed to get ip Default TTL\n");
675 return ERROR_NOT_SUPPORTED;
678 needed = sizeof(ip_forwarding);
679 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
681 ERR ("failed to get ip forwarding\n");
682 return ERROR_NOT_SUPPORTED;
685 stats->u.dwForwarding = ip_forwarding;
686 stats->dwDefaultTTL = ip_ttl;
687 stats->dwInDelivers = ip_stat.ips_delivered;
688 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
689 stats->dwInAddrErrors = ip_stat.ips_cantforward;
690 stats->dwInReceives = ip_stat.ips_total;
691 stats->dwForwDatagrams = ip_stat.ips_forward;
692 stats->dwInUnknownProtos = ip_stat.ips_noproto;
693 stats->dwInDiscards = ip_stat.ips_fragdropped;
694 stats->dwOutDiscards = ip_stat.ips_odropped;
695 stats->dwReasmOks = ip_stat.ips_reassembled;
696 stats->dwFragOks = ip_stat.ips_fragmented;
697 stats->dwFragFails = ip_stat.ips_cantfrag;
698 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
699 stats->dwOutNoRoutes = ip_stat.ips_noroute;
700 stats->dwOutRequests = ip_stat.ips_localout;
701 stats->dwReasmReqds = ip_stat.ips_fragments;
702 ret = NO_ERROR;
704 #else
705 FIXME( "unimplemented\n" );
706 #endif
707 return ret;
711 /******************************************************************
712 * GetTcpStatistics (IPHLPAPI.@)
714 * Get the TCP statistics for the local computer.
716 * PARAMS
717 * stats [Out] buffer for TCP statistics
719 * RETURNS
720 * Success: NO_ERROR
721 * Failure: error code from winerror.h
723 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
725 DWORD ret = ERROR_NOT_SUPPORTED;
727 if (!stats) return ERROR_INVALID_PARAMETER;
728 memset( stats, 0, sizeof(*stats) );
730 #ifdef __linux__
732 FILE *fp;
734 if ((fp = fopen("/proc/net/snmp", "r")))
736 static const char hdr[] = "Tcp:";
737 MIB_TCPTABLE *tcp_table;
738 char buf[512], *ptr;
740 while ((ptr = fgets(buf, sizeof(buf), fp)))
742 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
743 /* last line was a header, get another */
744 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
745 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
747 ptr += sizeof(hdr);
748 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
749 &stats->u.dwRtoAlgorithm,
750 &stats->dwRtoMin,
751 &stats->dwRtoMax,
752 &stats->dwMaxConn,
753 &stats->dwActiveOpens,
754 &stats->dwPassiveOpens,
755 &stats->dwAttemptFails,
756 &stats->dwEstabResets,
757 &stats->dwCurrEstab,
758 &stats->dwInSegs,
759 &stats->dwOutSegs,
760 &stats->dwRetransSegs,
761 &stats->dwInErrs,
762 &stats->dwOutRsts );
763 break;
766 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
768 stats->dwNumConns = tcp_table->dwNumEntries;
769 HeapFree( GetProcessHeap(), 0, tcp_table );
771 fclose(fp);
772 ret = NO_ERROR;
775 #elif defined(HAVE_LIBKSTAT)
777 static char tcp[] = "tcp";
778 kstat_ctl_t *kc;
779 kstat_t *ksp;
781 if ((kc = kstat_open()) &&
782 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
783 kstat_read( kc, ksp, NULL ) != -1 &&
784 ksp->ks_type == KSTAT_TYPE_NAMED)
786 stats->u.dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
787 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
788 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
789 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
790 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
791 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
792 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
793 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
794 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
795 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
796 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
797 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
798 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
799 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
800 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
801 ret = NO_ERROR;
803 if (kc) kstat_close( kc );
805 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
807 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
808 #define TCPTV_MIN 2
809 #define TCPTV_REXMTMAX 128
810 #endif
811 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
812 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
813 #define hz 1000
814 struct tcpstat tcp_stat;
815 size_t needed = sizeof(tcp_stat);
817 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
819 stats->u.RtoAlgorithm = MIB_TCP_RTO_VANJ;
820 stats->dwRtoMin = TCPTV_MIN;
821 stats->dwRtoMax = TCPTV_REXMTMAX;
822 stats->dwMaxConn = -1;
823 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
824 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
825 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
826 stats->dwEstabResets = tcp_stat.tcps_drops;
827 stats->dwCurrEstab = 0;
828 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
829 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
830 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
831 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
832 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
833 stats->dwNumConns = tcp_stat.tcps_connects;
834 ret = NO_ERROR;
836 else ERR ("failed to get tcpstat\n");
838 #else
839 FIXME( "unimplemented\n" );
840 #endif
841 return ret;
845 /******************************************************************
846 * GetUdpStatistics (IPHLPAPI.@)
848 * Get the UDP statistics for the local computer.
850 * PARAMS
851 * stats [Out] buffer for UDP statistics
853 * RETURNS
854 * Success: NO_ERROR
855 * Failure: error code from winerror.h
857 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
859 DWORD ret = ERROR_NOT_SUPPORTED;
861 if (!stats) return ERROR_INVALID_PARAMETER;
862 memset( stats, 0, sizeof(*stats) );
864 #ifdef __linux__
866 FILE *fp;
868 if ((fp = fopen("/proc/net/snmp", "r")))
870 static const char hdr[] = "Udp:";
871 char buf[512], *ptr;
873 while ((ptr = fgets(buf, sizeof(buf), fp)))
875 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
876 /* last line was a header, get another */
877 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
878 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
880 ptr += sizeof(hdr);
881 sscanf( ptr, "%u %u %u %u %u",
882 &stats->dwInDatagrams, &stats->dwNoPorts,
883 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
884 break;
887 fclose(fp);
888 ret = NO_ERROR;
891 #elif defined(HAVE_LIBKSTAT)
893 static char udp[] = "udp";
894 kstat_ctl_t *kc;
895 kstat_t *ksp;
896 MIB_UDPTABLE *udp_table;
898 if ((kc = kstat_open()) &&
899 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
900 kstat_read( kc, ksp, NULL ) != -1 &&
901 ksp->ks_type == KSTAT_TYPE_NAMED)
903 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
904 stats->dwNoPorts = 0; /* FIXME */
905 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
906 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
907 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
909 stats->dwNumAddrs = udp_table->dwNumEntries;
910 HeapFree( GetProcessHeap(), 0, udp_table );
912 ret = NO_ERROR;
914 if (kc) kstat_close( kc );
916 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
918 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
919 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
920 struct udpstat udp_stat;
921 MIB_UDPTABLE *udp_table;
922 size_t needed = sizeof(udp_stat);
924 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
926 stats->dwInDatagrams = udp_stat.udps_ipackets;
927 stats->dwOutDatagrams = udp_stat.udps_opackets;
928 stats->dwNoPorts = udp_stat.udps_noport;
929 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
930 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
932 stats->dwNumAddrs = udp_table->dwNumEntries;
933 HeapFree( GetProcessHeap(), 0, udp_table );
935 ret = NO_ERROR;
937 else ERR ("failed to get udpstat\n");
939 #else
940 FIXME( "unimplemented\n" );
941 #endif
942 return ret;
946 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
947 DWORD *count, const MIB_IPFORWARDROW *row )
949 if (table->dwNumEntries >= *count)
951 MIB_IPFORWARDTABLE *new_table;
952 DWORD new_count = table->dwNumEntries * 2;
954 if (!(new_table = HeapReAlloc( heap, flags, table,
955 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
957 HeapFree( heap, 0, table );
958 return NULL;
960 *count = new_count;
961 table = new_table;
963 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
964 return table;
967 static int compare_ipforward_rows(const void *a, const void *b)
969 const MIB_IPFORWARDROW *rowA = a;
970 const MIB_IPFORWARDROW *rowB = b;
971 int ret;
973 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
974 if ((ret = rowA->u2.dwForwardProto - rowB->u2.dwForwardProto) != 0) return ret;
975 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
976 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
979 /******************************************************************
980 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
982 * Get the route table.
983 * Like GetIpForwardTable(), but allocate the returned table from heap.
985 * PARAMS
986 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
987 * allocated and returned.
988 * bOrder [In] whether to sort the table
989 * heap [In] heap from which the table is allocated
990 * flags [In] flags to HeapAlloc
992 * RETURNS
993 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
994 * on failure, NO_ERROR on success.
996 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
997 HANDLE heap, DWORD flags)
999 MIB_IPFORWARDTABLE *table;
1000 MIB_IPFORWARDROW row;
1001 DWORD ret = NO_ERROR, count = 16;
1003 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1005 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1007 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1008 return ERROR_OUTOFMEMORY;
1010 table->dwNumEntries = 0;
1012 #ifdef __linux__
1014 FILE *fp;
1016 if ((fp = fopen("/proc/net/route", "r")))
1018 char buf[512], *ptr;
1019 DWORD flags;
1021 /* skip header line */
1022 ptr = fgets(buf, sizeof(buf), fp);
1023 while ((ptr = fgets(buf, sizeof(buf), fp)))
1025 memset( &row, 0, sizeof(row) );
1027 while (!isspace(*ptr)) ptr++;
1028 *ptr++ = 0;
1029 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1030 continue;
1032 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1033 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1034 flags = strtoul(ptr + 1, &ptr, 16);
1036 if (!(flags & RTF_UP)) row.u1.ForwardType = MIB_IPROUTE_TYPE_INVALID;
1037 else if (flags & RTF_GATEWAY) row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1038 else row.u1.ForwardType = MIB_IPROUTE_TYPE_DIRECT;
1040 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1041 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1042 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1043 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1044 /* FIXME: other protos might be appropriate, e.g. the default
1045 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1046 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1048 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1049 break;
1051 fclose(fp);
1053 else ret = ERROR_NOT_SUPPORTED;
1055 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1057 void *data;
1058 int fd, len, namelen;
1059 mib2_ipRouteEntry_t *entry;
1060 char name[64];
1062 if ((fd = open_streams_mib( NULL )) != -1)
1064 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1066 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1068 row.dwForwardDest = entry->ipRouteDest;
1069 row.dwForwardMask = entry->ipRouteMask;
1070 row.dwForwardPolicy = 0;
1071 row.dwForwardNextHop = entry->ipRouteNextHop;
1072 row.u1.dwForwardType = entry->ipRouteType;
1073 row.u2.dwForwardProto = entry->ipRouteProto;
1074 row.dwForwardAge = entry->ipRouteAge;
1075 row.dwForwardNextHopAS = 0;
1076 row.dwForwardMetric1 = entry->ipRouteMetric1;
1077 row.dwForwardMetric2 = entry->ipRouteMetric2;
1078 row.dwForwardMetric3 = entry->ipRouteMetric3;
1079 row.dwForwardMetric4 = entry->ipRouteMetric4;
1080 row.dwForwardMetric5 = entry->ipRouteMetric5;
1081 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1082 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1083 name[namelen] = 0;
1084 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1085 if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1087 HeapFree( GetProcessHeap(), 0, data );
1089 close( fd );
1091 else ret = ERROR_NOT_SUPPORTED;
1093 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1095 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1096 size_t needed;
1097 char *buf = NULL, *lim, *next, *addrPtr;
1098 struct rt_msghdr *rtm;
1100 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1102 ERR ("sysctl 1 failed!\n");
1103 ret = ERROR_NOT_SUPPORTED;
1104 goto done;
1107 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1108 if (!buf)
1110 ret = ERROR_OUTOFMEMORY;
1111 goto done;
1114 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1116 ret = ERROR_NOT_SUPPORTED;
1117 goto done;
1120 lim = buf + needed;
1121 for (next = buf; next < lim; next += rtm->rtm_msglen)
1123 int i;
1125 rtm = (struct rt_msghdr *)next;
1127 if (rtm->rtm_type != RTM_GET)
1129 WARN ("Got unexpected message type 0x%x!\n",
1130 rtm->rtm_type);
1131 continue;
1134 /* Ignore all entries except for gateway routes which aren't
1135 multicast */
1136 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1137 (rtm->rtm_flags & RTF_MULTICAST))
1138 continue;
1140 memset( &row, 0, sizeof(row) );
1141 row.dwForwardIfIndex = rtm->rtm_index;
1142 row.u1.ForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1143 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1144 row.u2.ForwardProto = MIB_IPPROTO_LOCAL;
1146 addrPtr = (char *)(rtm + 1);
1148 for (i = 1; i; i <<= 1)
1150 struct sockaddr *sa;
1151 DWORD addr;
1153 if (!(i & rtm->rtm_addrs))
1154 continue;
1156 sa = (struct sockaddr *)addrPtr;
1157 ADVANCE (addrPtr, sa);
1159 /* default routes are encoded by length-zero sockaddr */
1160 if (sa->sa_len == 0)
1161 addr = 0;
1162 else if (sa->sa_family != AF_INET)
1164 WARN ("Received unsupported sockaddr family 0x%x\n",
1165 sa->sa_family);
1166 addr = 0;
1168 else
1170 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1172 addr = sin->sin_addr.s_addr;
1175 switch (i)
1177 case RTA_DST: row.dwForwardDest = addr; break;
1178 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1179 case RTA_NETMASK: row.dwForwardMask = addr; break;
1180 default:
1181 WARN ("Unexpected address type 0x%x\n", i);
1185 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1186 break;
1188 done:
1189 HeapFree( GetProcessHeap (), 0, buf );
1191 #else
1192 FIXME( "not implemented\n" );
1193 ret = ERROR_NOT_SUPPORTED;
1194 #endif
1196 if (!table) return ERROR_OUTOFMEMORY;
1197 if (!ret)
1199 if (bOrder && table->dwNumEntries)
1200 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1201 *ppIpForwardTable = table;
1203 else HeapFree( heap, flags, table );
1204 TRACE( "returning ret %u table %p\n", ret, table );
1205 return ret;
1208 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1209 DWORD *count, const MIB_IPNETROW *row )
1211 if (table->dwNumEntries >= *count)
1213 MIB_IPNETTABLE *new_table;
1214 DWORD new_count = table->dwNumEntries * 2;
1216 if (!(new_table = HeapReAlloc( heap, flags, table,
1217 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1219 HeapFree( heap, 0, table );
1220 return NULL;
1222 *count = new_count;
1223 table = new_table;
1225 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1226 return table;
1229 static int compare_ipnet_rows(const void *a, const void *b)
1231 const MIB_IPNETROW *rowA = a;
1232 const MIB_IPNETROW *rowB = b;
1234 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1238 /******************************************************************
1239 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1241 * Get the IP-to-physical address mapping table.
1242 * Like GetIpNetTable(), but allocate the returned table from heap.
1244 * PARAMS
1245 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1246 * allocated and returned.
1247 * bOrder [In] whether to sort the table
1248 * heap [In] heap from which the table is allocated
1249 * flags [In] flags to HeapAlloc
1251 * RETURNS
1252 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1253 * on failure, NO_ERROR on success.
1255 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1256 HANDLE heap, DWORD flags)
1258 MIB_IPNETTABLE *table;
1259 MIB_IPNETROW row;
1260 DWORD ret = NO_ERROR, count = 16;
1262 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1264 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1266 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1267 return ERROR_OUTOFMEMORY;
1269 table->dwNumEntries = 0;
1271 #ifdef __linux__
1273 FILE *fp;
1275 if ((fp = fopen("/proc/net/arp", "r")))
1277 char buf[512], *ptr;
1278 DWORD flags;
1280 /* skip header line */
1281 ptr = fgets(buf, sizeof(buf), fp);
1282 while ((ptr = fgets(buf, sizeof(buf), fp)))
1284 memset( &row, 0, sizeof(row) );
1286 row.dwAddr = inet_addr(ptr);
1287 while (*ptr && !isspace(*ptr)) ptr++;
1288 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1289 flags = strtoul(ptr + 1, &ptr, 16);
1291 #ifdef ATF_COM
1292 if (flags & ATF_COM) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1293 else
1294 #endif
1295 #ifdef ATF_PERM
1296 if (flags & ATF_PERM) row.u.Type = MIB_IPNET_TYPE_STATIC;
1297 else
1298 #endif
1299 row.u.Type = MIB_IPNET_TYPE_OTHER;
1301 while (*ptr && isspace(*ptr)) ptr++;
1302 while (*ptr && !isspace(*ptr))
1304 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1305 if (*ptr) ptr++;
1307 while (*ptr && isspace(*ptr)) ptr++;
1308 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1309 while (*ptr && isspace(*ptr)) ptr++;
1310 getInterfaceIndexByName(ptr, &row.dwIndex);
1312 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1313 break;
1315 fclose(fp);
1317 else ret = ERROR_NOT_SUPPORTED;
1319 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1321 void *data;
1322 int fd, len, namelen;
1323 mib2_ipNetToMediaEntry_t *entry;
1324 char name[64];
1326 if ((fd = open_streams_mib( NULL )) != -1)
1328 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1330 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1332 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1333 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1334 row.dwAddr = entry->ipNetToMediaNetAddress;
1335 row.u.Type = entry->ipNetToMediaType;
1336 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1337 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1338 name[namelen] = 0;
1339 getInterfaceIndexByName( name, &row.dwIndex );
1340 if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1342 HeapFree( GetProcessHeap(), 0, data );
1344 close( fd );
1346 else ret = ERROR_NOT_SUPPORTED;
1348 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1350 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1351 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1352 size_t needed;
1353 char *buf = NULL, *lim, *next;
1354 struct rt_msghdr *rtm;
1355 struct sockaddr_inarp *sinarp;
1356 struct sockaddr_dl *sdl;
1358 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1360 ERR ("failed to get arp table\n");
1361 ret = ERROR_NOT_SUPPORTED;
1362 goto done;
1365 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1366 if (!buf)
1368 ret = ERROR_OUTOFMEMORY;
1369 goto done;
1372 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1374 ret = ERROR_NOT_SUPPORTED;
1375 goto done;
1378 lim = buf + needed;
1379 next = buf;
1380 while(next < lim)
1382 rtm = (struct rt_msghdr *)next;
1383 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1384 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1385 if(sdl->sdl_alen) /* arp entry */
1387 memset( &row, 0, sizeof(row) );
1388 row.dwAddr = sinarp->sin_addr.s_addr;
1389 row.dwIndex = sdl->sdl_index;
1390 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1391 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1392 if(rtm->rtm_rmx.rmx_expire == 0) row.u.Type = MIB_IPNET_TYPE_STATIC;
1393 else if(sinarp->sin_other & SIN_PROXY) row.u.Type = MIB_IPNET_TYPE_OTHER;
1394 else if(rtm->rtm_rmx.rmx_expire != 0) row.u.Type = MIB_IPNET_TYPE_DYNAMIC;
1395 else row.u.Type = MIB_IPNET_TYPE_INVALID;
1397 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1398 break;
1400 next += rtm->rtm_msglen;
1402 done:
1403 HeapFree( GetProcessHeap (), 0, buf );
1405 #else
1406 FIXME( "not implemented\n" );
1407 ret = ERROR_NOT_SUPPORTED;
1408 #endif
1410 if (!table) return ERROR_OUTOFMEMORY;
1411 if (!ret)
1413 if (bOrder && table->dwNumEntries)
1414 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1415 *ppIpNetTable = table;
1417 else HeapFree( heap, flags, table );
1418 TRACE( "returning ret %u table %p\n", ret, table );
1419 return ret;
1423 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1424 DWORD *count, const MIB_UDPROW *row )
1426 if (table->dwNumEntries >= *count)
1428 MIB_UDPTABLE *new_table;
1429 DWORD new_count = table->dwNumEntries * 2;
1431 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1433 HeapFree( heap, 0, table );
1434 return NULL;
1436 *count = new_count;
1437 table = new_table;
1439 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1440 return table;
1443 static int compare_udp_rows(const void *a, const void *b)
1445 const MIB_UDPROW *rowA = a;
1446 const MIB_UDPROW *rowB = b;
1447 int ret;
1449 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1450 return rowA->dwLocalPort - rowB->dwLocalPort;
1454 /******************************************************************
1455 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1457 * Get the UDP listener table.
1458 * Like GetUdpTable(), but allocate the returned table from heap.
1460 * PARAMS
1461 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1462 * allocated and returned.
1463 * bOrder [In] whether to sort the table
1464 * heap [In] heap from which the table is allocated
1465 * flags [In] flags to HeapAlloc
1467 * RETURNS
1468 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1469 * returns otherwise.
1471 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1472 HANDLE heap, DWORD flags)
1474 MIB_UDPTABLE *table;
1475 MIB_UDPROW row;
1476 DWORD ret = NO_ERROR, count = 16;
1478 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1480 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1482 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1483 return ERROR_OUTOFMEMORY;
1485 table->dwNumEntries = 0;
1487 #ifdef __linux__
1489 FILE *fp;
1491 if ((fp = fopen("/proc/net/udp", "r")))
1493 char buf[512], *ptr;
1494 DWORD dummy;
1496 /* skip header line */
1497 ptr = fgets(buf, sizeof(buf), fp);
1498 while ((ptr = fgets(buf, sizeof(buf), fp)))
1500 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1501 continue;
1502 row.dwLocalPort = htons( row.dwLocalPort );
1503 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1504 break;
1506 fclose(fp);
1508 else ret = ERROR_NOT_SUPPORTED;
1510 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1512 void *data;
1513 int fd, len;
1514 mib2_udpEntry_t *entry;
1516 if ((fd = open_streams_mib( "udp" )) != -1)
1518 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
1520 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1522 row.dwLocalAddr = entry->udpLocalAddress;
1523 row.dwLocalPort = htons( entry->udpLocalPort );
1524 if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1526 HeapFree( GetProcessHeap(), 0, data );
1528 close( fd );
1530 else ret = ERROR_NOT_SUPPORTED;
1532 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1534 size_t Len = 0;
1535 char *Buf = NULL;
1536 struct xinpgen *pXIG, *pOrigXIG;
1538 if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
1540 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1541 ret = ERROR_NOT_SUPPORTED;
1542 goto done;
1545 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1546 if (!Buf)
1548 ret = ERROR_OUTOFMEMORY;
1549 goto done;
1552 if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
1554 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1555 ret = ERROR_NOT_SUPPORTED;
1556 goto done;
1559 /* Might be nothing here; first entry is just a header it seems */
1560 if (Len <= sizeof (struct xinpgen)) goto done;
1562 pOrigXIG = (struct xinpgen *)Buf;
1563 pXIG = pOrigXIG;
1565 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1566 pXIG->xig_len > sizeof (struct xinpgen);
1567 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1569 struct inpcb *pINData;
1570 struct xsocket *pSockData;
1572 pINData = &((struct xinpcb *)pXIG)->xi_inp;
1573 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
1575 /* Ignore sockets for other protocols */
1576 if (pSockData->xso_protocol != IPPROTO_UDP)
1577 continue;
1579 /* Ignore PCBs that were freed while generating the data */
1580 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1581 continue;
1583 /* we're only interested in IPv4 addresses */
1584 if (!(pINData->inp_vflag & INP_IPV4) ||
1585 (pINData->inp_vflag & INP_IPV6))
1586 continue;
1588 /* If all 0's, skip it */
1589 if (!pINData->inp_laddr.s_addr &&
1590 !pINData->inp_lport)
1591 continue;
1593 /* Fill in structure details */
1594 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1595 row.dwLocalPort = pINData->inp_lport;
1596 if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1599 done:
1600 HeapFree (GetProcessHeap (), 0, Buf);
1602 #else
1603 FIXME( "not implemented\n" );
1604 ret = ERROR_NOT_SUPPORTED;
1605 #endif
1607 if (!table) return ERROR_OUTOFMEMORY;
1608 if (!ret)
1610 if (bOrder && table->dwNumEntries)
1611 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1612 *ppUdpTable = table;
1614 else HeapFree( heap, flags, table );
1615 TRACE( "returning ret %u table %p\n", ret, table );
1616 return ret;
1620 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1621 DWORD *count, const MIB_TCPROW *row )
1623 if (table->dwNumEntries >= *count)
1625 MIB_TCPTABLE *new_table;
1626 DWORD new_count = table->dwNumEntries * 2;
1628 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1630 HeapFree( heap, 0, table );
1631 return NULL;
1633 *count = new_count;
1634 table = new_table;
1636 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1637 return table;
1641 /* Why not a lookup table? Because the TCPS_* constants are different
1642 on different platforms */
1643 static inline MIB_TCP_STATE TCPStateToMIBState (int state)
1645 switch (state)
1647 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1648 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1649 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1650 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1651 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1652 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1653 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1654 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1655 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1656 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1657 default:
1658 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1663 static int compare_tcp_rows(const void *a, const void *b)
1665 const MIB_TCPROW *rowA = a;
1666 const MIB_TCPROW *rowB = b;
1667 int ret;
1669 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1670 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1671 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1672 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1673 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1677 /******************************************************************
1678 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1680 * Get the TCP connection table.
1681 * Like GetTcpTable(), but allocate the returned table from heap.
1683 * PARAMS
1684 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1685 * allocated and returned.
1686 * bOrder [In] whether to sort the table
1687 * heap [In] heap from which the table is allocated
1688 * flags [In] flags to HeapAlloc
1690 * RETURNS
1691 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1692 * returns otherwise.
1694 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1695 HANDLE heap, DWORD flags)
1697 MIB_TCPTABLE *table;
1698 MIB_TCPROW row;
1699 DWORD ret = NO_ERROR, count = 16;
1701 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1703 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1705 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1706 return ERROR_OUTOFMEMORY;
1708 table->dwNumEntries = 0;
1710 #ifdef __linux__
1712 FILE *fp;
1714 if ((fp = fopen("/proc/net/tcp", "r")))
1716 char buf[512], *ptr;
1717 DWORD dummy;
1719 /* skip header line */
1720 ptr = fgets(buf, sizeof(buf), fp);
1721 while ((ptr = fgets(buf, sizeof(buf), fp)))
1723 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1724 &row.dwRemoteAddr, &row.dwRemotePort, &row.u.dwState ) != 6)
1725 continue;
1726 row.dwLocalPort = htons( row.dwLocalPort );
1727 row.dwRemotePort = htons( row.dwRemotePort );
1728 row.u.State = TCPStateToMIBState( row.u.dwState );
1729 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1730 break;
1732 fclose( fp );
1734 else ret = ERROR_NOT_SUPPORTED;
1736 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1738 void *data;
1739 int fd, len;
1740 mib2_tcpConnEntry_t *entry;
1742 if ((fd = open_streams_mib( "tcp" )) != -1)
1744 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
1746 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1748 row.dwLocalAddr = entry->tcpConnLocalAddress;
1749 row.dwLocalPort = htons( entry->tcpConnLocalPort );
1750 row.dwRemoteAddr = entry->tcpConnRemAddress;
1751 row.dwRemotePort = htons( entry->tcpConnRemPort );
1752 row.u.dwState = entry->tcpConnState;
1753 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1755 HeapFree( GetProcessHeap(), 0, data );
1757 close( fd );
1759 else ret = ERROR_NOT_SUPPORTED;
1761 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1763 size_t Len = 0;
1764 char *Buf = NULL;
1765 struct xinpgen *pXIG, *pOrigXIG;
1767 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1769 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1770 ret = ERROR_NOT_SUPPORTED;
1771 goto done;
1774 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1775 if (!Buf)
1777 ret = ERROR_OUTOFMEMORY;
1778 goto done;
1781 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1783 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1784 ret = ERROR_NOT_SUPPORTED;
1785 goto done;
1788 /* Might be nothing here; first entry is just a header it seems */
1789 if (Len <= sizeof (struct xinpgen)) goto done;
1791 pOrigXIG = (struct xinpgen *)Buf;
1792 pXIG = pOrigXIG;
1794 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1795 pXIG->xig_len > sizeof (struct xinpgen);
1796 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1798 struct tcpcb *pTCPData = NULL;
1799 struct inpcb *pINData;
1800 struct xsocket *pSockData;
1802 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1803 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1804 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1806 /* Ignore sockets for other protocols */
1807 if (pSockData->xso_protocol != IPPROTO_TCP)
1808 continue;
1810 /* Ignore PCBs that were freed while generating the data */
1811 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1812 continue;
1814 /* we're only interested in IPv4 addresses */
1815 if (!(pINData->inp_vflag & INP_IPV4) ||
1816 (pINData->inp_vflag & INP_IPV6))
1817 continue;
1819 /* If all 0's, skip it */
1820 if (!pINData->inp_laddr.s_addr &&
1821 !pINData->inp_lport &&
1822 !pINData->inp_faddr.s_addr &&
1823 !pINData->inp_fport)
1824 continue;
1826 /* Fill in structure details */
1827 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1828 row.dwLocalPort = pINData->inp_lport;
1829 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1830 row.dwRemotePort = pINData->inp_fport;
1831 row.u.State = TCPStateToMIBState (pTCPData->t_state);
1832 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1835 done:
1836 HeapFree (GetProcessHeap (), 0, Buf);
1838 #else
1839 FIXME( "not implemented\n" );
1840 ret = ERROR_NOT_SUPPORTED;
1841 #endif
1843 if (!table) return ERROR_OUTOFMEMORY;
1844 if (!ret)
1846 if (bOrder && table->dwNumEntries)
1847 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1848 *ppTcpTable = table;
1850 else HeapFree( heap, flags, table );
1851 TRACE( "returning ret %u table %p\n", ret, table );
1852 return ret;