iphlpapi: Implemented GetTcpStatistics for Solaris.
[wine/multimedia.git] / dlls / iphlpapi / ipstats.c
blob7db48c6d3296b7a6c5aff7edc6cc365b303b2cb8
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;
164 #endif
166 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
168 DWORD ret = ERROR_NOT_SUPPORTED;
170 if (!name || !entry) return ERROR_INVALID_PARAMETER;
172 #ifdef __linux__
174 FILE *fp;
176 if ((fp = fopen("/proc/net/dev", "r")))
178 DWORD skip;
179 char buf[512], *ptr;
180 int nameLen = strlen(name);
182 while ((ptr = fgets(buf, sizeof(buf), fp)))
184 while (*ptr && isspace(*ptr)) ptr++;
185 if (strncasecmp(ptr, name, nameLen) == 0 && *(ptr + nameLen) == ':')
187 ptr += nameLen + 1;
188 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u",
189 &entry->dwInOctets, &entry->dwInUcastPkts,
190 &entry->dwInErrors, &entry->dwInDiscards,
191 &skip, &skip, &skip,
192 &entry->dwInNUcastPkts, &entry->dwOutOctets,
193 &entry->dwOutUcastPkts, &entry->dwOutErrors,
194 &entry->dwOutDiscards );
195 break;
198 fclose(fp);
199 ret = NO_ERROR;
202 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
204 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(name)};
205 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
207 size_t needed;
208 char *buf = NULL, *end;
209 struct if_msghdr *ifm;
210 struct if_data ifdata;
212 if(sysctl(mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
214 ERR ("failed to get size of iflist\n");
215 goto done;
217 buf = HeapAlloc (GetProcessHeap (), 0, needed);
218 if (!buf)
220 ret = ERROR_OUTOFMEMORY;
221 goto done;
223 if(sysctl(mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
225 ERR ("failed to get iflist\n");
226 goto done;
228 for ( end = buf + needed; buf < end; buf += ifm->ifm_msglen)
230 ifm = (struct if_msghdr *) buf;
231 if(ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER)
233 ifdata = ifm->ifm_data;
234 entry->dwMtu = ifdata.ifi_mtu;
235 entry->dwSpeed = ifdata.ifi_baudrate;
236 entry->dwInOctets = ifdata.ifi_ibytes;
237 entry->dwInErrors = ifdata.ifi_ierrors;
238 entry->dwInDiscards = ifdata.ifi_iqdrops;
239 entry->dwInUcastPkts = ifdata.ifi_ipackets;
240 entry->dwInNUcastPkts = ifdata.ifi_imcasts;
241 entry->dwOutOctets = ifdata.ifi_obytes;
242 entry->dwOutUcastPkts = ifdata.ifi_opackets;
243 entry->dwOutErrors = ifdata.ifi_oerrors;
244 ret = NO_ERROR;
245 break;
248 done:
249 HeapFree (GetProcessHeap (), 0, buf);
251 #else
252 FIXME( "unimplemented\n" );
253 #endif
254 return ret;
258 /******************************************************************
259 * GetIcmpStatistics (IPHLPAPI.@)
261 * Get the ICMP statistics for the local computer.
263 * PARAMS
264 * stats [Out] buffer for ICMP statistics
266 * RETURNS
267 * Success: NO_ERROR
268 * Failure: error code from winerror.h
270 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP stats)
272 DWORD ret = ERROR_NOT_SUPPORTED;
274 if (!stats) return ERROR_INVALID_PARAMETER;
275 memset( stats, 0, sizeof(MIB_ICMP) );
277 #ifdef __linux__
279 FILE *fp;
281 if ((fp = fopen("/proc/net/snmp", "r")))
283 static const char hdr[] = "Icmp:";
284 char buf[512], *ptr;
286 while ((ptr = fgets(buf, sizeof(buf), fp)))
288 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
289 /* last line was a header, get another */
290 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
291 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
293 ptr += sizeof(hdr);
294 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",
295 &stats->stats.icmpInStats.dwMsgs,
296 &stats->stats.icmpInStats.dwErrors,
297 &stats->stats.icmpInStats.dwDestUnreachs,
298 &stats->stats.icmpInStats.dwTimeExcds,
299 &stats->stats.icmpInStats.dwParmProbs,
300 &stats->stats.icmpInStats.dwSrcQuenchs,
301 &stats->stats.icmpInStats.dwRedirects,
302 &stats->stats.icmpInStats.dwEchoReps,
303 &stats->stats.icmpInStats.dwTimestamps,
304 &stats->stats.icmpInStats.dwTimestampReps,
305 &stats->stats.icmpInStats.dwAddrMasks,
306 &stats->stats.icmpInStats.dwAddrMaskReps,
307 &stats->stats.icmpOutStats.dwMsgs,
308 &stats->stats.icmpOutStats.dwErrors,
309 &stats->stats.icmpOutStats.dwDestUnreachs,
310 &stats->stats.icmpOutStats.dwTimeExcds,
311 &stats->stats.icmpOutStats.dwParmProbs,
312 &stats->stats.icmpOutStats.dwSrcQuenchs,
313 &stats->stats.icmpOutStats.dwRedirects,
314 &stats->stats.icmpOutStats.dwEchoReps,
315 &stats->stats.icmpOutStats.dwTimestamps,
316 &stats->stats.icmpOutStats.dwTimestampReps,
317 &stats->stats.icmpOutStats.dwAddrMasks,
318 &stats->stats.icmpOutStats.dwAddrMaskReps );
319 break;
322 fclose(fp);
323 ret = NO_ERROR;
326 #elif defined(HAVE_LIBKSTAT)
328 static char ip[] = "ip", icmp[] = "icmp";
329 kstat_ctl_t *kc;
330 kstat_t *ksp;
332 if ((kc = kstat_open()) &&
333 (ksp = kstat_lookup( kc, ip, 0, icmp )) &&
334 kstat_read( kc, ksp, NULL ) != -1 &&
335 ksp->ks_type == KSTAT_TYPE_NAMED)
337 stats->stats.icmpInStats.dwMsgs = kstat_get_ui32( ksp, "inMsgs" );
338 stats->stats.icmpInStats.dwErrors = kstat_get_ui32( ksp, "inErrors" );
339 stats->stats.icmpInStats.dwDestUnreachs = kstat_get_ui32( ksp, "inDestUnreachs" );
340 stats->stats.icmpInStats.dwTimeExcds = kstat_get_ui32( ksp, "inTimeExcds" );
341 stats->stats.icmpInStats.dwParmProbs = kstat_get_ui32( ksp, "inParmProbs" );
342 stats->stats.icmpInStats.dwSrcQuenchs = kstat_get_ui32( ksp, "inSrcQuenchs" );
343 stats->stats.icmpInStats.dwRedirects = kstat_get_ui32( ksp, "inRedirects" );
344 stats->stats.icmpInStats.dwEchos = kstat_get_ui32( ksp, "inEchos" );
345 stats->stats.icmpInStats.dwEchoReps = kstat_get_ui32( ksp, "inEchoReps" );
346 stats->stats.icmpInStats.dwTimestamps = kstat_get_ui32( ksp, "inTimestamps" );
347 stats->stats.icmpInStats.dwTimestampReps = kstat_get_ui32( ksp, "inTimestampReps" );
348 stats->stats.icmpInStats.dwAddrMasks = kstat_get_ui32( ksp, "inAddrMasks" );
349 stats->stats.icmpInStats.dwAddrMaskReps = kstat_get_ui32( ksp, "inAddrMaskReps" );
350 stats->stats.icmpOutStats.dwMsgs = kstat_get_ui32( ksp, "outMsgs" );
351 stats->stats.icmpOutStats.dwErrors = kstat_get_ui32( ksp, "outErrors" );
352 stats->stats.icmpOutStats.dwDestUnreachs = kstat_get_ui32( ksp, "outDestUnreachs" );
353 stats->stats.icmpOutStats.dwTimeExcds = kstat_get_ui32( ksp, "outTimeExcds" );
354 stats->stats.icmpOutStats.dwParmProbs = kstat_get_ui32( ksp, "outParmProbs" );
355 stats->stats.icmpOutStats.dwSrcQuenchs = kstat_get_ui32( ksp, "outSrcQuenchs" );
356 stats->stats.icmpOutStats.dwRedirects = kstat_get_ui32( ksp, "outRedirects" );
357 stats->stats.icmpOutStats.dwEchos = kstat_get_ui32( ksp, "outEchos" );
358 stats->stats.icmpOutStats.dwEchoReps = kstat_get_ui32( ksp, "outEchoReps" );
359 stats->stats.icmpOutStats.dwTimestamps = kstat_get_ui32( ksp, "outTimestamps" );
360 stats->stats.icmpOutStats.dwTimestampReps = kstat_get_ui32( ksp, "outTimestampReps" );
361 stats->stats.icmpOutStats.dwAddrMasks = kstat_get_ui32( ksp, "outAddrMasks" );
362 stats->stats.icmpOutStats.dwAddrMaskReps = kstat_get_ui32( ksp, "outAddrMaskReps" );
363 ret = NO_ERROR;
365 if (kc) kstat_close( kc );
367 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
369 int mib[] = {CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS};
370 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
371 struct icmpstat icmp_stat;
372 size_t needed = sizeof(icmp_stat);
373 int i;
375 if(sysctl(mib, MIB_LEN, &icmp_stat, &needed, NULL, 0) != -1)
377 /*in stats */
378 stats->stats.icmpInStats.dwMsgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
379 for(i = 0; i <= ICMP_MAXTYPE; i++)
380 stats->stats.icmpInStats.dwMsgs += icmp_stat.icps_inhist[i];
382 stats->stats.icmpInStats.dwErrors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
384 stats->stats.icmpInStats.dwDestUnreachs = icmp_stat.icps_inhist[ICMP_UNREACH];
385 stats->stats.icmpInStats.dwTimeExcds = icmp_stat.icps_inhist[ICMP_TIMXCEED];
386 stats->stats.icmpInStats.dwParmProbs = icmp_stat.icps_inhist[ICMP_PARAMPROB];
387 stats->stats.icmpInStats.dwSrcQuenchs = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
388 stats->stats.icmpInStats.dwRedirects = icmp_stat.icps_inhist[ICMP_REDIRECT];
389 stats->stats.icmpInStats.dwEchos = icmp_stat.icps_inhist[ICMP_ECHO];
390 stats->stats.icmpInStats.dwEchoReps = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
391 stats->stats.icmpInStats.dwTimestamps = icmp_stat.icps_inhist[ICMP_TSTAMP];
392 stats->stats.icmpInStats.dwTimestampReps = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
393 stats->stats.icmpInStats.dwAddrMasks = icmp_stat.icps_inhist[ICMP_MASKREQ];
394 stats->stats.icmpInStats.dwAddrMaskReps = icmp_stat.icps_inhist[ICMP_MASKREPLY];
396 #ifdef HAVE_ICPS_OUTHIST
397 /* out stats */
398 stats->stats.icmpOutStats.dwMsgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
399 for(i = 0; i <= ICMP_MAXTYPE; i++)
400 stats->stats.icmpOutStats.dwMsgs += icmp_stat.icps_outhist[i];
402 stats->stats.icmpOutStats.dwErrors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
404 stats->stats.icmpOutStats.dwDestUnreachs = icmp_stat.icps_outhist[ICMP_UNREACH];
405 stats->stats.icmpOutStats.dwTimeExcds = icmp_stat.icps_outhist[ICMP_TIMXCEED];
406 stats->stats.icmpOutStats.dwParmProbs = icmp_stat.icps_outhist[ICMP_PARAMPROB];
407 stats->stats.icmpOutStats.dwSrcQuenchs = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
408 stats->stats.icmpOutStats.dwRedirects = icmp_stat.icps_outhist[ICMP_REDIRECT];
409 stats->stats.icmpOutStats.dwEchos = icmp_stat.icps_outhist[ICMP_ECHO];
410 stats->stats.icmpOutStats.dwEchoReps = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
411 stats->stats.icmpOutStats.dwTimestamps = icmp_stat.icps_outhist[ICMP_TSTAMP];
412 stats->stats.icmpOutStats.dwTimestampReps = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
413 stats->stats.icmpOutStats.dwAddrMasks = icmp_stat.icps_outhist[ICMP_MASKREQ];
414 stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
415 #endif /* ICPS_OUTHIST */
416 ret = NO_ERROR;
419 #else /* ICMPCTL_STATS */
420 FIXME( "unimplemented\n" );
421 #endif
422 return ret;
426 /******************************************************************
427 * GetIpStatistics (IPHLPAPI.@)
429 * Get the IP statistics for the local computer.
431 * PARAMS
432 * stats [Out] buffer for IP statistics
434 * RETURNS
435 * Success: NO_ERROR
436 * Failure: error code from winerror.h
438 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS stats)
440 DWORD ret = ERROR_NOT_SUPPORTED;
441 MIB_IPFORWARDTABLE *fwd_table;
443 if (!stats) return ERROR_INVALID_PARAMETER;
444 memset( stats, 0, sizeof(*stats) );
446 stats->dwNumIf = stats->dwNumAddr = getNumInterfaces();
447 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table, FALSE, GetProcessHeap(), 0 ))
449 stats->dwNumRoutes = fwd_table->dwNumEntries;
450 HeapFree( GetProcessHeap(), 0, fwd_table );
453 #ifdef __linux__
455 FILE *fp;
457 if ((fp = fopen("/proc/net/snmp", "r")))
459 static const char hdr[] = "Ip:";
460 char buf[512], *ptr;
462 while ((ptr = fgets(buf, sizeof(buf), fp)))
464 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
465 /* last line was a header, get another */
466 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
467 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
469 ptr += sizeof(hdr);
470 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
471 &stats->dwForwarding,
472 &stats->dwDefaultTTL,
473 &stats->dwInReceives,
474 &stats->dwInHdrErrors,
475 &stats->dwInAddrErrors,
476 &stats->dwForwDatagrams,
477 &stats->dwInUnknownProtos,
478 &stats->dwInDiscards,
479 &stats->dwInDelivers,
480 &stats->dwOutRequests,
481 &stats->dwOutDiscards,
482 &stats->dwOutNoRoutes,
483 &stats->dwReasmTimeout,
484 &stats->dwReasmReqds,
485 &stats->dwReasmOks,
486 &stats->dwReasmFails,
487 &stats->dwFragOks,
488 &stats->dwFragFails,
489 &stats->dwFragCreates );
490 /* hmm, no routingDiscards */
491 break;
494 fclose(fp);
495 ret = NO_ERROR;
498 #elif defined(HAVE_LIBKSTAT)
500 static char ip[] = "ip";
501 kstat_ctl_t *kc;
502 kstat_t *ksp;
504 if ((kc = kstat_open()) &&
505 (ksp = kstat_lookup( kc, ip, 0, ip )) &&
506 kstat_read( kc, ksp, NULL ) != -1 &&
507 ksp->ks_type == KSTAT_TYPE_NAMED)
509 stats->dwForwarding = kstat_get_ui32( ksp, "forwarding" );
510 stats->dwDefaultTTL = kstat_get_ui32( ksp, "defaultTTL" );
511 stats->dwInReceives = kstat_get_ui32( ksp, "inReceives" );
512 stats->dwInHdrErrors = kstat_get_ui32( ksp, "inHdrErrors" );
513 stats->dwInAddrErrors = kstat_get_ui32( ksp, "inAddrErrors" );
514 stats->dwForwDatagrams = kstat_get_ui32( ksp, "forwDatagrams" );
515 stats->dwInUnknownProtos = kstat_get_ui32( ksp, "inUnknownProtos" );
516 stats->dwInDiscards = kstat_get_ui32( ksp, "inDiscards" );
517 stats->dwInDelivers = kstat_get_ui32( ksp, "inDelivers" );
518 stats->dwOutRequests = kstat_get_ui32( ksp, "outRequests" );
519 stats->dwRoutingDiscards = kstat_get_ui32( ksp, "routingDiscards" );
520 stats->dwOutDiscards = kstat_get_ui32( ksp, "outDiscards" );
521 stats->dwOutNoRoutes = kstat_get_ui32( ksp, "outNoRoutes" );
522 stats->dwReasmTimeout = kstat_get_ui32( ksp, "reasmTimeout" );
523 stats->dwReasmReqds = kstat_get_ui32( ksp, "reasmReqds" );
524 stats->dwReasmOks = kstat_get_ui32( ksp, "reasmOKs" );
525 stats->dwReasmFails = kstat_get_ui32( ksp, "reasmFails" );
526 stats->dwFragOks = kstat_get_ui32( ksp, "fragOKs" );
527 stats->dwFragFails = kstat_get_ui32( ksp, "fragFails" );
528 stats->dwFragCreates = kstat_get_ui32( ksp, "fragCreates" );
529 ret = NO_ERROR;
531 if (kc) kstat_close( kc );
533 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
535 int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS};
536 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
537 int ip_ttl, ip_forwarding;
538 struct ipstat ip_stat;
539 size_t needed;
541 needed = sizeof(ip_stat);
542 if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1)
544 ERR ("failed to get ipstat\n");
545 return ERROR_NOT_SUPPORTED;
548 needed = sizeof(ip_ttl);
549 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1)
551 ERR ("failed to get ip Default TTL\n");
552 return ERROR_NOT_SUPPORTED;
555 needed = sizeof(ip_forwarding);
556 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1)
558 ERR ("failed to get ip forwarding\n");
559 return ERROR_NOT_SUPPORTED;
562 stats->dwForwarding = ip_forwarding;
563 stats->dwDefaultTTL = ip_ttl;
564 stats->dwInDelivers = ip_stat.ips_delivered;
565 stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen;
566 stats->dwInAddrErrors = ip_stat.ips_cantforward;
567 stats->dwInReceives = ip_stat.ips_total;
568 stats->dwForwDatagrams = ip_stat.ips_forward;
569 stats->dwInUnknownProtos = ip_stat.ips_noproto;
570 stats->dwInDiscards = ip_stat.ips_fragdropped;
571 stats->dwOutDiscards = ip_stat.ips_odropped;
572 stats->dwReasmOks = ip_stat.ips_reassembled;
573 stats->dwFragOks = ip_stat.ips_fragmented;
574 stats->dwFragFails = ip_stat.ips_cantfrag;
575 stats->dwReasmTimeout = ip_stat.ips_fragtimeout;
576 stats->dwOutNoRoutes = ip_stat.ips_noroute;
577 stats->dwOutRequests = ip_stat.ips_localout;
578 stats->dwReasmReqds = ip_stat.ips_fragments;
579 ret = NO_ERROR;
581 #else
582 FIXME( "unimplemented\n" );
583 #endif
584 return ret;
588 /******************************************************************
589 * GetTcpStatistics (IPHLPAPI.@)
591 * Get the TCP statistics for the local computer.
593 * PARAMS
594 * stats [Out] buffer for TCP statistics
596 * RETURNS
597 * Success: NO_ERROR
598 * Failure: error code from winerror.h
600 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS stats)
602 DWORD ret = ERROR_NOT_SUPPORTED;
604 if (!stats) return ERROR_INVALID_PARAMETER;
605 memset( stats, 0, sizeof(*stats) );
607 #ifdef __linux__
609 FILE *fp;
611 if ((fp = fopen("/proc/net/snmp", "r")))
613 static const char hdr[] = "Tcp:";
614 MIB_TCPTABLE *tcp_table;
615 char buf[512], *ptr;
617 while ((ptr = fgets(buf, sizeof(buf), fp)))
619 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
620 /* last line was a header, get another */
621 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
622 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
624 ptr += sizeof(hdr);
625 sscanf( ptr, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
626 &stats->dwRtoAlgorithm,
627 &stats->dwRtoMin,
628 &stats->dwRtoMax,
629 &stats->dwMaxConn,
630 &stats->dwActiveOpens,
631 &stats->dwPassiveOpens,
632 &stats->dwAttemptFails,
633 &stats->dwEstabResets,
634 &stats->dwCurrEstab,
635 &stats->dwInSegs,
636 &stats->dwOutSegs,
637 &stats->dwRetransSegs,
638 &stats->dwInErrs,
639 &stats->dwOutRsts );
640 break;
643 if (!AllocateAndGetTcpTableFromStack( &tcp_table, FALSE, GetProcessHeap(), 0 ))
645 stats->dwNumConns = tcp_table->dwNumEntries;
646 HeapFree( GetProcessHeap(), 0, tcp_table );
648 fclose(fp);
649 ret = NO_ERROR;
652 #elif defined(HAVE_LIBKSTAT)
654 static char tcp[] = "tcp";
655 kstat_ctl_t *kc;
656 kstat_t *ksp;
658 if ((kc = kstat_open()) &&
659 (ksp = kstat_lookup( kc, tcp, 0, tcp )) &&
660 kstat_read( kc, ksp, NULL ) != -1 &&
661 ksp->ks_type == KSTAT_TYPE_NAMED)
663 stats->dwRtoAlgorithm = kstat_get_ui32( ksp, "rtoAlgorithm" );
664 stats->dwRtoMin = kstat_get_ui32( ksp, "rtoMin" );
665 stats->dwRtoMax = kstat_get_ui32( ksp, "rtoMax" );
666 stats->dwMaxConn = kstat_get_ui32( ksp, "maxConn" );
667 stats->dwActiveOpens = kstat_get_ui32( ksp, "activeOpens" );
668 stats->dwPassiveOpens = kstat_get_ui32( ksp, "passiveOpens" );
669 stats->dwAttemptFails = kstat_get_ui32( ksp, "attemptFails" );
670 stats->dwEstabResets = kstat_get_ui32( ksp, "estabResets" );
671 stats->dwCurrEstab = kstat_get_ui32( ksp, "currEstab" );
672 stats->dwInSegs = kstat_get_ui32( ksp, "inSegs" );
673 stats->dwOutSegs = kstat_get_ui32( ksp, "outSegs" );
674 stats->dwRetransSegs = kstat_get_ui32( ksp, "retransSegs" );
675 stats->dwInErrs = kstat_get_ui32( ksp, "inErrs" );
676 stats->dwOutRsts = kstat_get_ui32( ksp, "outRsts" );
677 stats->dwNumConns = kstat_get_ui32( ksp, "connTableSize" );
678 ret = NO_ERROR;
680 if (kc) kstat_close( kc );
682 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
684 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
685 #define TCPTV_MIN 2
686 #define TCPTV_REXMTMAX 128
687 #endif
688 int mib[] = {CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS};
689 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
690 #define hz 1000
691 struct tcpstat tcp_stat;
692 size_t needed = sizeof(tcp_stat);
694 if(sysctl(mib, MIB_LEN, &tcp_stat, &needed, NULL, 0) != -1)
696 stats->dwRtoAlgorithm = MIB_TCP_RTO_VANJ;
697 stats->dwRtoMin = TCPTV_MIN;
698 stats->dwRtoMax = TCPTV_REXMTMAX;
699 stats->dwMaxConn = -1;
700 stats->dwActiveOpens = tcp_stat.tcps_connattempt;
701 stats->dwPassiveOpens = tcp_stat.tcps_accepts;
702 stats->dwAttemptFails = tcp_stat.tcps_conndrops;
703 stats->dwEstabResets = tcp_stat.tcps_drops;
704 stats->dwCurrEstab = 0;
705 stats->dwInSegs = tcp_stat.tcps_rcvtotal;
706 stats->dwOutSegs = tcp_stat.tcps_sndtotal - tcp_stat.tcps_sndrexmitpack;
707 stats->dwRetransSegs = tcp_stat.tcps_sndrexmitpack;
708 stats->dwInErrs = tcp_stat.tcps_rcvbadsum + tcp_stat.tcps_rcvbadoff + tcp_stat.tcps_rcvmemdrop + tcp_stat.tcps_rcvshort;
709 stats->dwOutRsts = tcp_stat.tcps_sndctrl - tcp_stat.tcps_closed;
710 stats->dwNumConns = tcp_stat.tcps_connects;
711 ret = NO_ERROR;
713 else ERR ("failed to get tcpstat\n");
715 #else
716 FIXME( "unimplemented\n" );
717 #endif
718 return ret;
722 /******************************************************************
723 * GetUdpStatistics (IPHLPAPI.@)
725 * Get the UDP statistics for the local computer.
727 * PARAMS
728 * stats [Out] buffer for UDP statistics
730 * RETURNS
731 * Success: NO_ERROR
732 * Failure: error code from winerror.h
734 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS stats)
736 DWORD ret = ERROR_NOT_SUPPORTED;
738 if (!stats) return ERROR_INVALID_PARAMETER;
739 memset( stats, 0, sizeof(*stats) );
741 #ifdef __linux__
743 FILE *fp;
745 if ((fp = fopen("/proc/net/snmp", "r")))
747 static const char hdr[] = "Udp:";
748 char buf[512], *ptr;
750 while ((ptr = fgets(buf, sizeof(buf), fp)))
752 if (strncasecmp(buf, hdr, sizeof(hdr) - 1)) continue;
753 /* last line was a header, get another */
754 if (!(ptr = fgets(buf, sizeof(buf), fp))) break;
755 if (!strncasecmp(buf, hdr, sizeof(hdr) - 1))
757 ptr += sizeof(hdr);
758 sscanf( ptr, "%u %u %u %u %u",
759 &stats->dwInDatagrams, &stats->dwNoPorts,
760 &stats->dwInErrors, &stats->dwOutDatagrams, &stats->dwNumAddrs );
761 break;
764 fclose(fp);
765 ret = NO_ERROR;
768 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
770 int mib[] = {CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_STATS};
771 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
772 struct udpstat udp_stat;
773 MIB_UDPTABLE *udp_table;
774 size_t needed = sizeof(udp_stat);
776 if(sysctl(mib, MIB_LEN, &udp_stat, &needed, NULL, 0) != -1)
778 stats->dwInDatagrams = udp_stat.udps_ipackets;
779 stats->dwOutDatagrams = udp_stat.udps_opackets;
780 stats->dwNoPorts = udp_stat.udps_noport;
781 stats->dwInErrors = udp_stat.udps_hdrops + udp_stat.udps_badsum + udp_stat.udps_fullsock + udp_stat.udps_badlen;
782 if (!AllocateAndGetUdpTableFromStack( &udp_table, FALSE, GetProcessHeap(), 0 ))
784 stats->dwNumAddrs = udp_table->dwNumEntries;
785 HeapFree( GetProcessHeap(), 0, udp_table );
787 ret = NO_ERROR;
789 else ERR ("failed to get udpstat\n");
791 #else
792 FIXME( "unimplemented\n" );
793 #endif
794 return ret;
798 static MIB_IPFORWARDTABLE *append_ipforward_row( HANDLE heap, DWORD flags, MIB_IPFORWARDTABLE *table,
799 DWORD *count, const MIB_IPFORWARDROW *row )
801 if (table->dwNumEntries >= *count)
803 MIB_IPFORWARDTABLE *new_table;
804 DWORD new_count = table->dwNumEntries * 2;
806 if (!(new_table = HeapReAlloc( heap, flags, table,
807 FIELD_OFFSET(MIB_IPFORWARDTABLE, table[new_count] ))))
809 HeapFree( heap, 0, table );
810 return NULL;
812 *count = new_count;
813 table = new_table;
815 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
816 return table;
819 static int compare_ipforward_rows(const void *a, const void *b)
821 const MIB_IPFORWARDROW *rowA = a;
822 const MIB_IPFORWARDROW *rowB = b;
823 int ret;
825 if ((ret = rowA->dwForwardDest - rowB->dwForwardDest) != 0) return ret;
826 if ((ret = rowA->dwForwardProto - rowB->dwForwardProto) != 0) return ret;
827 if ((ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy) != 0) return ret;
828 return rowA->dwForwardNextHop - rowB->dwForwardNextHop;
831 /******************************************************************
832 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
834 * Get the route table.
835 * Like GetIpForwardTable(), but allocate the returned table from heap.
837 * PARAMS
838 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
839 * allocated and returned.
840 * bOrder [In] whether to sort the table
841 * heap [In] heap from which the table is allocated
842 * flags [In] flags to HeapAlloc
844 * RETURNS
845 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
846 * on failure, NO_ERROR on success.
848 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *ppIpForwardTable, BOOL bOrder,
849 HANDLE heap, DWORD flags)
851 MIB_IPFORWARDTABLE *table;
852 MIB_IPFORWARDROW row;
853 DWORD ret = NO_ERROR, count = 16;
855 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable, bOrder, heap, flags);
857 if (!ppIpForwardTable) return ERROR_INVALID_PARAMETER;
859 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPFORWARDTABLE, table[count] ))))
860 return ERROR_OUTOFMEMORY;
862 table->dwNumEntries = 0;
864 #ifdef __linux__
866 FILE *fp;
868 if ((fp = fopen("/proc/net/route", "r")))
870 char buf[512], *ptr;
871 DWORD flags;
873 /* skip header line */
874 ptr = fgets(buf, sizeof(buf), fp);
875 while ((ptr = fgets(buf, sizeof(buf), fp)))
877 memset( &row, 0, sizeof(row) );
879 while (!isspace(*ptr)) ptr++;
880 *ptr++ = 0;
881 if (getInterfaceIndexByName(buf, &row.dwForwardIfIndex) != NO_ERROR)
882 continue;
884 row.dwForwardDest = strtoul(ptr, &ptr, 16);
885 row.dwForwardNextHop = strtoul(ptr + 1, &ptr, 16);
886 flags = strtoul(ptr + 1, &ptr, 16);
888 if (!(flags & RTF_UP)) row.dwForwardType = MIB_IPROUTE_TYPE_INVALID;
889 else if (flags & RTF_GATEWAY) row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
890 else row.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
892 strtoul(ptr + 1, &ptr, 16); /* refcount, skip */
893 strtoul(ptr + 1, &ptr, 16); /* use, skip */
894 row.dwForwardMetric1 = strtoul(ptr + 1, &ptr, 16);
895 row.dwForwardMask = strtoul(ptr + 1, &ptr, 16);
896 /* FIXME: other protos might be appropriate, e.g. the default
897 * route is typically set with MIB_IPPROTO_NETMGMT instead */
898 row.dwForwardProto = MIB_IPPROTO_LOCAL;
900 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
901 break;
903 fclose(fp);
905 else ret = ERROR_NOT_SUPPORTED;
907 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
909 int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0};
910 size_t needed;
911 char *buf = NULL, *lim, *next, *addrPtr;
912 struct rt_msghdr *rtm;
914 if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
916 ERR ("sysctl 1 failed!\n");
917 ret = ERROR_NOT_SUPPORTED;
918 goto done;
921 buf = HeapAlloc (GetProcessHeap (), 0, needed);
922 if (!buf)
924 ret = ERROR_OUTOFMEMORY;
925 goto done;
928 if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
930 ret = ERROR_NOT_SUPPORTED;
931 goto done;
934 lim = buf + needed;
935 for (next = buf; next < lim; next += rtm->rtm_msglen)
937 int i;
939 rtm = (struct rt_msghdr *)next;
941 if (rtm->rtm_type != RTM_GET)
943 WARN ("Got unexpected message type 0x%x!\n",
944 rtm->rtm_type);
945 continue;
948 /* Ignore all entries except for gateway routes which aren't
949 multicast */
950 if (!(rtm->rtm_flags & RTF_GATEWAY) ||
951 (rtm->rtm_flags & RTF_MULTICAST))
952 continue;
954 memset( &row, 0, sizeof(row) );
955 row.dwForwardIfIndex = rtm->rtm_index;
956 row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
957 row.dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount;
958 row.dwForwardProto = MIB_IPPROTO_LOCAL;
960 addrPtr = (char *)(rtm + 1);
962 for (i = 1; i; i <<= 1)
964 struct sockaddr *sa;
965 DWORD addr;
967 if (!(i & rtm->rtm_addrs))
968 continue;
970 sa = (struct sockaddr *)addrPtr;
971 ADVANCE (addrPtr, sa);
973 /* default routes are encoded by length-zero sockaddr */
974 if (sa->sa_len == 0)
975 addr = 0;
976 else if (sa->sa_family != AF_INET)
978 WARN ("Received unsupported sockaddr family 0x%x\n",
979 sa->sa_family);
980 addr = 0;
982 else
984 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
986 addr = sin->sin_addr.s_addr;
989 switch (i)
991 case RTA_DST: row.dwForwardDest = addr; break;
992 case RTA_GATEWAY: row.dwForwardNextHop = addr; break;
993 case RTA_NETMASK: row.dwForwardMask = addr; break;
994 default:
995 WARN ("Unexpected address type 0x%x\n", i);
999 if (!(table = append_ipforward_row( heap, flags, table, &count, &row )))
1000 break;
1002 done:
1003 HeapFree( GetProcessHeap (), 0, buf );
1005 #else
1006 FIXME( "not implemented\n" );
1007 ret = ERROR_NOT_SUPPORTED;
1008 #endif
1010 if (!table) return ERROR_OUTOFMEMORY;
1011 if (!ret)
1013 if (bOrder && table->dwNumEntries)
1014 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipforward_rows );
1015 *ppIpForwardTable = table;
1017 else HeapFree( heap, flags, table );
1018 TRACE( "returning ret %u table %p\n", ret, table );
1019 return ret;
1022 static MIB_IPNETTABLE *append_ipnet_row( HANDLE heap, DWORD flags, MIB_IPNETTABLE *table,
1023 DWORD *count, const MIB_IPNETROW *row )
1025 if (table->dwNumEntries >= *count)
1027 MIB_IPNETTABLE *new_table;
1028 DWORD new_count = table->dwNumEntries * 2;
1030 if (!(new_table = HeapReAlloc( heap, flags, table,
1031 FIELD_OFFSET(MIB_IPNETTABLE, table[new_count] ))))
1033 HeapFree( heap, 0, table );
1034 return NULL;
1036 *count = new_count;
1037 table = new_table;
1039 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1040 return table;
1043 static int compare_ipnet_rows(const void *a, const void *b)
1045 const MIB_IPNETROW *rowA = a;
1046 const MIB_IPNETROW *rowB = b;
1048 return ntohl(rowA->dwAddr) - ntohl(rowB->dwAddr);
1052 /******************************************************************
1053 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1055 * Get the IP-to-physical address mapping table.
1056 * Like GetIpNetTable(), but allocate the returned table from heap.
1058 * PARAMS
1059 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1060 * allocated and returned.
1061 * bOrder [In] whether to sort the table
1062 * heap [In] heap from which the table is allocated
1063 * flags [In] flags to HeapAlloc
1065 * RETURNS
1066 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1067 * on failure, NO_ERROR on success.
1069 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable, BOOL bOrder,
1070 HANDLE heap, DWORD flags)
1072 MIB_IPNETTABLE *table;
1073 MIB_IPNETROW row;
1074 DWORD ret = NO_ERROR, count = 16;
1076 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable, bOrder, heap, flags);
1078 if (!ppIpNetTable) return ERROR_INVALID_PARAMETER;
1080 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_IPNETTABLE, table[count] ))))
1081 return ERROR_OUTOFMEMORY;
1083 table->dwNumEntries = 0;
1085 #ifdef __linux__
1087 FILE *fp;
1089 if ((fp = fopen("/proc/net/arp", "r")))
1091 char buf[512], *ptr;
1092 DWORD flags;
1094 /* skip header line */
1095 ptr = fgets(buf, sizeof(buf), fp);
1096 while ((ptr = fgets(buf, sizeof(buf), fp)))
1098 memset( &row, 0, sizeof(row) );
1100 row.dwAddr = inet_addr(ptr);
1101 while (*ptr && !isspace(*ptr)) ptr++;
1102 strtoul(ptr + 1, &ptr, 16); /* hw type (skip) */
1103 flags = strtoul(ptr + 1, &ptr, 16);
1105 #ifdef ATF_COM
1106 if (flags & ATF_COM) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1107 else
1108 #endif
1109 #ifdef ATF_PERM
1110 if (flags & ATF_PERM) row.dwType = MIB_IPNET_TYPE_STATIC;
1111 else
1112 #endif
1113 row.dwType = MIB_IPNET_TYPE_OTHER;
1115 while (*ptr && isspace(*ptr)) ptr++;
1116 while (*ptr && !isspace(*ptr))
1118 row.bPhysAddr[row.dwPhysAddrLen++] = strtoul(ptr, &ptr, 16);
1119 if (*ptr) ptr++;
1121 while (*ptr && isspace(*ptr)) ptr++;
1122 while (*ptr && !isspace(*ptr)) ptr++; /* mask (skip) */
1123 while (*ptr && isspace(*ptr)) ptr++;
1124 getInterfaceIndexByName(ptr, &row.dwIndex);
1126 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1127 break;
1129 fclose(fp);
1131 else ret = ERROR_NOT_SUPPORTED;
1133 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1135 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO};
1136 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1137 size_t needed;
1138 char *buf = NULL, *lim, *next;
1139 struct rt_msghdr *rtm;
1140 struct sockaddr_inarp *sinarp;
1141 struct sockaddr_dl *sdl;
1143 if (sysctl (mib, MIB_LEN, NULL, &needed, NULL, 0) == -1)
1145 ERR ("failed to get arp table\n");
1146 ret = ERROR_NOT_SUPPORTED;
1147 goto done;
1150 buf = HeapAlloc (GetProcessHeap (), 0, needed);
1151 if (!buf)
1153 ret = ERROR_OUTOFMEMORY;
1154 goto done;
1157 if (sysctl (mib, MIB_LEN, buf, &needed, NULL, 0) == -1)
1159 ret = ERROR_NOT_SUPPORTED;
1160 goto done;
1163 lim = buf + needed;
1164 next = buf;
1165 while(next < lim)
1167 rtm = (struct rt_msghdr *)next;
1168 sinarp=(struct sockaddr_inarp *)(rtm + 1);
1169 sdl = (struct sockaddr_dl *)((char *)sinarp + ROUNDUP(sinarp->sin_len));
1170 if(sdl->sdl_alen) /* arp entry */
1172 memset( &row, 0, sizeof(row) );
1173 row.dwAddr = sinarp->sin_addr.s_addr;
1174 row.dwIndex = sdl->sdl_index;
1175 row.dwPhysAddrLen = min( 8, sdl->sdl_alen );
1176 memcpy( row.bPhysAddr, &sdl->sdl_data[sdl->sdl_nlen], row.dwPhysAddrLen );
1177 if(rtm->rtm_rmx.rmx_expire == 0) row.dwType = MIB_IPNET_TYPE_STATIC;
1178 else if(sinarp->sin_other & SIN_PROXY) row.dwType = MIB_IPNET_TYPE_OTHER;
1179 else if(rtm->rtm_rmx.rmx_expire != 0) row.dwType = MIB_IPNET_TYPE_DYNAMIC;
1180 else row.dwType = MIB_IPNET_TYPE_INVALID;
1182 if (!(table = append_ipnet_row( heap, flags, table, &count, &row )))
1183 break;
1185 next += rtm->rtm_msglen;
1187 done:
1188 HeapFree( GetProcessHeap (), 0, buf );
1190 #else
1191 FIXME( "not implemented\n" );
1192 ret = ERROR_NOT_SUPPORTED;
1193 #endif
1195 if (!table) return ERROR_OUTOFMEMORY;
1196 if (!ret)
1198 if (bOrder && table->dwNumEntries)
1199 qsort( table->table, table->dwNumEntries, sizeof(row), compare_ipnet_rows );
1200 *ppIpNetTable = table;
1202 else HeapFree( heap, flags, table );
1203 TRACE( "returning ret %u table %p\n", ret, table );
1204 return ret;
1208 static MIB_UDPTABLE *append_udp_row( HANDLE heap, DWORD flags, MIB_UDPTABLE *table,
1209 DWORD *count, const MIB_UDPROW *row )
1211 if (table->dwNumEntries >= *count)
1213 MIB_UDPTABLE *new_table;
1214 DWORD new_count = table->dwNumEntries * 2;
1216 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_UDPTABLE, table[new_count] ))))
1218 HeapFree( heap, 0, table );
1219 return NULL;
1221 *count = new_count;
1222 table = new_table;
1224 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1225 return table;
1228 static int compare_udp_rows(const void *a, const void *b)
1230 const MIB_UDPROW *rowA = a;
1231 const MIB_UDPROW *rowB = b;
1232 int ret;
1234 if ((ret = rowA->dwLocalAddr - rowB->dwLocalAddr) != 0) return ret;
1235 return rowA->dwLocalPort - rowB->dwLocalPort;
1239 /******************************************************************
1240 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1242 * Get the UDP listener table.
1243 * Like GetUdpTable(), but allocate the returned table from heap.
1245 * PARAMS
1246 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1247 * allocated and returned.
1248 * bOrder [In] whether to sort the table
1249 * heap [In] heap from which the table is allocated
1250 * flags [In] flags to HeapAlloc
1252 * RETURNS
1253 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1254 * returns otherwise.
1256 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable, BOOL bOrder,
1257 HANDLE heap, DWORD flags)
1259 MIB_UDPTABLE *table;
1260 MIB_UDPROW row;
1261 DWORD ret = NO_ERROR, count = 16;
1263 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable, bOrder, heap, flags);
1265 if (!ppUdpTable) return ERROR_INVALID_PARAMETER;
1267 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_UDPTABLE, table[count] ))))
1268 return ERROR_OUTOFMEMORY;
1270 table->dwNumEntries = 0;
1272 #ifdef __linux__
1274 FILE *fp;
1276 if ((fp = fopen("/proc/net/udp", "r")))
1278 char buf[512], *ptr;
1279 DWORD dummy;
1281 /* skip header line */
1282 ptr = fgets(buf, sizeof(buf), fp);
1283 while ((ptr = fgets(buf, sizeof(buf), fp)))
1285 if (sscanf( ptr, "%u: %x:%x", &dummy, &row.dwLocalAddr, &row.dwLocalPort ) != 3)
1286 continue;
1287 row.dwLocalPort = htons( row.dwLocalPort );
1288 if (!(table = append_udp_row( heap, flags, table, &count, &row )))
1289 break;
1291 fclose(fp);
1293 else ret = ERROR_NOT_SUPPORTED;
1295 #else
1296 FIXME( "not implemented\n" );
1297 ret = ERROR_NOT_SUPPORTED;
1298 #endif
1300 if (!table) return ERROR_OUTOFMEMORY;
1301 if (!ret)
1303 if (bOrder && table->dwNumEntries)
1304 qsort( table->table, table->dwNumEntries, sizeof(row), compare_udp_rows );
1305 *ppUdpTable = table;
1307 else HeapFree( heap, flags, table );
1308 TRACE( "returning ret %u table %p\n", ret, table );
1309 return ret;
1313 static MIB_TCPTABLE *append_tcp_row( HANDLE heap, DWORD flags, MIB_TCPTABLE *table,
1314 DWORD *count, const MIB_TCPROW *row )
1316 if (table->dwNumEntries >= *count)
1318 MIB_TCPTABLE *new_table;
1319 DWORD new_count = table->dwNumEntries * 2;
1321 if (!(new_table = HeapReAlloc( heap, flags, table, FIELD_OFFSET(MIB_TCPTABLE, table[new_count] ))))
1323 HeapFree( heap, 0, table );
1324 return NULL;
1326 *count = new_count;
1327 table = new_table;
1329 memcpy( &table->table[table->dwNumEntries++], row, sizeof(*row) );
1330 return table;
1334 /* Why not a lookup table? Because the TCPS_* constants are different
1335 on different platforms */
1336 static DWORD TCPStateToMIBState (int state)
1338 switch (state)
1340 case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
1341 case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
1342 case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
1343 case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
1344 case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
1345 case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
1346 case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
1347 case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
1348 case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
1349 case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
1350 default:
1351 case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
1356 static int compare_tcp_rows(const void *a, const void *b)
1358 const MIB_TCPROW *rowA = a;
1359 const MIB_TCPROW *rowB = b;
1360 int ret;
1362 if ((ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr)) != 0) return ret;
1363 if ((ret = ntohs ((unsigned short)rowA->dwLocalPort) -
1364 ntohs ((unsigned short)rowB->dwLocalPort)) != 0) return ret;
1365 if ((ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr)) != 0) return ret;
1366 return ntohs ((unsigned short)rowA->dwRemotePort) - ntohs ((unsigned short)rowB->dwRemotePort);
1370 /******************************************************************
1371 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1373 * Get the TCP connection table.
1374 * Like GetTcpTable(), but allocate the returned table from heap.
1376 * PARAMS
1377 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1378 * allocated and returned.
1379 * bOrder [In] whether to sort the table
1380 * heap [In] heap from which the table is allocated
1381 * flags [In] flags to HeapAlloc
1383 * RETURNS
1384 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1385 * returns otherwise.
1387 DWORD WINAPI AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE *ppTcpTable, BOOL bOrder,
1388 HANDLE heap, DWORD flags)
1390 MIB_TCPTABLE *table;
1391 MIB_TCPROW row;
1392 DWORD ret = NO_ERROR, count = 16;
1394 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable, bOrder, heap, flags);
1396 if (!ppTcpTable) return ERROR_INVALID_PARAMETER;
1398 if (!(table = HeapAlloc( heap, flags, FIELD_OFFSET(MIB_TCPTABLE, table[count] ))))
1399 return ERROR_OUTOFMEMORY;
1401 table->dwNumEntries = 0;
1403 #ifdef __linux__
1405 FILE *fp;
1407 if ((fp = fopen("/proc/net/tcp", "r")))
1409 char buf[512], *ptr;
1410 DWORD dummy;
1412 /* skip header line */
1413 ptr = fgets(buf, sizeof(buf), fp);
1414 while ((ptr = fgets(buf, sizeof(buf), fp)))
1416 if (sscanf( ptr, "%x: %x:%x %x:%x %x", &dummy, &row.dwLocalAddr, &row.dwLocalPort,
1417 &row.dwRemoteAddr, &row.dwRemotePort, &row.dwState ) != 6)
1418 continue;
1419 row.dwLocalPort = htons( row.dwLocalPort );
1420 row.dwRemotePort = htons( row.dwRemotePort );
1421 row.dwState = TCPStateToMIBState( row.dwState );
1422 if (!(table = append_tcp_row( heap, flags, table, &count, &row )))
1423 break;
1425 fclose( fp );
1427 else ret = ERROR_NOT_SUPPORTED;
1429 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1431 size_t Len = 0;
1432 char *Buf = NULL;
1433 struct xinpgen *pXIG, *pOrigXIG;
1435 if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
1437 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1438 ret = ERROR_NOT_SUPPORTED;
1439 goto done;
1442 Buf = HeapAlloc (GetProcessHeap (), 0, Len);
1443 if (!Buf)
1445 ret = ERROR_OUTOFMEMORY;
1446 goto done;
1449 if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
1451 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1452 ret = ERROR_NOT_SUPPORTED;
1453 goto done;
1456 /* Might be nothing here; first entry is just a header it seems */
1457 if (Len <= sizeof (struct xinpgen)) goto done;
1459 pOrigXIG = (struct xinpgen *)Buf;
1460 pXIG = pOrigXIG;
1462 for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
1463 pXIG->xig_len > sizeof (struct xinpgen);
1464 pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
1466 struct tcpcb *pTCPData = NULL;
1467 struct inpcb *pINData;
1468 struct xsocket *pSockData;
1470 pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
1471 pINData = &((struct xtcpcb *)pXIG)->xt_inp;
1472 pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
1474 /* Ignore sockets for other protocols */
1475 if (pSockData->xso_protocol != IPPROTO_TCP)
1476 continue;
1478 /* Ignore PCBs that were freed while generating the data */
1479 if (pINData->inp_gencnt > pOrigXIG->xig_gen)
1480 continue;
1482 /* we're only interested in IPv4 addresses */
1483 if (!(pINData->inp_vflag & INP_IPV4) ||
1484 (pINData->inp_vflag & INP_IPV6))
1485 continue;
1487 /* If all 0's, skip it */
1488 if (!pINData->inp_laddr.s_addr &&
1489 !pINData->inp_lport &&
1490 !pINData->inp_faddr.s_addr &&
1491 !pINData->inp_fport)
1492 continue;
1494 /* Fill in structure details */
1495 row.dwLocalAddr = pINData->inp_laddr.s_addr;
1496 row.dwLocalPort = pINData->inp_lport;
1497 row.dwRemoteAddr = pINData->inp_faddr.s_addr;
1498 row.dwRemotePort = pINData->inp_fport;
1499 row.dwState = TCPStateToMIBState (pTCPData->t_state);
1500 if (!(table = append_tcp_row( heap, flags, table, &count, &row ))) break;
1503 done:
1504 HeapFree (GetProcessHeap (), 0, Buf);
1506 #else
1507 FIXME( "not implemented\n" );
1508 ret = ERROR_NOT_SUPPORTED;
1509 #endif
1511 if (!table) return ERROR_OUTOFMEMORY;
1512 if (!ret)
1514 if (bOrder && table->dwNumEntries)
1515 qsort( table->table, table->dwNumEntries, sizeof(row), compare_tcp_rows );
1516 *ppTcpTable = table;
1518 else HeapFree( heap, flags, table );
1519 TRACE( "returning ret %u table %p\n", ret, table );
1520 return ret;