push 297972334720102b8c295c34d3cd5b0b9aafc558
[wine/hacks.git] / dlls / iphlpapi / ipstats.c
blobf630906cd2ce755bdc5255db423523a64e1331e5
1 /*
2 * Copyright (C) 2003,2006 Juan Lang
3 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * Copyright (C) 2009 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #ifdef HAVE_ALIAS_H
30 #include <alias.h>
31 #endif
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
35 #ifdef HAVE_SYS_SOCKETVAR_H
36 #include <sys/socketvar.h>
37 #endif
38 #ifdef HAVE_SYS_TIMEOUT_H
39 #include <sys/timeout.h>
40 #endif
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
46 #endif
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
50 #ifdef HAVE_NET_IF_H
51 #include <net/if.h>
52 #endif
53 #ifdef HAVE_NET_IF_DL_H
54 #include <net/if_dl.h>
55 #endif
56 #ifdef HAVE_NET_IF_TYPES_H
57 #include <net/if_types.h>
58 #endif
59 #ifdef HAVE_NET_ROUTE_H
60 #include <net/route.h>
61 #endif
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
64 #endif
65 #ifdef HAVE_NETINET_IF_ETHER_H
66 #include <netinet/if_ether.h>
67 #endif
68 #ifdef HAVE_NETINET_IF_INARP_H
69 #include <netinet/if_inarp.h>
70 #endif
71 #ifdef HAVE_NETINET_IP_H
72 #include <netinet/ip.h>
73 #endif
74 #ifdef HAVE_NETINET_TCP_H
75 #include <netinet/tcp.h>
76 #endif
77 #ifdef HAVE_NETINET_IP_VAR_H
78 #include <netinet/ip_var.h>
79 #endif
80 #ifdef HAVE_NETINET_TCP_FSM_H
81 #include <netinet/tcp_fsm.h>
82 #endif
83 #ifdef HAVE_NETINET_IN_PCB_H
84 #include <netinet/in_pcb.h>
85 #endif
86 #ifdef HAVE_NETINET_TCP_TIMER_H
87 #include <netinet/tcp_timer.h>
88 #endif
89 #ifdef HAVE_NETINET_TCP_VAR_H
90 #include <netinet/tcp_var.h>
91 #endif
92 #ifdef HAVE_NETINET_IP_ICMP_H
93 #include <netinet/ip_icmp.h>
94 #endif
95 #ifdef HAVE_NETINET_ICMP_VAR_H
96 #include <netinet/icmp_var.h>
97 #endif
98 #ifdef HAVE_NETINET_UDP_H
99 #include <netinet/udp.h>
100 #endif
101 #ifdef HAVE_NETINET_UDP_VAR_H
102 #include <netinet/udp_var.h>
103 #endif
104 #ifdef HAVE_SYS_PROTOSW_H
105 #include <sys/protosw.h>
106 #endif
107 #ifdef HAVE_SYS_SYSCTL_H
108 #include <sys/sysctl.h>
109 #endif
111 #ifndef ROUNDUP
112 #define ROUNDUP(a) \
113 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
114 #endif
115 #ifndef ADVANCE
116 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
117 #endif
119 #include "windef.h"
120 #include "winbase.h"
121 #include "iprtrmib.h"
122 #include "ifenum.h"
123 #include "ipstats.h"
125 #include "wine/debug.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];
326 #ifdef HAVE_ICPS_OUTHIST
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];
345 #else /* ICPS_OUTHIST */
346 memset( &stats->stats.icmpOutStats, 0, sizeof(stats->stats.icmpOutStats) );
347 #endif /* ICPS_OUTHIST */
349 return NO_ERROR;
351 #else /* ICMPCTL_STATS */
352 FILE *fp;
354 if (!stats)
355 return ERROR_INVALID_PARAMETER;
357 memset(stats, 0, sizeof(MIB_ICMP));
358 /* get most of these stats from /proc/net/snmp, no error if can't */
359 fp = fopen("/proc/net/snmp", "r");
360 if (fp) {
361 static const char hdr[] = "Icmp:";
362 char buf[512] = { 0 }, *ptr;
364 do {
365 ptr = fgets(buf, sizeof(buf), fp);
366 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
367 if (ptr) {
368 /* last line was a header, get another */
369 ptr = fgets(buf, sizeof(buf), fp);
370 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
371 char *endPtr;
373 ptr += sizeof(hdr);
374 if (ptr && *ptr) {
375 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
376 ptr = endPtr;
378 if (ptr && *ptr) {
379 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
380 ptr = endPtr;
382 if (ptr && *ptr) {
383 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
384 ptr = endPtr;
386 if (ptr && *ptr) {
387 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
388 ptr = endPtr;
390 if (ptr && *ptr) {
391 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
392 ptr = endPtr;
394 if (ptr && *ptr) {
395 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
396 ptr = endPtr;
398 if (ptr && *ptr) {
399 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
400 ptr = endPtr;
402 if (ptr && *ptr) {
403 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
404 ptr = endPtr;
406 if (ptr && *ptr) {
407 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
408 ptr = endPtr;
410 if (ptr && *ptr) {
411 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
412 ptr = endPtr;
414 if (ptr && *ptr) {
415 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
416 ptr = endPtr;
418 if (ptr && *ptr) {
419 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
420 ptr = endPtr;
422 if (ptr && *ptr) {
423 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
424 ptr = endPtr;
426 if (ptr && *ptr) {
427 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
428 ptr = endPtr;
430 if (ptr && *ptr) {
431 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
432 ptr = endPtr;
434 if (ptr && *ptr) {
435 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
436 ptr = endPtr;
438 if (ptr && *ptr) {
439 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
440 ptr = endPtr;
442 if (ptr && *ptr) {
443 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
444 ptr = endPtr;
446 if (ptr && *ptr) {
447 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
448 ptr = endPtr;
450 if (ptr && *ptr) {
451 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
452 ptr = endPtr;
454 if (ptr && *ptr) {
455 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
456 ptr = endPtr;
458 if (ptr && *ptr) {
459 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
460 ptr = endPtr;
462 if (ptr && *ptr) {
463 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
464 ptr = endPtr;
466 if (ptr && *ptr) {
467 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
468 ptr = endPtr;
472 fclose(fp);
474 else
476 ERR ("unimplemented!\n");
477 return ERROR_NOT_SUPPORTED;
480 return NO_ERROR;
481 #endif
484 DWORD getIPStats(PMIB_IPSTATS stats)
486 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
487 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
488 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
489 int ip_ttl, ip_forwarding;
490 struct ipstat ip_stat;
491 size_t needed;
493 if (!stats)
494 return ERROR_INVALID_PARAMETER;
496 needed = sizeof(ip_stat);
497 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
499 ERR ("failed to get ipstat\n");
500 return ERROR_NOT_SUPPORTED;
503 needed = sizeof(ip_ttl);
504 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
506 ERR ("failed to get ip Default TTL\n");
507 return ERROR_NOT_SUPPORTED;
510 needed = sizeof(ip_forwarding);
511 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
513 ERR ("failed to get ip forwarding\n");
514 return ERROR_NOT_SUPPORTED;
517 stats->dwForwarding = ip_forwarding;
518 stats->dwDefaultTTL = ip_ttl;
519 stats->dwInDelivers = ip_stat.ips_delivered;
520 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
521 stats->dwInAddrErrors = ip_stat.ips_cantforward;
522 stats->dwInReceives = ip_stat.ips_total;
523 stats->dwForwDatagrams = ip_stat.ips_forward;
524 stats->dwInUnknownProtos = ip_stat.ips_noproto;
525 stats->dwInDiscards = ip_stat.ips_fragdropped;
526 stats->dwOutDiscards = ip_stat.ips_odropped;
527 stats->dwReasmOks = ip_stat.ips_reassembled;
528 stats->dwFragOks = ip_stat.ips_fragmented;
529 stats->dwFragFails = ip_stat.ips_cantfrag;
530 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
531 stats->dwOutNoRoutes = ip_stat.ips_noroute;
532 stats->dwOutRequests = ip_stat.ips_localout;
533 stats->dwReasmReqds = ip_stat.ips_fragments;
535 return NO_ERROR;
536 #else
537 FILE *fp;
538 MIB_IPFORWARDTABLE *fwd_table;
540 if (!stats)
541 return ERROR_INVALID_PARAMETER;
543 memset(stats, 0, sizeof(MIB_IPSTATS));
544 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
545 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
547 stats->dwNumRoutes = fwd_table->dwNumEntries;
548 HeapFree( GetProcessHeap(), 0, fwd_table );
551 /* get most of these stats from /proc/net/snmp, no error if can't */
552 fp = fopen("/proc/net/snmp", "r");
553 if (fp) {
554 static const char hdr[] = "Ip:";
555 char buf[512] = { 0 }, *ptr;
557 do {
558 ptr = fgets(buf, sizeof(buf), fp);
559 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
560 if (ptr) {
561 /* last line was a header, get another */
562 ptr = fgets(buf, sizeof(buf), fp);
563 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
564 char *endPtr;
566 ptr += sizeof(hdr);
567 if (ptr && *ptr) {
568 stats->dwForwarding = strtoul(ptr, &endPtr, 10);
569 ptr = endPtr;
571 if (ptr && *ptr) {
572 stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10);
573 ptr = endPtr;
575 if (ptr && *ptr) {
576 stats->dwInReceives = strtoul(ptr, &endPtr, 10);
577 ptr = endPtr;
579 if (ptr && *ptr) {
580 stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10);
581 ptr = endPtr;
583 if (ptr && *ptr) {
584 stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10);
585 ptr = endPtr;
587 if (ptr && *ptr) {
588 stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10);
589 ptr = endPtr;
591 if (ptr && *ptr) {
592 stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10);
593 ptr = endPtr;
595 if (ptr && *ptr) {
596 stats->dwInDiscards = strtoul(ptr, &endPtr, 10);
597 ptr = endPtr;
599 if (ptr && *ptr) {
600 stats->dwInDelivers = strtoul(ptr, &endPtr, 10);
601 ptr = endPtr;
603 if (ptr && *ptr) {
604 stats->dwOutRequests = strtoul(ptr, &endPtr, 10);
605 ptr = endPtr;
607 if (ptr && *ptr) {
608 stats->dwOutDiscards = strtoul(ptr, &endPtr, 10);
609 ptr = endPtr;
611 if (ptr && *ptr) {
612 stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10);
613 ptr = endPtr;
615 if (ptr && *ptr) {
616 stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10);
617 ptr = endPtr;
619 if (ptr && *ptr) {
620 stats->dwReasmReqds = strtoul(ptr, &endPtr, 10);
621 ptr = endPtr;
623 if (ptr && *ptr) {
624 stats->dwReasmOks = strtoul(ptr, &endPtr, 10);
625 ptr = endPtr;
627 if (ptr && *ptr) {
628 stats->dwReasmFails = strtoul(ptr, &endPtr, 10);
629 ptr = endPtr;
631 if (ptr && *ptr) {
632 stats->dwFragOks = strtoul(ptr, &endPtr, 10);
633 ptr = endPtr;
635 if (ptr && *ptr) {
636 stats->dwFragFails = strtoul(ptr, &endPtr, 10);
637 ptr = endPtr;
639 if (ptr && *ptr) {
640 stats->dwFragCreates = strtoul(ptr, &endPtr, 10);
641 ptr = endPtr;
643 /* hmm, no routingDiscards */
646 fclose(fp);
648 else
650 ERR ("unimplemented!\n");
651 return ERROR_NOT_SUPPORTED;
654 return NO_ERROR;
655 #endif
658 DWORD getTCPStats(MIB_TCPSTATS *stats)
660 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
661 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
662 #define TCPTV_MIN 2
663 #define TCPTV_REXMTMAX 128
664 #endif
665 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
666 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
667 #define hz 1000
668 struct tcpstat tcp_stat;
669 size_t needed;
671 if (!stats)
672 return ERROR_INVALID_PARAMETER;
673 needed = sizeof(tcp_stat);
675 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) == -1)
677 ERR ("failed to get tcpstat\n");
678 return ERROR_NOT_SUPPORTED;
681 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
682 stats->dwRtoMin = TCPTV_MIN;
683 stats->dwRtoMax = TCPTV_REXMTMAX;
684 stats->dwMaxConn = -1;
685 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
686 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
687 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
688 stats->dwEstabResets = tcp_stat.tcps_drops;
689 stats->dwCurrEstab = 0;
690 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
691 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
692 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
693 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
694 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
695 stats->dwNumConns = tcp_stat.tcps_connects;
697 return NO_ERROR;
699 #else
700 FILE *fp;
701 MIB_TCPTABLE *tcp_table;
703 if (!stats)
704 return ERROR_INVALID_PARAMETER;
706 memset(stats, 0, sizeof(MIB_TCPSTATS));
708 /* get from /proc/net/snmp, no error if can't */
709 fp = fopen("/proc/net/snmp", "r");
710 if (fp) {
711 static const char hdr[] = "Tcp:";
712 char buf[512] = { 0 }, *ptr;
715 do {
716 ptr = fgets(buf, sizeof(buf), fp);
717 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
718 if (ptr) {
719 /* last line was a header, get another */
720 ptr = fgets(buf, sizeof(buf), fp);
721 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
722 char *endPtr;
724 ptr += sizeof(hdr);
725 if (ptr && *ptr) {
726 stats->dwRtoAlgorithm = strtoul(ptr, &endPtr, 10);
727 ptr = endPtr;
729 if (ptr && *ptr) {
730 stats->dwRtoMin = strtoul(ptr, &endPtr, 10);
731 ptr = endPtr;
733 if (ptr && *ptr) {
734 stats->dwRtoMax = strtoul(ptr, &endPtr, 10);
735 ptr = endPtr;
737 if (ptr && *ptr) {
738 stats->dwMaxConn = strtoul(ptr, &endPtr, 10);
739 ptr = endPtr;
741 if (ptr && *ptr) {
742 stats->dwActiveOpens = strtoul(ptr, &endPtr, 10);
743 ptr = endPtr;
745 if (ptr && *ptr) {
746 stats->dwPassiveOpens = strtoul(ptr, &endPtr, 10);
747 ptr = endPtr;
749 if (ptr && *ptr) {
750 stats->dwAttemptFails = strtoul(ptr, &endPtr, 10);
751 ptr = endPtr;
753 if (ptr && *ptr) {
754 stats->dwEstabResets = strtoul(ptr, &endPtr, 10);
755 ptr = endPtr;
757 if (ptr && *ptr) {
758 stats->dwCurrEstab = strtoul(ptr, &endPtr, 10);
759 ptr = endPtr;
761 if (ptr && *ptr) {
762 stats->dwInSegs = strtoul(ptr, &endPtr, 10);
763 ptr = endPtr;
765 if (ptr && *ptr) {
766 stats->dwOutSegs = strtoul(ptr, &endPtr, 10);
767 ptr = endPtr;
769 if (ptr && *ptr) {
770 stats->dwRetransSegs = strtoul(ptr, &endPtr, 10);
771 ptr = endPtr;
773 if (ptr && *ptr) {
774 stats->dwInErrs = strtoul(ptr, &endPtr, 10);
775 ptr = endPtr;
777 if (ptr && *ptr) {
778 stats->dwOutRsts = strtoul(ptr, &endPtr, 10);
779 ptr = endPtr;
781 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
783 stats->dwNumConns = tcp_table->dwNumEntries;
784 HeapFree( GetProcessHeap(), 0, tcp_table );
788 fclose(fp);
790 else
792 ERR ("unimplemented!\n");
793 return ERROR_NOT_SUPPORTED;
796 return NO_ERROR;
797 #endif
800 DWORD getUDPStats(MIB_UDPSTATS *stats)
802 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
803 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
804 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
805 struct udpstat udp_stat;
806 MIB_UDPTABLE *udp_table;
807 size_t needed;
808 if (!stats)
809 return ERROR_INVALID_PARAMETER;
811 needed = sizeof(udp_stat);
813 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) == -1)
815 ERR ("failed to get udpstat\n");
816 return ERROR_NOT_SUPPORTED;
819 stats->dwInDatagrams = udp_stat.udps_ipackets;
820 stats->dwOutDatagrams = udp_stat.udps_opackets;
821 stats->dwNoPorts = udp_stat.udps_noport;
822 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
823 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
825 stats->dwNumAddrs = udp_table->dwNumEntries;
826 HeapFree( GetProcessHeap(), 0, udp_table );
828 else stats->dwNumAddrs = 0;
830 return NO_ERROR;
831 #else
832 FILE *fp;
834 if (!stats)
835 return ERROR_INVALID_PARAMETER;
837 memset(stats, 0, sizeof(MIB_UDPSTATS));
839 /* get from /proc/net/snmp, no error if can't */
840 fp = fopen("/proc/net/snmp", "r");
841 if (fp) {
842 static const char hdr[] = "Udp:";
843 char buf[512] = { 0 }, *ptr;
846 do {
847 ptr = fgets(buf, sizeof(buf), fp);
848 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
849 if (ptr) {
850 /* last line was a header, get another */
851 ptr = fgets(buf, sizeof(buf), fp);
852 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
853 char *endPtr;
855 ptr += sizeof(hdr);
856 if (ptr && *ptr) {
857 stats->dwInDatagrams = strtoul(ptr, &endPtr, 10);
858 ptr = endPtr;
860 if (ptr && *ptr) {
861 stats->dwNoPorts = strtoul(ptr, &endPtr, 10);
862 ptr = endPtr;
864 if (ptr && *ptr) {
865 stats->dwInErrors = strtoul(ptr, &endPtr, 10);
866 ptr = endPtr;
868 if (ptr && *ptr) {
869 stats->dwOutDatagrams = strtoul(ptr, &endPtr, 10);
870 ptr = endPtr;
872 if (ptr && *ptr) {
873 stats->dwNumAddrs = strtoul(ptr, &endPtr, 10);
874 ptr = endPtr;
878 fclose(fp);
880 else
882 ERR ("unimplemented!\n");
883 return ERROR_NOT_SUPPORTED;
886 return NO_ERROR;
887 #endif
891 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
892 DWORD *count, const MIB_IPFORWARDROW *row )
894 if (table->dwNumEntries >= *count)
896 MIB_IPFORWARDTABLE *new_table;
897 DWORD new_count = table->dwNumEntries * 2;
899 if (!(new_table = HeapReAlloc( heap, flags, table,
900 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
902 HeapFree( heap, 0, table );
903 return NULL;
905 *count = new_count;
906 table = new_table;
908 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
909 return table;
912 static int compare_ipforward_rows(const void *a, const void *b)
914 const MIB_IPFORWARDROW *rowA = a;
915 const MIB_IPFORWARDROW *rowB = b;
916 int ret;
918 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
919 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
920 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
921 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
924 /******************************************************************
925 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
927 * Get the route table.
928 * Like GetIpForwardTable(), but allocate the returned table from heap.
930 * PARAMS
931 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
932 * allocated and returned.
933 * bOrder [In] whether to sort the table
934 * heap [In] heap from which the table is allocated
935 * flags [In] flags to HeapAlloc
937 * RETURNS
938 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
939 * on failure, NO_ERROR on success.
941 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
942 HANDLE heap, DWORD flags)
944 MIB_IPFORWARDTABLE *table;
945 MIB_IPFORWARDROW row;
946 DWORD ret = NO_ERROR, count = 16;
948 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
950 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
952 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
953 return ERROR_OUTOFMEMORY;
955 table->dwNumEntries = 0;
957 #ifdef __linux__
959 FILE *fp;
961 if ((fp = fopen("/proc/net/route", "r")))
963 char buf[512], *ptr;
964 DWORD flags;
966 /* skip header line */
967 ptr = fgets(buf, sizeof(buf), fp);
968 while ((ptr = fgets(buf, sizeof(buf), fp)))
970 memset( &row, 0, sizeof(row) );
972 while (!isspace(*ptr)) ptr++;
973 *ptr++ = 0;
974 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
975 continue;
977 row.dwForwardDest = strtoul(ptr, &ptr, 16);
978 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
979 flags = strtoul(ptr + 1, &ptr, 16);
981 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
982 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
983 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
985 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
986 strtoul(ptr + 1, &ptr, 16); /* use, skip */
987 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
988 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
989 /* FIXME: other protos might be appropriate, e.g. the default
990 * route is typically set with MIB_IPPROTO_NETMGMT instead */
991 row.dwForwardProto = MIB_IPPROTO_LOCAL;
993 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
994 break;
996 fclose(fp);
998 else ret = ERROR_NOT_SUPPORTED;
1000 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1002 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
1003 size_t needed;
1004 char *buf = NULL, *lim, *next, *addrPtr;
1005 struct rt_msghdr *rtm;
1007 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
1009 ERR ("sysctl 1 failed!\n");
1010 ret = ERROR_NOT_SUPPORTED;
1011 goto done;
1014 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1015 if (!buf)
1017 ret = ERROR_OUTOFMEMORY;
1018 goto done;
1021 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
1023 ret = ERROR_NOT_SUPPORTED;
1024 goto done;
1027 lim = buf + needed;
1028 for (next = buf; next < lim; next += rtm->rtm_msglen)
1030 int i;
1032 rtm = (struct rt_msghdr *)next;
1034 if (rtm->rtm_type != RTM_GET)
1036 WARN ("Got unexpected message type 0x%x!\n",
1037 rtm->rtm_type);
1038 continue;
1041 /* Ignore all entries except for gateway routes which aren't
1042 multicast */
1043 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1044 (rtm->rtm_flags & RTF_MULTICAST))
1045 continue;
1047 memset( &row, 0, sizeof(row) );
1048 row.dwForwardIfIndex = rtm->rtm_index;
1049 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1050 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1051 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1053 addrPtr = (char *)(rtm + 1);
1055 for (i = 1; i; i <<= 1)
1057 struct sockaddr *sa;
1058 DWORD addr;
1060 if (!(i & rtm->rtm_addrs))
1061 continue;
1063 sa = (struct sockaddr *)addrPtr;
1064 ADVANCE (addrPtr, sa);
1066 /* default routes are encoded by length-zero sockaddr */
1067 if (sa->sa_len == 0)
1068 addr = 0;
1069 else if (sa->sa_family != AF_INET)
1071 WARN ("Received unsupported sockaddr family 0x%x\n",
1072 sa->sa_family);
1073 addr = 0;
1075 else
1077 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1079 addr = sin->sin_addr.s_addr;
1082 switch (i)
1084 case RTA_DST: row.dwForwardDest = addr; break;
1085 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1086 case RTA_NETMASK: row.dwForwardMask = addr; break;
1087 default:
1088 WARN ("Unexpected address type 0x%x\n", i);
1092 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1093 break;
1095 done:
1096 HeapFree( GetProcessHeap (), 0, buf );
1098 #else
1099 FIXME( "not implemented\n" );
1100 ret = ERROR_NOT_SUPPORTED;
1101 #endif
1103 if (!table) return ERROR_OUTOFMEMORY;
1104 if (!ret)
1106 if (bOrder && table->dwNumEntries)
1107 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1108 *ppIpForwardTable = table;
1110 else HeapFree( heap, flags, table );
1111 TRACE( "returning ret %u table %p\n", ret, table );
1112 return ret;
1115 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1116 DWORD *count, const MIB_IPNETROW *row )
1118 if (table->dwNumEntries >= *count)
1120 MIB_IPNETTABLE *new_table;
1121 DWORD new_count = table->dwNumEntries * 2;
1123 if (!(new_table = HeapReAlloc( heap, flags, table,
1124 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1126 HeapFree( heap, 0, table );
1127 return NULL;
1129 *count = new_count;
1130 table = new_table;
1132 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1133 return table;
1136 static int compare_ipnet_rows(const void *a, const void *b)
1138 const MIB_IPNETROW *rowA = a;
1139 const MIB_IPNETROW *rowB = b;
1141 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1145 /******************************************************************
1146 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1148 * Get the IP-to-physical address mapping table.
1149 * Like GetIpNetTable(), but allocate the returned table from heap.
1151 * PARAMS
1152 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1153 * allocated and returned.
1154 * bOrder [In] whether to sort the table
1155 * heap [In] heap from which the table is allocated
1156 * flags [In] flags to HeapAlloc
1158 * RETURNS
1159 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1160 * on failure, NO_ERROR on success.
1162 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1163 HANDLE heap, DWORD flags)
1165 MIB_IPNETTABLE *table;
1166 MIB_IPNETROW row;
1167 DWORD ret = NO_ERROR, count = 16;
1169 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1171 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1173 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1174 return ERROR_OUTOFMEMORY;
1176 table->dwNumEntries = 0;
1178 #ifdef __linux__
1180 FILE *fp;
1182 if ((fp = fopen("/proc/net/arp", "r")))
1184 char buf[512], *ptr;
1185 DWORD flags;
1187 /* skip header line */
1188 ptr = fgets(buf, sizeof(buf), fp);
1189 while ((ptr = fgets(buf, sizeof(buf), fp)))
1191 memset( &row, 0, sizeof(row) );
1193 row.dwAddr = inet_addr(ptr);
1194 while (*ptr && !isspace(*ptr)) ptr++;
1195 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1196 flags = strtoul(ptr + 1, &ptr, 16);
1198 #ifdef ATF_COM
1199 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1200 else
1201 #endif
1202 #ifdef ATF_PERM
1203 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1204 else
1205 #endif
1206 row.dwType = MIB_IPNET_TYPE_OTHER;
1208 while (*ptr && isspace(*ptr)) ptr++;
1209 while (*ptr && !isspace(*ptr))
1211 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1212 if (*ptr) ptr++;
1214 while (*ptr && isspace(*ptr)) ptr++;
1215 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1216 while (*ptr && isspace(*ptr)) ptr++;
1217 getInterfaceIndexByName(ptr, &row.dwIndex);
1219 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1220 break;
1222 fclose(fp);
1224 else ret = ERROR_NOT_SUPPORTED;
1226 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1228 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1229 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1230 size_t needed;
1231 char *buf = NULL, *lim, *next;
1232 struct rt_msghdr *rtm;
1233 struct sockaddr_inarp *sinarp;
1234 struct sockaddr_dl *sdl;
1236 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1238 ERR ("failed to get arp table\n");
1239 ret = ERROR_NOT_SUPPORTED;
1240 goto done;
1243 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1244 if (!buf)
1246 ret = ERROR_OUTOFMEMORY;
1247 goto done;
1250 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1252 ret = ERROR_NOT_SUPPORTED;
1253 goto done;
1256 lim = buf + needed;
1257 next = buf;
1258 while(next < lim)
1260 rtm = (struct rt_msghdr *)next;
1261 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1262 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1263 if(sdl->sdl_alen) /* arp entry */
1265 memset( &row, 0, sizeof(row) );
1266 row.dwAddr = sinarp->sin_addr.s_addr;
1267 row.dwIndex = sdl->sdl_index;
1268 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1269 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1270 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1271 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1272 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1273 else row.dwType = MIB_IPNET_TYPE_INVALID;
1275 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1276 break;
1278 next += rtm->rtm_msglen;
1280 done:
1281 HeapFree( GetProcessHeap (), 0, buf );
1283 #else
1284 FIXME( "not implemented\n" );
1285 ret = ERROR_NOT_SUPPORTED;
1286 #endif
1288 if (!table) return ERROR_OUTOFMEMORY;
1289 if (!ret)
1291 if (bOrder && table->dwNumEntries)
1292 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1293 *ppIpNetTable = table;
1295 else HeapFree( heap, flags, table );
1296 TRACE( "returning ret %u table %p\n", ret, table );
1297 return ret;
1301 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1302 DWORD *count, const MIB_UDPROW *row )
1304 if (table->dwNumEntries >= *count)
1306 MIB_UDPTABLE *new_table;
1307 DWORD new_count = table->dwNumEntries * 2;
1309 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1311 HeapFree( heap, 0, table );
1312 return NULL;
1314 *count = new_count;
1315 table = new_table;
1317 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1318 return table;
1321 static int compare_udp_rows(const void *a, const void *b)
1323 const MIB_UDPROW *rowA = a;
1324 const MIB_UDPROW *rowB = b;
1325 int ret;
1327 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1328 return rowA->dwLocalPort - rowB->dwLocalPort;
1332 /******************************************************************
1333 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1335 * Get the UDP listener table.
1336 * Like GetUdpTable(), but allocate the returned table from heap.
1338 * PARAMS
1339 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1340 * allocated and returned.
1341 * bOrder [In] whether to sort the table
1342 * heap [In] heap from which the table is allocated
1343 * flags [In] flags to HeapAlloc
1345 * RETURNS
1346 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1347 * returns otherwise.
1349 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1350 HANDLE heap, DWORD flags)
1352 MIB_UDPTABLE *table;
1353 MIB_UDPROW row;
1354 DWORD ret = NO_ERROR, count = 16;
1356 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1358 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1360 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1361 return ERROR_OUTOFMEMORY;
1363 table->dwNumEntries = 0;
1365 #ifdef __linux__
1367 FILE *fp;
1369 if ((fp = fopen("/proc/net/udp", "r")))
1371 char buf[512], *ptr;
1372 DWORD dummy;
1374 /* skip header line */
1375 ptr = fgets(buf, sizeof(buf), fp);
1376 while ((ptr = fgets(buf, sizeof(buf), fp)))
1378 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1379 continue;
1380 row.dwLocalPort = htons( row.dwLocalPort );
1381 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1382 break;
1384 fclose(fp);
1386 else ret = ERROR_NOT_SUPPORTED;
1388 #else
1389 FIXME( "not implemented\n" );
1390 ret = ERROR_NOT_SUPPORTED;
1391 #endif
1393 if (!table) return ERROR_OUTOFMEMORY;
1394 if (!ret)
1396 if (bOrder && table->dwNumEntries)
1397 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1398 *ppUdpTable = table;
1400 else HeapFree( heap, flags, table );
1401 TRACE( "returning ret %u table %p\n", ret, table );
1402 return ret;
1406 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1407 DWORD *count, const MIB_TCPROW *row )
1409 if (table->dwNumEntries >= *count)
1411 MIB_TCPTABLE *new_table;
1412 DWORD new_count = table->dwNumEntries * 2;
1414 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1416 HeapFree( heap, 0, table );
1417 return NULL;
1419 *count = new_count;
1420 table = new_table;
1422 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1423 return table;
1427 /* Why not a lookup table? Because the TCPS_* constants are different
1428 on different platforms */
1429 static DWORD TCPStateToMIBState (int state)
1431 switch (state)
1433 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1434 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1435 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1436 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1437 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1438 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1439 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1440 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1441 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1442 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1443 default:
1444 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1449 static int compare_tcp_rows(const void *a, const void *b)
1451 const MIB_TCPROW *rowA = a;
1452 const MIB_TCPROW *rowB = b;
1453 int ret;
1455 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1456 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1457 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1458 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1459 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1463 /******************************************************************
1464 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1466 * Get the TCP connection table.
1467 * Like GetTcpTable(), but allocate the returned table from heap.
1469 * PARAMS
1470 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1471 * allocated and returned.
1472 * bOrder [In] whether to sort the table
1473 * heap [In] heap from which the table is allocated
1474 * flags [In] flags to HeapAlloc
1476 * RETURNS
1477 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1478 * returns otherwise.
1480 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1481 HANDLE heap, DWORD flags)
1483 MIB_TCPTABLE *table;
1484 MIB_TCPROW row;
1485 DWORD ret = NO_ERROR, count = 16;
1487 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1489 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1491 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1492 return ERROR_OUTOFMEMORY;
1494 table->dwNumEntries = 0;
1496 #ifdef __linux__
1498 FILE *fp;
1500 if ((fp = fopen("/proc/net/tcp", "r")))
1502 char buf[512], *ptr;
1503 DWORD dummy;
1505 /* skip header line */
1506 ptr = fgets(buf, sizeof(buf), fp);
1507 while ((ptr = fgets(buf, sizeof(buf), fp)))
1509 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1510 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1511 continue;
1512 row.dwLocalPort = htons( row.dwLocalPort );
1513 row.dwRemotePort = htons( row.dwRemotePort );
1514 row.dwState = TCPStateToMIBState( row.dwState );
1515 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1516 break;
1518 fclose( fp );
1520 else ret = ERROR_NOT_SUPPORTED;
1522 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1524 size_t Len = 0;
1525 char *Buf = NULL;
1526 struct xinpgen *pXIG, *pOrigXIG;
1528 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1530 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1531 ret = ERROR_NOT_SUPPORTED;
1532 goto done;
1535 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1536 if (!Buf)
1538 ret = ERROR_OUTOFMEMORY;
1539 goto done;
1542 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1544 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1545 ret = ERROR_NOT_SUPPORTED;
1546 goto done;
1549 /* Might be nothing here; first entry is just a header it seems */
1550 if (Len <= sizeof (struct xinpgen)) goto done;
1552 pOrigXIG = (struct xinpgen *)Buf;
1553 pXIG = pOrigXIG;
1555 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1556 pXIG->xig_len > sizeof (struct xinpgen);
1557 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1559 struct tcpcb *pTCPData = NULL;
1560 struct inpcb *pINData;
1561 struct xsocket *pSockData;
1563 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1564 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1565 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1567 /* Ignore sockets for other protocols */
1568 if (pSockData->xso_protocol != IPPROTO_TCP)
1569 continue;
1571 /* Ignore PCBs that were freed while generating the data */
1572 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1573 continue;
1575 /* we're only interested in IPv4 addresses */
1576 if (!(pINData->inp_vflag & INP_IPV4) ||
1577 (pINData->inp_vflag & INP_IPV6))
1578 continue;
1580 /* If all 0's, skip it */
1581 if (!pINData->inp_laddr.s_addr &&
1582 !pINData->inp_lport &&
1583 !pINData->inp_faddr.s_addr &&
1584 !pINData->inp_fport)
1585 continue;
1587 /* Fill in structure details */
1588 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1589 row.dwLocalPort = pINData->inp_lport;
1590 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1591 row.dwRemotePort = pINData->inp_fport;
1592 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1593 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1596 done:
1597 HeapFree (GetProcessHeap (), 0, Buf);
1599 #else
1600 FIXME( "not implemented\n" );
1601 ret = ERROR_NOT_SUPPORTED;
1602 #endif
1604 if (!table) return ERROR_OUTOFMEMORY;
1605 if (!ret)
1607 if (bOrder && table->dwNumEntries)
1608 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1609 *ppTcpTable = table;
1611 else HeapFree( heap, flags, table );
1612 TRACE( "returning ret %u table %p\n", ret, table );
1613 return ret;