push eb25bf65c4616aa55a810ed5c29198b1a080b208
[wine/hacks.git] / dlls / iphlpapi / ipstats.c
bloba1b99818962a453a2f2197902b0f432a1a0790af
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
110 #ifdef HAVE_KSTAT_H
111 #include <kstat.h>
112 #endif
114 #ifndef ROUNDUP
115 #define ROUNDUP(a) \
116 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
117 #endif
118 #ifndef ADVANCE
119 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
120 #endif
122 #include "windef.h"
123 #include "winbase.h"
124 #include "iprtrmib.h"
125 #include "ifenum.h"
126 #include "ipstats.h"
128 #include "wine/debug.h"
130 #ifndef HAVE_NETINET_TCP_FSM_H
131 #define TCPS_ESTABLISHED 1
132 #define TCPS_SYN_SENT 2
133 #define TCPS_SYN_RECEIVED 3
134 #define TCPS_FIN_WAIT_1 4
135 #define TCPS_FIN_WAIT_2 5
136 #define TCPS_TIME_WAIT 6
137 #define TCPS_CLOSED 7
138 #define TCPS_CLOSE_WAIT 8
139 #define TCPS_LAST_ACK 9
140 #define TCPS_LISTEN 10
141 #define TCPS_CLOSING 11
142 #endif
144 #ifndef RTF_MULTICAST
145 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
146 #endif
148 #ifndef RTF_LLINFO
149 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
150 #endif
152 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
154 #ifdef HAVE_LIBKSTAT
155 static DWORD kstat_get_ui32( kstat_t *ksp, const char *name )
157 unsigned int i;
158 kstat_named_t *data = ksp->ks_data;
160 for (i = 0; i < ksp->ks_ndata; i++)
161 if (!strcmp( data[i].name, name )) return data[i].value.ui32;
162 return 0;
165 static ULONGLONG kstat_get_ui64( kstat_t *ksp, const char *name )
167 unsigned int i;
168 kstat_named_t *data = ksp->ks_data;
170 for (i = 0; i < ksp->ks_ndata; i++)
171 if (!strcmp( data[i].name, name )) return data[i].value.ui64;
172 return 0;
174 #endif
176 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
178 DWORD ret = ERROR_NOT_SUPPORTED;
180 if (!name || !entry) return ERROR_INVALID_PARAMETER;
182 #ifdef __linux__
184 FILE *fp;
186 if ((fp = fopen("/proc/net/dev", "r")))
188 DWORD skip;
189 char buf[512], *ptr;
190 int nameLen = strlen(name);
192 while ((ptr = fgets(buf, sizeof(buf), fp)))
194 while (*ptr && isspace(*ptr)) ptr++;
195 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
197 ptr += nameLen + 1;
198 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
199 &entry->dwInOctets, &entry->dwInUcastPkts,
200 &entry->dwInErrors, &entry->dwInDiscards,
201 &skip, &skip, &skip,
202 &entry->dwInNUcastPkts, &entry->dwOutOctets,
203 &entry->dwOutUcastPkts, &entry->dwOutErrors,
204 &entry->dwOutDiscards );
205 break;
208 fclose(fp);
209 ret = NO_ERROR;
212 #elif defined(HAVE_LIBKSTAT)
214 kstat_ctl_t *kc;
215 kstat_t *ksp;
217 if ((kc = kstat_open()) &&
218 (ksp = kstat_lookup( kc, NULL, -1, (char *)name )) &&
219 kstat_read( kc, ksp, NULL ) != -1 &&
220 ksp->ks_type == KSTAT_TYPE_NAMED)
222 entry->dwMtu = 1500; /* FIXME */
223 entry->dwSpeed = min( kstat_get_ui64( ksp, "ifspeed" ), ~0u );
224 entry->dwInOctets = kstat_get_ui32( ksp, "rbytes" );
225 entry->dwInNUcastPkts = kstat_get_ui32( ksp, "multircv" );
226 entry->dwInNUcastPkts += kstat_get_ui32( ksp, "brdcstrcv" );
227 entry->dwInUcastPkts = kstat_get_ui32( ksp, "ipackets" ) - entry->dwInNUcastPkts;
228 entry->dwInDiscards = kstat_get_ui32( ksp, "norcvbuf" );
229 entry->dwInErrors = kstat_get_ui32( ksp, "ierrors" );
230 entry->dwInUnknownProtos = kstat_get_ui32( ksp, "unknowns" );
231 entry->dwOutOctets = kstat_get_ui32( ksp, "obytes" );
232 entry->dwOutNUcastPkts = kstat_get_ui32( ksp, "multixmt" );
233 entry->dwOutNUcastPkts += kstat_get_ui32( ksp, "brdcstxmt" );
234 entry->dwOutUcastPkts = kstat_get_ui32( ksp, "opackets" ) - entry->dwOutNUcastPkts;
235 entry->dwOutDiscards = 0; /* FIXME */
236 entry->dwOutErrors = kstat_get_ui32( ksp, "oerrors" );
237 entry->dwOutQLen = kstat_get_ui32( ksp, "noxmtbuf" );
238 ret = NO_ERROR;
240 if (kc) kstat_close( kc );
242 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
244 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
245 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
247 size_t needed;
248 char *buf = NULL, *end;
249 struct if_msghdr *ifm;
250 struct if_data ifdata;
252 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
254 ERR ("failed to get size of iflist\n");
255 goto done;
257 buf = HeapAlloc (GetProcessHeap (), 0, needed);
258 if (!buf)
260 ret = ERROR_OUTOFMEMORY;
261 goto done;
263 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
265 ERR ("failed to get iflist\n");
266 goto done;
268 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
270 ifm = (struct if_msghdr *) buf;
271 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
273 ifdata = ifm->ifm_data;
274 entry->dwMtu = ifdata.ifi_mtu;
275 entry->dwSpeed = ifdata.ifi_baudrate;
276 entry->dwInOctets = ifdata.ifi_ibytes;
277 entry->dwInErrors = ifdata.ifi_ierrors;
278 entry->dwInDiscards = ifdata.ifi_iqdrops;
279 entry->dwInUcastPkts = ifdata.ifi_ipackets;
280 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
281 entry->dwOutOctets = ifdata.ifi_obytes;
282 entry->dwOutUcastPkts = ifdata.ifi_opackets;
283 entry->dwOutErrors = ifdata.ifi_oerrors;
284 ret = NO_ERROR;
285 break;
288 done:
289 HeapFree (GetProcessHeap (), 0, buf);
291 #else
292 FIXME( "unimplemented\n" );
293 #endif
294 return ret;
298 /******************************************************************
299 * GetIcmpStatistics (IPHLPAPI.@)
301 * Get the ICMP statistics for the local computer.
303 * PARAMS
304 * stats [Out] buffer for ICMP statistics
306 * RETURNS
307 * Success: NO_ERROR
308 * Failure: error code from winerror.h
310 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
312 DWORD ret = ERROR_NOT_SUPPORTED;
314 if (!stats) return ERROR_INVALID_PARAMETER;
315 memset( stats, 0, sizeof(MIB_ICMP) );
317 #ifdef __linux__
319 FILE *fp;
321 if ((fp = fopen("/proc/net/snmp", "r")))
323 static const char hdr[] = "Icmp:";
324 char buf[512], *ptr;
326 while ((ptr = fgets(buf, sizeof(buf), fp)))
328 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
329 /* last line was a header, get another */
330 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
331 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
333 ptr += sizeof(hdr);
334 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
335 &stats->stats.icmpInStats.dwMsgs,
336 &stats->stats.icmpInStats.dwErrors,
337 &stats->stats.icmpInStats.dwDestUnreachs,
338 &stats->stats.icmpInStats.dwTimeExcds,
339 &stats->stats.icmpInStats.dwParmProbs,
340 &stats->stats.icmpInStats.dwSrcQuenchs,
341 &stats->stats.icmpInStats.dwRedirects,
342 &stats->stats.icmpInStats.dwEchoReps,
343 &stats->stats.icmpInStats.dwTimestamps,
344 &stats->stats.icmpInStats.dwTimestampReps,
345 &stats->stats.icmpInStats.dwAddrMasks,
346 &stats->stats.icmpInStats.dwAddrMaskReps,
347 &stats->stats.icmpOutStats.dwMsgs,
348 &stats->stats.icmpOutStats.dwErrors,
349 &stats->stats.icmpOutStats.dwDestUnreachs,
350 &stats->stats.icmpOutStats.dwTimeExcds,
351 &stats->stats.icmpOutStats.dwParmProbs,
352 &stats->stats.icmpOutStats.dwSrcQuenchs,
353 &stats->stats.icmpOutStats.dwRedirects,
354 &stats->stats.icmpOutStats.dwEchoReps,
355 &stats->stats.icmpOutStats.dwTimestamps,
356 &stats->stats.icmpOutStats.dwTimestampReps,
357 &stats->stats.icmpOutStats.dwAddrMasks,
358 &stats->stats.icmpOutStats.dwAddrMaskReps );
359 break;
362 fclose(fp);
363 ret = NO_ERROR;
366 #elif defined(HAVE_LIBKSTAT)
368 static char ip[] = "ip", icmp[] = "icmp";
369 kstat_ctl_t *kc;
370 kstat_t *ksp;
372 if ((kc = kstat_open()) &&
373 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
374 kstat_read( kc, ksp, NULL ) != -1 &&
375 ksp->ks_type == KSTAT_TYPE_NAMED)
377 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
378 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
379 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
380 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
381 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
382 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
383 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
384 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
385 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
386 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
387 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
388 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
389 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
390 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
391 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
392 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
393 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
394 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
395 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
396 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
397 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
398 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
399 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
400 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
401 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
402 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
403 ret = NO_ERROR;
405 if (kc) kstat_close( kc );
407 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
409 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
410 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
411 struct icmpstat icmp_stat;
412 size_t needed = sizeof(icmp_stat);
413 int i;
415 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
417 /*in stats */
418 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
419 for(i = 0; i <= ICMP_MAXTYPE; i++)
420 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
422 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
424 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
425 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
426 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
427 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
428 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
429 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
430 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
431 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
432 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
433 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
434 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
436 #ifdef HAVE_ICPS_OUTHIST
437 /* out stats */
438 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
439 for(i = 0; i <= ICMP_MAXTYPE; i++)
440 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
442 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
444 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
445 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
446 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
447 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
448 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
449 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
450 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
451 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
452 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
453 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
454 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
455 #endif /* ICPS_OUTHIST */
456 ret = NO_ERROR;
459 #else /* ICMPCTL_STATS */
460 FIXME( "unimplemented\n" );
461 #endif
462 return ret;
466 /******************************************************************
467 * GetIpStatistics (IPHLPAPI.@)
469 * Get the IP statistics for the local computer.
471 * PARAMS
472 * stats [Out] buffer for IP statistics
474 * RETURNS
475 * Success: NO_ERROR
476 * Failure: error code from winerror.h
478 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
480 DWORD ret = ERROR_NOT_SUPPORTED;
481 MIB_IPFORWARDTABLE *fwd_table;
483 if (!stats) return ERROR_INVALID_PARAMETER;
484 memset( stats, 0, sizeof(*stats) );
486 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
487 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
489 stats->dwNumRoutes = fwd_table->dwNumEntries;
490 HeapFree( GetProcessHeap(), 0, fwd_table );
493 #ifdef __linux__
495 FILE *fp;
497 if ((fp = fopen("/proc/net/snmp", "r")))
499 static const char hdr[] = "Ip:";
500 char buf[512], *ptr;
502 while ((ptr = fgets(buf, sizeof(buf), fp)))
504 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
505 /* last line was a header, get another */
506 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
507 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
509 ptr += sizeof(hdr);
510 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
511 &stats->dwForwarding,
512 &stats->dwDefaultTTL,
513 &stats->dwInReceives,
514 &stats->dwInHdrErrors,
515 &stats->dwInAddrErrors,
516 &stats->dwForwDatagrams,
517 &stats->dwInUnknownProtos,
518 &stats->dwInDiscards,
519 &stats->dwInDelivers,
520 &stats->dwOutRequests,
521 &stats->dwOutDiscards,
522 &stats->dwOutNoRoutes,
523 &stats->dwReasmTimeout,
524 &stats->dwReasmReqds,
525 &stats->dwReasmOks,
526 &stats->dwReasmFails,
527 &stats->dwFragOks,
528 &stats->dwFragFails,
529 &stats->dwFragCreates );
530 /* hmm, no routingDiscards */
531 break;
534 fclose(fp);
535 ret = NO_ERROR;
538 #elif defined(HAVE_LIBKSTAT)
540 static char ip[] = "ip";
541 kstat_ctl_t *kc;
542 kstat_t *ksp;
544 if ((kc = kstat_open()) &&
545 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
546 kstat_read( kc, ksp, NULL ) != -1 &&
547 ksp->ks_type == KSTAT_TYPE_NAMED)
549 stats->dwForwarding = kstat_get_ui32( ksp, "forwarding" );
550 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
551 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
552 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
553 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
554 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
555 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
556 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
557 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
558 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
559 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
560 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
561 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
562 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
563 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
564 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
565 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
566 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
567 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
568 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
569 ret = NO_ERROR;
571 if (kc) kstat_close( kc );
573 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
575 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
576 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
577 int ip_ttl, ip_forwarding;
578 struct ipstat ip_stat;
579 size_t needed;
581 needed = sizeof(ip_stat);
582 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
584 ERR ("failed to get ipstat\n");
585 return ERROR_NOT_SUPPORTED;
588 needed = sizeof(ip_ttl);
589 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
591 ERR ("failed to get ip Default TTL\n");
592 return ERROR_NOT_SUPPORTED;
595 needed = sizeof(ip_forwarding);
596 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
598 ERR ("failed to get ip forwarding\n");
599 return ERROR_NOT_SUPPORTED;
602 stats->dwForwarding = ip_forwarding;
603 stats->dwDefaultTTL = ip_ttl;
604 stats->dwInDelivers = ip_stat.ips_delivered;
605 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
606 stats->dwInAddrErrors = ip_stat.ips_cantforward;
607 stats->dwInReceives = ip_stat.ips_total;
608 stats->dwForwDatagrams = ip_stat.ips_forward;
609 stats->dwInUnknownProtos = ip_stat.ips_noproto;
610 stats->dwInDiscards = ip_stat.ips_fragdropped;
611 stats->dwOutDiscards = ip_stat.ips_odropped;
612 stats->dwReasmOks = ip_stat.ips_reassembled;
613 stats->dwFragOks = ip_stat.ips_fragmented;
614 stats->dwFragFails = ip_stat.ips_cantfrag;
615 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
616 stats->dwOutNoRoutes = ip_stat.ips_noroute;
617 stats->dwOutRequests = ip_stat.ips_localout;
618 stats->dwReasmReqds = ip_stat.ips_fragments;
619 ret = NO_ERROR;
621 #else
622 FIXME( "unimplemented\n" );
623 #endif
624 return ret;
628 /******************************************************************
629 * GetTcpStatistics (IPHLPAPI.@)
631 * Get the TCP statistics for the local computer.
633 * PARAMS
634 * stats [Out] buffer for TCP statistics
636 * RETURNS
637 * Success: NO_ERROR
638 * Failure: error code from winerror.h
640 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
642 DWORD ret = ERROR_NOT_SUPPORTED;
644 if (!stats) return ERROR_INVALID_PARAMETER;
645 memset( stats, 0, sizeof(*stats) );
647 #ifdef __linux__
649 FILE *fp;
651 if ((fp = fopen("/proc/net/snmp", "r")))
653 static const char hdr[] = "Tcp:";
654 MIB_TCPTABLE *tcp_table;
655 char buf[512], *ptr;
657 while ((ptr = fgets(buf, sizeof(buf), fp)))
659 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
660 /* last line was a header, get another */
661 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
662 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
664 ptr += sizeof(hdr);
665 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
666 &stats->dwRtoAlgorithm,
667 &stats->dwRtoMin,
668 &stats->dwRtoMax,
669 &stats->dwMaxConn,
670 &stats->dwActiveOpens,
671 &stats->dwPassiveOpens,
672 &stats->dwAttemptFails,
673 &stats->dwEstabResets,
674 &stats->dwCurrEstab,
675 &stats->dwInSegs,
676 &stats->dwOutSegs,
677 &stats->dwRetransSegs,
678 &stats->dwInErrs,
679 &stats->dwOutRsts );
680 break;
683 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
685 stats->dwNumConns = tcp_table->dwNumEntries;
686 HeapFree( GetProcessHeap(), 0, tcp_table );
688 fclose(fp);
689 ret = NO_ERROR;
692 #elif defined(HAVE_LIBKSTAT)
694 static char tcp[] = "tcp";
695 kstat_ctl_t *kc;
696 kstat_t *ksp;
698 if ((kc = kstat_open()) &&
699 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
700 kstat_read( kc, ksp, NULL ) != -1 &&
701 ksp->ks_type == KSTAT_TYPE_NAMED)
703 stats->dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
704 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
705 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
706 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
707 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
708 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
709 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
710 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
711 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
712 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
713 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
714 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
715 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
716 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
717 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
718 ret = NO_ERROR;
720 if (kc) kstat_close( kc );
722 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
724 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
725 #define TCPTV_MIN 2
726 #define TCPTV_REXMTMAX 128
727 #endif
728 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
729 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
730 #define hz 1000
731 struct tcpstat tcp_stat;
732 size_t needed = sizeof(tcp_stat);
734 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
736 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
737 stats->dwRtoMin = TCPTV_MIN;
738 stats->dwRtoMax = TCPTV_REXMTMAX;
739 stats->dwMaxConn = -1;
740 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
741 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
742 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
743 stats->dwEstabResets = tcp_stat.tcps_drops;
744 stats->dwCurrEstab = 0;
745 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
746 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
747 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
748 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
749 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
750 stats->dwNumConns = tcp_stat.tcps_connects;
751 ret = NO_ERROR;
753 else ERR ("failed to get tcpstat\n");
755 #else
756 FIXME( "unimplemented\n" );
757 #endif
758 return ret;
762 /******************************************************************
763 * GetUdpStatistics (IPHLPAPI.@)
765 * Get the UDP statistics for the local computer.
767 * PARAMS
768 * stats [Out] buffer for UDP statistics
770 * RETURNS
771 * Success: NO_ERROR
772 * Failure: error code from winerror.h
774 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
776 DWORD ret = ERROR_NOT_SUPPORTED;
778 if (!stats) return ERROR_INVALID_PARAMETER;
779 memset( stats, 0, sizeof(*stats) );
781 #ifdef __linux__
783 FILE *fp;
785 if ((fp = fopen("/proc/net/snmp", "r")))
787 static const char hdr[] = "Udp:";
788 char buf[512], *ptr;
790 while ((ptr = fgets(buf, sizeof(buf), fp)))
792 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
793 /* last line was a header, get another */
794 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
795 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
797 ptr += sizeof(hdr);
798 sscanf( ptr, "%u %u %u %u %u",
799 &stats->dwInDatagrams, &stats->dwNoPorts,
800 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
801 break;
804 fclose(fp);
805 ret = NO_ERROR;
808 #elif defined(HAVE_LIBKSTAT)
810 static char udp[] = "udp";
811 kstat_ctl_t *kc;
812 kstat_t *ksp;
813 MIB_UDPTABLE *udp_table;
815 if ((kc = kstat_open()) &&
816 (ksp = kstat_lookup( kc, udp, 0, udp )) &&
817 kstat_read( kc, ksp, NULL ) != -1 &&
818 ksp->ks_type == KSTAT_TYPE_NAMED)
820 stats->dwInDatagrams = kstat_get_ui32( ksp, "inDatagrams" );
821 stats->dwNoPorts = 0; /* FIXME */
822 stats->dwInErrors = kstat_get_ui32( ksp, "inErrors" );
823 stats->dwOutDatagrams = kstat_get_ui32( ksp, "outDatagrams" );
824 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
826 stats->dwNumAddrs = udp_table->dwNumEntries;
827 HeapFree( GetProcessHeap(), 0, udp_table );
829 ret = NO_ERROR;
831 if (kc) kstat_close( kc );
833 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
835 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
836 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
837 struct udpstat udp_stat;
838 MIB_UDPTABLE *udp_table;
839 size_t needed = sizeof(udp_stat);
841 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
843 stats->dwInDatagrams = udp_stat.udps_ipackets;
844 stats->dwOutDatagrams = udp_stat.udps_opackets;
845 stats->dwNoPorts = udp_stat.udps_noport;
846 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
847 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
849 stats->dwNumAddrs = udp_table->dwNumEntries;
850 HeapFree( GetProcessHeap(), 0, udp_table );
852 ret = NO_ERROR;
854 else ERR ("failed to get udpstat\n");
856 #else
857 FIXME( "unimplemented\n" );
858 #endif
859 return ret;
863 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
864 DWORD *count, const MIB_IPFORWARDROW *row )
866 if (table->dwNumEntries >= *count)
868 MIB_IPFORWARDTABLE *new_table;
869 DWORD new_count = table->dwNumEntries * 2;
871 if (!(new_table = HeapReAlloc( heap, flags, table,
872 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
874 HeapFree( heap, 0, table );
875 return NULL;
877 *count = new_count;
878 table = new_table;
880 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
881 return table;
884 static int compare_ipforward_rows(const void *a, const void *b)
886 const MIB_IPFORWARDROW *rowA = a;
887 const MIB_IPFORWARDROW *rowB = b;
888 int ret;
890 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
891 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
892 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
893 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
896 /******************************************************************
897 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
899 * Get the route table.
900 * Like GetIpForwardTable(), but allocate the returned table from heap.
902 * PARAMS
903 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
904 * allocated and returned.
905 * bOrder [In] whether to sort the table
906 * heap [In] heap from which the table is allocated
907 * flags [In] flags to HeapAlloc
909 * RETURNS
910 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
911 * on failure, NO_ERROR on success.
913 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
914 HANDLE heap, DWORD flags)
916 MIB_IPFORWARDTABLE *table;
917 MIB_IPFORWARDROW row;
918 DWORD ret = NO_ERROR, count = 16;
920 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
922 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
924 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
925 return ERROR_OUTOFMEMORY;
927 table->dwNumEntries = 0;
929 #ifdef __linux__
931 FILE *fp;
933 if ((fp = fopen("/proc/net/route", "r")))
935 char buf[512], *ptr;
936 DWORD flags;
938 /* skip header line */
939 ptr = fgets(buf, sizeof(buf), fp);
940 while ((ptr = fgets(buf, sizeof(buf), fp)))
942 memset( &row, 0, sizeof(row) );
944 while (!isspace(*ptr)) ptr++;
945 *ptr++ = 0;
946 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
947 continue;
949 row.dwForwardDest = strtoul(ptr, &ptr, 16);
950 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
951 flags = strtoul(ptr + 1, &ptr, 16);
953 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
954 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
955 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
957 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
958 strtoul(ptr + 1, &ptr, 16); /* use, skip */
959 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
960 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
961 /* FIXME: other protos might be appropriate, e.g. the default
962 * route is typically set with MIB_IPPROTO_NETMGMT instead */
963 row.dwForwardProto = MIB_IPPROTO_LOCAL;
965 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
966 break;
968 fclose(fp);
970 else ret = ERROR_NOT_SUPPORTED;
972 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
974 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
975 size_t needed;
976 char *buf = NULL, *lim, *next, *addrPtr;
977 struct rt_msghdr *rtm;
979 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
981 ERR ("sysctl 1 failed!\n");
982 ret = ERROR_NOT_SUPPORTED;
983 goto done;
986 buf = HeapAlloc (GetProcessHeap (), 0, needed);
987 if (!buf)
989 ret = ERROR_OUTOFMEMORY;
990 goto done;
993 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
995 ret = ERROR_NOT_SUPPORTED;
996 goto done;
999 lim = buf + needed;
1000 for (next = buf; next < lim; next += rtm->rtm_msglen)
1002 int i;
1004 rtm = (struct rt_msghdr *)next;
1006 if (rtm->rtm_type != RTM_GET)
1008 WARN ("Got unexpected message type 0x%x!\n",
1009 rtm->rtm_type);
1010 continue;
1013 /* Ignore all entries except for gateway routes which aren't
1014 multicast */
1015 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
1016 (rtm->rtm_flags & RTF_MULTICAST))
1017 continue;
1019 memset( &row, 0, sizeof(row) );
1020 row.dwForwardIfIndex = rtm->rtm_index;
1021 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
1022 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
1023 row.dwForwardProto = MIB_IPPROTO_LOCAL;
1025 addrPtr = (char *)(rtm + 1);
1027 for (i = 1; i; i <<= 1)
1029 struct sockaddr *sa;
1030 DWORD addr;
1032 if (!(i & rtm->rtm_addrs))
1033 continue;
1035 sa = (struct sockaddr *)addrPtr;
1036 ADVANCE (addrPtr, sa);
1038 /* default routes are encoded by length-zero sockaddr */
1039 if (sa->sa_len == 0)
1040 addr = 0;
1041 else if (sa->sa_family != AF_INET)
1043 WARN ("Received unsupported sockaddr family 0x%x\n",
1044 sa->sa_family);
1045 addr = 0;
1047 else
1049 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1051 addr = sin->sin_addr.s_addr;
1054 switch (i)
1056 case RTA_DST: row.dwForwardDest = addr; break;
1057 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
1058 case RTA_NETMASK: row.dwForwardMask = addr; break;
1059 default:
1060 WARN ("Unexpected address type 0x%x\n", i);
1064 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1065 break;
1067 done:
1068 HeapFree( GetProcessHeap (), 0, buf );
1070 #else
1071 FIXME( "not implemented\n" );
1072 ret = ERROR_NOT_SUPPORTED;
1073 #endif
1075 if (!table) return ERROR_OUTOFMEMORY;
1076 if (!ret)
1078 if (bOrder && table->dwNumEntries)
1079 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1080 *ppIpForwardTable = table;
1082 else HeapFree( heap, flags, table );
1083 TRACE( "returning ret %u table %p\n", ret, table );
1084 return ret;
1087 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1088 DWORD *count, const MIB_IPNETROW *row )
1090 if (table->dwNumEntries >= *count)
1092 MIB_IPNETTABLE *new_table;
1093 DWORD new_count = table->dwNumEntries * 2;
1095 if (!(new_table = HeapReAlloc( heap, flags, table,
1096 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1098 HeapFree( heap, 0, table );
1099 return NULL;
1101 *count = new_count;
1102 table = new_table;
1104 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1105 return table;
1108 static int compare_ipnet_rows(const void *a, const void *b)
1110 const MIB_IPNETROW *rowA = a;
1111 const MIB_IPNETROW *rowB = b;
1113 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1117 /******************************************************************
1118 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1120 * Get the IP-to-physical address mapping table.
1121 * Like GetIpNetTable(), but allocate the returned table from heap.
1123 * PARAMS
1124 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1125 * allocated and returned.
1126 * bOrder [In] whether to sort the table
1127 * heap [In] heap from which the table is allocated
1128 * flags [In] flags to HeapAlloc
1130 * RETURNS
1131 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1132 * on failure, NO_ERROR on success.
1134 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1135 HANDLE heap, DWORD flags)
1137 MIB_IPNETTABLE *table;
1138 MIB_IPNETROW row;
1139 DWORD ret = NO_ERROR, count = 16;
1141 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1143 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1145 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1146 return ERROR_OUTOFMEMORY;
1148 table->dwNumEntries = 0;
1150 #ifdef __linux__
1152 FILE *fp;
1154 if ((fp = fopen("/proc/net/arp", "r")))
1156 char buf[512], *ptr;
1157 DWORD flags;
1159 /* skip header line */
1160 ptr = fgets(buf, sizeof(buf), fp);
1161 while ((ptr = fgets(buf, sizeof(buf), fp)))
1163 memset( &row, 0, sizeof(row) );
1165 row.dwAddr = inet_addr(ptr);
1166 while (*ptr && !isspace(*ptr)) ptr++;
1167 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1168 flags = strtoul(ptr + 1, &ptr, 16);
1170 #ifdef ATF_COM
1171 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1172 else
1173 #endif
1174 #ifdef ATF_PERM
1175 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1176 else
1177 #endif
1178 row.dwType = MIB_IPNET_TYPE_OTHER;
1180 while (*ptr && isspace(*ptr)) ptr++;
1181 while (*ptr && !isspace(*ptr))
1183 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1184 if (*ptr) ptr++;
1186 while (*ptr && isspace(*ptr)) ptr++;
1187 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1188 while (*ptr && isspace(*ptr)) ptr++;
1189 getInterfaceIndexByName(ptr, &row.dwIndex);
1191 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1192 break;
1194 fclose(fp);
1196 else ret = ERROR_NOT_SUPPORTED;
1198 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1200 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1201 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1202 size_t needed;
1203 char *buf = NULL, *lim, *next;
1204 struct rt_msghdr *rtm;
1205 struct sockaddr_inarp *sinarp;
1206 struct sockaddr_dl *sdl;
1208 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1210 ERR ("failed to get arp table\n");
1211 ret = ERROR_NOT_SUPPORTED;
1212 goto done;
1215 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1216 if (!buf)
1218 ret = ERROR_OUTOFMEMORY;
1219 goto done;
1222 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1224 ret = ERROR_NOT_SUPPORTED;
1225 goto done;
1228 lim = buf + needed;
1229 next = buf;
1230 while(next < lim)
1232 rtm = (struct rt_msghdr *)next;
1233 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1234 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1235 if(sdl->sdl_alen) /* arp entry */
1237 memset( &row, 0, sizeof(row) );
1238 row.dwAddr = sinarp->sin_addr.s_addr;
1239 row.dwIndex = sdl->sdl_index;
1240 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1241 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1242 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1243 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1244 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1245 else row.dwType = MIB_IPNET_TYPE_INVALID;
1247 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1248 break;
1250 next += rtm->rtm_msglen;
1252 done:
1253 HeapFree( GetProcessHeap (), 0, buf );
1255 #else
1256 FIXME( "not implemented\n" );
1257 ret = ERROR_NOT_SUPPORTED;
1258 #endif
1260 if (!table) return ERROR_OUTOFMEMORY;
1261 if (!ret)
1263 if (bOrder && table->dwNumEntries)
1264 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1265 *ppIpNetTable = table;
1267 else HeapFree( heap, flags, table );
1268 TRACE( "returning ret %u table %p\n", ret, table );
1269 return ret;
1273 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1274 DWORD *count, const MIB_UDPROW *row )
1276 if (table->dwNumEntries >= *count)
1278 MIB_UDPTABLE *new_table;
1279 DWORD new_count = table->dwNumEntries * 2;
1281 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1283 HeapFree( heap, 0, table );
1284 return NULL;
1286 *count = new_count;
1287 table = new_table;
1289 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1290 return table;
1293 static int compare_udp_rows(const void *a, const void *b)
1295 const MIB_UDPROW *rowA = a;
1296 const MIB_UDPROW *rowB = b;
1297 int ret;
1299 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1300 return rowA->dwLocalPort - rowB->dwLocalPort;
1304 /******************************************************************
1305 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1307 * Get the UDP listener table.
1308 * Like GetUdpTable(), but allocate the returned table from heap.
1310 * PARAMS
1311 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1312 * allocated and returned.
1313 * bOrder [In] whether to sort the table
1314 * heap [In] heap from which the table is allocated
1315 * flags [In] flags to HeapAlloc
1317 * RETURNS
1318 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1319 * returns otherwise.
1321 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1322 HANDLE heap, DWORD flags)
1324 MIB_UDPTABLE *table;
1325 MIB_UDPROW row;
1326 DWORD ret = NO_ERROR, count = 16;
1328 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1330 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1332 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1333 return ERROR_OUTOFMEMORY;
1335 table->dwNumEntries = 0;
1337 #ifdef __linux__
1339 FILE *fp;
1341 if ((fp = fopen("/proc/net/udp", "r")))
1343 char buf[512], *ptr;
1344 DWORD dummy;
1346 /* skip header line */
1347 ptr = fgets(buf, sizeof(buf), fp);
1348 while ((ptr = fgets(buf, sizeof(buf), fp)))
1350 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1351 continue;
1352 row.dwLocalPort = htons( row.dwLocalPort );
1353 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1354 break;
1356 fclose(fp);
1358 else ret = ERROR_NOT_SUPPORTED;
1360 #else
1361 FIXME( "not implemented\n" );
1362 ret = ERROR_NOT_SUPPORTED;
1363 #endif
1365 if (!table) return ERROR_OUTOFMEMORY;
1366 if (!ret)
1368 if (bOrder && table->dwNumEntries)
1369 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1370 *ppUdpTable = table;
1372 else HeapFree( heap, flags, table );
1373 TRACE( "returning ret %u table %p\n", ret, table );
1374 return ret;
1378 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1379 DWORD *count, const MIB_TCPROW *row )
1381 if (table->dwNumEntries >= *count)
1383 MIB_TCPTABLE *new_table;
1384 DWORD new_count = table->dwNumEntries * 2;
1386 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1388 HeapFree( heap, 0, table );
1389 return NULL;
1391 *count = new_count;
1392 table = new_table;
1394 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1395 return table;
1399 /* Why not a lookup table? Because the TCPS_* constants are different
1400 on different platforms */
1401 static DWORD TCPStateToMIBState (int state)
1403 switch (state)
1405 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1406 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1407 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1408 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1409 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1410 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1411 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1412 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1413 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1414 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1415 default:
1416 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1421 static int compare_tcp_rows(const void *a, const void *b)
1423 const MIB_TCPROW *rowA = a;
1424 const MIB_TCPROW *rowB = b;
1425 int ret;
1427 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1428 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1429 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1430 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1431 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1435 /******************************************************************
1436 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1438 * Get the TCP connection table.
1439 * Like GetTcpTable(), but allocate the returned table from heap.
1441 * PARAMS
1442 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1443 * allocated and returned.
1444 * bOrder [In] whether to sort the table
1445 * heap [In] heap from which the table is allocated
1446 * flags [In] flags to HeapAlloc
1448 * RETURNS
1449 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1450 * returns otherwise.
1452 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1453 HANDLE heap, DWORD flags)
1455 MIB_TCPTABLE *table;
1456 MIB_TCPROW row;
1457 DWORD ret = NO_ERROR, count = 16;
1459 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1461 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1463 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1464 return ERROR_OUTOFMEMORY;
1466 table->dwNumEntries = 0;
1468 #ifdef __linux__
1470 FILE *fp;
1472 if ((fp = fopen("/proc/net/tcp", "r")))
1474 char buf[512], *ptr;
1475 DWORD dummy;
1477 /* skip header line */
1478 ptr = fgets(buf, sizeof(buf), fp);
1479 while ((ptr = fgets(buf, sizeof(buf), fp)))
1481 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1482 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1483 continue;
1484 row.dwLocalPort = htons( row.dwLocalPort );
1485 row.dwRemotePort = htons( row.dwRemotePort );
1486 row.dwState = TCPStateToMIBState( row.dwState );
1487 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1488 break;
1490 fclose( fp );
1492 else ret = ERROR_NOT_SUPPORTED;
1494 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1496 size_t Len = 0;
1497 char *Buf = NULL;
1498 struct xinpgen *pXIG, *pOrigXIG;
1500 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1502 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1503 ret = ERROR_NOT_SUPPORTED;
1504 goto done;
1507 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1508 if (!Buf)
1510 ret = ERROR_OUTOFMEMORY;
1511 goto done;
1514 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1516 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1517 ret = ERROR_NOT_SUPPORTED;
1518 goto done;
1521 /* Might be nothing here; first entry is just a header it seems */
1522 if (Len <= sizeof (struct xinpgen)) goto done;
1524 pOrigXIG = (struct xinpgen *)Buf;
1525 pXIG = pOrigXIG;
1527 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1528 pXIG->xig_len > sizeof (struct xinpgen);
1529 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1531 struct tcpcb *pTCPData = NULL;
1532 struct inpcb *pINData;
1533 struct xsocket *pSockData;
1535 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1536 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1537 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1539 /* Ignore sockets for other protocols */
1540 if (pSockData->xso_protocol != IPPROTO_TCP)
1541 continue;
1543 /* Ignore PCBs that were freed while generating the data */
1544 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1545 continue;
1547 /* we're only interested in IPv4 addresses */
1548 if (!(pINData->inp_vflag & INP_IPV4) ||
1549 (pINData->inp_vflag & INP_IPV6))
1550 continue;
1552 /* If all 0's, skip it */
1553 if (!pINData->inp_laddr.s_addr &&
1554 !pINData->inp_lport &&
1555 !pINData->inp_faddr.s_addr &&
1556 !pINData->inp_fport)
1557 continue;
1559 /* Fill in structure details */
1560 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1561 row.dwLocalPort = pINData->inp_lport;
1562 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1563 row.dwRemotePort = pINData->inp_fport;
1564 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1565 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1568 done:
1569 HeapFree (GetProcessHeap (), 0, Buf);
1571 #else
1572 FIXME( "not implemented\n" );
1573 ret = ERROR_NOT_SUPPORTED;
1574 #endif
1576 if (!table) return ERROR_OUTOFMEMORY;
1577 if (!ret)
1579 if (bOrder && table->dwNumEntries)
1580 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1581 *ppTcpTable = table;
1583 else HeapFree( heap, flags, table );
1584 TRACE( "returning ret %u table %p\n", ret, table );
1585 return ret;