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 && ifm->ifm_data.ifi_type == IFT_ETHER)
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_SYSCTL_H) && defined(NET_RT_DUMP)
1059 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1061 char *buf = NULL, *lim, *next, *addrPtr;
1062 struct rt_msghdr *rtm;
1064 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1066 ERR ("sysctl 1 failed!\n");
1067 ret = ERROR_NOT_SUPPORTED;
1071 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1074 ret = ERROR_OUTOFMEMORY;
1078 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1080 ret = ERROR_NOT_SUPPORTED;
1085 for (next = buf; next < lim; next += rtm->rtm_msglen)
1089 rtm = (struct rt_msghdr *)next;
1091 if (rtm->rtm_type != RTM_GET)
1093 WARN ("Got unexpected message type 0x%x!\n",
1098 /* Ignore all entries except for gateway routes which aren't
1100 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1101 (rtm->rtm_flags & RTF_MULTICAST))
1104 memset( &row, 0, sizeof(row) );
1105 row.dwForwardIfIndex = rtm->rtm_index;
1106 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1107 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1108 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1110 addrPtr = (char *)(rtm + 1);
1112 for (i = 1; i; i <<= 1)
1114 struct sockaddr *sa;
1117 if (!(i & rtm->rtm_addrs))
1120 sa = (struct sockaddr *)addrPtr;
1121 ADVANCE (addrPtr, sa);
1123 /* default routes are encoded by length-zero sockaddr */
1124 if (sa->sa_len == 0)
1126 else if (sa->sa_family != AF_INET)
1128 WARN ("Received unsupported sockaddr family 0x%x\n",
1134 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1136 addr = sin->sin_addr.s_addr;
1141 case RTA_DST: row.dwForwardDest = addr; break;
1142 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1143 case RTA_NETMASK: row.dwForwardMask = addr; break;
1145 WARN ("Unexpected address type 0x%x\n", i);
1149 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1153 HeapFree( GetProcessHeap (), 0, buf );
1156 FIXME( "not implemented\n" );
1157 ret = ERROR_NOT_SUPPORTED;
1160 if (!table) return ERROR_OUTOFMEMORY;
1163 if (bOrder && table->dwNumEntries)
1164 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1165 *ppIpForwardTable = table;
1167 else HeapFree( heap, flags, table );
1168 TRACE( "returning ret %u table %p\n", ret, table );
1172 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1173 DWORD *count, const MIB_IPNETROW *row )
1175 if (table->dwNumEntries >= *count)
1177 MIB_IPNETTABLE *new_table;
1178 DWORD new_count = table->dwNumEntries * 2;
1180 if (!(new_table = HeapReAlloc( heap, flags, table,
1181 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1183 HeapFree( heap, 0, table );
1189 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1193 static int compare_ipnet_rows(const void *a, const void *b)
1195 const MIB_IPNETROW *rowA = a;
1196 const MIB_IPNETROW *rowB = b;
1198 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1202 /******************************************************************
1203 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1205 * Get the IP-to-physical address mapping table.
1206 * Like GetIpNetTable(), but allocate the returned table from heap.
1209 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1210 * allocated and returned.
1211 * bOrder [In] whether to sort the table
1212 * heap [In] heap from which the table is allocated
1213 * flags [In] flags to HeapAlloc
1216 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1217 * on failure, NO_ERROR on success.
1219 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1220 HANDLE heap, DWORD flags)
1222 MIB_IPNETTABLE *table;
1224 DWORD ret = NO_ERROR, count = 16;
1226 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1228 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1230 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1231 return ERROR_OUTOFMEMORY;
1233 table->dwNumEntries = 0;
1239 if ((fp = fopen("/proc/net/arp", "r")))
1241 char buf[512], *ptr;
1244 /* skip header line */
1245 ptr = fgets(buf, sizeof(buf), fp);
1246 while ((ptr = fgets(buf, sizeof(buf), fp)))
1248 memset( &row, 0, sizeof(row) );
1250 row.dwAddr = inet_addr(ptr);
1251 while (*ptr && !isspace(*ptr)) ptr++;
1252 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1253 flags = strtoul(ptr + 1, &ptr, 16);
1256 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1260 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1263 row.dwType = MIB_IPNET_TYPE_OTHER;
1265 while (*ptr && isspace(*ptr)) ptr++;
1266 while (*ptr && !isspace(*ptr))
1268 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1271 while (*ptr && isspace(*ptr)) ptr++;
1272 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1273 while (*ptr && isspace(*ptr)) ptr++;
1274 getInterfaceIndexByName(ptr, &row.dwIndex);
1276 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1281 else ret = ERROR_NOT_SUPPORTED;
1283 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1285 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1286 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1288 char *buf = NULL, *lim, *next;
1289 struct rt_msghdr *rtm;
1290 struct sockaddr_inarp *sinarp;
1291 struct sockaddr_dl *sdl;
1293 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1295 ERR ("failed to get arp table\n");
1296 ret = ERROR_NOT_SUPPORTED;
1300 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1303 ret = ERROR_OUTOFMEMORY;
1307 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1309 ret = ERROR_NOT_SUPPORTED;
1317 rtm = (struct rt_msghdr *)next;
1318 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1319 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1320 if(sdl->sdl_alen) /* arp entry */
1322 memset( &row, 0, sizeof(row) );
1323 row.dwAddr = sinarp->sin_addr.s_addr;
1324 row.dwIndex = sdl->sdl_index;
1325 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1326 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1327 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1328 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1329 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1330 else row.dwType = MIB_IPNET_TYPE_INVALID;
1332 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1335 next += rtm->rtm_msglen;
1338 HeapFree( GetProcessHeap (), 0, buf );
1341 FIXME( "not implemented\n" );
1342 ret = ERROR_NOT_SUPPORTED;
1345 if (!table) return ERROR_OUTOFMEMORY;
1348 if (bOrder && table->dwNumEntries)
1349 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1350 *ppIpNetTable = table;
1352 else HeapFree( heap, flags, table );
1353 TRACE( "returning ret %u table %p\n", ret, table );
1358 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1359 DWORD *count, const MIB_UDPROW *row )
1361 if (table->dwNumEntries >= *count)
1363 MIB_UDPTABLE *new_table;
1364 DWORD new_count = table->dwNumEntries * 2;
1366 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1368 HeapFree( heap, 0, table );
1374 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1378 static int compare_udp_rows(const void *a, const void *b)
1380 const MIB_UDPROW *rowA = a;
1381 const MIB_UDPROW *rowB = b;
1384 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1385 return rowA->dwLocalPort - rowB->dwLocalPort;
1389 /******************************************************************
1390 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1392 * Get the UDP listener table.
1393 * Like GetUdpTable(), but allocate the returned table from heap.
1396 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1397 * allocated and returned.
1398 * bOrder [In] whether to sort the table
1399 * heap [In] heap from which the table is allocated
1400 * flags [In] flags to HeapAlloc
1403 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1404 * returns otherwise.
1406 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1407 HANDLE heap, DWORD flags)
1409 MIB_UDPTABLE *table;
1411 DWORD ret = NO_ERROR, count = 16;
1413 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1415 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1417 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1418 return ERROR_OUTOFMEMORY;
1420 table->dwNumEntries = 0;
1426 if ((fp = fopen("/proc/net/udp", "r")))
1428 char buf[512], *ptr;
1431 /* skip header line */
1432 ptr = fgets(buf, sizeof(buf), fp);
1433 while ((ptr = fgets(buf, sizeof(buf), fp)))
1435 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1437 row.dwLocalPort = htons( row.dwLocalPort );
1438 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1443 else ret = ERROR_NOT_SUPPORTED;
1446 FIXME( "not implemented\n" );
1447 ret = ERROR_NOT_SUPPORTED;
1450 if (!table) return ERROR_OUTOFMEMORY;
1453 if (bOrder && table->dwNumEntries)
1454 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1455 *ppUdpTable = table;
1457 else HeapFree( heap, flags, table );
1458 TRACE( "returning ret %u table %p\n", ret, table );
1463 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1464 DWORD *count, const MIB_TCPROW *row )
1466 if (table->dwNumEntries >= *count)
1468 MIB_TCPTABLE *new_table;
1469 DWORD new_count = table->dwNumEntries * 2;
1471 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1473 HeapFree( heap, 0, table );
1479 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1484 /* Why not a lookup table? Because the TCPS_* constants are different
1485 on different platforms */
1486 static inline DWORD TCPStateToMIBState (int state)
1490 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1491 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1492 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1493 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1494 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1495 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1496 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1497 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1498 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1499 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1501 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1506 static int compare_tcp_rows(const void *a, const void *b)
1508 const MIB_TCPROW *rowA = a;
1509 const MIB_TCPROW *rowB = b;
1512 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1513 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1514 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1515 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1516 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1520 /******************************************************************
1521 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1523 * Get the TCP connection table.
1524 * Like GetTcpTable(), but allocate the returned table from heap.
1527 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1528 * allocated and returned.
1529 * bOrder [In] whether to sort the table
1530 * heap [In] heap from which the table is allocated
1531 * flags [In] flags to HeapAlloc
1534 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1535 * returns otherwise.
1537 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1538 HANDLE heap, DWORD flags)
1540 MIB_TCPTABLE *table;
1542 DWORD ret = NO_ERROR, count = 16;
1544 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1546 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1548 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1549 return ERROR_OUTOFMEMORY;
1551 table->dwNumEntries = 0;
1557 if ((fp = fopen("/proc/net/tcp", "r")))
1559 char buf[512], *ptr;
1562 /* skip header line */
1563 ptr = fgets(buf, sizeof(buf), fp);
1564 while ((ptr = fgets(buf, sizeof(buf), fp)))
1566 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1567 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1569 row.dwLocalPort = htons( row.dwLocalPort );
1570 row.dwRemotePort = htons( row.dwRemotePort );
1571 row.dwState = TCPStateToMIBState( row.dwState );
1572 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1577 else ret = ERROR_NOT_SUPPORTED;
1579 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1583 mib2_tcpConnEntry_t *entry;
1585 if ((fd = open_streams_mib( "tcp" )) != -1)
1587 if ((data = read_mib_entry( fd, MIB2_TCP, MIB2_TCP_CONN, &len )))
1589 for (entry = data; (char *)(entry + 1) <= (char *)data + len; entry++)
1591 row.dwLocalAddr = entry->tcpConnLocalAddress;
1592 row.dwLocalPort = htons( entry->tcpConnLocalPort );
1593 row.dwRemoteAddr = entry->tcpConnRemAddress;
1594 row.dwRemotePort = htons( entry->tcpConnRemPort );
1595 row.dwState = entry->tcpConnState;
1596 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1598 HeapFree( GetProcessHeap(), 0, data );
1602 else ret = ERROR_NOT_SUPPORTED;
1604 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1608 struct xinpgen *pXIG, *pOrigXIG;
1610 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1612 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1613 ret = ERROR_NOT_SUPPORTED;
1617 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1620 ret = ERROR_OUTOFMEMORY;
1624 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1626 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1627 ret = ERROR_NOT_SUPPORTED;
1631 /* Might be nothing here; first entry is just a header it seems */
1632 if (Len <= sizeof (struct xinpgen)) goto done;
1634 pOrigXIG = (struct xinpgen *)Buf;
1637 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1638 pXIG->xig_len > sizeof (struct xinpgen);
1639 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1641 struct tcpcb *pTCPData = NULL;
1642 struct inpcb *pINData;
1643 struct xsocket *pSockData;
1645 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1646 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1647 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1649 /* Ignore sockets for other protocols */
1650 if (pSockData->xso_protocol != IPPROTO_TCP)
1653 /* Ignore PCBs that were freed while generating the data */
1654 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1657 /* we're only interested in IPv4 addresses */
1658 if (!(pINData->inp_vflag & INP_IPV4) ||
1659 (pINData->inp_vflag & INP_IPV6))
1662 /* If all 0's, skip it */
1663 if (!pINData->inp_laddr.s_addr &&
1664 !pINData->inp_lport &&
1665 !pINData->inp_faddr.s_addr &&
1666 !pINData->inp_fport)
1669 /* Fill in structure details */
1670 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1671 row.dwLocalPort = pINData->inp_lport;
1672 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1673 row.dwRemotePort = pINData->inp_fport;
1674 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1675 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1679 HeapFree (GetProcessHeap (), 0, Buf);
1682 FIXME( "not implemented\n" );
1683 ret = ERROR_NOT_SUPPORTED;
1686 if (!table) return ERROR_OUTOFMEMORY;
1689 if (bOrder && table->dwNumEntries)
1690 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1691 *ppTcpTable = table;
1693 else HeapFree( heap, flags, table );
1694 TRACE( "returning ret %u table %p\n", ret, table );