crypt32: Reduce valid usages count when removing a valid usage.
[wine] / dlls / iphlpapi / ipstats.c
1 /* Copyright (C) 2003,2006 Juan Lang
2  * Copyright (C) 2007 TransGaming Technologies Inc.
3  *
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.
8  *
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.
13  *
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
17  *
18  * This file implements statistics getting using the /proc filesystem exported
19  * by Linux, and maybe other OSes.
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKETVAR_H
35 #include <sys/socketvar.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 #include <arpa/inet.h>
42 #endif
43 #ifdef HAVE_NET_IF_H
44 #include <net/if.h>
45 #endif
46 #ifdef HAVE_NET_ROUTE_H
47 #include <net/route.h>
48 #endif
49 #ifdef HAVE_NET_IF_ARP_H
50 #include <net/if_arp.h>
51 #endif
52 #ifdef HAVE_NETINET_TCP_H
53 #include <netinet/tcp.h>
54 #endif
55 #ifdef HAVE_NETINET_TCP_FSM_H
56 #include <netinet/tcp_fsm.h>
57 #endif
58
59 #ifdef HAVE_NETINET_IN_PCB_H
60 #include <netinet/in_pcb.h>
61 #endif
62 #ifdef HAVE_NETINET_TCP_VAR_H
63 #include <netinet/tcp_var.h>
64 #endif
65 #ifdef HAVE_NETINET_IP_VAR_H
66 #include <netinet/ip_var.h>
67 #endif
68
69 #ifdef HAVE_SYS_SYSCTL_H
70 #include <sys/sysctl.h>
71 #endif
72
73 #ifndef ROUNDUP
74 #define ROUNDUP(a) \
75         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
76 #endif
77 #ifndef ADVANCE
78 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
79 #endif
80
81 #include "windef.h"
82 #include "winbase.h"
83 #include "iprtrmib.h"
84 #include "ifenum.h"
85 #include "ipstats.h"
86
87 #ifndef HAVE_NETINET_TCP_FSM_H
88 #define TCPS_ESTABLISHED  1
89 #define TCPS_SYN_SENT     2
90 #define TCPS_SYN_RECEIVED 3
91 #define TCPS_FIN_WAIT_1   4
92 #define TCPS_FIN_WAIT_2   5
93 #define TCPS_TIME_WAIT    6
94 #define TCPS_CLOSED       7
95 #define TCPS_CLOSE_WAIT   8
96 #define TCPS_LAST_ACK     9
97 #define TCPS_LISTEN      10
98 #define TCPS_CLOSING     11
99 #endif
100
101 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
102
103 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
104 {
105   FILE *fp;
106
107   if (!name)
108     return ERROR_INVALID_PARAMETER;
109   if (!entry)
110     return ERROR_INVALID_PARAMETER;
111
112   /* get interface stats from /proc/net/dev, no error if can't
113      no inUnknownProtos, outNUcastPkts, outQLen */
114   fp = fopen("/proc/net/dev", "r");
115   if (fp) {
116     char buf[512] = { 0 }, *ptr;
117     int nameLen = strlen(name), nameFound = 0;
118
119
120     ptr = fgets(buf, sizeof(buf), fp);
121     while (ptr && !nameFound) {
122       while (*ptr && isspace(*ptr))
123         ptr++;
124       if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
125         nameFound = 1;
126       else
127         ptr = fgets(buf, sizeof(buf), fp);
128     }
129     if (nameFound) {
130       char *endPtr;
131
132       ptr += nameLen + 1;
133       if (ptr && *ptr) {
134         entry->dwInOctets = strtoul(ptr, &endPtr, 10);
135         ptr = endPtr;
136       }
137       if (ptr && *ptr) {
138         entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
139         ptr = endPtr;
140       }
141       if (ptr && *ptr) {
142         entry->dwInErrors = strtoul(ptr, &endPtr, 10);
143         ptr = endPtr;
144       }
145       if (ptr && *ptr) {
146         entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
147         ptr = endPtr;
148       }
149       if (ptr && *ptr) {
150         strtoul(ptr, &endPtr, 10); /* skip */
151         ptr = endPtr;
152       }
153       if (ptr && *ptr) {
154         strtoul(ptr, &endPtr, 10); /* skip */
155         ptr = endPtr;
156       }
157       if (ptr && *ptr) {
158         strtoul(ptr, &endPtr, 10); /* skip */
159         ptr = endPtr;
160       }
161       if (ptr && *ptr) {
162         entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
163         ptr = endPtr;
164       }
165       if (ptr && *ptr) {
166         entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
167         ptr = endPtr;
168       }
169       if (ptr && *ptr) {
170         entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
171         ptr = endPtr;
172       }
173       if (ptr && *ptr) {
174         entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
175         ptr = endPtr;
176       }
177       if (ptr && *ptr) {
178         entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
179         ptr = endPtr;
180       }
181     }
182     fclose(fp);
183   }
184   else
185      ERR ("unimplemented!\n");
186
187   return NO_ERROR;
188 }
189
190 DWORD getICMPStats(MIB_ICMP *stats)
191 {
192   FILE *fp;
193
194   if (!stats)
195     return ERROR_INVALID_PARAMETER;
196
197   memset(stats, 0, sizeof(MIB_ICMP));
198   /* get most of these stats from /proc/net/snmp, no error if can't */
199   fp = fopen("/proc/net/snmp", "r");
200   if (fp) {
201     static const char hdr[] = "Icmp:";
202     char buf[512] = { 0 }, *ptr;
203
204     do {
205       ptr = fgets(buf, sizeof(buf), fp);
206     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
207     if (ptr) {
208       /* last line was a header, get another */
209       ptr = fgets(buf, sizeof(buf), fp);
210       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
211         char *endPtr;
212
213         ptr += sizeof(hdr);
214         if (ptr && *ptr) {
215           stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
216           ptr = endPtr;
217         }
218         if (ptr && *ptr) {
219           stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
220           ptr = endPtr;
221         }
222         if (ptr && *ptr) {
223           stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
224           ptr = endPtr;
225         }
226         if (ptr && *ptr) {
227           stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
228           ptr = endPtr;
229         }
230         if (ptr && *ptr) {
231           stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
232           ptr = endPtr;
233         }
234         if (ptr && *ptr) {
235           stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
236           ptr = endPtr;
237         }
238         if (ptr && *ptr) {
239           stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
240           ptr = endPtr;
241         }
242         if (ptr && *ptr) {
243           stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
244           ptr = endPtr;
245         }
246         if (ptr && *ptr) {
247           stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
248           ptr = endPtr;
249         }
250         if (ptr && *ptr) {
251           stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
252           ptr = endPtr;
253         }
254         if (ptr && *ptr) {
255           stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
256           ptr = endPtr;
257         }
258         if (ptr && *ptr) {
259           stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
260           ptr = endPtr;
261         }
262         if (ptr && *ptr) {
263           stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
264           ptr = endPtr;
265         }
266         if (ptr && *ptr) {
267           stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
268           ptr = endPtr;
269         }
270         if (ptr && *ptr) {
271           stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
272           ptr = endPtr;
273         }
274         if (ptr && *ptr) {
275           stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
276           ptr = endPtr;
277         }
278         if (ptr && *ptr) {
279           stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
280           ptr = endPtr;
281         }
282         if (ptr && *ptr) {
283           stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
284           ptr = endPtr;
285         }
286         if (ptr && *ptr) {
287           stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
288           ptr = endPtr;
289         }
290         if (ptr && *ptr) {
291           stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
292           ptr = endPtr;
293         }
294         if (ptr && *ptr) {
295           stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
296           ptr = endPtr;
297         }
298         if (ptr && *ptr) {
299           stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
300           ptr = endPtr;
301         }
302         if (ptr && *ptr) {
303           stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
304           ptr = endPtr;
305         }
306         if (ptr && *ptr) {
307           stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
308           ptr = endPtr;
309         }
310       }
311     }
312     fclose(fp);
313   }
314   else
315      ERR ("unimplemented!\n");
316
317   return NO_ERROR;
318 }
319
320 DWORD getIPStats(PMIB_IPSTATS stats)
321 {
322   FILE *fp;
323
324   if (!stats)
325     return ERROR_INVALID_PARAMETER;
326
327   memset(stats, 0, sizeof(MIB_IPSTATS));
328   stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
329   stats->dwNumRoutes = getNumRoutes();
330
331   /* get most of these stats from /proc/net/snmp, no error if can't */
332   fp = fopen("/proc/net/snmp", "r");
333   if (fp) {
334     static const char hdr[] = "Ip:";
335     char buf[512] = { 0 }, *ptr;
336
337     do {
338       ptr = fgets(buf, sizeof(buf), fp);
339     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
340     if (ptr) {
341       /* last line was a header, get another */
342       ptr = fgets(buf, sizeof(buf), fp);
343       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
344         char *endPtr;
345
346         ptr += sizeof(hdr);
347         if (ptr && *ptr) {
348           stats->dwForwarding = strtoul(ptr, &endPtr, 10);
349           ptr = endPtr;
350         }
351         if (ptr && *ptr) {
352           stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
353           ptr = endPtr;
354         }
355         if (ptr && *ptr) {
356           stats->dwInReceives = strtoul(ptr, &endPtr, 10);
357           ptr = endPtr;
358         }
359         if (ptr && *ptr) {
360           stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
361           ptr = endPtr;
362         }
363         if (ptr && *ptr) {
364           stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
365           ptr = endPtr;
366         }
367         if (ptr && *ptr) {
368           stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
369           ptr = endPtr;
370         }
371         if (ptr && *ptr) {
372           stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
373           ptr = endPtr;
374         }
375         if (ptr && *ptr) {
376           stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
377           ptr = endPtr;
378         }
379         if (ptr && *ptr) {
380           stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
381           ptr = endPtr;
382         }
383         if (ptr && *ptr) {
384           stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
385           ptr = endPtr;
386         }
387         if (ptr && *ptr) {
388           stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
389           ptr = endPtr;
390         }
391         if (ptr && *ptr) {
392           stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
393           ptr = endPtr;
394         }
395         if (ptr && *ptr) {
396           stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
397           ptr = endPtr;
398         }
399         if (ptr && *ptr) {
400           stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
401           ptr = endPtr;
402         }
403         if (ptr && *ptr) {
404           stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
405           ptr = endPtr;
406         }
407         if (ptr && *ptr) {
408           stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
409           ptr = endPtr;
410         }
411         if (ptr && *ptr) {
412           stats->dwFragOks = strtoul(ptr, &endPtr, 10);
413           ptr = endPtr;
414         }
415         if (ptr && *ptr) {
416           stats->dwFragFails = strtoul(ptr, &endPtr, 10);
417           ptr = endPtr;
418         }
419         if (ptr && *ptr) {
420           stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
421           ptr = endPtr;
422         }
423         /* hmm, no routingDiscards */
424       }
425     }
426     fclose(fp);
427   }
428   else
429      ERR ("unimplemented!\n");
430
431   return NO_ERROR;
432 }
433
434 DWORD getTCPStats(MIB_TCPSTATS *stats)
435 {
436   FILE *fp;
437
438   if (!stats)
439     return ERROR_INVALID_PARAMETER;
440
441   memset(stats, 0, sizeof(MIB_TCPSTATS));
442
443   /* get from /proc/net/snmp, no error if can't */
444   fp = fopen("/proc/net/snmp", "r");
445   if (fp) {
446     static const char hdr[] = "Tcp:";
447     char buf[512] = { 0 }, *ptr;
448
449
450     do {
451       ptr = fgets(buf, sizeof(buf), fp);
452     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
453     if (ptr) {
454       /* last line was a header, get another */
455       ptr = fgets(buf, sizeof(buf), fp);
456       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
457         char *endPtr;
458
459         ptr += sizeof(hdr);
460         if (ptr && *ptr) {
461           stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
462           ptr = endPtr;
463         }
464         if (ptr && *ptr) {
465           stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
466           ptr = endPtr;
467         }
468         if (ptr && *ptr) {
469           stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
470           ptr = endPtr;
471         }
472         if (ptr && *ptr) {
473           stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
474           ptr = endPtr;
475         }
476         if (ptr && *ptr) {
477           stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
478           ptr = endPtr;
479         }
480         if (ptr && *ptr) {
481           stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
482           ptr = endPtr;
483         }
484         if (ptr && *ptr) {
485           stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
486           ptr = endPtr;
487         }
488         if (ptr && *ptr) {
489           stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
490           ptr = endPtr;
491         }
492         if (ptr && *ptr) {
493           stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
494           ptr = endPtr;
495         }
496         if (ptr && *ptr) {
497           stats->dwInSegs = strtoul(ptr, &endPtr, 10);
498           ptr = endPtr;
499         }
500         if (ptr && *ptr) {
501           stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
502           ptr = endPtr;
503         }
504         if (ptr && *ptr) {
505           stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
506           ptr = endPtr;
507         }
508         if (ptr && *ptr) {
509           stats->dwInErrs = strtoul(ptr, &endPtr, 10);
510           ptr = endPtr;
511         }
512         if (ptr && *ptr) {
513           stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
514           ptr = endPtr;
515         }
516         stats->dwNumConns = getNumTcpEntries();
517       }
518     }
519     fclose(fp);
520   }
521   else
522      ERR ("unimplemented!\n");
523
524   return NO_ERROR;
525 }
526
527 DWORD getUDPStats(MIB_UDPSTATS *stats)
528 {
529   FILE *fp;
530
531   if (!stats)
532     return ERROR_INVALID_PARAMETER;
533
534   memset(stats, 0, sizeof(MIB_UDPSTATS));
535
536   /* get from /proc/net/snmp, no error if can't */
537   fp = fopen("/proc/net/snmp", "r");
538   if (fp) {
539     static const char hdr[] = "Udp:";
540     char buf[512] = { 0 }, *ptr;
541
542
543     do {
544       ptr = fgets(buf, sizeof(buf), fp);
545     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
546     if (ptr) {
547       /* last line was a header, get another */
548       ptr = fgets(buf, sizeof(buf), fp);
549       if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
550         char *endPtr;
551
552         ptr += sizeof(hdr);
553         if (ptr && *ptr) {
554           stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
555           ptr = endPtr;
556         }
557         if (ptr && *ptr) {
558           stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
559           ptr = endPtr;
560         }
561         if (ptr && *ptr) {
562           stats->dwInErrors = strtoul(ptr, &endPtr, 10);
563           ptr = endPtr;
564         }
565         if (ptr && *ptr) {
566           stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
567           ptr = endPtr;
568         }
569         if (ptr && *ptr) {
570           stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
571           ptr = endPtr;
572         }
573       }
574     }
575     fclose(fp);
576   }
577   else
578      ERR ("unimplemented!\n");
579
580   return NO_ERROR;
581 }
582
583 static DWORD getNumWithOneHeader(const char *filename)
584 {
585 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
586    size_t Len = 0;
587    char *Buf;
588    struct xinpgen *pXIG, *pOrigXIG;
589    int Protocol;
590    DWORD NumEntries = 0;
591
592    if (!strcmp (filename, "net.inet.tcp.pcblist"))
593       Protocol = IPPROTO_TCP;
594    else if (!strcmp (filename, "net.inet.udp.pcblist"))
595       Protocol = IPPROTO_UDP;
596    else
597    {
598       ERR ("Unsupported mib '%s', needs protocol mapping\n",
599            filename);
600       return 0;
601    }
602
603    if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
604    {
605       WARN ("Unable to read '%s' via sysctlbyname\n", filename);
606       return 0;
607    }
608
609    Buf = HeapAlloc (GetProcessHeap (), 0, Len);
610    if (!Buf)
611    {
612       ERR ("Out of memory!\n");
613       return 0;
614    }
615
616    if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
617    {
618       ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
619       HeapFree (GetProcessHeap (), 0, Buf);
620       return 0;
621    }
622
623    /* Might be nothing here; first entry is just a header it seems */
624    if (Len <= sizeof (struct xinpgen))
625    {
626       HeapFree (GetProcessHeap (), 0, Buf);
627       return 0;
628    }
629
630    pOrigXIG = (struct xinpgen *)Buf;
631    pXIG = pOrigXIG;
632
633    for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
634         pXIG->xig_len > sizeof (struct xinpgen);
635         pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
636    {
637       struct tcpcb *pTCPData = NULL;
638       struct inpcb *pINData;
639       struct xsocket *pSockData;
640
641       if (Protocol == IPPROTO_TCP)
642       {
643          pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
644          pINData = &((struct xtcpcb *)pXIG)->xt_inp;
645          pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
646       }
647       else
648       {
649          pINData = &((struct xinpcb *)pXIG)->xi_inp;
650          pSockData = &((struct xinpcb *)pXIG)->xi_socket;
651       }
652
653       /* Ignore sockets for other protocols */
654       if (pSockData->xso_protocol != Protocol)
655          continue;
656
657       /* Ignore PCBs that were freed while generating the data */
658       if (pINData->inp_gencnt > pOrigXIG->xig_gen)
659          continue;
660
661       /* we're only interested in IPv4 addresses */
662       if (!(pINData->inp_vflag & INP_IPV4) ||
663           (pINData->inp_vflag & INP_IPV6))
664          continue;
665
666       /* If all 0's, skip it */
667       if (!pINData->inp_laddr.s_addr &&
668           !pINData->inp_lport &&
669           !pINData->inp_faddr.s_addr &&
670           !pINData->inp_fport)
671          continue;
672
673       NumEntries++;
674    }
675
676    HeapFree (GetProcessHeap (), 0, Buf);
677    return NumEntries;
678 #else
679   FILE *fp;
680   int ret = 0;
681
682   fp = fopen(filename, "r");
683   if (fp) {
684     char buf[512] = { 0 }, *ptr;
685
686
687     ptr = fgets(buf, sizeof(buf), fp);
688     if (ptr) {
689       do {
690         ptr = fgets(buf, sizeof(buf), fp);
691         if (ptr)
692           ret++;
693       } while (ptr);
694     }
695     fclose(fp);
696   }
697   else
698      ERR ("Unable to open '%s' to count entries!\n", filename);
699
700   return ret;
701 #endif
702 }
703
704 DWORD getNumRoutes(void)
705 {
706 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
707    int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
708    size_t needed;
709    char *buf, *lim, *next;
710    struct rt_msghdr *rtm;
711    DWORD RouteCount = 0;
712
713    if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
714    {
715       ERR ("sysctl 1 failed!\n");
716       return 0;
717    }
718
719    buf = HeapAlloc (GetProcessHeap (), 0, needed);
720    if (!buf) return 0;
721
722    if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
723    {
724       ERR ("sysctl 2 failed!\n");
725       HeapFree (GetProcessHeap (), 0, buf);
726       return 0;
727    }
728
729    lim = buf + needed;
730    for (next = buf; next < lim; next += rtm->rtm_msglen)
731    {
732       rtm = (struct rt_msghdr *)next;
733
734       if (rtm->rtm_type != RTM_GET)
735       {
736          WARN ("Got unexpected message type 0x%x!\n",
737                rtm->rtm_type);
738          continue;
739       }
740
741       /* Ignore all entries except for gateway routes which aren't
742          multicast */
743       if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
744          continue;
745
746       RouteCount++;
747    }
748
749    HeapFree (GetProcessHeap (), 0, buf);
750    return RouteCount;
751 #else
752    return getNumWithOneHeader("/proc/net/route");
753 #endif
754 }
755
756 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
757  DWORD flags)
758 {
759   DWORD ret;
760
761   if (!ppIpForwardTable)
762     ret = ERROR_INVALID_PARAMETER;
763   else {
764     DWORD numRoutes = getNumRoutes();
765     PMIB_IPFORWARDTABLE table = HeapAlloc(heap, flags,
766      sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) * sizeof(MIB_IPFORWARDROW));
767
768     if (table) {
769 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
770        int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
771        size_t needed;
772        char *buf, *lim, *next, *addrPtr;
773        struct rt_msghdr *rtm;
774
775        if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
776        {
777           ERR ("sysctl 1 failed!\n");
778           HeapFree (GetProcessHeap (), 0, table);
779           return NO_ERROR;
780        }
781
782        buf = HeapAlloc (GetProcessHeap (), 0, needed);
783        if (!buf)
784        {
785           HeapFree (GetProcessHeap (), 0, table);
786           return ERROR_OUTOFMEMORY;
787        }
788
789        if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
790        {
791           ERR ("sysctl 2 failed!\n");
792           HeapFree (GetProcessHeap (), 0, table);
793           HeapFree (GetProcessHeap (), 0, buf);
794           return NO_ERROR;
795        }
796
797        *ppIpForwardTable = table;
798        table->dwNumEntries = 0;
799
800        lim = buf + needed;
801        for (next = buf; next < lim; next += rtm->rtm_msglen)
802        {
803           int i;
804
805           rtm = (struct rt_msghdr *)next;
806
807           if (rtm->rtm_type != RTM_GET)
808           {
809              WARN ("Got unexpected message type 0x%x!\n",
810                    rtm->rtm_type);
811              continue;
812           }
813
814           /* Ignore all entries except for gateway routes which aren't
815              multicast */
816           if (!(rtm->rtm_flags & RTF_GATEWAY) ||
817               (rtm->rtm_flags & RTF_MULTICAST))
818              continue;
819
820           memset (&table->table[table->dwNumEntries], 0,
821                   sizeof (MIB_IPFORWARDROW));
822           table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
823           table->table[table->dwNumEntries].dwForwardType =
824              MIB_IPROUTE_TYPE_INDIRECT;
825           table->table[table->dwNumEntries].dwForwardMetric1 =
826              rtm->rtm_rmx.rmx_hopcount;
827           table->table[table->dwNumEntries].dwForwardProto =
828              MIB_IPPROTO_LOCAL;
829
830           addrPtr = (char *)(rtm + 1);
831
832           for (i = 1; i; i <<= 1)
833           {
834              struct sockaddr *sa;
835              DWORD addr;
836
837              if (!(i & rtm->rtm_addrs))
838                 continue;
839
840              sa = (struct sockaddr *)addrPtr;
841              ADVANCE (addrPtr, sa);
842
843              /* default routes are encoded by length-zero sockaddr */
844              if (sa->sa_len == 0)
845                 addr = 0;
846              else if (sa->sa_family != AF_INET)
847              {
848                 ERR ("Received unsupported sockaddr family 0x%x\n",
849                      sa->sa_family);
850                 addr = 0;
851              }
852              else
853              {
854                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
855
856                 addr = sin->sin_addr.s_addr;
857              }
858
859              switch (i)
860              {
861                 case RTA_DST:
862                    table->table[table->dwNumEntries].dwForwardDest = addr;
863                    break;
864
865                 case RTA_GATEWAY:
866                    table->table[table->dwNumEntries].dwForwardNextHop = addr;
867                    break;
868
869                 case RTA_NETMASK:
870                    table->table[table->dwNumEntries].dwForwardMask = addr;
871                    break;
872
873                 default:
874                    ERR ("Unexpected address type 0x%x\n", i);
875              }
876           }
877
878           table->dwNumEntries++;
879        }
880
881        HeapFree (GetProcessHeap (), 0, buf);
882        ret = NO_ERROR;
883 #else
884       FILE *fp;
885
886       ret = NO_ERROR;
887       *ppIpForwardTable = table;
888       table->dwNumEntries = 0;
889       /* get from /proc/net/route, no error if can't */
890       fp = fopen("/proc/net/route", "r");
891       if (fp) {
892         char buf[512] = { 0 }, *ptr;
893
894         /* skip header line */
895         ptr = fgets(buf, sizeof(buf), fp);
896         while (ptr && table->dwNumEntries < numRoutes) {
897           memset(&table->table[table->dwNumEntries], 0,
898            sizeof(MIB_IPFORWARDROW));
899           ptr = fgets(buf, sizeof(buf), fp);
900           if (ptr) {
901             DWORD index;
902
903             while (!isspace(*ptr))
904               ptr++;
905             *ptr = '\0';
906             ptr++;
907             if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
908               char *endPtr;
909
910               table->table[table->dwNumEntries].dwForwardIfIndex = index;
911               if (*ptr) {
912                 table->table[table->dwNumEntries].dwForwardDest =
913                  strtoul(ptr, &endPtr, 16);
914                 ptr = endPtr;
915               }
916               if (ptr && *ptr) {
917                 table->table[table->dwNumEntries].dwForwardNextHop =
918                  strtoul(ptr, &endPtr, 16);
919                 ptr = endPtr;
920               }
921               if (ptr && *ptr) {
922                 DWORD flags = strtoul(ptr, &endPtr, 16);
923
924                 if (!(flags & RTF_UP))
925                   table->table[table->dwNumEntries].dwForwardType =
926                    MIB_IPROUTE_TYPE_INVALID;
927                 else if (flags & RTF_GATEWAY)
928                   table->table[table->dwNumEntries].dwForwardType =
929                    MIB_IPROUTE_TYPE_INDIRECT;
930                 else
931                   table->table[table->dwNumEntries].dwForwardType =
932                    MIB_IPROUTE_TYPE_DIRECT;
933                 ptr = endPtr;
934               }
935               if (ptr && *ptr) {
936                 strtoul(ptr, &endPtr, 16); /* refcount, skip */
937                 ptr = endPtr;
938               }
939               if (ptr && *ptr) {
940                 strtoul(ptr, &endPtr, 16); /* use, skip */
941                 ptr = endPtr;
942               }
943               if (ptr && *ptr) {
944                 table->table[table->dwNumEntries].dwForwardMetric1 =
945                  strtoul(ptr, &endPtr, 16);
946                 ptr = endPtr;
947               }
948               if (ptr && *ptr) {
949                 table->table[table->dwNumEntries].dwForwardMask =
950                  strtoul(ptr, &endPtr, 16);
951                 ptr = endPtr;
952               }
953               /* FIXME: other protos might be appropriate, e.g. the default
954                * route is typically set with MIB_IPPROTO_NETMGMT instead */
955               table->table[table->dwNumEntries].dwForwardProto =
956                MIB_IPPROTO_LOCAL;
957               table->dwNumEntries++;
958             }
959           }
960         }
961         fclose(fp);
962       }
963       else
964       {
965         ERR ("unimplemented!\n");
966         return ERROR_INVALID_PARAMETER;
967       }
968 #endif
969     }
970     else
971       ret = ERROR_OUTOFMEMORY;
972   }
973   return ret;
974 }
975
976 DWORD getNumArpEntries(void)
977 {
978   return getNumWithOneHeader("/proc/net/arp");
979 }
980
981 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
982 {
983   DWORD ret;
984
985 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
986   ERR ("unimplemented!\n");
987   return ERROR_INVALID_PARAMETER;
988 #endif
989
990   if (!ppIpNetTable)
991     ret = ERROR_INVALID_PARAMETER;
992   else {
993     DWORD numEntries = getNumArpEntries();
994     PMIB_IPNETTABLE table = HeapAlloc(heap, flags,
995      sizeof(MIB_IPNETTABLE) + (numEntries - 1) * sizeof(MIB_IPNETROW));
996
997     if (table) {
998       FILE *fp;
999
1000       ret = NO_ERROR;
1001       *ppIpNetTable = table;
1002       table->dwNumEntries = 0;
1003       /* get from /proc/net/arp, no error if can't */
1004       fp = fopen("/proc/net/arp", "r");
1005       if (fp) {
1006         char buf[512] = { 0 }, *ptr;
1007
1008         /* skip header line */
1009         ptr = fgets(buf, sizeof(buf), fp);
1010         while (ptr && table->dwNumEntries < numEntries) {
1011           ptr = fgets(buf, sizeof(buf), fp);
1012           if (ptr) {
1013             char *endPtr;
1014
1015             memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1016             table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1017             while (ptr && *ptr && !isspace(*ptr))
1018               ptr++;
1019
1020             if (ptr && *ptr) {
1021               strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1022               ptr = endPtr;
1023             }
1024             if (ptr && *ptr) {
1025               DWORD flags = strtoul(ptr, &endPtr, 16);
1026
1027 #ifdef ATF_COM
1028               if (flags & ATF_COM)
1029                 table->table[table->dwNumEntries].dwType =
1030                  MIB_IPNET_TYPE_DYNAMIC;
1031               else
1032 #endif
1033 #ifdef ATF_PERM
1034               if (flags & ATF_PERM)
1035                 table->table[table->dwNumEntries].dwType =
1036                  MIB_IPNET_TYPE_STATIC;
1037               else
1038 #endif
1039                 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1040
1041               ptr = endPtr;
1042             }
1043             while (ptr && *ptr && isspace(*ptr))
1044               ptr++;
1045             while (ptr && *ptr && !isspace(*ptr)) {
1046               DWORD byte = strtoul(ptr, &endPtr, 16);
1047
1048               if (endPtr && *endPtr) {
1049                 endPtr++;
1050                 table->table[table->dwNumEntries].bPhysAddr[
1051                  table->table[table->dwNumEntries].dwPhysAddrLen++] =
1052                  byte & 0x0ff;
1053               }
1054               ptr = endPtr;
1055             }
1056             if (ptr && *ptr) {
1057               strtoul(ptr, &endPtr, 16); /* mask (skip) */
1058               ptr = endPtr;
1059             }
1060             getInterfaceIndexByName(ptr,
1061              &table->table[table->dwNumEntries].dwIndex);
1062             table->dwNumEntries++;
1063           }
1064         }
1065         fclose(fp);
1066       }
1067     }
1068     else
1069       ret = ERROR_OUTOFMEMORY;
1070   }
1071   return ret;
1072 }
1073
1074 DWORD getNumUdpEntries(void)
1075 {
1076   return getNumWithOneHeader("/proc/net/udp");
1077 }
1078
1079 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1080 {
1081   DWORD ret;
1082
1083 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1084   ERR ("unimplemented!\n");
1085   return ERROR_INVALID_PARAMETER;
1086 #endif
1087
1088   if (!ppUdpTable)
1089     ret = ERROR_INVALID_PARAMETER;
1090   else {
1091     DWORD numEntries = getNumUdpEntries();
1092     PMIB_UDPTABLE table = HeapAlloc(heap, flags,
1093      sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW));
1094
1095     if (table) {
1096       FILE *fp;
1097
1098       ret = NO_ERROR;
1099       *ppUdpTable = table;
1100       table->dwNumEntries = 0;
1101       /* get from /proc/net/udp, no error if can't */
1102       fp = fopen("/proc/net/udp", "r");
1103       if (fp) {
1104         char buf[512] = { 0 }, *ptr;
1105
1106         /* skip header line */
1107         ptr = fgets(buf, sizeof(buf), fp);
1108         while (ptr && table->dwNumEntries < numEntries) {
1109           memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1110           ptr = fgets(buf, sizeof(buf), fp);
1111           if (ptr) {
1112             char *endPtr;
1113
1114             if (ptr && *ptr) {
1115               strtoul(ptr, &endPtr, 16); /* skip */
1116               ptr = endPtr;
1117             }
1118             if (ptr && *ptr) {
1119               ptr++;
1120               table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1121                &endPtr, 16);
1122               ptr = endPtr;
1123             }
1124             if (ptr && *ptr) {
1125               ptr++;
1126               table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1127                &endPtr, 16);
1128               ptr = endPtr;
1129             }
1130             table->dwNumEntries++;
1131           }
1132         }
1133         fclose(fp);
1134       }
1135     }
1136     else
1137       ret = ERROR_OUTOFMEMORY;
1138   }
1139   return ret;
1140 }
1141
1142
1143 DWORD getNumTcpEntries(void)
1144 {
1145 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1146    return getNumWithOneHeader ("net.inet.tcp.pcblist");
1147 #else
1148    return getNumWithOneHeader ("/proc/net/tcp");
1149 #endif
1150 }
1151
1152
1153 /* Why not a lookup table? Because the TCPS_* constants are different
1154    on different platforms */
1155 static DWORD TCPStateToMIBState (int state)
1156 {
1157    switch (state)
1158    {
1159       case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1160       case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1161       case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1162       case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1163       case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1164       case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1165       case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1166       case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1167       case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1168       case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1169       default:
1170       case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1171    }
1172 }
1173
1174
1175 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1176                   DWORD flags)
1177 {
1178    DWORD numEntries;
1179    PMIB_TCPTABLE table;
1180 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1181    size_t Len = 0;
1182    char *Buf;
1183    struct xinpgen *pXIG, *pOrigXIG;
1184 #else
1185    FILE *fp;
1186    char buf[512] = { 0 }, *ptr;
1187 #endif
1188
1189    if (!ppTcpTable)
1190       return ERROR_INVALID_PARAMETER;
1191
1192    numEntries = getNumTcpEntries ();
1193
1194    if (!*ppTcpTable)
1195    {
1196       *ppTcpTable = HeapAlloc (heap, flags,
1197                                sizeof (MIB_TCPTABLE) +
1198                                (numEntries - 1) * sizeof (MIB_TCPROW));
1199       if (!*ppTcpTable)
1200       {
1201          ERR ("Out of memory!\n");
1202          return ERROR_OUTOFMEMORY;
1203       }
1204       maxEntries = numEntries;
1205    }
1206
1207    table = *ppTcpTable;
1208    table->dwNumEntries = 0;
1209    if (!numEntries)
1210       return NO_ERROR;
1211
1212 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1213
1214    if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1215    {
1216       ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1217       return ERROR_OUTOFMEMORY;
1218    }
1219
1220    Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1221    if (!Buf)
1222    {
1223       ERR ("Out of memory!\n");
1224       return ERROR_OUTOFMEMORY;
1225    }
1226
1227    if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1228    {
1229       ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1230       HeapFree (GetProcessHeap (), 0, Buf);
1231       return ERROR_OUTOFMEMORY;
1232    }
1233
1234    /* Might be nothing here; first entry is just a header it seems */
1235    if (Len <= sizeof (struct xinpgen))
1236    {
1237       HeapFree (GetProcessHeap (), 0, Buf);
1238       return NO_ERROR;
1239    }
1240
1241    pOrigXIG = (struct xinpgen *)Buf;
1242    pXIG = pOrigXIG;
1243
1244    for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1245         (pXIG->xig_len > sizeof (struct xinpgen)) &&
1246            (table->dwNumEntries < maxEntries);
1247         pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1248    {
1249       struct tcpcb *pTCPData = NULL;
1250       struct inpcb *pINData;
1251       struct xsocket *pSockData;
1252
1253       pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1254       pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1255       pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1256
1257       /* Ignore sockets for other protocols */
1258       if (pSockData->xso_protocol != IPPROTO_TCP)
1259          continue;
1260
1261       /* Ignore PCBs that were freed while generating the data */
1262       if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1263          continue;
1264
1265       /* we're only interested in IPv4 addresses */
1266       if (!(pINData->inp_vflag & INP_IPV4) ||
1267           (pINData->inp_vflag & INP_IPV6))
1268          continue;
1269
1270       /* If all 0's, skip it */
1271       if (!pINData->inp_laddr.s_addr &&
1272           !pINData->inp_lport &&
1273           !pINData->inp_faddr.s_addr &&
1274           !pINData->inp_fport)
1275          continue;
1276
1277       /* Fill in structure details */
1278       table->table[table->dwNumEntries].dwLocalAddr =
1279          pINData->inp_laddr.s_addr;
1280       table->table[table->dwNumEntries].dwLocalPort =
1281          pINData->inp_lport;
1282       table->table[table->dwNumEntries].dwRemoteAddr =
1283          pINData->inp_faddr.s_addr;
1284       table->table[table->dwNumEntries].dwRemotePort =
1285          pINData->inp_fport;
1286       table->table[table->dwNumEntries].dwState =
1287          TCPStateToMIBState (pTCPData->t_state);
1288
1289       table->dwNumEntries++;
1290    }
1291
1292    HeapFree (GetProcessHeap (), 0, Buf);
1293 #else
1294    /* get from /proc/net/tcp, no error if can't */
1295    fp = fopen("/proc/net/tcp", "r");
1296    if (!fp)
1297       return NO_ERROR;
1298
1299    /* skip header line */
1300    ptr = fgets(buf, sizeof(buf), fp);
1301    while (ptr && table->dwNumEntries < maxEntries) {
1302       memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1303       ptr = fgets(buf, sizeof(buf), fp);
1304       if (ptr) {
1305          char *endPtr;
1306
1307          while (ptr && *ptr && *ptr != ':')
1308             ptr++;
1309          if (ptr && *ptr)
1310             ptr++;
1311          if (ptr && *ptr) {
1312             table->table[table->dwNumEntries].dwLocalAddr =
1313                strtoul(ptr, &endPtr, 16);
1314             ptr = endPtr;
1315          }
1316          if (ptr && *ptr) {
1317             ptr++;
1318             table->table[table->dwNumEntries].dwLocalPort =
1319                htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1320             ptr = endPtr;
1321          }
1322          if (ptr && *ptr) {
1323             table->table[table->dwNumEntries].dwRemoteAddr =
1324                strtoul(ptr, &endPtr, 16);
1325             ptr = endPtr;
1326          }
1327          if (ptr && *ptr) {
1328             ptr++;
1329             table->table[table->dwNumEntries].dwRemotePort =
1330                htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1331             ptr = endPtr;
1332          }
1333          if (ptr && *ptr) {
1334             DWORD state = strtoul(ptr, &endPtr, 16);
1335
1336             table->table[table->dwNumEntries].dwState =
1337                TCPStateToMIBState (state);
1338             ptr = endPtr;
1339          }
1340          table->dwNumEntries++;
1341       }
1342    }
1343    fclose(fp);
1344 #endif
1345
1346    return NO_ERROR;
1347 }