iphlpapi: Remove a few redundant include directives.
[wine/multimedia.git] / dlls / iphlpapi / ipstats.c
blob7c8e7474407fc4609e716e499a91ba754faaa66f
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 #include "ifenum.h"
133 #include "ipstats.h"
135 #include "wine/debug.h"
137 #ifndef HAVE_NETINET_TCP_FSM_H
138 #define TCPS_ESTABLISHED 1
139 #define TCPS_SYN_SENT 2
140 #define TCPS_SYN_RECEIVED 3
141 #define TCPS_FIN_WAIT_1 4
142 #define TCPS_FIN_WAIT_2 5
143 #define TCPS_TIME_WAIT 6
144 #define TCPS_CLOSED 7
145 #define TCPS_CLOSE_WAIT 8
146 #define TCPS_LAST_ACK 9
147 #define TCPS_LISTEN 10
148 #define TCPS_CLOSING 11
149 #endif
151 #ifndef RTF_MULTICAST
152 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
153 #endif
155 #ifndef RTF_LLINFO
156 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
157 #endif
159 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
161 #ifdef HAVE_LIBKSTAT
162 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
164 unsigned int i;
165 kstat_named_t *data = ksp->ks_data;
167 for (i = 0; i < ksp->ks_ndata; i++)
168 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
169 return 0;
172 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
174 unsigned int i;
175 kstat_named_t *data = ksp->ks_data;
177 for (i = 0; i < ksp->ks_ndata; i++)
178 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
179 return 0;
181 #endif
183 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
184 static int open_streams_mib( const char *proto )
186 int fd;
187 struct strbuf buf;
188 struct request
190 struct T_optmgmt_req req_header;
191 struct opthdr opt_header;
192 } request;
194 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
196 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
197 return -1;
199 if (proto) ioctl( fd, I_PUSH, proto );
201 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
202 request.req_header.OPT_length = sizeof(request.opt_header);
203 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
204 request.req_header.MGMT_flags = T_CURRENT;
205 request.opt_header.level = MIB2_IP;
206 request.opt_header.name = 0;
207 request.opt_header.len = 0;
209 buf.len = sizeof(request);
210 buf.buf = (caddr_t)&request;
211 if (putmsg( fd, &buf, NULL, 0 ) == -1)
213 WARN( "putmsg: %s\n", strerror(errno) );
214 close( fd );
215 fd = -1;
217 return fd;
220 static void *read_mib_entry( int fd, int level, int name, int *len )
222 struct strbuf buf;
223 void *data;
224 int ret, flags = 0;
226 struct reply
228 struct T_optmgmt_ack ack_header;
229 struct opthdr opt_header;
230 } reply;
232 for (;;)
234 buf.maxlen = sizeof(reply);
235 buf.buf = (caddr_t)&reply;
236 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
237 if (!(ret & MOREDATA)) return NULL;
238 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
239 if (buf.len < sizeof(reply.ack_header)) return NULL;
240 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
242 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
243 buf.maxlen = reply.opt_header.len;
244 buf.buf = (caddr_t)data;
245 flags = 0;
246 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
247 reply.opt_header.level == level &&
248 reply.opt_header.name == name)
250 *len = buf.len;
251 return data;
253 HeapFree( GetProcessHeap(), 0, data );
256 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
258 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
260 DWORD ret = ERROR_NOT_SUPPORTED;
262 if (!name || !entry) return ERROR_INVALID_PARAMETER;
264 #ifdef __linux__
266 FILE *fp;
268 if ((fp = fopen("/proc/net/dev", "r")))
270 DWORD skip;
271 char buf[512], *ptr;
272 int nameLen = strlen(name);
274 while ((ptr = fgets(buf, sizeof(buf), fp)))
276 while (*ptr && isspace(*ptr)) ptr++;
277 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
279 ptr += nameLen + 1;
280 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
281 &entry->dwInOctets, &entry->dwInUcastPkts,
282 &entry->dwInErrors, &entry->dwInDiscards,
283 &skip, &skip, &skip,
284 &entry->dwInNUcastPkts, &entry->dwOutOctets,
285 &entry->dwOutUcastPkts, &entry->dwOutErrors,
286 &entry->dwOutDiscards );
287 break;
290 fclose(fp);
291 ret = NO_ERROR;
294 #elif defined(HAVE_LIBKSTAT)
296 kstat_ctl_t *kc;
297 kstat_t *ksp;
299 if ((kc = kstat_open()) &&
300 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
301 kstat_read( kc, ksp, NULL ) != -1 &&
302 ksp->ks_type == KSTAT_TYPE_NAMED)
304 entry->dwMtu = 1500; /* FIXME */
305 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
306 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
307 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
308 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
309 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
310 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
311 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
312 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
313 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
314 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
315 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
316 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
317 entry->dwOutDiscards = 0; /* FIXME */
318 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
319 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
320 ret = NO_ERROR;
322 if (kc) kstat_close( kc );
324 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
326 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
327 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
329 size_t needed;
330 char *buf = NULL, *end;
331 struct if_msghdr *ifm;
332 struct if_data ifdata;
334 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
336 ERR ("failed to get size of iflist\n");
337 goto done;
339 buf = HeapAlloc (GetProcessHeap (), 0, needed);
340 if (!buf)
342 ret = ERROR_OUTOFMEMORY;
343 goto done;
345 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
347 ERR ("failed to get iflist\n");
348 goto done;
350 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
352 ifm = (struct if_msghdr *) buf;
353 if(ifm->ifm_type == RTM_IFINFO)
355 ifdata = ifm->ifm_data;
356 entry->dwMtu = ifdata.ifi_mtu;
357 entry->dwSpeed = ifdata.ifi_baudrate;
358 entry->dwInOctets = ifdata.ifi_ibytes;
359 entry->dwInErrors = ifdata.ifi_ierrors;
360 entry->dwInDiscards = ifdata.ifi_iqdrops;
361 entry->dwInUcastPkts = ifdata.ifi_ipackets;
362 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
363 entry->dwOutOctets = ifdata.ifi_obytes;
364 entry->dwOutUcastPkts = ifdata.ifi_opackets;
365 entry->dwOutErrors = ifdata.ifi_oerrors;
366 ret = NO_ERROR;
367 break;
370 done:
371 HeapFree (GetProcessHeap (), 0, buf);
373 #else
374 FIXME( "unimplemented\n" );
375 #endif
376 return ret;
380 /******************************************************************
381 * GetIcmpStatistics (IPHLPAPI.@)
383 * Get the ICMP statistics for the local computer.
385 * PARAMS
386 * stats [Out] buffer for ICMP statistics
388 * RETURNS
389 * Success: NO_ERROR
390 * Failure: error code from winerror.h
392 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
394 DWORD ret = ERROR_NOT_SUPPORTED;
396 if (!stats) return ERROR_INVALID_PARAMETER;
397 memset( stats, 0, sizeof(MIB_ICMP) );
399 #ifdef __linux__
401 FILE *fp;
403 if ((fp = fopen("/proc/net/snmp", "r")))
405 static const char hdr[] = "Icmp:";
406 char buf[512], *ptr;
408 while ((ptr = fgets(buf, sizeof(buf), fp)))
410 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
411 /* last line was a header, get another */
412 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
413 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
415 ptr += sizeof(hdr);
416 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",
417 &stats->stats.icmpInStats.dwMsgs,
418 &stats->stats.icmpInStats.dwErrors,
419 &stats->stats.icmpInStats.dwDestUnreachs,
420 &stats->stats.icmpInStats.dwTimeExcds,
421 &stats->stats.icmpInStats.dwParmProbs,
422 &stats->stats.icmpInStats.dwSrcQuenchs,
423 &stats->stats.icmpInStats.dwRedirects,
424 &stats->stats.icmpInStats.dwEchoReps,
425 &stats->stats.icmpInStats.dwTimestamps,
426 &stats->stats.icmpInStats.dwTimestampReps,
427 &stats->stats.icmpInStats.dwAddrMasks,
428 &stats->stats.icmpInStats.dwAddrMaskReps,
429 &stats->stats.icmpOutStats.dwMsgs,
430 &stats->stats.icmpOutStats.dwErrors,
431 &stats->stats.icmpOutStats.dwDestUnreachs,
432 &stats->stats.icmpOutStats.dwTimeExcds,
433 &stats->stats.icmpOutStats.dwParmProbs,
434 &stats->stats.icmpOutStats.dwSrcQuenchs,
435 &stats->stats.icmpOutStats.dwRedirects,
436 &stats->stats.icmpOutStats.dwEchoReps,
437 &stats->stats.icmpOutStats.dwTimestamps,
438 &stats->stats.icmpOutStats.dwTimestampReps,
439 &stats->stats.icmpOutStats.dwAddrMasks,
440 &stats->stats.icmpOutStats.dwAddrMaskReps );
441 break;
444 fclose(fp);
445 ret = NO_ERROR;
448 #elif defined(HAVE_LIBKSTAT)
450 static char ip[] = "ip", icmp[] = "icmp";
451 kstat_ctl_t *kc;
452 kstat_t *ksp;
454 if ((kc = kstat_open()) &&
455 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
456 kstat_read( kc, ksp, NULL ) != -1 &&
457 ksp->ks_type == KSTAT_TYPE_NAMED)
459 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
460 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
461 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
462 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
463 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
464 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
465 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
466 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
467 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
468 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
469 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
470 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
471 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
472 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
473 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
474 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
475 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
476 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
477 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
478 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
479 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
480 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
481 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
482 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
483 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
484 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
485 ret = NO_ERROR;
487 if (kc) kstat_close( kc );
489 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
491 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
492 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
493 struct icmpstat icmp_stat;
494 size_t needed = sizeof(icmp_stat);
495 int i;
497 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
499 /*in stats */
500 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
501 for(i = 0; i <= ICMP_MAXTYPE; i++)
502 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
504 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
506 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
507 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
508 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
509 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
510 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
511 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
512 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
513 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
514 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
515 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
516 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
518 #ifdef HAVE_ICPS_OUTHIST
519 /* out stats */
520 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
521 for(i = 0; i <= ICMP_MAXTYPE; i++)
522 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
524 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
526 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
527 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
528 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
529 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
530 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
531 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
532 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
533 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
534 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
535 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
536 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
537 #endif /* ICPS_OUTHIST */
538 ret = NO_ERROR;
541 #else /* ICMPCTL_STATS */
542 FIXME( "unimplemented\n" );
543 #endif
544 return ret;
548 /******************************************************************
549 * GetIpStatistics (IPHLPAPI.@)
551 * Get the IP statistics for the local computer.
553 * PARAMS
554 * stats [Out] buffer for IP statistics
556 * RETURNS
557 * Success: NO_ERROR
558 * Failure: error code from winerror.h
560 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
562 DWORD ret = ERROR_NOT_SUPPORTED;
563 MIB_IPFORWARDTABLE *fwd_table;
565 if (!stats) return ERROR_INVALID_PARAMETER;
566 memset( stats, 0, sizeof(*stats) );
568 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
569 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
571 stats->dwNumRoutes = fwd_table->dwNumEntries;
572 HeapFree( GetProcessHeap(), 0, fwd_table );
575 #ifdef __linux__
577 FILE *fp;
579 if ((fp = fopen("/proc/net/snmp", "r")))
581 static const char hdr[] = "Ip:";
582 char buf[512], *ptr;
584 while ((ptr = fgets(buf, sizeof(buf), fp)))
586 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
587 /* last line was a header, get another */
588 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
589 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
591 ptr += sizeof(hdr);
592 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
593 &stats->dwForwarding,
594 &stats->dwDefaultTTL,
595 &stats->dwInReceives,
596 &stats->dwInHdrErrors,
597 &stats->dwInAddrErrors,
598 &stats->dwForwDatagrams,
599 &stats->dwInUnknownProtos,
600 &stats->dwInDiscards,
601 &stats->dwInDelivers,
602 &stats->dwOutRequests,
603 &stats->dwOutDiscards,
604 &stats->dwOutNoRoutes,
605 &stats->dwReasmTimeout,
606 &stats->dwReasmReqds,
607 &stats->dwReasmOks,
608 &stats->dwReasmFails,
609 &stats->dwFragOks,
610 &stats->dwFragFails,
611 &stats->dwFragCreates );
612 /* hmm, no routingDiscards */
613 break;
616 fclose(fp);
617 ret = NO_ERROR;
620 #elif defined(HAVE_LIBKSTAT)
622 static char ip[] = "ip";
623 kstat_ctl_t *kc;
624 kstat_t *ksp;
626 if ((kc = kstat_open()) &&
627 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
628 kstat_read( kc, ksp, NULL ) != -1 &&
629 ksp->ks_type == KSTAT_TYPE_NAMED)
631 stats->dwForwarding = kstat_get_ui32( ksp, "forwarding" );
632 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
633 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
634 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
635 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
636 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
637 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
638 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
639 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
640 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
641 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
642 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
643 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
644 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
645 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
646 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
647 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
648 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
649 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
650 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
651 ret = NO_ERROR;
653 if (kc) kstat_close( kc );
655 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
657 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
658 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
659 int ip_ttl, ip_forwarding;
660 struct ipstat ip_stat;
661 size_t needed;
663 needed = sizeof(ip_stat);
664 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
666 ERR ("failed to get ipstat\n");
667 return ERROR_NOT_SUPPORTED;
670 needed = sizeof(ip_ttl);
671 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
673 ERR ("failed to get ip Default TTL\n");
674 return ERROR_NOT_SUPPORTED;
677 needed = sizeof(ip_forwarding);
678 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
680 ERR ("failed to get ip forwarding\n");
681 return ERROR_NOT_SUPPORTED;
684 stats->dwForwarding = ip_forwarding;
685 stats->dwDefaultTTL = ip_ttl;
686 stats->dwInDelivers = ip_stat.ips_delivered;
687 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
688 stats->dwInAddrErrors = ip_stat.ips_cantforward;
689 stats->dwInReceives = ip_stat.ips_total;
690 stats->dwForwDatagrams = ip_stat.ips_forward;
691 stats->dwInUnknownProtos = ip_stat.ips_noproto;
692 stats->dwInDiscards = ip_stat.ips_fragdropped;
693 stats->dwOutDiscards = ip_stat.ips_odropped;
694 stats->dwReasmOks = ip_stat.ips_reassembled;
695 stats->dwFragOks = ip_stat.ips_fragmented;
696 stats->dwFragFails = ip_stat.ips_cantfrag;
697 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
698 stats->dwOutNoRoutes = ip_stat.ips_noroute;
699 stats->dwOutRequests = ip_stat.ips_localout;
700 stats->dwReasmReqds = ip_stat.ips_fragments;
701 ret = NO_ERROR;
703 #else
704 FIXME( "unimplemented\n" );
705 #endif
706 return ret;
710 /******************************************************************
711 * GetTcpStatistics (IPHLPAPI.@)
713 * Get the TCP statistics for the local computer.
715 * PARAMS
716 * stats [Out] buffer for TCP statistics
718 * RETURNS
719 * Success: NO_ERROR
720 * Failure: error code from winerror.h
722 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
724 DWORD ret = ERROR_NOT_SUPPORTED;
726 if (!stats) return ERROR_INVALID_PARAMETER;
727 memset( stats, 0, sizeof(*stats) );
729 #ifdef __linux__
731 FILE *fp;
733 if ((fp = fopen("/proc/net/snmp", "r")))
735 static const char hdr[] = "Tcp:";
736 MIB_TCPTABLE *tcp_table;
737 char buf[512], *ptr;
739 while ((ptr = fgets(buf, sizeof(buf), fp)))
741 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
742 /* last line was a header, get another */
743 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
744 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
746 ptr += sizeof(hdr);
747 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
748 &stats->dwRtoAlgorithm,
749 &stats->dwRtoMin,
750 &stats->dwRtoMax,
751 &stats->dwMaxConn,
752 &stats->dwActiveOpens,
753 &stats->dwPassiveOpens,
754 &stats->dwAttemptFails,
755 &stats->dwEstabResets,
756 &stats->dwCurrEstab,
757 &stats->dwInSegs,
758 &stats->dwOutSegs,
759 &stats->dwRetransSegs,
760 &stats->dwInErrs,
761 &stats->dwOutRsts );
762 break;
765 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
767 stats->dwNumConns = tcp_table->dwNumEntries;
768 HeapFree( GetProcessHeap(), 0, tcp_table );
770 fclose(fp);
771 ret = NO_ERROR;
774 #elif defined(HAVE_LIBKSTAT)
776 static char tcp[] = "tcp";
777 kstat_ctl_t *kc;
778 kstat_t *ksp;
780 if ((kc = kstat_open()) &&
781 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
782 kstat_read( kc, ksp, NULL ) != -1 &&
783 ksp->ks_type == KSTAT_TYPE_NAMED)
785 stats->dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
786 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
787 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
788 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
789 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
790 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
791 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
792 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
793 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
794 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
795 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
796 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
797 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
798 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
799 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
800 ret = NO_ERROR;
802 if (kc) kstat_close( kc );
804 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
806 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
807 #define TCPTV_MIN 2
808 #define TCPTV_REXMTMAX 128
809 #endif
810 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
811 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
812 #define hz 1000
813 struct tcpstat tcp_stat;
814 size_t needed = sizeof(tcp_stat);
816 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
818 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
819 stats->dwRtoMin = TCPTV_MIN;
820 stats->dwRtoMax = TCPTV_REXMTMAX;
821 stats->dwMaxConn = -1;
822 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
823 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
824 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
825 stats->dwEstabResets = tcp_stat.tcps_drops;
826 stats->dwCurrEstab = 0;
827 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
828 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
829 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
830 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
831 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
832 stats->dwNumConns = tcp_stat.tcps_connects;
833 ret = NO_ERROR;
835 else ERR ("failed to get tcpstat\n");
837 #else
838 FIXME( "unimplemented\n" );
839 #endif
840 return ret;
844 /******************************************************************
845 * GetUdpStatistics (IPHLPAPI.@)
847 * Get the UDP statistics for the local computer.
849 * PARAMS
850 * stats [Out] buffer for UDP statistics
852 * RETURNS
853 * Success: NO_ERROR
854 * Failure: error code from winerror.h
856 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
858 DWORD ret = ERROR_NOT_SUPPORTED;
860 if (!stats) return ERROR_INVALID_PARAMETER;
861 memset( stats, 0, sizeof(*stats) );
863 #ifdef __linux__
865 FILE *fp;
867 if ((fp = fopen("/proc/net/snmp", "r")))
869 static const char hdr[] = "Udp:";
870 char buf[512], *ptr;
872 while ((ptr = fgets(buf, sizeof(buf), fp)))
874 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
875 /* last line was a header, get another */
876 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
877 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
879 ptr += sizeof(hdr);
880 sscanf( ptr, "%u %u %u %u %u",
881 &stats->dwInDatagrams, &stats->dwNoPorts,
882 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
883 break;
886 fclose(fp);
887 ret = NO_ERROR;
890 #elif defined(HAVE_LIBKSTAT)
892 static char udp[] = "udp";
893 kstat_ctl_t *kc;
894 kstat_t *ksp;
895 MIB_UDPTABLE *udp_table;
897 if ((kc = kstat_open()) &&
898 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
899 kstat_read( kc, ksp, NULL ) != -1 &&
900 ksp->ks_type == KSTAT_TYPE_NAMED)
902 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
903 stats->dwNoPorts = 0; /* FIXME */
904 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
905 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
906 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
908 stats->dwNumAddrs = udp_table->dwNumEntries;
909 HeapFree( GetProcessHeap(), 0, udp_table );
911 ret = NO_ERROR;
913 if (kc) kstat_close( kc );
915 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
917 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
918 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
919 struct udpstat udp_stat;
920 MIB_UDPTABLE *udp_table;
921 size_t needed = sizeof(udp_stat);
923 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
925 stats->dwInDatagrams = udp_stat.udps_ipackets;
926 stats->dwOutDatagrams = udp_stat.udps_opackets;
927 stats->dwNoPorts = udp_stat.udps_noport;
928 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
929 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
931 stats->dwNumAddrs = udp_table->dwNumEntries;
932 HeapFree( GetProcessHeap(), 0, udp_table );
934 ret = NO_ERROR;
936 else ERR ("failed to get udpstat\n");
938 #else
939 FIXME( "unimplemented\n" );
940 #endif
941 return ret;
945 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
946 DWORD *count, const MIB_IPFORWARDROW *row )
948 if (table->dwNumEntries >= *count)
950 MIB_IPFORWARDTABLE *new_table;
951 DWORD new_count = table->dwNumEntries * 2;
953 if (!(new_table = HeapReAlloc( heap, flags, table,
954 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
956 HeapFree( heap, 0, table );
957 return NULL;
959 *count = new_count;
960 table = new_table;
962 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
963 return table;
966 static int compare_ipforward_rows(const void *a, const void *b)
968 const MIB_IPFORWARDROW *rowA = a;
969 const MIB_IPFORWARDROW *rowB = b;
970 int ret;
972 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
973 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
974 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
975 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
978 /******************************************************************
979 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
981 * Get the route table.
982 * Like GetIpForwardTable(), but allocate the returned table from heap.
984 * PARAMS
985 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
986 * allocated and returned.
987 * bOrder [In] whether to sort the table
988 * heap [In] heap from which the table is allocated
989 * flags [In] flags to HeapAlloc
991 * RETURNS
992 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
993 * on failure, NO_ERROR on success.
995 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
996 HANDLE heap, DWORD flags)
998 MIB_IPFORWARDTABLE *table;
999 MIB_IPFORWARDROW row;
1000 DWORD ret = NO_ERROR, count = 16;
1002 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1004 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1006 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1007 return ERROR_OUTOFMEMORY;
1009 table->dwNumEntries = 0;
1011 #ifdef __linux__
1013 FILE *fp;
1015 if ((fp = fopen("/proc/net/route", "r")))
1017 char buf[512], *ptr;
1018 DWORD flags;
1020 /* skip header line */
1021 ptr = fgets(buf, sizeof(buf), fp);
1022 while ((ptr = fgets(buf, sizeof(buf), fp)))
1024 memset( &row, 0, sizeof(row) );
1026 while (!isspace(*ptr)) ptr++;
1027 *ptr++ = 0;
1028 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1029 continue;
1031 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1032 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1033 flags = strtoul(ptr + 1, &ptr, 16);
1035 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
1036 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1037 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1039 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1040 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1041 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1042 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1043 /* FIXME: other protos might be appropriate, e.g. the default
1044 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1045 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1047 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1048 break;
1050 fclose(fp);
1052 else ret = ERROR_NOT_SUPPORTED;
1054 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1056 void *data;
1057 int fd, len, namelen;
1058 mib2_ipRouteEntry_t *entry;
1059 char name[64];
1061 if ((fd = open_streams_mib( NULL )) != -1)
1063 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1065 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1067 row.dwForwardDest = entry->ipRouteDest;
1068 row.dwForwardMask = entry->ipRouteMask;
1069 row.dwForwardPolicy = 0;
1070 row.dwForwardNextHop = entry->ipRouteNextHop;
1071 row.dwForwardType = entry->ipRouteType;
1072 row.dwForwardProto = entry->ipRouteProto;
1073 row.dwForwardAge = entry->ipRouteAge;
1074 row.dwForwardNextHopAS = 0;
1075 row.dwForwardMetric1 = entry->ipRouteMetric1;
1076 row.dwForwardMetric2 = entry->ipRouteMetric2;
1077 row.dwForwardMetric3 = entry->ipRouteMetric3;
1078 row.dwForwardMetric4 = entry->ipRouteMetric4;
1079 row.dwForwardMetric5 = entry->ipRouteMetric5;
1080 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1081 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1082 name[namelen] = 0;
1083 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1084 if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1086 HeapFree( GetProcessHeap(), 0, data );
1088 close( fd );
1090 else ret = ERROR_NOT_SUPPORTED;
1092 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1094 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1095 size_t needed;
1096 char *buf = NULL, *lim, *next, *addrPtr;
1097 struct rt_msghdr *rtm;
1099 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1101 ERR ("sysctl 1 failed!\n");
1102 ret = ERROR_NOT_SUPPORTED;
1103 goto done;
1106 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1107 if (!buf)
1109 ret = ERROR_OUTOFMEMORY;
1110 goto done;
1113 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1115 ret = ERROR_NOT_SUPPORTED;
1116 goto done;
1119 lim = buf + needed;
1120 for (next = buf; next < lim; next += rtm->rtm_msglen)
1122 int i;
1124 rtm = (struct rt_msghdr *)next;
1126 if (rtm->rtm_type != RTM_GET)
1128 WARN ("Got unexpected message type 0x%x!\n",
1129 rtm->rtm_type);
1130 continue;
1133 /* Ignore all entries except for gateway routes which aren't
1134 multicast */
1135 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1136 (rtm->rtm_flags & RTF_MULTICAST))
1137 continue;
1139 memset( &row, 0, sizeof(row) );
1140 row.dwForwardIfIndex = rtm->rtm_index;
1141 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1142 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1143 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1145 addrPtr = (char *)(rtm + 1);
1147 for (i = 1; i; i <<= 1)
1149 struct sockaddr *sa;
1150 DWORD addr;
1152 if (!(i & rtm->rtm_addrs))
1153 continue;
1155 sa = (struct sockaddr *)addrPtr;
1156 ADVANCE (addrPtr, sa);
1158 /* default routes are encoded by length-zero sockaddr */
1159 if (sa->sa_len == 0)
1160 addr = 0;
1161 else if (sa->sa_family != AF_INET)
1163 WARN ("Received unsupported sockaddr family 0x%x\n",
1164 sa->sa_family);
1165 addr = 0;
1167 else
1169 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1171 addr = sin->sin_addr.s_addr;
1174 switch (i)
1176 case RTA_DST: row.dwForwardDest = addr; break;
1177 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1178 case RTA_NETMASK: row.dwForwardMask = addr; break;
1179 default:
1180 WARN ("Unexpected address type 0x%x\n", i);
1184 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1185 break;
1187 done:
1188 HeapFree( GetProcessHeap (), 0, buf );
1190 #else
1191 FIXME( "not implemented\n" );
1192 ret = ERROR_NOT_SUPPORTED;
1193 #endif
1195 if (!table) return ERROR_OUTOFMEMORY;
1196 if (!ret)
1198 if (bOrder && table->dwNumEntries)
1199 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1200 *ppIpForwardTable = table;
1202 else HeapFree( heap, flags, table );
1203 TRACE( "returning ret %u table %p\n", ret, table );
1204 return ret;
1207 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1208 DWORD *count, const MIB_IPNETROW *row )
1210 if (table->dwNumEntries >= *count)
1212 MIB_IPNETTABLE *new_table;
1213 DWORD new_count = table->dwNumEntries * 2;
1215 if (!(new_table = HeapReAlloc( heap, flags, table,
1216 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1218 HeapFree( heap, 0, table );
1219 return NULL;
1221 *count = new_count;
1222 table = new_table;
1224 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1225 return table;
1228 static int compare_ipnet_rows(const void *a, const void *b)
1230 const MIB_IPNETROW *rowA = a;
1231 const MIB_IPNETROW *rowB = b;
1233 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1237 /******************************************************************
1238 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1240 * Get the IP-to-physical address mapping table.
1241 * Like GetIpNetTable(), but allocate the returned table from heap.
1243 * PARAMS
1244 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1245 * allocated and returned.
1246 * bOrder [In] whether to sort the table
1247 * heap [In] heap from which the table is allocated
1248 * flags [In] flags to HeapAlloc
1250 * RETURNS
1251 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1252 * on failure, NO_ERROR on success.
1254 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1255 HANDLE heap, DWORD flags)
1257 MIB_IPNETTABLE *table;
1258 MIB_IPNETROW row;
1259 DWORD ret = NO_ERROR, count = 16;
1261 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1263 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1265 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1266 return ERROR_OUTOFMEMORY;
1268 table->dwNumEntries = 0;
1270 #ifdef __linux__
1272 FILE *fp;
1274 if ((fp = fopen("/proc/net/arp", "r")))
1276 char buf[512], *ptr;
1277 DWORD flags;
1279 /* skip header line */
1280 ptr = fgets(buf, sizeof(buf), fp);
1281 while ((ptr = fgets(buf, sizeof(buf), fp)))
1283 memset( &row, 0, sizeof(row) );
1285 row.dwAddr = inet_addr(ptr);
1286 while (*ptr && !isspace(*ptr)) ptr++;
1287 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1288 flags = strtoul(ptr + 1, &ptr, 16);
1290 #ifdef ATF_COM
1291 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1292 else
1293 #endif
1294 #ifdef ATF_PERM
1295 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1296 else
1297 #endif
1298 row.dwType = MIB_IPNET_TYPE_OTHER;
1300 while (*ptr && isspace(*ptr)) ptr++;
1301 while (*ptr && !isspace(*ptr))
1303 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1304 if (*ptr) ptr++;
1306 while (*ptr && isspace(*ptr)) ptr++;
1307 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1308 while (*ptr && isspace(*ptr)) ptr++;
1309 getInterfaceIndexByName(ptr, &row.dwIndex);
1311 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1312 break;
1314 fclose(fp);
1316 else ret = ERROR_NOT_SUPPORTED;
1318 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1320 void *data;
1321 int fd, len, namelen;
1322 mib2_ipNetToMediaEntry_t *entry;
1323 char name[64];
1325 if ((fd = open_streams_mib( NULL )) != -1)
1327 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1329 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1331 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1332 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1333 row.dwAddr = entry->ipNetToMediaNetAddress;
1334 row.dwType = entry->ipNetToMediaType;
1335 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1336 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1337 name[namelen] = 0;
1338 getInterfaceIndexByName( name, &row.dwIndex );
1339 if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1341 HeapFree( GetProcessHeap(), 0, data );
1343 close( fd );
1345 else ret = ERROR_NOT_SUPPORTED;
1347 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1349 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1350 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1351 size_t needed;
1352 char *buf = NULL, *lim, *next;
1353 struct rt_msghdr *rtm;
1354 struct sockaddr_inarp *sinarp;
1355 struct sockaddr_dl *sdl;
1357 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1359 ERR ("failed to get arp table\n");
1360 ret = ERROR_NOT_SUPPORTED;
1361 goto done;
1364 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1365 if (!buf)
1367 ret = ERROR_OUTOFMEMORY;
1368 goto done;
1371 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1373 ret = ERROR_NOT_SUPPORTED;
1374 goto done;
1377 lim = buf + needed;
1378 next = buf;
1379 while(next < lim)
1381 rtm = (struct rt_msghdr *)next;
1382 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1383 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1384 if(sdl->sdl_alen) /* arp entry */
1386 memset( &row, 0, sizeof(row) );
1387 row.dwAddr = sinarp->sin_addr.s_addr;
1388 row.dwIndex = sdl->sdl_index;
1389 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1390 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1391 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1392 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1393 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1394 else row.dwType = MIB_IPNET_TYPE_INVALID;
1396 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1397 break;
1399 next += rtm->rtm_msglen;
1401 done:
1402 HeapFree( GetProcessHeap (), 0, buf );
1404 #else
1405 FIXME( "not implemented\n" );
1406 ret = ERROR_NOT_SUPPORTED;
1407 #endif
1409 if (!table) return ERROR_OUTOFMEMORY;
1410 if (!ret)
1412 if (bOrder && table->dwNumEntries)
1413 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1414 *ppIpNetTable = table;
1416 else HeapFree( heap, flags, table );
1417 TRACE( "returning ret %u table %p\n", ret, table );
1418 return ret;
1422 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1423 DWORD *count, const MIB_UDPROW *row )
1425 if (table->dwNumEntries >= *count)
1427 MIB_UDPTABLE *new_table;
1428 DWORD new_count = table->dwNumEntries * 2;
1430 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1432 HeapFree( heap, 0, table );
1433 return NULL;
1435 *count = new_count;
1436 table = new_table;
1438 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1439 return table;
1442 static int compare_udp_rows(const void *a, const void *b)
1444 const MIB_UDPROW *rowA = a;
1445 const MIB_UDPROW *rowB = b;
1446 int ret;
1448 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1449 return rowA->dwLocalPort - rowB->dwLocalPort;
1453 /******************************************************************
1454 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1456 * Get the UDP listener table.
1457 * Like GetUdpTable(), but allocate the returned table from heap.
1459 * PARAMS
1460 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1461 * allocated and returned.
1462 * bOrder [In] whether to sort the table
1463 * heap [In] heap from which the table is allocated
1464 * flags [In] flags to HeapAlloc
1466 * RETURNS
1467 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1468 * returns otherwise.
1470 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1471 HANDLE heap, DWORD flags)
1473 MIB_UDPTABLE *table;
1474 MIB_UDPROW row;
1475 DWORD ret = NO_ERROR, count = 16;
1477 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1479 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1481 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1482 return ERROR_OUTOFMEMORY;
1484 table->dwNumEntries = 0;
1486 #ifdef __linux__
1488 FILE *fp;
1490 if ((fp = fopen("/proc/net/udp", "r")))
1492 char buf[512], *ptr;
1493 DWORD dummy;
1495 /* skip header line */
1496 ptr = fgets(buf, sizeof(buf), fp);
1497 while ((ptr = fgets(buf, sizeof(buf), fp)))
1499 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1500 continue;
1501 row.dwLocalPort = htons( row.dwLocalPort );
1502 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1503 break;
1505 fclose(fp);
1507 else ret = ERROR_NOT_SUPPORTED;
1509 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1511 void *data;
1512 int fd, len;
1513 mib2_udpEntry_t *entry;
1515 if ((fd = open_streams_mib( "udp" )) != -1)
1517 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
1519 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1521 row.dwLocalAddr = entry->udpLocalAddress;
1522 row.dwLocalPort = htons( entry->udpLocalPort );
1523 if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1525 HeapFree( GetProcessHeap(), 0, data );
1527 close( fd );
1529 else ret = ERROR_NOT_SUPPORTED;
1531 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1533 size_t Len = 0;
1534 char *Buf = NULL;
1535 struct xinpgen *pXIG, *pOrigXIG;
1537 if (sysctlbyname ("net.inet.udp.pcblist", NULL, &Len, NULL, 0) < 0)
1539 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1540 ret = ERROR_NOT_SUPPORTED;
1541 goto done;
1544 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1545 if (!Buf)
1547 ret = ERROR_OUTOFMEMORY;
1548 goto done;
1551 if (sysctlbyname ("net.inet.udp.pcblist", Buf, &Len, NULL, 0) < 0)
1553 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1554 ret = ERROR_NOT_SUPPORTED;
1555 goto done;
1558 /* Might be nothing here; first entry is just a header it seems */
1559 if (Len <= sizeof (struct xinpgen)) goto done;
1561 pOrigXIG = (struct xinpgen *)Buf;
1562 pXIG = pOrigXIG;
1564 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1565 pXIG->xig_len > sizeof (struct xinpgen);
1566 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1568 struct inpcb *pINData;
1569 struct xsocket *pSockData;
1571 pINData = &((struct xinpcb *)pXIG)->xi_inp;
1572 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
1574 /* Ignore sockets for other protocols */
1575 if (pSockData->xso_protocol != IPPROTO_UDP)
1576 continue;
1578 /* Ignore PCBs that were freed while generating the data */
1579 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1580 continue;
1582 /* we're only interested in IPv4 addresses */
1583 if (!(pINData->inp_vflag & INP_IPV4) ||
1584 (pINData->inp_vflag & INP_IPV6))
1585 continue;
1587 /* If all 0's, skip it */
1588 if (!pINData->inp_laddr.s_addr &&
1589 !pINData->inp_lport)
1590 continue;
1592 /* Fill in structure details */
1593 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1594 row.dwLocalPort = pINData->inp_lport;
1595 if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1598 done:
1599 HeapFree (GetProcessHeap (), 0, Buf);
1601 #else
1602 FIXME( "not implemented\n" );
1603 ret = ERROR_NOT_SUPPORTED;
1604 #endif
1606 if (!table) return ERROR_OUTOFMEMORY;
1607 if (!ret)
1609 if (bOrder && table->dwNumEntries)
1610 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1611 *ppUdpTable = table;
1613 else HeapFree( heap, flags, table );
1614 TRACE( "returning ret %u table %p\n", ret, table );
1615 return ret;
1619 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1620 DWORD *count, const MIB_TCPROW *row )
1622 if (table->dwNumEntries >= *count)
1624 MIB_TCPTABLE *new_table;
1625 DWORD new_count = table->dwNumEntries * 2;
1627 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1629 HeapFree( heap, 0, table );
1630 return NULL;
1632 *count = new_count;
1633 table = new_table;
1635 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1636 return table;
1640 /* Why not a lookup table? Because the TCPS_* constants are different
1641 on different platforms */
1642 static inline DWORD TCPStateToMIBState (int state)
1644 switch (state)
1646 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1647 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1648 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1649 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1650 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1651 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1652 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1653 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1654 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1655 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1656 default:
1657 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1662 static int compare_tcp_rows(const void *a, const void *b)
1664 const MIB_TCPROW *rowA = a;
1665 const MIB_TCPROW *rowB = b;
1666 int ret;
1668 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1669 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1670 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1671 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1672 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1676 /******************************************************************
1677 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1679 * Get the TCP connection table.
1680 * Like GetTcpTable(), but allocate the returned table from heap.
1682 * PARAMS
1683 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1684 * allocated and returned.
1685 * bOrder [In] whether to sort the table
1686 * heap [In] heap from which the table is allocated
1687 * flags [In] flags to HeapAlloc
1689 * RETURNS
1690 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1691 * returns otherwise.
1693 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1694 HANDLE heap, DWORD flags)
1696 MIB_TCPTABLE *table;
1697 MIB_TCPROW row;
1698 DWORD ret = NO_ERROR, count = 16;
1700 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1702 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1704 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1705 return ERROR_OUTOFMEMORY;
1707 table->dwNumEntries = 0;
1709 #ifdef __linux__
1711 FILE *fp;
1713 if ((fp = fopen("/proc/net/tcp", "r")))
1715 char buf[512], *ptr;
1716 DWORD dummy;
1718 /* skip header line */
1719 ptr = fgets(buf, sizeof(buf), fp);
1720 while ((ptr = fgets(buf, sizeof(buf), fp)))
1722 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1723 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1724 continue;
1725 row.dwLocalPort = htons( row.dwLocalPort );
1726 row.dwRemotePort = htons( row.dwRemotePort );
1727 row.dwState = TCPStateToMIBState( row.dwState );
1728 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1729 break;
1731 fclose( fp );
1733 else ret = ERROR_NOT_SUPPORTED;
1735 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1737 void *data;
1738 int fd, len;
1739 mib2_tcpConnEntry_t *entry;
1741 if ((fd = open_streams_mib( "tcp" )) != -1)
1743 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
1745 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1747 row.dwLocalAddr = entry->tcpConnLocalAddress;
1748 row.dwLocalPort = htons( entry->tcpConnLocalPort );
1749 row.dwRemoteAddr = entry->tcpConnRemAddress;
1750 row.dwRemotePort = htons( entry->tcpConnRemPort );
1751 row.dwState = entry->tcpConnState;
1752 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1754 HeapFree( GetProcessHeap(), 0, data );
1756 close( fd );
1758 else ret = ERROR_NOT_SUPPORTED;
1760 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1762 size_t Len = 0;
1763 char *Buf = NULL;
1764 struct xinpgen *pXIG, *pOrigXIG;
1766 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1768 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1769 ret = ERROR_NOT_SUPPORTED;
1770 goto done;
1773 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1774 if (!Buf)
1776 ret = ERROR_OUTOFMEMORY;
1777 goto done;
1780 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1782 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1783 ret = ERROR_NOT_SUPPORTED;
1784 goto done;
1787 /* Might be nothing here; first entry is just a header it seems */
1788 if (Len <= sizeof (struct xinpgen)) goto done;
1790 pOrigXIG = (struct xinpgen *)Buf;
1791 pXIG = pOrigXIG;
1793 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1794 pXIG->xig_len > sizeof (struct xinpgen);
1795 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1797 struct tcpcb *pTCPData = NULL;
1798 struct inpcb *pINData;
1799 struct xsocket *pSockData;
1801 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1802 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1803 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1805 /* Ignore sockets for other protocols */
1806 if (pSockData->xso_protocol != IPPROTO_TCP)
1807 continue;
1809 /* Ignore PCBs that were freed while generating the data */
1810 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1811 continue;
1813 /* we're only interested in IPv4 addresses */
1814 if (!(pINData->inp_vflag & INP_IPV4) ||
1815 (pINData->inp_vflag & INP_IPV6))
1816 continue;
1818 /* If all 0's, skip it */
1819 if (!pINData->inp_laddr.s_addr &&
1820 !pINData->inp_lport &&
1821 !pINData->inp_faddr.s_addr &&
1822 !pINData->inp_fport)
1823 continue;
1825 /* Fill in structure details */
1826 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1827 row.dwLocalPort = pINData->inp_lport;
1828 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1829 row.dwRemotePort = pINData->inp_fport;
1830 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1831 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1834 done:
1835 HeapFree (GetProcessHeap (), 0, Buf);
1837 #else
1838 FIXME( "not implemented\n" );
1839 ret = ERROR_NOT_SUPPORTED;
1840 #endif
1842 if (!table) return ERROR_OUTOFMEMORY;
1843 if (!ret)
1845 if (bOrder && table->dwNumEntries)
1846 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1847 *ppTcpTable = table;
1849 else HeapFree( heap, flags, table );
1850 TRACE( "returning ret %u table %p\n", ret, table );
1851 return ret;