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
22 #include "wine/port.h"
29 #include <sys/types.h>
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
36 #ifdef HAVE_SYS_SOCKETVAR_H
37 #include <sys/socketvar.h>
39 #ifdef HAVE_SYS_TIMEOUT_H
40 #include <sys/timeout.h>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #ifdef HAVE_NETINET_IN_SYSTM_H
46 #include <netinet/in_systm.h>
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
54 #ifdef HAVE_NET_IF_DL_H
55 #include <net/if_dl.h>
57 #ifdef HAVE_NET_IF_TYPES_H
58 #include <net/if_types.h>
60 #ifdef HAVE_NET_ROUTE_H
61 #include <net/route.h>
63 #ifdef HAVE_NET_IF_ARP_H
64 #include <net/if_arp.h>
66 #ifdef HAVE_NETINET_IF_ETHER_H
67 #include <netinet/if_ether.h>
69 #ifdef HAVE_NETINET_IF_INARP_H
70 #include <netinet/if_inarp.h>
72 #ifdef HAVE_NETINET_IP_H
73 #include <netinet/ip.h>
75 #ifdef HAVE_NETINET_TCP_H
76 #include <netinet/tcp.h>
78 #ifdef HAVE_NETINET_IP_VAR_H
79 #include <netinet/ip_var.h>
81 #ifdef HAVE_NETINET_TCP_FSM_H
82 #include <netinet/tcp_fsm.h>
84 #ifdef HAVE_NETINET_IN_PCB_H
85 #include <netinet/in_pcb.h>
87 #ifdef HAVE_NETINET_TCP_TIMER_H
88 #include <netinet/tcp_timer.h>
90 #ifdef HAVE_NETINET_TCP_VAR_H
91 #include <netinet/tcp_var.h>
93 #ifdef HAVE_NETINET_IP_ICMP_H
94 #include <netinet/ip_icmp.h>
96 #ifdef HAVE_NETINET_ICMP_VAR_H
97 #include <netinet/icmp_var.h>
99 #ifdef HAVE_NETINET_UDP_H
100 #include <netinet/udp.h>
102 #ifdef HAVE_NETINET_UDP_VAR_H
103 #include <netinet/udp_var.h>
105 #ifdef HAVE_SYS_PROTOSW_H
106 #include <sys/protosw.h>
108 #ifdef HAVE_SYS_SYSCTL_H
109 #include <sys/sysctl.h>
114 #ifdef HAVE_INET_MIB2_H
115 #include <inet/mib2.h>
117 #ifdef HAVE_STROPTS_H
120 #ifdef HAVE_SYS_TIHDR_H
121 #include <sys/tihdr.h>
126 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
129 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
134 #include "iprtrmib.h"
138 #include "wine/debug.h"
140 #ifndef HAVE_NETINET_TCP_FSM_H
141 #define TCPS_ESTABLISHED 1
142 #define TCPS_SYN_SENT 2
143 #define TCPS_SYN_RECEIVED 3
144 #define TCPS_FIN_WAIT_1 4
145 #define TCPS_FIN_WAIT_2 5
146 #define TCPS_TIME_WAIT 6
147 #define TCPS_CLOSED 7
148 #define TCPS_CLOSE_WAIT 8
149 #define TCPS_LAST_ACK 9
150 #define TCPS_LISTEN 10
151 #define TCPS_CLOSING 11
154 #ifndef RTF_MULTICAST
155 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
159 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
162 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
165 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
168 kstat_named_t *data = ksp->ks_data;
170 for (i = 0; i < ksp->ks_ndata; i++)
171 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
175 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
178 kstat_named_t *data = ksp->ks_data;
180 for (i = 0; i < ksp->ks_ndata; i++)
181 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
186 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
187 static int open_streams_mib( const char *proto )
193 struct T_optmgmt_req req_header;
194 struct opthdr opt_header;
197 if ((fd = open( "/dev/arp", O_RDWR )) == -1)
199 WARN( "could not open /dev/arp: %s\n", strerror(errno) );
202 if (proto) ioctl( fd, I_PUSH, proto );
204 request.req_header.PRIM_type = T_SVR4_OPTMGMT_REQ;
205 request.req_header.OPT_length = sizeof(request.opt_header);
206 request.req_header.OPT_offset = FIELD_OFFSET( struct request, opt_header );
207 request.req_header.MGMT_flags = T_CURRENT;
208 request.opt_header.level = MIB2_IP;
209 request.opt_header.name = 0;
210 request.opt_header.len = 0;
212 buf.len = sizeof(request);
213 buf.buf = (caddr_t)&request;
214 if (putmsg( fd, &buf, NULL, 0 ) == -1)
216 WARN( "putmsg: %s\n", strerror(errno) );
223 static void *read_mib_entry( int fd, int level, int name, int *len )
231 struct T_optmgmt_ack ack_header;
232 struct opthdr opt_header;
237 buf.maxlen = sizeof(reply);
238 buf.buf = (caddr_t)&reply;
239 if ((ret = getmsg( fd, &buf, NULL, &flags )) < 0) return NULL;
240 if (!(ret & MOREDATA)) return NULL;
241 if (reply.ack_header.PRIM_type != T_OPTMGMT_ACK) return NULL;
242 if (buf.len < sizeof(reply.ack_header)) return NULL;
243 if (reply.ack_header.OPT_length < sizeof(reply.opt_header)) return NULL;
245 if (!(data = HeapAlloc( GetProcessHeap(), 0, reply.opt_header.len ))) return NULL;
246 buf.maxlen = reply.opt_header.len;
247 buf.buf = (caddr_t)data;
249 if (getmsg( fd, NULL, &buf, &flags ) >= 0 &&
250 reply.opt_header.level == level &&
251 reply.opt_header.name == name)
256 HeapFree( GetProcessHeap(), 0, data );
259 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
261 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
263 DWORD ret = ERROR_NOT_SUPPORTED;
265 if (!name || !entry) return ERROR_INVALID_PARAMETER;
271 if ((fp = fopen("/proc/net/dev", "r")))
275 int nameLen = strlen(name);
277 while ((ptr = fgets(buf, sizeof(buf), fp)))
279 while (*ptr && isspace(*ptr)) ptr++;
280 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
283 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
284 &entry->dwInOctets, &entry->dwInUcastPkts,
285 &entry->dwInErrors, &entry->dwInDiscards,
287 &entry->dwInNUcastPkts, &entry->dwOutOctets,
288 &entry->dwOutUcastPkts, &entry->dwOutErrors,
289 &entry->dwOutDiscards );
297 #elif defined(HAVE_LIBKSTAT)
302 if ((kc = kstat_open()) &&
303 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
304 kstat_read( kc, ksp, NULL ) != -1 &&
305 ksp->ks_type == KSTAT_TYPE_NAMED)
307 entry->dwMtu = 1500; /* FIXME */
308 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
309 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
310 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
311 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
312 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
313 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
314 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
315 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
316 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
317 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
318 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
319 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
320 entry->dwOutDiscards = 0; /* FIXME */
321 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
322 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
325 if (kc) kstat_close( kc );
327 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
329 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
330 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
333 char *buf = NULL, *end;
334 struct if_msghdr *ifm;
335 struct if_data ifdata;
337 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
339 ERR ("failed to get size of iflist\n");
342 buf = HeapAlloc (GetProcessHeap (), 0, needed);
345 ret = ERROR_OUTOFMEMORY;
348 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
350 ERR ("failed to get iflist\n");
353 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
355 ifm = (struct if_msghdr *) buf;
356 if(ifm->ifm_type == RTM_IFINFO)
358 ifdata = ifm->ifm_data;
359 entry->dwMtu = ifdata.ifi_mtu;
360 entry->dwSpeed = ifdata.ifi_baudrate;
361 entry->dwInOctets = ifdata.ifi_ibytes;
362 entry->dwInErrors = ifdata.ifi_ierrors;
363 entry->dwInDiscards = ifdata.ifi_iqdrops;
364 entry->dwInUcastPkts = ifdata.ifi_ipackets;
365 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
366 entry->dwOutOctets = ifdata.ifi_obytes;
367 entry->dwOutUcastPkts = ifdata.ifi_opackets;
368 entry->dwOutErrors = ifdata.ifi_oerrors;
374 HeapFree (GetProcessHeap (), 0, buf);
377 FIXME( "unimplemented\n" );
383 /******************************************************************
384 * GetIcmpStatistics (IPHLPAPI.@)
386 * Get the ICMP statistics for the local computer.
389 * stats [Out] buffer for ICMP statistics
393 * Failure: error code from winerror.h
395 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
397 DWORD ret = ERROR_NOT_SUPPORTED;
399 if (!stats) return ERROR_INVALID_PARAMETER;
400 memset( stats, 0, sizeof(MIB_ICMP) );
406 if ((fp = fopen("/proc/net/snmp", "r")))
408 static const char hdr[] = "Icmp:";
411 while ((ptr = fgets(buf, sizeof(buf), fp)))
413 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
414 /* last line was a header, get another */
415 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
416 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
419 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",
420 &stats->stats.icmpInStats.dwMsgs,
421 &stats->stats.icmpInStats.dwErrors,
422 &stats->stats.icmpInStats.dwDestUnreachs,
423 &stats->stats.icmpInStats.dwTimeExcds,
424 &stats->stats.icmpInStats.dwParmProbs,
425 &stats->stats.icmpInStats.dwSrcQuenchs,
426 &stats->stats.icmpInStats.dwRedirects,
427 &stats->stats.icmpInStats.dwEchoReps,
428 &stats->stats.icmpInStats.dwTimestamps,
429 &stats->stats.icmpInStats.dwTimestampReps,
430 &stats->stats.icmpInStats.dwAddrMasks,
431 &stats->stats.icmpInStats.dwAddrMaskReps,
432 &stats->stats.icmpOutStats.dwMsgs,
433 &stats->stats.icmpOutStats.dwErrors,
434 &stats->stats.icmpOutStats.dwDestUnreachs,
435 &stats->stats.icmpOutStats.dwTimeExcds,
436 &stats->stats.icmpOutStats.dwParmProbs,
437 &stats->stats.icmpOutStats.dwSrcQuenchs,
438 &stats->stats.icmpOutStats.dwRedirects,
439 &stats->stats.icmpOutStats.dwEchoReps,
440 &stats->stats.icmpOutStats.dwTimestamps,
441 &stats->stats.icmpOutStats.dwTimestampReps,
442 &stats->stats.icmpOutStats.dwAddrMasks,
443 &stats->stats.icmpOutStats.dwAddrMaskReps );
451 #elif defined(HAVE_LIBKSTAT)
453 static char ip[] = "ip", icmp[] = "icmp";
457 if ((kc = kstat_open()) &&
458 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
459 kstat_read( kc, ksp, NULL ) != -1 &&
460 ksp->ks_type == KSTAT_TYPE_NAMED)
462 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
463 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
464 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
465 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
466 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
467 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
468 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
469 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
470 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
471 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
472 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
473 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
474 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
475 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
476 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
477 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
478 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
479 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
480 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
481 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
482 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
483 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
484 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
485 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
486 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
487 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
490 if (kc) kstat_close( kc );
492 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
494 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
495 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
496 struct icmpstat icmp_stat;
497 size_t needed = sizeof(icmp_stat);
500 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
503 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
504 for(i = 0; i <= ICMP_MAXTYPE; i++)
505 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
507 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
509 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
510 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
511 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
512 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
513 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
514 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
515 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
516 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
517 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
518 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
519 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
521 #ifdef HAVE_ICPS_OUTHIST
523 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
524 for(i = 0; i <= ICMP_MAXTYPE; i++)
525 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
527 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
529 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
530 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
531 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
532 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
533 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
534 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
535 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
536 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
537 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
538 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
539 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
540 #endif /* ICPS_OUTHIST */
544 #else /* ICMPCTL_STATS */
545 FIXME( "unimplemented\n" );
551 /******************************************************************
552 * GetIpStatistics (IPHLPAPI.@)
554 * Get the IP statistics for the local computer.
557 * stats [Out] buffer for IP statistics
561 * Failure: error code from winerror.h
563 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
565 DWORD ret = ERROR_NOT_SUPPORTED;
566 MIB_IPFORWARDTABLE *fwd_table;
568 if (!stats) return ERROR_INVALID_PARAMETER;
569 memset( stats, 0, sizeof(*stats) );
571 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
572 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
574 stats->dwNumRoutes = fwd_table->dwNumEntries;
575 HeapFree( GetProcessHeap(), 0, fwd_table );
582 if ((fp = fopen("/proc/net/snmp", "r")))
584 static const char hdr[] = "Ip:";
587 while ((ptr = fgets(buf, sizeof(buf), fp)))
589 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
590 /* last line was a header, get another */
591 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
592 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
595 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
596 &stats->dwForwarding,
597 &stats->dwDefaultTTL,
598 &stats->dwInReceives,
599 &stats->dwInHdrErrors,
600 &stats->dwInAddrErrors,
601 &stats->dwForwDatagrams,
602 &stats->dwInUnknownProtos,
603 &stats->dwInDiscards,
604 &stats->dwInDelivers,
605 &stats->dwOutRequests,
606 &stats->dwOutDiscards,
607 &stats->dwOutNoRoutes,
608 &stats->dwReasmTimeout,
609 &stats->dwReasmReqds,
611 &stats->dwReasmFails,
614 &stats->dwFragCreates );
615 /* hmm, no routingDiscards */
623 #elif defined(HAVE_LIBKSTAT)
625 static char ip[] = "ip";
629 if ((kc = kstat_open()) &&
630 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
631 kstat_read( kc, ksp, NULL ) != -1 &&
632 ksp->ks_type == KSTAT_TYPE_NAMED)
634 stats->dwForwarding = kstat_get_ui32( ksp, "forwarding" );
635 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
636 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
637 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
638 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
639 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
640 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
641 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
642 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
643 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
644 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
645 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
646 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
647 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
648 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
649 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
650 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
651 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
652 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
653 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
656 if (kc) kstat_close( kc );
658 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
660 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
661 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
662 int ip_ttl, ip_forwarding;
663 struct ipstat ip_stat;
666 needed = sizeof(ip_stat);
667 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
669 ERR ("failed to get ipstat\n");
670 return ERROR_NOT_SUPPORTED;
673 needed = sizeof(ip_ttl);
674 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
676 ERR ("failed to get ip Default TTL\n");
677 return ERROR_NOT_SUPPORTED;
680 needed = sizeof(ip_forwarding);
681 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
683 ERR ("failed to get ip forwarding\n");
684 return ERROR_NOT_SUPPORTED;
687 stats->dwForwarding = ip_forwarding;
688 stats->dwDefaultTTL = ip_ttl;
689 stats->dwInDelivers = ip_stat.ips_delivered;
690 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
691 stats->dwInAddrErrors = ip_stat.ips_cantforward;
692 stats->dwInReceives = ip_stat.ips_total;
693 stats->dwForwDatagrams = ip_stat.ips_forward;
694 stats->dwInUnknownProtos = ip_stat.ips_noproto;
695 stats->dwInDiscards = ip_stat.ips_fragdropped;
696 stats->dwOutDiscards = ip_stat.ips_odropped;
697 stats->dwReasmOks = ip_stat.ips_reassembled;
698 stats->dwFragOks = ip_stat.ips_fragmented;
699 stats->dwFragFails = ip_stat.ips_cantfrag;
700 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
701 stats->dwOutNoRoutes = ip_stat.ips_noroute;
702 stats->dwOutRequests = ip_stat.ips_localout;
703 stats->dwReasmReqds = ip_stat.ips_fragments;
707 FIXME( "unimplemented\n" );
713 /******************************************************************
714 * GetTcpStatistics (IPHLPAPI.@)
716 * Get the TCP statistics for the local computer.
719 * stats [Out] buffer for TCP statistics
723 * Failure: error code from winerror.h
725 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
727 DWORD ret = ERROR_NOT_SUPPORTED;
729 if (!stats) return ERROR_INVALID_PARAMETER;
730 memset( stats, 0, sizeof(*stats) );
736 if ((fp = fopen("/proc/net/snmp", "r")))
738 static const char hdr[] = "Tcp:";
739 MIB_TCPTABLE *tcp_table;
742 while ((ptr = fgets(buf, sizeof(buf), fp)))
744 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
745 /* last line was a header, get another */
746 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
747 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
750 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
751 &stats->dwRtoAlgorithm,
755 &stats->dwActiveOpens,
756 &stats->dwPassiveOpens,
757 &stats->dwAttemptFails,
758 &stats->dwEstabResets,
762 &stats->dwRetransSegs,
768 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
770 stats->dwNumConns = tcp_table->dwNumEntries;
771 HeapFree( GetProcessHeap(), 0, tcp_table );
777 #elif defined(HAVE_LIBKSTAT)
779 static char tcp[] = "tcp";
783 if ((kc = kstat_open()) &&
784 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
785 kstat_read( kc, ksp, NULL ) != -1 &&
786 ksp->ks_type == KSTAT_TYPE_NAMED)
788 stats->dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
789 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
790 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
791 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
792 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
793 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
794 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
795 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
796 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
797 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
798 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
799 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
800 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
801 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
802 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
805 if (kc) kstat_close( kc );
807 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
809 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
811 #define TCPTV_REXMTMAX 128
813 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
814 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
816 struct tcpstat tcp_stat;
817 size_t needed = sizeof(tcp_stat);
819 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
821 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
822 stats->dwRtoMin = TCPTV_MIN;
823 stats->dwRtoMax = TCPTV_REXMTMAX;
824 stats->dwMaxConn = -1;
825 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
826 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
827 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
828 stats->dwEstabResets = tcp_stat.tcps_drops;
829 stats->dwCurrEstab = 0;
830 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
831 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
832 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
833 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
834 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
835 stats->dwNumConns = tcp_stat.tcps_connects;
838 else ERR ("failed to get tcpstat\n");
841 FIXME( "unimplemented\n" );
847 /******************************************************************
848 * GetUdpStatistics (IPHLPAPI.@)
850 * Get the UDP statistics for the local computer.
853 * stats [Out] buffer for UDP statistics
857 * Failure: error code from winerror.h
859 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
861 DWORD ret = ERROR_NOT_SUPPORTED;
863 if (!stats) return ERROR_INVALID_PARAMETER;
864 memset( stats, 0, sizeof(*stats) );
870 if ((fp = fopen("/proc/net/snmp", "r")))
872 static const char hdr[] = "Udp:";
875 while ((ptr = fgets(buf, sizeof(buf), fp)))
877 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
878 /* last line was a header, get another */
879 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
880 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
883 sscanf( ptr, "%u %u %u %u %u",
884 &stats->dwInDatagrams, &stats->dwNoPorts,
885 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
893 #elif defined(HAVE_LIBKSTAT)
895 static char udp[] = "udp";
898 MIB_UDPTABLE *udp_table;
900 if ((kc = kstat_open()) &&
901 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
902 kstat_read( kc, ksp, NULL ) != -1 &&
903 ksp->ks_type == KSTAT_TYPE_NAMED)
905 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
906 stats->dwNoPorts = 0; /* FIXME */
907 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
908 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
909 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
911 stats->dwNumAddrs = udp_table->dwNumEntries;
912 HeapFree( GetProcessHeap(), 0, udp_table );
916 if (kc) kstat_close( kc );
918 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
920 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
921 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
922 struct udpstat udp_stat;
923 MIB_UDPTABLE *udp_table;
924 size_t needed = sizeof(udp_stat);
926 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
928 stats->dwInDatagrams = udp_stat.udps_ipackets;
929 stats->dwOutDatagrams = udp_stat.udps_opackets;
930 stats->dwNoPorts = udp_stat.udps_noport;
931 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
932 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
934 stats->dwNumAddrs = udp_table->dwNumEntries;
935 HeapFree( GetProcessHeap(), 0, udp_table );
939 else ERR ("failed to get udpstat\n");
942 FIXME( "unimplemented\n" );
948 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
949 DWORD *count, const MIB_IPFORWARDROW *row )
951 if (table->dwNumEntries >= *count)
953 MIB_IPFORWARDTABLE *new_table;
954 DWORD new_count = table->dwNumEntries * 2;
956 if (!(new_table = HeapReAlloc( heap, flags, table,
957 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
959 HeapFree( heap, 0, table );
965 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
969 static int compare_ipforward_rows(const void *a, const void *b)
971 const MIB_IPFORWARDROW *rowA = a;
972 const MIB_IPFORWARDROW *rowB = b;
975 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
976 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
977 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
978 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
981 /******************************************************************
982 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
984 * Get the route table.
985 * Like GetIpForwardTable(), but allocate the returned table from heap.
988 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
989 * allocated and returned.
990 * bOrder [In] whether to sort the table
991 * heap [In] heap from which the table is allocated
992 * flags [In] flags to HeapAlloc
995 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
996 * on failure, NO_ERROR on success.
998 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
999 HANDLE heap, DWORD flags)
1001 MIB_IPFORWARDTABLE *table;
1002 MIB_IPFORWARDROW row;
1003 DWORD ret = NO_ERROR, count = 16;
1005 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
1007 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
1009 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
1010 return ERROR_OUTOFMEMORY;
1012 table->dwNumEntries = 0;
1018 if ((fp = fopen("/proc/net/route", "r")))
1020 char buf[512], *ptr;
1023 /* skip header line */
1024 ptr = fgets(buf, sizeof(buf), fp);
1025 while ((ptr = fgets(buf, sizeof(buf), fp)))
1027 memset( &row, 0, sizeof(row) );
1029 while (!isspace(*ptr)) ptr++;
1031 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
1034 row.dwForwardDest = strtoul(ptr, &ptr, 16);
1035 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
1036 flags = strtoul(ptr + 1, &ptr, 16);
1038 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
1039 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1040 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1042 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
1043 strtoul(ptr + 1, &ptr, 16); /* use, skip */
1044 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
1045 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
1046 /* FIXME: other protos might be appropriate, e.g. the default
1047 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1048 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1050 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1055 else ret = ERROR_NOT_SUPPORTED;
1057 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1060 int fd, len, namelen;
1061 mib2_ipRouteEntry_t *entry;
1064 if ((fd = open_streams_mib( NULL )) != -1)
1066 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_ROUTE, &len )))
1068 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1070 row.dwForwardDest = entry->ipRouteDest;
1071 row.dwForwardMask = entry->ipRouteMask;
1072 row.dwForwardPolicy = 0;
1073 row.dwForwardNextHop = entry->ipRouteNextHop;
1074 row.dwForwardType = entry->ipRouteType;
1075 row.dwForwardProto = entry->ipRouteProto;
1076 row.dwForwardAge = entry->ipRouteAge;
1077 row.dwForwardNextHopAS = 0;
1078 row.dwForwardMetric1 = entry->ipRouteMetric1;
1079 row.dwForwardMetric2 = entry->ipRouteMetric2;
1080 row.dwForwardMetric3 = entry->ipRouteMetric3;
1081 row.dwForwardMetric4 = entry->ipRouteMetric4;
1082 row.dwForwardMetric5 = entry->ipRouteMetric5;
1083 namelen = min( sizeof(name) - 1, entry->ipRouteIfIndex.o_length );
1084 memcpy( name, entry->ipRouteIfIndex.o_bytes, namelen );
1086 getInterfaceIndexByName( name, &row.dwForwardIfIndex );
1087 if (!(table = append_ipforward_row( heap, flags, table, &count, &row ))) break;
1089 HeapFree( GetProcessHeap(), 0, data );
1093 else ret = ERROR_NOT_SUPPORTED;
1095 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1097 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1099 char *buf = NULL, *lim, *next, *addrPtr;
1100 struct rt_msghdr *rtm;
1102 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1104 ERR ("sysctl 1 failed!\n");
1105 ret = ERROR_NOT_SUPPORTED;
1109 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1112 ret = ERROR_OUTOFMEMORY;
1116 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1118 ret = ERROR_NOT_SUPPORTED;
1123 for (next = buf; next < lim; next += rtm->rtm_msglen)
1127 rtm = (struct rt_msghdr *)next;
1129 if (rtm->rtm_type != RTM_GET)
1131 WARN ("Got unexpected message type 0x%x!\n",
1136 /* Ignore all entries except for gateway routes which aren't
1138 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1139 (rtm->rtm_flags & RTF_MULTICAST))
1142 memset( &row, 0, sizeof(row) );
1143 row.dwForwardIfIndex = rtm->rtm_index;
1144 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1145 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1146 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1148 addrPtr = (char *)(rtm + 1);
1150 for (i = 1; i; i <<= 1)
1152 struct sockaddr *sa;
1155 if (!(i & rtm->rtm_addrs))
1158 sa = (struct sockaddr *)addrPtr;
1159 ADVANCE (addrPtr, sa);
1161 /* default routes are encoded by length-zero sockaddr */
1162 if (sa->sa_len == 0)
1164 else if (sa->sa_family != AF_INET)
1166 WARN ("Received unsupported sockaddr family 0x%x\n",
1172 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1174 addr = sin->sin_addr.s_addr;
1179 case RTA_DST: row.dwForwardDest = addr; break;
1180 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1181 case RTA_NETMASK: row.dwForwardMask = addr; break;
1183 WARN ("Unexpected address type 0x%x\n", i);
1187 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1191 HeapFree( GetProcessHeap (), 0, buf );
1194 FIXME( "not implemented\n" );
1195 ret = ERROR_NOT_SUPPORTED;
1198 if (!table) return ERROR_OUTOFMEMORY;
1201 if (bOrder && table->dwNumEntries)
1202 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1203 *ppIpForwardTable = table;
1205 else HeapFree( heap, flags, table );
1206 TRACE( "returning ret %u table %p\n", ret, table );
1210 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1211 DWORD *count, const MIB_IPNETROW *row )
1213 if (table->dwNumEntries >= *count)
1215 MIB_IPNETTABLE *new_table;
1216 DWORD new_count = table->dwNumEntries * 2;
1218 if (!(new_table = HeapReAlloc( heap, flags, table,
1219 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1221 HeapFree( heap, 0, table );
1227 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1231 static int compare_ipnet_rows(const void *a, const void *b)
1233 const MIB_IPNETROW *rowA = a;
1234 const MIB_IPNETROW *rowB = b;
1236 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1240 /******************************************************************
1241 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1243 * Get the IP-to-physical address mapping table.
1244 * Like GetIpNetTable(), but allocate the returned table from heap.
1247 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1248 * allocated and returned.
1249 * bOrder [In] whether to sort the table
1250 * heap [In] heap from which the table is allocated
1251 * flags [In] flags to HeapAlloc
1254 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1255 * on failure, NO_ERROR on success.
1257 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1258 HANDLE heap, DWORD flags)
1260 MIB_IPNETTABLE *table;
1262 DWORD ret = NO_ERROR, count = 16;
1264 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1266 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1268 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1269 return ERROR_OUTOFMEMORY;
1271 table->dwNumEntries = 0;
1277 if ((fp = fopen("/proc/net/arp", "r")))
1279 char buf[512], *ptr;
1282 /* skip header line */
1283 ptr = fgets(buf, sizeof(buf), fp);
1284 while ((ptr = fgets(buf, sizeof(buf), fp)))
1286 memset( &row, 0, sizeof(row) );
1288 row.dwAddr = inet_addr(ptr);
1289 while (*ptr && !isspace(*ptr)) ptr++;
1290 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1291 flags = strtoul(ptr + 1, &ptr, 16);
1294 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1298 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1301 row.dwType = MIB_IPNET_TYPE_OTHER;
1303 while (*ptr && isspace(*ptr)) ptr++;
1304 while (*ptr && !isspace(*ptr))
1306 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1309 while (*ptr && isspace(*ptr)) ptr++;
1310 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1311 while (*ptr && isspace(*ptr)) ptr++;
1312 getInterfaceIndexByName(ptr, &row.dwIndex);
1314 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1319 else ret = ERROR_NOT_SUPPORTED;
1321 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1324 int fd, len, namelen;
1325 mib2_ipNetToMediaEntry_t *entry;
1328 if ((fd = open_streams_mib( NULL )) != -1)
1330 if ((data = read_mib_entry( fd, MIB2_IP, MIB2_IP_MEDIA, &len )))
1332 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1334 row.dwPhysAddrLen = min( entry->ipNetToMediaPhysAddress.o_length, MAXLEN_PHYSADDR );
1335 memcpy( row.bPhysAddr, entry->ipNetToMediaPhysAddress.o_bytes, row.dwPhysAddrLen );
1336 row.dwAddr = entry->ipNetToMediaNetAddress;
1337 row.dwType = entry->ipNetToMediaType;
1338 namelen = min( sizeof(name) - 1, entry->ipNetToMediaIfIndex.o_length );
1339 memcpy( name, entry->ipNetToMediaIfIndex.o_bytes, namelen );
1341 getInterfaceIndexByName( name, &row.dwIndex );
1342 if (!(table = append_ipnet_row( heap, flags, table, &count, &row ))) break;
1344 HeapFree( GetProcessHeap(), 0, data );
1348 else ret = ERROR_NOT_SUPPORTED;
1350 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1352 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1353 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1355 char *buf = NULL, *lim, *next;
1356 struct rt_msghdr *rtm;
1357 struct sockaddr_inarp *sinarp;
1358 struct sockaddr_dl *sdl;
1360 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1362 ERR ("failed to get arp table\n");
1363 ret = ERROR_NOT_SUPPORTED;
1367 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1370 ret = ERROR_OUTOFMEMORY;
1374 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1376 ret = ERROR_NOT_SUPPORTED;
1384 rtm = (struct rt_msghdr *)next;
1385 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1386 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1387 if(sdl->sdl_alen) /* arp entry */
1389 memset( &row, 0, sizeof(row) );
1390 row.dwAddr = sinarp->sin_addr.s_addr;
1391 row.dwIndex = sdl->sdl_index;
1392 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1393 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1394 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1395 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1396 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1397 else row.dwType = MIB_IPNET_TYPE_INVALID;
1399 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1402 next += rtm->rtm_msglen;
1405 HeapFree( GetProcessHeap (), 0, buf );
1408 FIXME( "not implemented\n" );
1409 ret = ERROR_NOT_SUPPORTED;
1412 if (!table) return ERROR_OUTOFMEMORY;
1415 if (bOrder && table->dwNumEntries)
1416 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1417 *ppIpNetTable = table;
1419 else HeapFree( heap, flags, table );
1420 TRACE( "returning ret %u table %p\n", ret, table );
1425 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1426 DWORD *count, const MIB_UDPROW *row )
1428 if (table->dwNumEntries >= *count)
1430 MIB_UDPTABLE *new_table;
1431 DWORD new_count = table->dwNumEntries * 2;
1433 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1435 HeapFree( heap, 0, table );
1441 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1445 static int compare_udp_rows(const void *a, const void *b)
1447 const MIB_UDPROW *rowA = a;
1448 const MIB_UDPROW *rowB = b;
1451 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1452 return rowA->dwLocalPort - rowB->dwLocalPort;
1456 /******************************************************************
1457 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1459 * Get the UDP listener table.
1460 * Like GetUdpTable(), but allocate the returned table from heap.
1463 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1464 * allocated and returned.
1465 * bOrder [In] whether to sort the table
1466 * heap [In] heap from which the table is allocated
1467 * flags [In] flags to HeapAlloc
1470 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1471 * returns otherwise.
1473 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1474 HANDLE heap, DWORD flags)
1476 MIB_UDPTABLE *table;
1478 DWORD ret = NO_ERROR, count = 16;
1480 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1482 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1484 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1485 return ERROR_OUTOFMEMORY;
1487 table->dwNumEntries = 0;
1493 if ((fp = fopen("/proc/net/udp", "r")))
1495 char buf[512], *ptr;
1498 /* skip header line */
1499 ptr = fgets(buf, sizeof(buf), fp);
1500 while ((ptr = fgets(buf, sizeof(buf), fp)))
1502 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1504 row.dwLocalPort = htons( row.dwLocalPort );
1505 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1510 else ret = ERROR_NOT_SUPPORTED;
1512 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1516 mib2_udpEntry_t *entry;
1518 if ((fd = open_streams_mib( "udp" )) != -1)
1520 if ((data = read_mib_entry( fd, MIB2_UDP, MIB2_UDP_ENTRY, &len )))
1522 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1524 row.dwLocalAddr = entry->udpLocalAddress;
1525 row.dwLocalPort = htons( entry->udpLocalPort );
1526 if (!(table = append_udp_row( heap, flags, table, &count, &row ))) break;
1528 HeapFree( GetProcessHeap(), 0, data );
1532 else ret = ERROR_NOT_SUPPORTED;
1535 FIXME( "not implemented\n" );
1536 ret = ERROR_NOT_SUPPORTED;
1539 if (!table) return ERROR_OUTOFMEMORY;
1542 if (bOrder && table->dwNumEntries)
1543 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1544 *ppUdpTable = table;
1546 else HeapFree( heap, flags, table );
1547 TRACE( "returning ret %u table %p\n", ret, table );
1552 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1553 DWORD *count, const MIB_TCPROW *row )
1555 if (table->dwNumEntries >= *count)
1557 MIB_TCPTABLE *new_table;
1558 DWORD new_count = table->dwNumEntries * 2;
1560 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1562 HeapFree( heap, 0, table );
1568 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1573 /* Why not a lookup table? Because the TCPS_* constants are different
1574 on different platforms */
1575 static inline DWORD TCPStateToMIBState (int state)
1579 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1580 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1581 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1582 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1583 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1584 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1585 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1586 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1587 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1588 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1590 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1595 static int compare_tcp_rows(const void *a, const void *b)
1597 const MIB_TCPROW *rowA = a;
1598 const MIB_TCPROW *rowB = b;
1601 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1602 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1603 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1604 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1605 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1609 /******************************************************************
1610 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1612 * Get the TCP connection table.
1613 * Like GetTcpTable(), but allocate the returned table from heap.
1616 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1617 * allocated and returned.
1618 * bOrder [In] whether to sort the table
1619 * heap [In] heap from which the table is allocated
1620 * flags [In] flags to HeapAlloc
1623 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1624 * returns otherwise.
1626 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1627 HANDLE heap, DWORD flags)
1629 MIB_TCPTABLE *table;
1631 DWORD ret = NO_ERROR, count = 16;
1633 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1635 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1637 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1638 return ERROR_OUTOFMEMORY;
1640 table->dwNumEntries = 0;
1646 if ((fp = fopen("/proc/net/tcp", "r")))
1648 char buf[512], *ptr;
1651 /* skip header line */
1652 ptr = fgets(buf, sizeof(buf), fp);
1653 while ((ptr = fgets(buf, sizeof(buf), fp)))
1655 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1656 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1658 row.dwLocalPort = htons( row.dwLocalPort );
1659 row.dwRemotePort = htons( row.dwRemotePort );
1660 row.dwState = TCPStateToMIBState( row.dwState );
1661 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1666 else ret = ERROR_NOT_SUPPORTED;
1668 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1672 mib2_tcpConnEntry_t *entry;
1674 if ((fd = open_streams_mib( "tcp" )) != -1)
1676 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
1678 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1680 row.dwLocalAddr = entry->tcpConnLocalAddress;
1681 row.dwLocalPort = htons( entry->tcpConnLocalPort );
1682 row.dwRemoteAddr = entry->tcpConnRemAddress;
1683 row.dwRemotePort = htons( entry->tcpConnRemPort );
1684 row.dwState = entry->tcpConnState;
1685 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1687 HeapFree( GetProcessHeap(), 0, data );
1691 else ret = ERROR_NOT_SUPPORTED;
1693 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1697 struct xinpgen *pXIG, *pOrigXIG;
1699 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1701 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1702 ret = ERROR_NOT_SUPPORTED;
1706 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1709 ret = ERROR_OUTOFMEMORY;
1713 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1715 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1716 ret = ERROR_NOT_SUPPORTED;
1720 /* Might be nothing here; first entry is just a header it seems */
1721 if (Len <= sizeof (struct xinpgen)) goto done;
1723 pOrigXIG = (struct xinpgen *)Buf;
1726 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1727 pXIG->xig_len > sizeof (struct xinpgen);
1728 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1730 struct tcpcb *pTCPData = NULL;
1731 struct inpcb *pINData;
1732 struct xsocket *pSockData;
1734 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1735 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1736 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1738 /* Ignore sockets for other protocols */
1739 if (pSockData->xso_protocol != IPPROTO_TCP)
1742 /* Ignore PCBs that were freed while generating the data */
1743 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1746 /* we're only interested in IPv4 addresses */
1747 if (!(pINData->inp_vflag & INP_IPV4) ||
1748 (pINData->inp_vflag & INP_IPV6))
1751 /* If all 0's, skip it */
1752 if (!pINData->inp_laddr.s_addr &&
1753 !pINData->inp_lport &&
1754 !pINData->inp_faddr.s_addr &&
1755 !pINData->inp_fport)
1758 /* Fill in structure details */
1759 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1760 row.dwLocalPort = pINData->inp_lport;
1761 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1762 row.dwRemotePort = pINData->inp_fport;
1763 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1764 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1768 HeapFree (GetProcessHeap (), 0, Buf);
1771 FIXME( "not implemented\n" );
1772 ret = ERROR_NOT_SUPPORTED;
1775 if (!table) return ERROR_OUTOFMEMORY;
1778 if (bOrder && table->dwNumEntries)
1779 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1780 *ppTcpTable = table;
1782 else HeapFree( heap, flags, table );
1783 TRACE( "returning ret %u table %p\n", ret, table );