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
22 #include "wine/port.h"
28 #include <sys/types.h>
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
35 #ifdef HAVE_SYS_SOCKETVAR_H
36 #include <sys/socketvar.h>
38 #ifdef HAVE_SYS_TIMEOUT_H
39 #include <sys/timeout.h>
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
53 #ifdef HAVE_NET_IF_DL_H
54 #include <net/if_dl.h>
56 #ifdef HAVE_NET_IF_TYPES_H
57 #include <net/if_types.h>
59 #ifdef HAVE_NET_ROUTE_H
60 #include <net/route.h>
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
65 #ifdef HAVE_NETINET_IF_ETHER_H
66 #include <netinet/if_ether.h>
68 #ifdef HAVE_NETINET_IF_INARP_H
69 #include <netinet/if_inarp.h>
71 #ifdef HAVE_NETINET_IP_H
72 #include <netinet/ip.h>
74 #ifdef HAVE_NETINET_TCP_H
75 #include <netinet/tcp.h>
77 #ifdef HAVE_NETINET_IP_VAR_H
78 #include <netinet/ip_var.h>
80 #ifdef HAVE_NETINET_TCP_FSM_H
81 #include <netinet/tcp_fsm.h>
83 #ifdef HAVE_NETINET_IN_PCB_H
84 #include <netinet/in_pcb.h>
86 #ifdef HAVE_NETINET_TCP_TIMER_H
87 #include <netinet/tcp_timer.h>
89 #ifdef HAVE_NETINET_TCP_VAR_H
90 #include <netinet/tcp_var.h>
92 #ifdef HAVE_NETINET_IP_ICMP_H
93 #include <netinet/ip_icmp.h>
95 #ifdef HAVE_NETINET_ICMP_VAR_H
96 #include <netinet/icmp_var.h>
98 #ifdef HAVE_NETINET_UDP_H
99 #include <netinet/udp.h>
101 #ifdef HAVE_NETINET_UDP_VAR_H
102 #include <netinet/udp_var.h>
104 #ifdef HAVE_SYS_PROTOSW_H
105 #include <sys/protosw.h>
107 #ifdef HAVE_SYS_SYSCTL_H
108 #include <sys/sysctl.h>
116 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
119 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
124 #include "iprtrmib.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
144 #ifndef RTF_MULTICAST
145 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
149 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
152 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
155 static DWORD
kstat_get_ui32( kstat_t
*ksp
, const char *name
)
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
;
165 static ULONGLONG
kstat_get_ui64( kstat_t
*ksp
, const char *name
)
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
;
176 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
178 DWORD ret
= ERROR_NOT_SUPPORTED
;
180 if (!name
|| !entry
) return ERROR_INVALID_PARAMETER
;
186 if ((fp
= fopen("/proc/net/dev", "r")))
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
) == ':')
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
,
202 &entry
->dwInNUcastPkts
, &entry
->dwOutOctets
,
203 &entry
->dwOutUcastPkts
, &entry
->dwOutErrors
,
204 &entry
->dwOutDiscards
);
212 #elif defined(HAVE_LIBKSTAT)
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" );
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]))
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");
257 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
260 ret
= ERROR_OUTOFMEMORY
;
263 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
265 ERR ("failed to get iflist\n");
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
;
289 HeapFree (GetProcessHeap (), 0, buf
);
292 FIXME( "unimplemented\n" );
298 /******************************************************************
299 * GetIcmpStatistics (IPHLPAPI.@)
301 * Get the ICMP statistics for the local computer.
304 * stats [Out] buffer for ICMP statistics
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
) );
321 if ((fp
= fopen("/proc/net/snmp", "r")))
323 static const char hdr
[] = "Icmp:";
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))
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
);
366 #elif defined(HAVE_LIBKSTAT)
368 static char ip
[] = "ip", icmp
[] = "icmp";
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" );
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
);
415 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) != -1)
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
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 */
459 #else /* ICMPCTL_STATS */
460 FIXME( "unimplemented\n" );
466 /******************************************************************
467 * GetIpStatistics (IPHLPAPI.@)
469 * Get the IP statistics for the local computer.
472 * stats [Out] buffer for IP statistics
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
);
497 if ((fp
= fopen("/proc/net/snmp", "r")))
499 static const char hdr
[] = "Ip:";
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))
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
,
526 &stats
->dwReasmFails
,
529 &stats
->dwFragCreates
);
530 /* hmm, no routingDiscards */
538 #elif defined(HAVE_LIBKSTAT)
540 static char ip
[] = "ip";
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" );
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
;
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
;
622 FIXME( "unimplemented\n" );
628 /******************************************************************
629 * GetTcpStatistics (IPHLPAPI.@)
631 * Get the TCP statistics for the local computer.
634 * stats [Out] buffer for TCP statistics
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
) );
651 if ((fp
= fopen("/proc/net/snmp", "r")))
653 static const char hdr
[] = "Tcp:";
654 MIB_TCPTABLE
*tcp_table
;
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))
665 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
666 &stats
->dwRtoAlgorithm
,
670 &stats
->dwActiveOpens
,
671 &stats
->dwPassiveOpens
,
672 &stats
->dwAttemptFails
,
673 &stats
->dwEstabResets
,
677 &stats
->dwRetransSegs
,
683 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
685 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
686 HeapFree( GetProcessHeap(), 0, tcp_table
);
692 #elif defined(HAVE_LIBKSTAT)
694 static char tcp
[] = "tcp";
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" );
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 */
726 #define TCPTV_REXMTMAX 128
728 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
729 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
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
;
753 else ERR ("failed to get tcpstat\n");
756 FIXME( "unimplemented\n" );
762 /******************************************************************
763 * GetUdpStatistics (IPHLPAPI.@)
765 * Get the UDP statistics for the local computer.
768 * stats [Out] buffer for UDP statistics
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
) );
785 if ((fp
= fopen("/proc/net/snmp", "r")))
787 static const char hdr
[] = "Udp:";
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))
798 sscanf( ptr
, "%u %u %u %u %u",
799 &stats
->dwInDatagrams
, &stats
->dwNoPorts
,
800 &stats
->dwInErrors
, &stats
->dwOutDatagrams
, &stats
->dwNumAddrs
);
808 #elif defined(HAVE_LIBKSTAT)
810 static char udp
[] = "udp";
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
);
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
);
854 else ERR ("failed to get udpstat\n");
857 FIXME( "unimplemented\n" );
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
);
880 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
884 static int compare_ipforward_rows(const void *a
, const void *b
)
886 const MIB_IPFORWARDROW
*rowA
= a
;
887 const MIB_IPFORWARDROW
*rowB
= b
;
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.
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
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;
933 if ((fp
= fopen("/proc/net/route", "r")))
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
++;
946 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
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
)))
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};
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
;
986 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
989 ret
= ERROR_OUTOFMEMORY
;
993 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
995 ret
= ERROR_NOT_SUPPORTED
;
1000 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1004 rtm
= (struct rt_msghdr
*)next
;
1006 if (rtm
->rtm_type
!= RTM_GET
)
1008 WARN ("Got unexpected message type 0x%x!\n",
1013 /* Ignore all entries except for gateway routes which aren't
1015 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1016 (rtm
->rtm_flags
& RTF_MULTICAST
))
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
;
1032 if (!(i
& rtm
->rtm_addrs
))
1035 sa
= (struct sockaddr
*)addrPtr
;
1036 ADVANCE (addrPtr
, sa
);
1038 /* default routes are encoded by length-zero sockaddr */
1039 if (sa
->sa_len
== 0)
1041 else if (sa
->sa_family
!= AF_INET
)
1043 WARN ("Received unsupported sockaddr family 0x%x\n",
1049 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1051 addr
= sin
->sin_addr
.s_addr
;
1056 case RTA_DST
: row
.dwForwardDest
= addr
; break;
1057 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
1058 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
1060 WARN ("Unexpected address type 0x%x\n", i
);
1064 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1068 HeapFree( GetProcessHeap (), 0, buf
);
1071 FIXME( "not implemented\n" );
1072 ret
= ERROR_NOT_SUPPORTED
;
1075 if (!table
) return ERROR_OUTOFMEMORY
;
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
);
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
);
1104 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
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.
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
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
;
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;
1154 if ((fp
= fopen("/proc/net/arp", "r")))
1156 char buf
[512], *ptr
;
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);
1171 if (flags
& ATF_COM
) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1175 if (flags
& ATF_PERM
) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
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);
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
)))
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]))
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
;
1215 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1218 ret
= ERROR_OUTOFMEMORY
;
1222 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1224 ret
= ERROR_NOT_SUPPORTED
;
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
)))
1250 next
+= rtm
->rtm_msglen
;
1253 HeapFree( GetProcessHeap (), 0, buf
);
1256 FIXME( "not implemented\n" );
1257 ret
= ERROR_NOT_SUPPORTED
;
1260 if (!table
) return ERROR_OUTOFMEMORY
;
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
);
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
);
1289 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1293 static int compare_udp_rows(const void *a
, const void *b
)
1295 const MIB_UDPROW
*rowA
= a
;
1296 const MIB_UDPROW
*rowB
= b
;
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.
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
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
;
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;
1341 if ((fp
= fopen("/proc/net/udp", "r")))
1343 char buf
[512], *ptr
;
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)
1352 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1353 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
)))
1358 else ret
= ERROR_NOT_SUPPORTED
;
1361 FIXME( "not implemented\n" );
1362 ret
= ERROR_NOT_SUPPORTED
;
1365 if (!table
) return ERROR_OUTOFMEMORY
;
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
);
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
);
1394 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1399 /* Why not a lookup table? Because the TCPS_* constants are different
1400 on different platforms */
1401 static DWORD
TCPStateToMIBState (int 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
;
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
;
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.
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
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
;
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;
1472 if ((fp
= fopen("/proc/net/tcp", "r")))
1474 char buf
[512], *ptr
;
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)
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
)))
1492 else ret
= ERROR_NOT_SUPPORTED
;
1494 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
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
;
1507 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1510 ret
= ERROR_OUTOFMEMORY
;
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
;
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
;
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
)
1543 /* Ignore PCBs that were freed while generating the data */
1544 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1547 /* we're only interested in IPv4 addresses */
1548 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1549 (pINData
->inp_vflag
& INP_IPV6
))
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
)
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;
1569 HeapFree (GetProcessHeap (), 0, Buf
);
1572 FIXME( "not implemented\n" );
1573 ret
= ERROR_NOT_SUPPORTED
;
1576 if (!table
) return ERROR_OUTOFMEMORY
;
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
);