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