iphlpapi: #define RTF_LLINFO if not in system headers.
[wine/hacks.git] / dlls / iphlpapi / ipstats.c
blob75d4611a5dbf76912177caf0072654589880f973
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.
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_ALIAS_H
32 #include <alias.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_SYS_SOCKETVAR_H
38 #include <sys/socketvar.h>
39 #endif
40 #ifdef HAVE_SYS_TIMEOUT_H
41 #include <sys/timeout.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_SYSTM_H
47 #include <netinet/in_systm.h>
48 #endif
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NET_IF_H
53 #include <net/if.h>
54 #endif
55 #ifdef HAVE_NET_IF_DL_H
56 #include <net/if_dl.h>
57 #endif
58 #ifdef HAVE_NET_IF_TYPES_H
59 #include <net/if_types.h>
60 #endif
61 #ifdef HAVE_NET_ROUTE_H
62 #include <net/route.h>
63 #endif
64 #ifdef HAVE_NET_IF_ARP_H
65 #include <net/if_arp.h>
66 #endif
67 #ifdef HAVE_NETINET_IF_ETHER_H
68 #include <netinet/if_ether.h>
69 #endif
70 #ifdef HAVE_NETINET_IF_INARP_H
71 #include <netinet/if_inarp.h>
72 #endif
73 #ifdef HAVE_NETINET_IP_H
74 #include <netinet/ip.h>
75 #endif
76 #ifdef HAVE_NETINET_TCP_H
77 #include <netinet/tcp.h>
78 #endif
79 #ifdef HAVE_NETINET_IP_VAR_H
80 #include <netinet/ip_var.h>
81 #endif
82 #ifdef HAVE_NETINET_TCP_FSM_H
83 #include <netinet/tcp_fsm.h>
84 #endif
85 #ifdef HAVE_NETINET_IN_PCB_H
86 #include <netinet/in_pcb.h>
87 #endif
88 #ifdef HAVE_NETINET_TCP_TIMER_H
89 #include <netinet/tcp_timer.h>
90 #endif
91 #ifdef HAVE_NETINET_TCP_VAR_H
92 #include <netinet/tcp_var.h>
93 #endif
94 #ifdef HAVE_NETINET_IP_ICMP_H
95 #include <netinet/ip_icmp.h>
96 #endif
97 #ifdef HAVE_NETINET_ICMP_VAR_H
98 #include <netinet/icmp_var.h>
99 #endif
100 #ifdef HAVE_NETINET_UDP_H
101 #include <netinet/udp.h>
102 #endif
103 #ifdef HAVE_NETINET_UDP_VAR_H
104 #include <netinet/udp_var.h>
105 #endif
106 #ifdef HAVE_SYS_PROTOSW_H
107 #include <sys/protosw.h>
108 #endif
109 #ifdef HAVE_SYS_SYSCTL_H
110 #include <sys/sysctl.h>
111 #endif
113 #ifndef ROUNDUP
114 #define ROUNDUP(a) \
115 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
116 #endif
117 #ifndef ADVANCE
118 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
119 #endif
121 #include "windef.h"
122 #include "winbase.h"
123 #include "iprtrmib.h"
124 #include "ifenum.h"
125 #include "ipstats.h"
127 #ifndef HAVE_NETINET_TCP_FSM_H
128 #define TCPS_ESTABLISHED 1
129 #define TCPS_SYN_SENT 2
130 #define TCPS_SYN_RECEIVED 3
131 #define TCPS_FIN_WAIT_1 4
132 #define TCPS_FIN_WAIT_2 5
133 #define TCPS_TIME_WAIT 6
134 #define TCPS_CLOSED 7
135 #define TCPS_CLOSE_WAIT 8
136 #define TCPS_LAST_ACK 9
137 #define TCPS_LISTEN 10
138 #define TCPS_CLOSING 11
139 #endif
141 #ifndef RTF_MULTICAST
142 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
143 #endif
145 #ifndef RTF_LLINFO
146 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
147 #endif
149 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
151 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
153 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
154 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
155 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
157 size_t needed;
158 char *buf, *end;
159 struct if_msghdr *ifm;
160 struct if_data ifdata;
161 if (!name || !entry)
162 return ERROR_INVALID_PARAMETER;
164 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
166 ERR ("failed to get size of iflist\n");
167 return ERROR_NOT_SUPPORTED;
169 buf = HeapAlloc (GetProcessHeap (), 0, needed);
170 if (!buf) return ERROR_NOT_SUPPORTED;
171 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
173 ERR ("failed to get iflist\n");
174 HeapFree (GetProcessHeap (), 0, buf);
175 return ERROR_NOT_SUPPORTED;
177 else
178 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
180 ifm = (struct if_msghdr *) buf;
181 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
183 ifdata = ifm->ifm_data;
184 entry->dwMtu = ifdata.ifi_mtu;
185 entry->dwSpeed = ifdata.ifi_baudrate;
186 entry->dwInOctets = ifdata.ifi_ibytes;
187 entry->dwInErrors = ifdata.ifi_ierrors;
188 entry->dwInDiscards = ifdata.ifi_iqdrops;
189 entry->dwInUcastPkts = ifdata.ifi_ipackets;
190 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
191 entry->dwOutOctets = ifdata.ifi_obytes;
192 entry->dwOutUcastPkts = ifdata.ifi_opackets;
193 entry->dwOutErrors = ifdata.ifi_oerrors;
194 HeapFree (GetProcessHeap (), 0, buf);
195 return NO_ERROR;
198 HeapFree (GetProcessHeap (), 0, buf);
199 return ERROR_NOT_SUPPORTED;
200 #else
201 /* get interface stats from /proc/net/dev, no error if can't
202 no inUnknownProtos, outNUcastPkts, outQLen */
203 FILE *fp;
205 if (!name || !entry)
206 return ERROR_INVALID_PARAMETER;
207 fp = fopen("/proc/net/dev", "r");
208 if (fp) {
209 char buf[512] = { 0 }, *ptr;
210 int nameLen = strlen(name), nameFound = 0;
213 ptr = fgets(buf, sizeof(buf), fp);
214 while (ptr && !nameFound) {
215 while (*ptr && isspace(*ptr))
216 ptr++;
217 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
218 nameFound = 1;
219 else
220 ptr = fgets(buf, sizeof(buf), fp);
222 if (nameFound) {
223 char *endPtr;
225 ptr += nameLen + 1;
226 if (ptr && *ptr) {
227 entry->dwInOctets = strtoul(ptr, &endPtr, 10);
228 ptr = endPtr;
230 if (ptr && *ptr) {
231 entry->dwInUcastPkts = strtoul(ptr, &endPtr, 10);
232 ptr = endPtr;
234 if (ptr && *ptr) {
235 entry->dwInErrors = strtoul(ptr, &endPtr, 10);
236 ptr = endPtr;
238 if (ptr && *ptr) {
239 entry->dwInDiscards = strtoul(ptr, &endPtr, 10);
240 ptr = endPtr;
242 if (ptr && *ptr) {
243 strtoul(ptr, &endPtr, 10); /* skip */
244 ptr = endPtr;
246 if (ptr && *ptr) {
247 strtoul(ptr, &endPtr, 10); /* skip */
248 ptr = endPtr;
250 if (ptr && *ptr) {
251 strtoul(ptr, &endPtr, 10); /* skip */
252 ptr = endPtr;
254 if (ptr && *ptr) {
255 entry->dwInNUcastPkts = strtoul(ptr, &endPtr, 10);
256 ptr = endPtr;
258 if (ptr && *ptr) {
259 entry->dwOutOctets = strtoul(ptr, &endPtr, 10);
260 ptr = endPtr;
262 if (ptr && *ptr) {
263 entry->dwOutUcastPkts = strtoul(ptr, &endPtr, 10);
264 ptr = endPtr;
266 if (ptr && *ptr) {
267 entry->dwOutErrors = strtoul(ptr, &endPtr, 10);
268 ptr = endPtr;
270 if (ptr && *ptr) {
271 entry->dwOutDiscards = strtoul(ptr, &endPtr, 10);
272 ptr = endPtr;
275 fclose(fp);
277 else
279 ERR ("unimplemented!\n");
280 return ERROR_NOT_SUPPORTED;
283 return NO_ERROR;
284 #endif
287 DWORD getICMPStats(MIB_ICMP *stats)
289 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
290 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
291 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
292 size_t needed;
293 struct icmpstat icmp_stat;
294 int i;
296 if (!stats)
297 return ERROR_INVALID_PARAMETER;
299 needed = sizeof(icmp_stat);
300 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) == -1)
302 ERR ("failed to get icmpstat\n");
303 return ERROR_NOT_SUPPORTED;
307 /*in stats */
308 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
309 for(i = 0; i <= ICMP_MAXTYPE; i++)
310 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
312 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
314 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
315 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
316 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
317 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
318 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
319 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
320 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
321 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
322 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
323 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
324 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
327 /* out stats */
328 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
329 for(i = 0; i <= ICMP_MAXTYPE; i++)
330 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
332 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
334 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
335 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
336 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
337 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
338 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
339 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
340 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
341 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
342 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
343 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
344 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
346 return NO_ERROR;
347 #else
348 FILE *fp;
350 if (!stats)
351 return ERROR_INVALID_PARAMETER;
353 memset(stats, 0, sizeof(MIB_ICMP));
354 /* get most of these stats from /proc/net/snmp, no error if can't */
355 fp = fopen("/proc/net/snmp", "r");
356 if (fp) {
357 static const char hdr[] = "Icmp:";
358 char buf[512] = { 0 }, *ptr;
360 do {
361 ptr = fgets(buf, sizeof(buf), fp);
362 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
363 if (ptr) {
364 /* last line was a header, get another */
365 ptr = fgets(buf, sizeof(buf), fp);
366 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
367 char *endPtr;
369 ptr += sizeof(hdr);
370 if (ptr && *ptr) {
371 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
372 ptr = endPtr;
374 if (ptr && *ptr) {
375 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
376 ptr = endPtr;
378 if (ptr && *ptr) {
379 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
380 ptr = endPtr;
382 if (ptr && *ptr) {
383 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
384 ptr = endPtr;
386 if (ptr && *ptr) {
387 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
388 ptr = endPtr;
390 if (ptr && *ptr) {
391 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
392 ptr = endPtr;
394 if (ptr && *ptr) {
395 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
396 ptr = endPtr;
398 if (ptr && *ptr) {
399 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
400 ptr = endPtr;
402 if (ptr && *ptr) {
403 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
404 ptr = endPtr;
406 if (ptr && *ptr) {
407 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
408 ptr = endPtr;
410 if (ptr && *ptr) {
411 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
412 ptr = endPtr;
414 if (ptr && *ptr) {
415 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
416 ptr = endPtr;
418 if (ptr && *ptr) {
419 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
420 ptr = endPtr;
422 if (ptr && *ptr) {
423 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
424 ptr = endPtr;
426 if (ptr && *ptr) {
427 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
428 ptr = endPtr;
430 if (ptr && *ptr) {
431 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
432 ptr = endPtr;
434 if (ptr && *ptr) {
435 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
436 ptr = endPtr;
438 if (ptr && *ptr) {
439 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
440 ptr = endPtr;
442 if (ptr && *ptr) {
443 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
444 ptr = endPtr;
446 if (ptr && *ptr) {
447 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
448 ptr = endPtr;
450 if (ptr && *ptr) {
451 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
452 ptr = endPtr;
454 if (ptr && *ptr) {
455 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
456 ptr = endPtr;
458 if (ptr && *ptr) {
459 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
460 ptr = endPtr;
462 if (ptr && *ptr) {
463 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
464 ptr = endPtr;
468 fclose(fp);
470 else
472 ERR ("unimplemented!\n");
473 return ERROR_NOT_SUPPORTED;
476 return NO_ERROR;
477 #endif
480 DWORD getIPStats(PMIB_IPSTATS stats)
482 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
483 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
484 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
485 int ip_ttl, ip_forwarding;
486 struct ipstat ip_stat;
487 size_t needed;
489 if (!stats)
490 return ERROR_INVALID_PARAMETER;
492 needed = sizeof(ip_stat);
493 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
495 ERR ("failed to get ipstat\n");
496 return ERROR_NOT_SUPPORTED;
499 needed = sizeof(ip_ttl);
500 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
502 ERR ("failed to get ip Default TTL\n");
503 return ERROR_NOT_SUPPORTED;
506 needed = sizeof(ip_forwarding);
507 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
509 ERR ("failed to get ip forwarding\n");
510 return ERROR_NOT_SUPPORTED;
513 stats->dwForwarding = ip_forwarding;
514 stats->dwDefaultTTL = ip_ttl;
515 stats->dwInDelivers = ip_stat.ips_delivered;
516 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
517 stats->dwInAddrErrors = ip_stat.ips_cantforward;
518 stats->dwInReceives = ip_stat.ips_total;
519 stats->dwForwDatagrams = ip_stat.ips_forward;
520 stats->dwInUnknownProtos = ip_stat.ips_noproto;
521 stats->dwInDiscards = ip_stat.ips_fragdropped;
522 stats->dwOutDiscards = ip_stat.ips_odropped;
523 stats->dwReasmOks = ip_stat.ips_reassembled;
524 stats->dwFragOks = ip_stat.ips_fragmented;
525 stats->dwFragFails = ip_stat.ips_cantfrag;
526 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
527 stats->dwOutNoRoutes = ip_stat.ips_noroute;
528 stats->dwOutRequests = ip_stat.ips_localout;
529 stats->dwReasmReqds = ip_stat.ips_fragments;
531 return NO_ERROR;
532 #else
533 FILE *fp;
535 if (!stats)
536 return ERROR_INVALID_PARAMETER;
538 memset(stats, 0, sizeof(MIB_IPSTATS));
539 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
540 stats->dwNumRoutes = getNumRoutes();
542 /* get most of these stats from /proc/net/snmp, no error if can't */
543 fp = fopen("/proc/net/snmp", "r");
544 if (fp) {
545 static const char hdr[] = "Ip:";
546 char buf[512] = { 0 }, *ptr;
548 do {
549 ptr = fgets(buf, sizeof(buf), fp);
550 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
551 if (ptr) {
552 /* last line was a header, get another */
553 ptr = fgets(buf, sizeof(buf), fp);
554 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
555 char *endPtr;
557 ptr += sizeof(hdr);
558 if (ptr && *ptr) {
559 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
560 ptr = endPtr;
562 if (ptr && *ptr) {
563 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
564 ptr = endPtr;
566 if (ptr && *ptr) {
567 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
568 ptr = endPtr;
570 if (ptr && *ptr) {
571 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
572 ptr = endPtr;
574 if (ptr && *ptr) {
575 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
576 ptr = endPtr;
578 if (ptr && *ptr) {
579 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
580 ptr = endPtr;
582 if (ptr && *ptr) {
583 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
584 ptr = endPtr;
586 if (ptr && *ptr) {
587 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
588 ptr = endPtr;
590 if (ptr && *ptr) {
591 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
592 ptr = endPtr;
594 if (ptr && *ptr) {
595 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
596 ptr = endPtr;
598 if (ptr && *ptr) {
599 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
600 ptr = endPtr;
602 if (ptr && *ptr) {
603 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
604 ptr = endPtr;
606 if (ptr && *ptr) {
607 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
608 ptr = endPtr;
610 if (ptr && *ptr) {
611 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
612 ptr = endPtr;
614 if (ptr && *ptr) {
615 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
616 ptr = endPtr;
618 if (ptr && *ptr) {
619 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
620 ptr = endPtr;
622 if (ptr && *ptr) {
623 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
624 ptr = endPtr;
626 if (ptr && *ptr) {
627 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
628 ptr = endPtr;
630 if (ptr && *ptr) {
631 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
632 ptr = endPtr;
634 /* hmm, no routingDiscards */
637 fclose(fp);
639 else
641 ERR ("unimplemented!\n");
642 return ERROR_NOT_SUPPORTED;
645 return NO_ERROR;
646 #endif
649 DWORD getTCPStats(MIB_TCPSTATS *stats)
651 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
652 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
653 #define TCPTV_MIN 2
654 #define TCPTV_REXMTMAX 128
655 #endif
656 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
657 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
658 #define hz 1000
659 struct tcpstat tcp_stat;
660 size_t needed;
662 if (!stats)
663 return ERROR_INVALID_PARAMETER;
664 needed = sizeof(tcp_stat);
666 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
668 ERR ("failed to get tcpstat\n");
669 return ERROR_NOT_SUPPORTED;
672 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
673 stats->dwRtoMin = TCPTV_MIN;
674 stats->dwRtoMax = TCPTV_REXMTMAX;
675 stats->dwMaxConn = -1;
676 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
677 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
678 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
679 stats->dwEstabResets = tcp_stat.tcps_drops;
680 stats->dwCurrEstab = 0;
681 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
682 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
683 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
684 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
685 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
686 stats->dwNumConns = tcp_stat.tcps_connects;
688 return NO_ERROR;
690 #else
691 FILE *fp;
693 if (!stats)
694 return ERROR_INVALID_PARAMETER;
696 memset(stats, 0, sizeof(MIB_TCPSTATS));
698 /* get from /proc/net/snmp, no error if can't */
699 fp = fopen("/proc/net/snmp", "r");
700 if (fp) {
701 static const char hdr[] = "Tcp:";
702 char buf[512] = { 0 }, *ptr;
705 do {
706 ptr = fgets(buf, sizeof(buf), fp);
707 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
708 if (ptr) {
709 /* last line was a header, get another */
710 ptr = fgets(buf, sizeof(buf), fp);
711 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
712 char *endPtr;
714 ptr += sizeof(hdr);
715 if (ptr && *ptr) {
716 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
717 ptr = endPtr;
719 if (ptr && *ptr) {
720 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
721 ptr = endPtr;
723 if (ptr && *ptr) {
724 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
725 ptr = endPtr;
727 if (ptr && *ptr) {
728 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
729 ptr = endPtr;
731 if (ptr && *ptr) {
732 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
733 ptr = endPtr;
735 if (ptr && *ptr) {
736 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
737 ptr = endPtr;
739 if (ptr && *ptr) {
740 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
741 ptr = endPtr;
743 if (ptr && *ptr) {
744 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
745 ptr = endPtr;
747 if (ptr && *ptr) {
748 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
749 ptr = endPtr;
751 if (ptr && *ptr) {
752 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
753 ptr = endPtr;
755 if (ptr && *ptr) {
756 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
757 ptr = endPtr;
759 if (ptr && *ptr) {
760 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
761 ptr = endPtr;
763 if (ptr && *ptr) {
764 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
765 ptr = endPtr;
767 if (ptr && *ptr) {
768 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
769 ptr = endPtr;
771 stats->dwNumConns = getNumTcpEntries();
774 fclose(fp);
776 else
778 ERR ("unimplemented!\n");
779 return ERROR_NOT_SUPPORTED;
782 return NO_ERROR;
783 #endif
786 DWORD getUDPStats(MIB_UDPSTATS *stats)
788 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
789 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
790 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
791 struct udpstat udp_stat;
792 size_t needed;
793 if (!stats)
794 return ERROR_INVALID_PARAMETER;
796 needed = sizeof(udp_stat);
798 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
800 ERR ("failed to get udpstat\n");
801 return ERROR_NOT_SUPPORTED;
804 stats->dwInDatagrams = udp_stat.udps_ipackets;
805 stats->dwOutDatagrams = udp_stat.udps_opackets;
806 stats->dwNoPorts = udp_stat.udps_noport;
807 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
808 stats->dwNumAddrs = getNumUdpEntries();
810 return NO_ERROR;
811 #else
812 FILE *fp;
814 if (!stats)
815 return ERROR_INVALID_PARAMETER;
817 memset(stats, 0, sizeof(MIB_UDPSTATS));
819 /* get from /proc/net/snmp, no error if can't */
820 fp = fopen("/proc/net/snmp", "r");
821 if (fp) {
822 static const char hdr[] = "Udp:";
823 char buf[512] = { 0 }, *ptr;
826 do {
827 ptr = fgets(buf, sizeof(buf), fp);
828 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
829 if (ptr) {
830 /* last line was a header, get another */
831 ptr = fgets(buf, sizeof(buf), fp);
832 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
833 char *endPtr;
835 ptr += sizeof(hdr);
836 if (ptr && *ptr) {
837 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
838 ptr = endPtr;
840 if (ptr && *ptr) {
841 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
842 ptr = endPtr;
844 if (ptr && *ptr) {
845 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
846 ptr = endPtr;
848 if (ptr && *ptr) {
849 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
850 ptr = endPtr;
852 if (ptr && *ptr) {
853 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
854 ptr = endPtr;
858 fclose(fp);
860 else
862 ERR ("unimplemented!\n");
863 return ERROR_NOT_SUPPORTED;
866 return NO_ERROR;
867 #endif
870 static DWORD getNumWithOneHeader(const char *filename)
872 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
873 size_t Len = 0;
874 char *Buf;
875 struct xinpgen *pXIG, *pOrigXIG;
876 int Protocol;
877 DWORD NumEntries = 0;
879 if (!strcmp (filename, "net.inet.tcp.pcblist"))
880 Protocol = IPPROTO_TCP;
881 else if (!strcmp (filename, "net.inet.udp.pcblist"))
882 Protocol = IPPROTO_UDP;
883 else
885 ERR ("Unsupported mib '%s', needs protocol mapping\n",
886 filename);
887 return 0;
890 if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
892 WARN ("Unable to read '%s' via sysctlbyname\n", filename);
893 return 0;
896 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
897 if (!Buf)
899 ERR ("Out of memory!\n");
900 return 0;
903 if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
905 ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
906 HeapFree (GetProcessHeap (), 0, Buf);
907 return 0;
910 /* Might be nothing here; first entry is just a header it seems */
911 if (Len <= sizeof (struct xinpgen))
913 HeapFree (GetProcessHeap (), 0, Buf);
914 return 0;
917 pOrigXIG = (struct xinpgen *)Buf;
918 pXIG = pOrigXIG;
920 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
921 pXIG->xig_len > sizeof (struct xinpgen);
922 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
924 struct tcpcb *pTCPData = NULL;
925 struct inpcb *pINData;
926 struct xsocket *pSockData;
928 if (Protocol == IPPROTO_TCP)
930 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
931 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
932 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
934 else
936 pINData = &((struct xinpcb *)pXIG)->xi_inp;
937 pSockData = &((struct xinpcb *)pXIG)->xi_socket;
940 /* Ignore sockets for other protocols */
941 if (pSockData->xso_protocol != Protocol)
942 continue;
944 /* Ignore PCBs that were freed while generating the data */
945 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
946 continue;
948 /* we're only interested in IPv4 addresses */
949 if (!(pINData->inp_vflag & INP_IPV4) ||
950 (pINData->inp_vflag & INP_IPV6))
951 continue;
953 /* If all 0's, skip it */
954 if (!pINData->inp_laddr.s_addr &&
955 !pINData->inp_lport &&
956 !pINData->inp_faddr.s_addr &&
957 !pINData->inp_fport)
958 continue;
960 NumEntries++;
963 HeapFree (GetProcessHeap (), 0, Buf);
964 return NumEntries;
965 #else
966 FILE *fp;
967 int ret = 0;
969 fp = fopen(filename, "r");
970 if (fp) {
971 char buf[512] = { 0 }, *ptr;
974 ptr = fgets(buf, sizeof(buf), fp);
975 if (ptr) {
976 do {
977 ptr = fgets(buf, sizeof(buf), fp);
978 if (ptr)
979 ret++;
980 } while (ptr);
982 fclose(fp);
984 else
985 ERR ("Unable to open '%s' to count entries!\n", filename);
987 return ret;
988 #endif
991 DWORD getNumRoutes(void)
993 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
994 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
995 size_t needed;
996 char *buf, *lim, *next;
997 struct rt_msghdr *rtm;
998 DWORD RouteCount = 0;
1000 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1002 ERR ("sysctl 1 failed!\n");
1003 return 0;
1006 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1007 if (!buf) return 0;
1009 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1011 ERR ("sysctl 2 failed!\n");
1012 HeapFree (GetProcessHeap (), 0, buf);
1013 return 0;
1016 lim = buf + needed;
1017 for (next = buf; next < lim; next += rtm->rtm_msglen)
1019 rtm = (struct rt_msghdr *)next;
1021 if (rtm->rtm_type != RTM_GET)
1023 WARN ("Got unexpected message type 0x%x!\n",
1024 rtm->rtm_type);
1025 continue;
1028 /* Ignore all entries except for gateway routes which aren't
1029 multicast */
1030 if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST))
1031 continue;
1033 RouteCount++;
1036 HeapFree (GetProcessHeap (), 0, buf);
1037 return RouteCount;
1038 #else
1039 return getNumWithOneHeader("/proc/net/route");
1040 #endif
1043 DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap,
1044 DWORD flags)
1046 DWORD ret;
1048 if (!ppIpForwardTable)
1049 ret = ERROR_INVALID_PARAMETER;
1050 else {
1051 DWORD numRoutes = getNumRoutes();
1052 DWORD size = sizeof(MIB_IPFORWARDTABLE);
1053 PMIB_IPFORWARDTABLE table;
1055 if (numRoutes > 1)
1056 size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1057 table = HeapAlloc(heap, flags, size);
1058 if (table) {
1059 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1060 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1061 size_t needed;
1062 char *buf, *lim, *next, *addrPtr;
1063 struct rt_msghdr *rtm;
1065 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1067 ERR ("sysctl 1 failed!\n");
1068 HeapFree (GetProcessHeap (), 0, table);
1069 return NO_ERROR;
1072 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1073 if (!buf)
1075 HeapFree (GetProcessHeap (), 0, table);
1076 return ERROR_OUTOFMEMORY;
1079 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1081 ERR ("sysctl 2 failed!\n");
1082 HeapFree (GetProcessHeap (), 0, table);
1083 HeapFree (GetProcessHeap (), 0, buf);
1084 return NO_ERROR;
1087 *ppIpForwardTable = table;
1088 table->dwNumEntries = 0;
1090 lim = buf + needed;
1091 for (next = buf; next < lim; next += rtm->rtm_msglen)
1093 int i;
1095 rtm = (struct rt_msghdr *)next;
1097 if (rtm->rtm_type != RTM_GET)
1099 WARN ("Got unexpected message type 0x%x!\n",
1100 rtm->rtm_type);
1101 continue;
1104 /* Ignore all entries except for gateway routes which aren't
1105 multicast */
1106 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1107 (rtm->rtm_flags & RTF_MULTICAST))
1108 continue;
1110 memset (&table->table[table->dwNumEntries], 0,
1111 sizeof (MIB_IPFORWARDROW));
1112 table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index;
1113 table->table[table->dwNumEntries].dwForwardType =
1114 MIB_IPROUTE_TYPE_INDIRECT;
1115 table->table[table->dwNumEntries].dwForwardMetric1 =
1116 rtm->rtm_rmx.rmx_hopcount;
1117 table->table[table->dwNumEntries].dwForwardProto =
1118 MIB_IPPROTO_LOCAL;
1120 addrPtr = (char *)(rtm + 1);
1122 for (i = 1; i; i <<= 1)
1124 struct sockaddr *sa;
1125 DWORD addr;
1127 if (!(i & rtm->rtm_addrs))
1128 continue;
1130 sa = (struct sockaddr *)addrPtr;
1131 ADVANCE (addrPtr, sa);
1133 /* default routes are encoded by length-zero sockaddr */
1134 if (sa->sa_len == 0)
1135 addr = 0;
1136 else if (sa->sa_family != AF_INET)
1138 WARN ("Received unsupported sockaddr family 0x%x\n",
1139 sa->sa_family);
1140 addr = 0;
1142 else
1144 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1146 addr = sin->sin_addr.s_addr;
1149 switch (i)
1151 case RTA_DST:
1152 table->table[table->dwNumEntries].dwForwardDest = addr;
1153 break;
1155 case RTA_GATEWAY:
1156 table->table[table->dwNumEntries].dwForwardNextHop = addr;
1157 break;
1159 case RTA_NETMASK:
1160 table->table[table->dwNumEntries].dwForwardMask = addr;
1161 break;
1163 default:
1164 WARN ("Unexpected address type 0x%x\n", i);
1168 table->dwNumEntries++;
1171 HeapFree (GetProcessHeap (), 0, buf);
1172 ret = NO_ERROR;
1173 #else
1174 FILE *fp;
1176 ret = NO_ERROR;
1177 *ppIpForwardTable = table;
1178 table->dwNumEntries = 0;
1179 /* get from /proc/net/route, no error if can't */
1180 fp = fopen("/proc/net/route", "r");
1181 if (fp) {
1182 char buf[512] = { 0 }, *ptr;
1184 /* skip header line */
1185 ptr = fgets(buf, sizeof(buf), fp);
1186 while (ptr && table->dwNumEntries < numRoutes) {
1187 memset(&table->table[table->dwNumEntries], 0,
1188 sizeof(MIB_IPFORWARDROW));
1189 ptr = fgets(buf, sizeof(buf), fp);
1190 if (ptr) {
1191 DWORD index;
1193 while (!isspace(*ptr))
1194 ptr++;
1195 *ptr = '\0';
1196 ptr++;
1197 if (getInterfaceIndexByName(buf, &index) == NO_ERROR) {
1198 char *endPtr;
1200 table->table[table->dwNumEntries].dwForwardIfIndex = index;
1201 if (*ptr) {
1202 table->table[table->dwNumEntries].dwForwardDest =
1203 strtoul(ptr, &endPtr, 16);
1204 ptr = endPtr;
1206 if (ptr && *ptr) {
1207 table->table[table->dwNumEntries].dwForwardNextHop =
1208 strtoul(ptr, &endPtr, 16);
1209 ptr = endPtr;
1211 if (ptr && *ptr) {
1212 DWORD flags = strtoul(ptr, &endPtr, 16);
1214 if (!(flags & RTF_UP))
1215 table->table[table->dwNumEntries].dwForwardType =
1216 MIB_IPROUTE_TYPE_INVALID;
1217 else if (flags & RTF_GATEWAY)
1218 table->table[table->dwNumEntries].dwForwardType =
1219 MIB_IPROUTE_TYPE_INDIRECT;
1220 else
1221 table->table[table->dwNumEntries].dwForwardType =
1222 MIB_IPROUTE_TYPE_DIRECT;
1223 ptr = endPtr;
1225 if (ptr && *ptr) {
1226 strtoul(ptr, &endPtr, 16); /* refcount, skip */
1227 ptr = endPtr;
1229 if (ptr && *ptr) {
1230 strtoul(ptr, &endPtr, 16); /* use, skip */
1231 ptr = endPtr;
1233 if (ptr && *ptr) {
1234 table->table[table->dwNumEntries].dwForwardMetric1 =
1235 strtoul(ptr, &endPtr, 16);
1236 ptr = endPtr;
1238 if (ptr && *ptr) {
1239 table->table[table->dwNumEntries].dwForwardMask =
1240 strtoul(ptr, &endPtr, 16);
1241 ptr = endPtr;
1243 /* FIXME: other protos might be appropriate, e.g. the default
1244 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1245 table->table[table->dwNumEntries].dwForwardProto =
1246 MIB_IPPROTO_LOCAL;
1247 table->dwNumEntries++;
1251 fclose(fp);
1253 else
1255 ERR ("unimplemented!\n");
1256 return ERROR_NOT_SUPPORTED;
1258 #endif
1260 else
1261 ret = ERROR_OUTOFMEMORY;
1263 return ret;
1266 DWORD getNumArpEntries(void)
1268 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1269 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1270 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1271 DWORD arpEntries = 0;
1272 size_t needed;
1273 char *buf, *lim, *next;
1274 struct rt_msghdr *rtm;
1275 struct sockaddr_inarp *sinarp;
1276 struct sockaddr_dl *sdl;
1278 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1280 ERR ("failed to get size of arp table\n");
1281 return 0;
1284 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1285 if (!buf) return 0;
1287 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1289 ERR ("failed to get arp table\n");
1290 HeapFree (GetProcessHeap (), 0, buf);
1291 return 0;
1294 lim = buf + needed;
1295 next = buf;
1296 while(next < lim)
1298 rtm = (struct rt_msghdr *)next;
1299 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1300 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1301 if(sdl->sdl_alen) /* arp entry */
1302 arpEntries++;
1303 next += rtm->rtm_msglen;
1305 HeapFree (GetProcessHeap (), 0, buf);
1306 return arpEntries;
1307 #endif
1308 return getNumWithOneHeader("/proc/net/arp");
1311 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
1313 DWORD ret = NO_ERROR;
1314 if (!ppIpNetTable)
1315 ret = ERROR_INVALID_PARAMETER;
1316 else {
1317 DWORD numEntries = getNumArpEntries();
1318 DWORD size = sizeof(MIB_IPNETTABLE);
1319 PMIB_IPNETTABLE table;
1321 if (numEntries > 1)
1322 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1323 table = HeapAlloc(heap, flags, size);
1324 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1325 if (table)
1327 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1328 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1329 size_t needed;
1330 char *buf, *lim, *next;
1331 struct rt_msghdr *rtm;
1332 struct sockaddr_inarp *sinarp;
1333 struct sockaddr_dl *sdl;
1335 *ppIpNetTable = table;
1336 table->dwNumEntries = 0;
1338 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1340 ERR ("failed to get size of arp table\n");
1341 return ERROR_NOT_SUPPORTED;
1344 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1345 if (!buf) return ERROR_OUTOFMEMORY;
1347 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1349 ERR ("failed to get arp table\n");
1350 HeapFree (GetProcessHeap (), 0, buf);
1351 return ERROR_NOT_SUPPORTED;
1354 lim = buf + needed;
1355 next = buf;
1356 while(next < lim)
1358 rtm = (struct rt_msghdr *)next;
1359 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1360 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1361 if(sdl->sdl_alen) /* arp entry */
1363 DWORD byte = strtoul(&sdl->sdl_data[sdl->sdl_alen], NULL, 16);
1364 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1365 table->table[table->dwNumEntries].dwAddr = sinarp->sin_addr.s_addr;
1366 table->table[table->dwNumEntries].dwIndex = sdl->sdl_index;
1367 table->table[table->dwNumEntries].dwPhysAddrLen = sdl->sdl_alen;
1369 table->table[table->dwNumEntries].bPhysAddr[
1370 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1371 byte & 0x0ff;
1372 if(rtm->rtm_rmx.rmx_expire == 0)
1373 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_STATIC;
1374 else if(sinarp->sin_other & SIN_PROXY)
1375 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1376 else if(rtm->rtm_rmx.rmx_expire != 0)
1377 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_DYNAMIC;
1378 else
1379 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_INVALID;
1381 table->dwNumEntries++;
1383 next += rtm->rtm_msglen;
1385 HeapFree (GetProcessHeap (), 0, buf);
1387 else
1388 ret = ERROR_OUTOFMEMORY;
1389 return ret;
1390 #endif
1392 if (table) {
1393 FILE *fp;
1394 *ppIpNetTable = table;
1395 table->dwNumEntries = 0;
1396 /* get from /proc/net/arp, no error if can't */
1397 fp = fopen("/proc/net/arp", "r");
1398 if (fp) {
1399 char buf[512] = { 0 }, *ptr;
1401 /* skip header line */
1402 ptr = fgets(buf, sizeof(buf), fp);
1403 while (ptr && table->dwNumEntries < numEntries) {
1404 ptr = fgets(buf, sizeof(buf), fp);
1405 if (ptr) {
1406 char *endPtr;
1408 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPNETROW));
1409 table->table[table->dwNumEntries].dwAddr = inet_addr(ptr);
1410 while (ptr && *ptr && !isspace(*ptr))
1411 ptr++;
1413 if (ptr && *ptr) {
1414 strtoul(ptr, &endPtr, 16); /* hw type (skip) */
1415 ptr = endPtr;
1417 if (ptr && *ptr) {
1418 DWORD flags = strtoul(ptr, &endPtr, 16);
1420 #ifdef ATF_COM
1421 if (flags & ATF_COM)
1422 table->table[table->dwNumEntries].dwType =
1423 MIB_IPNET_TYPE_DYNAMIC;
1424 else
1425 #endif
1426 #ifdef ATF_PERM
1427 if (flags & ATF_PERM)
1428 table->table[table->dwNumEntries].dwType =
1429 MIB_IPNET_TYPE_STATIC;
1430 else
1431 #endif
1432 table->table[table->dwNumEntries].dwType = MIB_IPNET_TYPE_OTHER;
1434 ptr = endPtr;
1436 while (ptr && *ptr && isspace(*ptr))
1437 ptr++;
1438 while (ptr && *ptr && !isspace(*ptr)) {
1439 DWORD byte = strtoul(ptr, &endPtr, 16);
1441 if (endPtr && *endPtr) {
1442 endPtr++;
1443 table->table[table->dwNumEntries].bPhysAddr[
1444 table->table[table->dwNumEntries].dwPhysAddrLen++] =
1445 byte & 0x0ff;
1447 ptr = endPtr;
1449 if (ptr && *ptr) {
1450 strtoul(ptr, &endPtr, 16); /* mask (skip) */
1451 ptr = endPtr;
1453 getInterfaceIndexByName(ptr,
1454 &table->table[table->dwNumEntries].dwIndex);
1455 table->dwNumEntries++;
1458 fclose(fp);
1460 else
1461 ret = ERROR_NOT_SUPPORTED;
1463 else
1464 ret = ERROR_OUTOFMEMORY;
1466 return ret;
1469 DWORD getNumUdpEntries(void)
1471 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1472 return getNumWithOneHeader ("net.inet.udp.pcblist");
1473 #else
1474 return getNumWithOneHeader("/proc/net/udp");
1475 #endif
1478 DWORD getUdpTable(PMIB_UDPTABLE *ppUdpTable, HANDLE heap, DWORD flags)
1480 DWORD ret;
1482 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1483 ERR ("unimplemented!\n");
1484 return ERROR_NOT_SUPPORTED;
1485 #endif
1487 if (!ppUdpTable)
1488 ret = ERROR_INVALID_PARAMETER;
1489 else {
1490 DWORD numEntries = getNumUdpEntries();
1491 DWORD size = sizeof(MIB_UDPTABLE);
1492 PMIB_UDPTABLE table;
1494 if (numEntries > 1)
1495 size += (numEntries - 1) * sizeof(MIB_UDPROW);
1496 table = HeapAlloc(heap, flags, size);
1497 if (table) {
1498 FILE *fp;
1500 ret = NO_ERROR;
1501 *ppUdpTable = table;
1502 table->dwNumEntries = 0;
1503 /* get from /proc/net/udp, no error if can't */
1504 fp = fopen("/proc/net/udp", "r");
1505 if (fp) {
1506 char buf[512] = { 0 }, *ptr;
1508 /* skip header line */
1509 ptr = fgets(buf, sizeof(buf), fp);
1510 while (ptr && table->dwNumEntries < numEntries) {
1511 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_UDPROW));
1512 ptr = fgets(buf, sizeof(buf), fp);
1513 if (ptr) {
1514 char *endPtr;
1516 if (ptr && *ptr) {
1517 strtoul(ptr, &endPtr, 16); /* skip */
1518 ptr = endPtr;
1520 if (ptr && *ptr) {
1521 ptr++;
1522 table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
1523 &endPtr, 16);
1524 ptr = endPtr;
1526 if (ptr && *ptr) {
1527 ptr++;
1528 table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
1529 &endPtr, 16);
1530 ptr = endPtr;
1532 table->dwNumEntries++;
1535 fclose(fp);
1537 else
1538 ret = ERROR_NOT_SUPPORTED;
1540 else
1541 ret = ERROR_OUTOFMEMORY;
1543 return ret;
1547 DWORD getNumTcpEntries(void)
1549 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1550 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1551 #else
1552 return getNumWithOneHeader ("/proc/net/tcp");
1553 #endif
1557 /* Why not a lookup table? Because the TCPS_* constants are different
1558 on different platforms */
1559 static DWORD TCPStateToMIBState (int state)
1561 switch (state)
1563 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1564 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1565 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1566 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1567 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1568 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1569 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1570 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1571 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1572 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1573 default:
1574 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1579 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
1580 DWORD flags)
1582 DWORD numEntries;
1583 PMIB_TCPTABLE table;
1584 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1585 size_t Len = 0;
1586 char *Buf;
1587 struct xinpgen *pXIG, *pOrigXIG;
1588 #else
1589 FILE *fp;
1590 char buf[512] = { 0 }, *ptr;
1591 #endif
1593 if (!ppTcpTable)
1594 return ERROR_INVALID_PARAMETER;
1596 numEntries = getNumTcpEntries ();
1598 if (!*ppTcpTable)
1600 DWORD size = sizeof(MIB_TCPTABLE);
1602 if (numEntries > 1)
1603 size += (numEntries - 1) * sizeof (MIB_TCPROW);
1604 *ppTcpTable = HeapAlloc (heap, flags, size);
1605 if (!*ppTcpTable)
1607 ERR ("Out of memory!\n");
1608 return ERROR_OUTOFMEMORY;
1610 maxEntries = numEntries;
1613 table = *ppTcpTable;
1614 table->dwNumEntries = 0;
1615 if (!numEntries)
1616 return NO_ERROR;
1618 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1620 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1622 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1623 return ERROR_OUTOFMEMORY;
1626 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1627 if (!Buf)
1629 ERR ("Out of memory!\n");
1630 return ERROR_OUTOFMEMORY;
1633 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1635 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1636 HeapFree (GetProcessHeap (), 0, Buf);
1637 return ERROR_OUTOFMEMORY;
1640 /* Might be nothing here; first entry is just a header it seems */
1641 if (Len <= sizeof (struct xinpgen))
1643 HeapFree (GetProcessHeap (), 0, Buf);
1644 return NO_ERROR;
1647 pOrigXIG = (struct xinpgen *)Buf;
1648 pXIG = pOrigXIG;
1650 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1651 (pXIG->xig_len > sizeof (struct xinpgen)) &&
1652 (table->dwNumEntries < maxEntries);
1653 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1655 struct tcpcb *pTCPData = NULL;
1656 struct inpcb *pINData;
1657 struct xsocket *pSockData;
1659 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1660 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1661 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1663 /* Ignore sockets for other protocols */
1664 if (pSockData->xso_protocol != IPPROTO_TCP)
1665 continue;
1667 /* Ignore PCBs that were freed while generating the data */
1668 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1669 continue;
1671 /* we're only interested in IPv4 addresses */
1672 if (!(pINData->inp_vflag & INP_IPV4) ||
1673 (pINData->inp_vflag & INP_IPV6))
1674 continue;
1676 /* If all 0's, skip it */
1677 if (!pINData->inp_laddr.s_addr &&
1678 !pINData->inp_lport &&
1679 !pINData->inp_faddr.s_addr &&
1680 !pINData->inp_fport)
1681 continue;
1683 /* Fill in structure details */
1684 table->table[table->dwNumEntries].dwLocalAddr =
1685 pINData->inp_laddr.s_addr;
1686 table->table[table->dwNumEntries].dwLocalPort =
1687 pINData->inp_lport;
1688 table->table[table->dwNumEntries].dwRemoteAddr =
1689 pINData->inp_faddr.s_addr;
1690 table->table[table->dwNumEntries].dwRemotePort =
1691 pINData->inp_fport;
1692 table->table[table->dwNumEntries].dwState =
1693 TCPStateToMIBState (pTCPData->t_state);
1695 table->dwNumEntries++;
1698 HeapFree (GetProcessHeap (), 0, Buf);
1699 #else
1700 /* get from /proc/net/tcp, no error if can't */
1701 fp = fopen("/proc/net/tcp", "r");
1702 if (!fp)
1703 return ERROR_NOT_SUPPORTED;
1705 /* skip header line */
1706 ptr = fgets(buf, sizeof(buf), fp);
1707 while (ptr && table->dwNumEntries < maxEntries) {
1708 memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
1709 ptr = fgets(buf, sizeof(buf), fp);
1710 if (ptr) {
1711 char *endPtr;
1713 while (ptr && *ptr && *ptr != ':')
1714 ptr++;
1715 if (ptr && *ptr)
1716 ptr++;
1717 if (ptr && *ptr) {
1718 table->table[table->dwNumEntries].dwLocalAddr =
1719 strtoul(ptr, &endPtr, 16);
1720 ptr = endPtr;
1722 if (ptr && *ptr) {
1723 ptr++;
1724 table->table[table->dwNumEntries].dwLocalPort =
1725 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1726 ptr = endPtr;
1728 if (ptr && *ptr) {
1729 table->table[table->dwNumEntries].dwRemoteAddr =
1730 strtoul(ptr, &endPtr, 16);
1731 ptr = endPtr;
1733 if (ptr && *ptr) {
1734 ptr++;
1735 table->table[table->dwNumEntries].dwRemotePort =
1736 htons ((unsigned short)strtoul(ptr, &endPtr, 16));
1737 ptr = endPtr;
1739 if (ptr && *ptr) {
1740 DWORD state = strtoul(ptr, &endPtr, 16);
1742 table->table[table->dwNumEntries].dwState =
1743 TCPStateToMIBState (state);
1744 ptr = endPtr;
1746 table->dwNumEntries++;
1749 fclose(fp);
1750 #endif
1752 return NO_ERROR;