1 /* Copyright (C) 2003,2006 Juan Lang
2 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * This file implements statistics getting using the /proc filesystem exported
19 * by Linux, and maybe other OSes.
23 #include "wine/port.h"
24 #include "wine/debug.h"
30 #include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
37 #ifdef HAVE_SYS_SOCKETVAR_H
38 #include <sys/socketvar.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
49 #ifdef HAVE_NET_IF_DL_H
50 #include <net/if_dl.h>
52 #ifdef HAVE_NET_IF_TYPES_H
53 #include <net/if_types.h>
55 #ifdef HAVE_NET_ROUTE_H
56 #include <net/route.h>
58 #ifdef HAVE_NET_IF_ARP_H
59 #include <net/if_arp.h>
61 #ifdef HAVE_NETINET_IF_ETHER_H
62 #include <netinet/if_ether.h>
64 #ifdef HAVE_NETINET_TCP_H
65 #include <netinet/tcp.h>
67 #ifdef HAVE_NETINET_TCP_FSM_H
68 #include <netinet/tcp_fsm.h>
71 #ifdef HAVE_NETINET_IN_PCB_H
72 #include <netinet/in_pcb.h>
74 #ifdef HAVE_NETINET_TCP_VAR_H
75 #include <netinet/tcp_var.h>
77 #ifdef HAVE_NETINET_TCP_TIMER_H
78 #include <netinet/tcp_timer.h>
80 #ifdef HAVE_NETINET_IP_ICMP_H
81 #include <netinet/ip_icmp.h>
83 #ifdef HAVE_NETINET_ICMP_VAR_H
84 #include <netinet/icmp_var.h>
86 #ifdef HAVE_NETINET_IP_VAR_H
87 #include <netinet/ip_var.h>
89 #ifdef HAVE_NETINET_UDP_H
90 #include <netinet/udp.h>
92 #ifdef HAVE_NETINET_UDP_VAR_H
93 #include <netinet/udp_var.h>
96 #ifdef HAVE_SYS_SYSCTL_H
97 #include <sys/sysctl.h>
102 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
105 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
110 #include "iprtrmib.h"
114 #ifndef HAVE_NETINET_TCP_FSM_H
115 #define TCPS_ESTABLISHED 1
116 #define TCPS_SYN_SENT 2
117 #define TCPS_SYN_RECEIVED 3
118 #define TCPS_FIN_WAIT_1 4
119 #define TCPS_FIN_WAIT_2 5
120 #define TCPS_TIME_WAIT 6
121 #define TCPS_CLOSED 7
122 #define TCPS_CLOSE_WAIT 8
123 #define TCPS_LAST_ACK 9
124 #define TCPS_LISTEN 10
125 #define TCPS_CLOSING 11
128 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
130 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
132 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
133 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
134 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
138 struct if_msghdr *ifm;
139 struct if_data ifdata;
141 return ERROR_INVALID_PARAMETER;
143 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
145 ERR ("failed to get size of iflist\n");
146 return ERROR_NOT_SUPPORTED;
148 buf = HeapAlloc (GetProcessHeap (), 0, needed);
149 if (!buf) return ERROR_NOT_SUPPORTED;
150 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
152 ERR ("failed to get iflist\n");
153 HeapFree (GetProcessHeap (), 0, buf);
154 return ERROR_NOT_SUPPORTED;
157 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
159 ifm = (struct if_msghdr *) buf;
160 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
162 ifdata = ifm->ifm_data;
163 entry->dwMtu = ifdata.ifi_mtu;
164 entry->dwSpeed = ifdata.ifi_baudrate;
165 entry->dwInOctets = ifdata.ifi_ibytes;
166 entry->dwInErrors = ifdata.ifi_ierrors;
167 entry->dwInDiscards = ifdata.ifi_iqdrops;
168 entry->dwInUcastPkts = ifdata.ifi_ipackets;
169 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
170 entry->dwOutOctets = ifdata.ifi_obytes;
171 entry->dwOutUcastPkts = ifdata.ifi_opackets;
172 entry->dwOutErrors = ifdata.ifi_oerrors;
173 HeapFree (GetProcessHeap (), 0, buf);
177 HeapFree (GetProcessHeap (), 0, buf);
178 return ERROR_NOT_SUPPORTED;
180 /* get interface stats from /proc/net/dev, no error if can't
181 no inUnknownProtos, outNUcastPkts, outQLen */
185 return ERROR_INVALID_PARAMETER;
186 fp = fopen("/proc/net/dev", "r");
188 char buf[512] = { 0 }, *ptr;
189 int nameLen = strlen(name), nameFound = 0;
192 ptr = fgets(buf, sizeof(buf), fp);
193 while (ptr && !nameFound) {
194 while (*ptr && isspace(*ptr))
196 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
199 ptr = fgets(buf, sizeof(buf), fp);
206 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
210 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
214 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
218 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
222 strtoul(ptr, &endPtr, 10); /* skip */
226 strtoul(ptr, &endPtr, 10); /* skip */
230 strtoul(ptr, &endPtr, 10); /* skip */
234 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
238 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
242 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
246 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
250 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
258 ERR ("unimplemented!\n");
259 return ERROR_NOT_SUPPORTED;
266 DWORD getICMPStats(MIB_ICMP *stats)
268 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
269 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
270 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
272 struct icmpstat icmp_stat;
276 return ERROR_INVALID_PARAMETER;
278 needed = sizeof(icmp_stat);
279 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
281 ERR ("failed to get icmpstat\n");
282 return ERROR_NOT_SUPPORTED;
287 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
288 for(i = 0; i <= ICMP_MAXTYPE; i++)
289 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
291 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
293 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
294 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
295 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
296 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
297 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
298 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
299 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
300 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
301 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
302 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
303 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
307 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
308 for(i = 0; i <= ICMP_MAXTYPE; i++)
309 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
311 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
313 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
314 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
315 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
316 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
317 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
318 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
319 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
320 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
321 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
322 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
323 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
330 return ERROR_INVALID_PARAMETER;
332 memset(stats, 0, sizeof(MIB_ICMP));
333 /* get most of these stats from /proc/net/snmp, no error if can't */
334 fp = fopen("/proc/net/snmp", "r");
336 static const char hdr[] = "Icmp:";
337 char buf[512] = { 0 }, *ptr;
340 ptr = fgets(buf, sizeof(buf), fp);
341 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
343 /* last line was a header, get another */
344 ptr = fgets(buf, sizeof(buf), fp);
345 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
350 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
354 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
358 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
362 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
366 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
370 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
374 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
378 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
382 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
386 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
390 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
394 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
398 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
402 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
406 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
410 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
414 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
418 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
422 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
426 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
430 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
434 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
438 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
442 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
451 ERR ("unimplemented!\n");
452 return ERROR_NOT_SUPPORTED;
459 DWORD getIPStats(PMIB_IPSTATS stats)
461 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
462 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
463 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
464 int ip_ttl, ip_forwarding;
465 struct ipstat ip_stat;
469 return ERROR_INVALID_PARAMETER;
471 needed = sizeof(ip_stat);
472 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
474 ERR ("failed to get ipstat\n");
475 return ERROR_NOT_SUPPORTED;
478 needed = sizeof(ip_ttl);
479 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
481 ERR ("failed to get ip Default TTL\n");
482 return ERROR_NOT_SUPPORTED;
485 needed = sizeof(ip_forwarding);
486 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
488 ERR ("failed to get ip forwarding\n");
489 return ERROR_NOT_SUPPORTED;
492 stats->dwForwarding = ip_forwarding;
493 stats->dwDefaultTTL = ip_ttl;
494 stats->dwInDelivers = ip_stat.ips_delivered;
495 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
496 stats->dwInAddrErrors = ip_stat.ips_cantforward;
497 stats->dwInReceives = ip_stat.ips_total;
498 stats->dwForwDatagrams = ip_stat.ips_forward;
499 stats->dwInUnknownProtos = ip_stat.ips_noproto;
500 stats->dwInDiscards = ip_stat.ips_fragdropped;
501 stats->dwOutDiscards = ip_stat.ips_odropped;
502 stats->dwReasmOks = ip_stat.ips_reassembled;
503 stats->dwFragOks = ip_stat.ips_fragmented;
504 stats->dwFragFails = ip_stat.ips_cantfrag;
505 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
506 stats->dwOutNoRoutes = ip_stat.ips_noroute;
507 stats->dwOutRequests = ip_stat.ips_localout;
508 stats->dwReasmReqds = ip_stat.ips_fragments;
515 return ERROR_INVALID_PARAMETER;
517 memset(stats, 0, sizeof(MIB_IPSTATS));
518 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
519 stats->dwNumRoutes = getNumRoutes();
521 /* get most of these stats from /proc/net/snmp, no error if can't */
522 fp = fopen("/proc/net/snmp", "r");
524 static const char hdr[] = "Ip:";
525 char buf[512] = { 0 }, *ptr;
528 ptr = fgets(buf, sizeof(buf), fp);
529 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
531 /* last line was a header, get another */
532 ptr = fgets(buf, sizeof(buf), fp);
533 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
538 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
542 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
546 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
550 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
554 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
558 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
562 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
566 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
570 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
574 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
578 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
582 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
586 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
590 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
594 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
598 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
602 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
606 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
610 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
613 /* hmm, no routingDiscards */
620 ERR ("unimplemented!\n");
621 return ERROR_NOT_SUPPORTED;
628 DWORD getTCPStats(MIB_TCPSTATS *stats)
630 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
631 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
632 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
634 struct tcpstat tcp_stat;
638 return ERROR_INVALID_PARAMETER;
639 needed = sizeof(tcp_stat);
641 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
643 ERR ("failed to get tcpstat\n");
644 return ERROR_NOT_SUPPORTED;
647 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
648 stats->dwRtoMin = TCPTV_MIN;
649 stats->dwRtoMax = TCPTV_REXMTMAX;
650 stats->dwMaxConn = -1;
651 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
652 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
653 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
654 stats->dwEstabResets = tcp_stat.tcps_drops;
655 stats->dwCurrEstab = 0;
656 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
657 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
658 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
659 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
660 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
661 stats->dwNumConns = tcp_stat.tcps_connects;
669 return ERROR_INVALID_PARAMETER;
671 memset(stats, 0, sizeof(MIB_TCPSTATS));
673 /* get from /proc/net/snmp, no error if can't */
674 fp = fopen("/proc/net/snmp", "r");
676 static const char hdr[] = "Tcp:";
677 char buf[512] = { 0 }, *ptr;
681 ptr = fgets(buf, sizeof(buf), fp);
682 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
684 /* last line was a header, get another */
685 ptr = fgets(buf, sizeof(buf), fp);
686 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
691 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
695 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
699 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
703 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
707 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
711 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
715 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
719 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
723 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
727 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
731 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
735 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
739 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
743 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
746 stats->dwNumConns = getNumTcpEntries();
753 ERR ("unimplemented!\n");
754 return ERROR_NOT_SUPPORTED;
761 DWORD getUDPStats(MIB_UDPSTATS *stats)
763 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
764 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
765 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
766 struct udpstat udp_stat;
769 return ERROR_INVALID_PARAMETER;
771 needed = sizeof(udp_stat);
773 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
775 ERR ("failed to get udpstat\n");
776 return ERROR_NOT_SUPPORTED;
779 stats->dwInDatagrams = udp_stat.udps_ipackets;
780 stats->dwOutDatagrams = udp_stat.udps_opackets;
781 stats->dwNoPorts = udp_stat.udps_noport;
782 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
783 stats->dwNumAddrs = getNumUdpEntries();
790 return ERROR_INVALID_PARAMETER;
792 memset(stats, 0, sizeof(MIB_UDPSTATS));
794 /* get from /proc/net/snmp, no error if can't */
795 fp = fopen("/proc/net/snmp", "r");
797 static const char hdr[] = "Udp:";
798 char buf[512] = { 0 }, *ptr;
802 ptr = fgets(buf, sizeof(buf), fp);
803 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
805 /* last line was a header, get another */
806 ptr = fgets(buf, sizeof(buf), fp);
807 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
812 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
816 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
820 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
824 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
828 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
837 ERR ("unimplemented!\n");
838 return ERROR_NOT_SUPPORTED;
845 static DWORD getNumWithOneHeader(const char *filename)
847 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
850 struct xinpgen *pXIG, *pOrigXIG;
852 DWORD NumEntries = 0;
854 if (!strcmp (filename, "net.inet.tcp.pcblist"))
855 Protocol = IPPROTO_TCP;
856 else if (!strcmp (filename, "net.inet.udp.pcblist"))
857 Protocol = IPPROTO_UDP;
860 ERR ("Unsupported mib '%s', needs protocol mapping\n",
865 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
867 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
871 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
874 ERR ("Out of memory!\n");
878 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
880 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
881 HeapFree (GetProcessHeap (), 0, Buf);
885 /* Might be nothing here; first entry is just a header it seems */
886 if (Len <= sizeof (struct xinpgen))
888 HeapFree (GetProcessHeap (), 0, Buf);
892 pOrigXIG = (struct xinpgen *)Buf;
895 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
896 pXIG->xig_len > sizeof (struct xinpgen);
897 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
899 struct tcpcb *pTCPData = NULL;
900 struct inpcb *pINData;
901 struct xsocket *pSockData;
903 if (Protocol == IPPROTO_TCP)
905 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
906 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
907 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
911 pINData = &((struct xinpcb *)pXIG)->xi_inp;
912 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
915 /* Ignore sockets for other protocols */
916 if (pSockData->xso_protocol != Protocol)
919 /* Ignore PCBs that were freed while generating the data */
920 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
923 /* we're only interested in IPv4 addresses */
924 if (!(pINData->inp_vflag & INP_IPV4) ||
925 (pINData->inp_vflag & INP_IPV6))
928 /* If all 0's, skip it */
929 if (!pINData->inp_laddr.s_addr &&
930 !pINData->inp_lport &&
931 !pINData->inp_faddr.s_addr &&
938 HeapFree (GetProcessHeap (), 0, Buf);
944 fp = fopen(filename, "r");
946 char buf[512] = { 0 }, *ptr;
949 ptr = fgets(buf, sizeof(buf), fp);
952 ptr = fgets(buf, sizeof(buf), fp);
960 ERR ("Unable to open '%s' to count entries!\n", filename);
966 DWORD getNumRoutes(void)
968 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
969 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
971 char *buf, *lim, *next;
972 struct rt_msghdr *rtm;
973 DWORD RouteCount = 0;
975 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
977 ERR ("sysctl 1 failed!\n");
981 buf = HeapAlloc (GetProcessHeap (), 0, needed);
984 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
986 ERR ("sysctl 2 failed!\n");
987 HeapFree (GetProcessHeap (), 0, buf);
992 for (next = buf; next < lim; next += rtm->rtm_msglen)
994 rtm = (struct rt_msghdr *)next;
996 if (rtm->rtm_type != RTM_GET)
998 WARN ("Got unexpected message type 0x%x!\n",
1003 /* Ignore all entries except for gateway routes which aren't
1005 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1011 HeapFree (GetProcessHeap (), 0, buf);
1014 return getNumWithOneHeader("/proc/net/route");
1018 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1023 if (!ppIpForwardTable)
1024 ret = ERROR_INVALID_PARAMETER;
1026 DWORD numRoutes = getNumRoutes();
1027 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1028 PMIB_IPFORWARDTABLE table;
1031 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1032 table = HeapAlloc(heap, flags, size);
1034 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1035 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1037 char *buf, *lim, *next, *addrPtr;
1038 struct rt_msghdr *rtm;
1040 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1042 ERR ("sysctl 1 failed!\n");
1043 HeapFree (GetProcessHeap (), 0, table);
1047 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1050 HeapFree (GetProcessHeap (), 0, table);
1051 return ERROR_OUTOFMEMORY;
1054 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1056 ERR ("sysctl 2 failed!\n");
1057 HeapFree (GetProcessHeap (), 0, table);
1058 HeapFree (GetProcessHeap (), 0, buf);
1062 *ppIpForwardTable = table;
1063 table->dwNumEntries = 0;
1066 for (next = buf; next < lim; next += rtm->rtm_msglen)
1070 rtm = (struct rt_msghdr *)next;
1072 if (rtm->rtm_type != RTM_GET)
1074 WARN ("Got unexpected message type 0x%x!\n",
1079 /* Ignore all entries except for gateway routes which aren't
1081 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1082 (rtm->rtm_flags & RTF_MULTICAST))
1085 memset (&table->table[table->dwNumEntries], 0,
1086 sizeof (MIB_IPFORWARDROW));
1087 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1088 table->table[table->dwNumEntries].dwForwardType =
1089 MIB_IPROUTE_TYPE_INDIRECT;
1090 table->table[table->dwNumEntries].dwForwardMetric1 =
1091 rtm->rtm_rmx.rmx_hopcount;
1092 table->table[table->dwNumEntries].dwForwardProto =
1095 addrPtr = (char *)(rtm + 1);
1097 for (i = 1; i; i <<= 1)
1099 struct sockaddr *sa;
1102 if (!(i & rtm->rtm_addrs))
1105 sa = (struct sockaddr *)addrPtr;
1106 ADVANCE (addrPtr, sa);
1108 /* default routes are encoded by length-zero sockaddr */
1109 if (sa->sa_len == 0)
1111 else if (sa->sa_family != AF_INET)
1113 WARN ("Received unsupported sockaddr family 0x%x\n",
1119 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1121 addr = sin->sin_addr.s_addr;
1127 table->table[table->dwNumEntries].dwForwardDest = addr;
1131 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1135 table->table[table->dwNumEntries].dwForwardMask = addr;
1139 WARN ("Unexpected address type 0x%x\n", i);
1143 table->dwNumEntries++;
1146 HeapFree (GetProcessHeap (), 0, buf);
1152 *ppIpForwardTable = table;
1153 table->dwNumEntries = 0;
1154 /* get from /proc/net/route, no error if can't */
1155 fp = fopen("/proc/net/route", "r");
1157 char buf[512] = { 0 }, *ptr;
1159 /* skip header line */
1160 ptr = fgets(buf, sizeof(buf), fp);
1161 while (ptr && table->dwNumEntries < numRoutes) {
1162 memset(&table->table[table->dwNumEntries], 0,
1163 sizeof(MIB_IPFORWARDROW));
1164 ptr = fgets(buf, sizeof(buf), fp);
1168 while (!isspace(*ptr))
1172 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1175 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1177 table->table[table->dwNumEntries].dwForwardDest =
1178 strtoul(ptr, &endPtr, 16);
1182 table->table[table->dwNumEntries].dwForwardNextHop =
1183 strtoul(ptr, &endPtr, 16);
1187 DWORD flags = strtoul(ptr, &endPtr, 16);
1189 if (!(flags & RTF_UP))
1190 table->table[table->dwNumEntries].dwForwardType =
1191 MIB_IPROUTE_TYPE_INVALID;
1192 else if (flags & RTF_GATEWAY)
1193 table->table[table->dwNumEntries].dwForwardType =
1194 MIB_IPROUTE_TYPE_INDIRECT;
1196 table->table[table->dwNumEntries].dwForwardType =
1197 MIB_IPROUTE_TYPE_DIRECT;
1201 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1205 strtoul(ptr, &endPtr, 16); /* use, skip */
1209 table->table[table->dwNumEntries].dwForwardMetric1 =
1210 strtoul(ptr, &endPtr, 16);
1214 table->table[table->dwNumEntries].dwForwardMask =
1215 strtoul(ptr, &endPtr, 16);
1218 /* FIXME: other protos might be appropriate, e.g. the default
1219 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1220 table->table[table->dwNumEntries].dwForwardProto =
1222 table->dwNumEntries++;
1230 ERR ("unimplemented!\n");
1231 return ERROR_NOT_SUPPORTED;
1236 ret = ERROR_OUTOFMEMORY;
1241 DWORD getNumArpEntries(void)
1243 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1244 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1245 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1246 DWORD arpEntries = 0;
1248 char *buf, *lim, *next;
1249 struct rt_msghdr *rtm;
1250 struct sockaddr_inarp *sinarp;
1251 struct sockaddr_dl *sdl;
1253 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1255 ERR ("failed to get size of arp table\n");
1259 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1262 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1264 ERR ("failed to get arp table\n");
1265 HeapFree (GetProcessHeap (), 0, buf);
1273 rtm = (struct rt_msghdr *)next;
1274 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1275 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1276 if(sdl->sdl_alen) /* arp entry */
1278 next += rtm->rtm_msglen;
1280 HeapFree (GetProcessHeap (), 0, buf);
1283 return getNumWithOneHeader("/proc/net/arp");
1286 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1290 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1291 ERR ("unimplemented!\n");
1292 return ERROR_NOT_SUPPORTED;
1296 ret = ERROR_INVALID_PARAMETER;
1298 DWORD numEntries = getNumArpEntries();
1299 DWORD size = sizeof(MIB_IPNETTABLE);
1300 PMIB_IPNETTABLE table;
1303 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1304 table = HeapAlloc(heap, flags, size);
1309 *ppIpNetTable = table;
1310 table->dwNumEntries = 0;
1311 /* get from /proc/net/arp, no error if can't */
1312 fp = fopen("/proc/net/arp", "r");
1314 char buf[512] = { 0 }, *ptr;
1316 /* skip header line */
1317 ptr = fgets(buf, sizeof(buf), fp);
1318 while (ptr && table->dwNumEntries < numEntries) {
1319 ptr = fgets(buf, sizeof(buf), fp);
1323 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1324 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1325 while (ptr && *ptr && !isspace(*ptr))
1329 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1333 DWORD flags = strtoul(ptr, &endPtr, 16);
1336 if (flags & ATF_COM)
1337 table->table[table->dwNumEntries].dwType =
1338 MIB_IPNET_TYPE_DYNAMIC;
1342 if (flags & ATF_PERM)
1343 table->table[table->dwNumEntries].dwType =
1344 MIB_IPNET_TYPE_STATIC;
1347 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1351 while (ptr && *ptr && isspace(*ptr))
1353 while (ptr && *ptr && !isspace(*ptr)) {
1354 DWORD byte = strtoul(ptr, &endPtr, 16);
1356 if (endPtr && *endPtr) {
1358 table->table[table->dwNumEntries].bPhysAddr[
1359 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1365 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1368 getInterfaceIndexByName(ptr,
1369 &table->table[table->dwNumEntries].dwIndex);
1370 table->dwNumEntries++;
1376 ret = ERROR_NOT_SUPPORTED;
1379 ret = ERROR_OUTOFMEMORY;
1384 DWORD getNumUdpEntries(void)
1386 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1387 return getNumWithOneHeader ("net.inet.udp.pcblist");
1389 return getNumWithOneHeader("/proc/net/udp");
1393 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1397 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1398 ERR ("unimplemented!\n");
1399 return ERROR_NOT_SUPPORTED;
1403 ret = ERROR_INVALID_PARAMETER;
1405 DWORD numEntries = getNumUdpEntries();
1406 DWORD size = sizeof(MIB_UDPTABLE);
1407 PMIB_UDPTABLE table;
1410 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1411 table = HeapAlloc(heap, flags, size);
1416 *ppUdpTable = table;
1417 table->dwNumEntries = 0;
1418 /* get from /proc/net/udp, no error if can't */
1419 fp = fopen("/proc/net/udp", "r");
1421 char buf[512] = { 0 }, *ptr;
1423 /* skip header line */
1424 ptr = fgets(buf, sizeof(buf), fp);
1425 while (ptr && table->dwNumEntries < numEntries) {
1426 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1427 ptr = fgets(buf, sizeof(buf), fp);
1432 strtoul(ptr, &endPtr, 16); /* skip */
1437 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1443 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1447 table->dwNumEntries++;
1453 ret = ERROR_NOT_SUPPORTED;
1456 ret = ERROR_OUTOFMEMORY;
1462 DWORD getNumTcpEntries(void)
1464 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1465 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1467 return getNumWithOneHeader ("/proc/net/tcp");
1472 /* Why not a lookup table? Because the TCPS_* constants are different
1473 on different platforms */
1474 static DWORD TCPStateToMIBState (int state)
1478 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1479 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1480 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1481 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1482 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1483 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1484 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1485 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1486 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1487 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1489 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1494 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1498 PMIB_TCPTABLE table;
1499 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1502 struct xinpgen *pXIG, *pOrigXIG;
1505 char buf[512] = { 0 }, *ptr;
1509 return ERROR_INVALID_PARAMETER;
1511 numEntries = getNumTcpEntries ();
1515 DWORD size = sizeof(MIB_TCPTABLE);
1518 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1519 *ppTcpTable = HeapAlloc (heap, flags, size);
1522 ERR ("Out of memory!\n");
1523 return ERROR_OUTOFMEMORY;
1525 maxEntries = numEntries;
1528 table = *ppTcpTable;
1529 table->dwNumEntries = 0;
1533 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1535 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1537 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1538 return ERROR_OUTOFMEMORY;
1541 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1544 ERR ("Out of memory!\n");
1545 return ERROR_OUTOFMEMORY;
1548 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1550 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1551 HeapFree (GetProcessHeap (), 0, Buf);
1552 return ERROR_OUTOFMEMORY;
1555 /* Might be nothing here; first entry is just a header it seems */
1556 if (Len <= sizeof (struct xinpgen))
1558 HeapFree (GetProcessHeap (), 0, Buf);
1562 pOrigXIG = (struct xinpgen *)Buf;
1565 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1566 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1567 (table->dwNumEntries < maxEntries);
1568 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1570 struct tcpcb *pTCPData = NULL;
1571 struct inpcb *pINData;
1572 struct xsocket *pSockData;
1574 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1575 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1576 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1578 /* Ignore sockets for other protocols */
1579 if (pSockData->xso_protocol != IPPROTO_TCP)
1582 /* Ignore PCBs that were freed while generating the data */
1583 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1586 /* we're only interested in IPv4 addresses */
1587 if (!(pINData->inp_vflag & INP_IPV4) ||
1588 (pINData->inp_vflag & INP_IPV6))
1591 /* If all 0's, skip it */
1592 if (!pINData->inp_laddr.s_addr &&
1593 !pINData->inp_lport &&
1594 !pINData->inp_faddr.s_addr &&
1595 !pINData->inp_fport)
1598 /* Fill in structure details */
1599 table->table[table->dwNumEntries].dwLocalAddr =
1600 pINData->inp_laddr.s_addr;
1601 table->table[table->dwNumEntries].dwLocalPort =
1603 table->table[table->dwNumEntries].dwRemoteAddr =
1604 pINData->inp_faddr.s_addr;
1605 table->table[table->dwNumEntries].dwRemotePort =
1607 table->table[table->dwNumEntries].dwState =
1608 TCPStateToMIBState (pTCPData->t_state);
1610 table->dwNumEntries++;
1613 HeapFree (GetProcessHeap (), 0, Buf);
1615 /* get from /proc/net/tcp, no error if can't */
1616 fp = fopen("/proc/net/tcp", "r");
1618 return ERROR_NOT_SUPPORTED;
1620 /* skip header line */
1621 ptr = fgets(buf, sizeof(buf), fp);
1622 while (ptr && table->dwNumEntries < maxEntries) {
1623 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1624 ptr = fgets(buf, sizeof(buf), fp);
1628 while (ptr && *ptr && *ptr != ':')
1633 table->table[table->dwNumEntries].dwLocalAddr =
1634 strtoul(ptr, &endPtr, 16);
1639 table->table[table->dwNumEntries].dwLocalPort =
1640 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1644 table->table[table->dwNumEntries].dwRemoteAddr =
1645 strtoul(ptr, &endPtr, 16);
1650 table->table[table->dwNumEntries].dwRemotePort =
1651 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1655 DWORD state = strtoul(ptr, &endPtr, 16);
1657 table->table[table->dwNumEntries].dwState =
1658 TCPStateToMIBState (state);
1661 table->dwNumEntries++;