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"
29 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
39 #ifdef HAVE_SYS_SOCKETVAR_H
40 #include <sys/socketvar.h>
42 #ifdef HAVE_SYS_TIMEOUT_H
43 #include <sys/timeout.h>
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
48 #ifdef HAVE_NETINET_IN_SYSTM_H
49 #include <netinet/in_systm.h>
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
57 #ifdef HAVE_NET_IF_DL_H
58 #include <net/if_dl.h>
60 #ifdef HAVE_NET_IF_TYPES_H
61 #include <net/if_types.h>
63 #ifdef HAVE_NET_ROUTE_H
64 #include <net/route.h>
66 #ifdef HAVE_NET_IF_ARP_H
67 #include <net/if_arp.h>
69 #ifdef HAVE_NETINET_IF_ETHER_H
70 #include <netinet/if_ether.h>
72 #ifdef HAVE_NETINET_IF_INARP_H
73 #include <netinet/if_inarp.h>
75 #ifdef HAVE_NETINET_IP_H
76 #include <netinet/ip.h>
78 #ifdef HAVE_NETINET_TCP_H
79 #include <netinet/tcp.h>
81 #ifdef HAVE_NETINET_IP_VAR_H
82 #include <netinet/ip_var.h>
84 #ifdef HAVE_NETINET_TCP_FSM_H
85 #include <netinet/tcp_fsm.h>
87 #ifdef HAVE_NETINET_IN_PCB_H
88 #include <netinet/in_pcb.h>
90 #ifdef HAVE_NETINET_TCP_TIMER_H
91 #include <netinet/tcp_timer.h>
93 #ifdef HAVE_NETINET_TCP_VAR_H
94 #include <netinet/tcp_var.h>
96 #ifdef HAVE_NETINET_IP_ICMP_H
97 #include <netinet/ip_icmp.h>
99 #ifdef HAVE_NETINET_ICMP_VAR_H
100 #include <netinet/icmp_var.h>
102 #ifdef HAVE_NETINET_UDP_H
103 #include <netinet/udp.h>
105 #ifdef HAVE_NETINET_UDP_VAR_H
106 #include <netinet/udp_var.h>
108 #ifdef HAVE_SYS_PROTOSW_H
109 #include <sys/protosw.h>
111 #ifdef HAVE_SYS_SYSCTL_H
112 #include <sys/sysctl.h>
117 #ifdef HAVE_INET_MIB2_H
118 #include <inet/mib2.h>
120 #ifdef HAVE_STROPTS_H
123 #ifdef HAVE_SYS_TIHDR_H
124 #include <sys/tihdr.h>
126 #ifdef HAVE_SYS_PARAM_H
127 #include <sys/param.h>
129 #ifdef HAVE_SYS_QUEUE_H
130 #include <sys/queue.h>
132 #ifdef HAVE_SYS_USER_H
133 /* Make sure the definitions of struct kinfo_proc are the same. */
134 #include <sys/user.h>
136 #ifdef HAVE_LIBPROCSTAT_H
137 #include <libprocstat.h>
139 #ifdef HAVE_LIBPROC_H
142 #ifdef HAVE_IFADDRS_H
148 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int) - 1))) : sizeof(int))
151 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
154 #include "ntstatus.h"
155 #define WIN32_NO_STATUS
156 #define NONAMELESSUNION
157 #define USE_WS_PREFIX
158 #include "winsock2.h"
159 #include "ws2ipdef.h"
162 #include "iphlpapi.h"
164 #include "wine/debug.h"
165 #include "wine/server.h"
166 #include "wine/unicode.h"
168 #ifndef HAVE_NETINET_TCP_FSM_H
169 #define TCPS_ESTABLISHED 1
170 #define TCPS_SYN_SENT 2
171 #define TCPS_SYN_RECEIVED 3
172 #define TCPS_FIN_WAIT_1 4
173 #define TCPS_FIN_WAIT_2 5
174 #define TCPS_TIME_WAIT 6
175 #define TCPS_CLOSED 7
176 #define TCPS_CLOSE_WAIT 8
177 #define TCPS_LAST_ACK 9
178 #define TCPS_LISTEN 10
179 #define TCPS_CLOSING 11
182 #ifndef RTF_MULTICAST
183 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
187 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
190 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
193 static DWORD
kstat_get_ui32( kstat_t
*ksp
, const char *name
)
196 kstat_named_t
*data
= ksp
->ks_data
;
198 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
199 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui32
;
203 static ULONGLONG
kstat_get_ui64( kstat_t
*ksp
, const char *name
)
206 kstat_named_t
*data
= ksp
->ks_data
;
208 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
209 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui64
;
214 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
215 static int open_streams_mib( const char *proto
)
221 struct T_optmgmt_req req_header
;
222 struct opthdr opt_header
;
225 if ((fd
= open( "/dev/arp", O_RDWR
)) == -1)
227 WARN( "could not open /dev/arp: %s\n", strerror(errno
) );
230 if (proto
) ioctl( fd
, I_PUSH
, proto
);
232 request
.req_header
.PRIM_type
= T_SVR4_OPTMGMT_REQ
;
233 request
.req_header
.OPT_length
= sizeof(request
.opt_header
);
234 request
.req_header
.OPT_offset
= FIELD_OFFSET( struct request
, opt_header
);
235 request
.req_header
.MGMT_flags
= T_CURRENT
;
236 request
.opt_header
.level
= MIB2_IP
;
237 request
.opt_header
.name
= 0;
238 request
.opt_header
.len
= 0;
240 buf
.len
= sizeof(request
);
241 buf
.buf
= (caddr_t
)&request
;
242 if (putmsg( fd
, &buf
, NULL
, 0 ) == -1)
244 WARN( "putmsg: %s\n", strerror(errno
) );
251 static void *read_mib_entry( int fd
, int level
, int name
, int *len
)
259 struct T_optmgmt_ack ack_header
;
260 struct opthdr opt_header
;
265 buf
.maxlen
= sizeof(reply
);
266 buf
.buf
= (caddr_t
)&reply
;
267 if ((ret
= getmsg( fd
, &buf
, NULL
, &flags
)) < 0) return NULL
;
268 if (!(ret
& MOREDATA
)) return NULL
;
269 if (reply
.ack_header
.PRIM_type
!= T_OPTMGMT_ACK
) return NULL
;
270 if (buf
.len
< sizeof(reply
.ack_header
)) return NULL
;
271 if (reply
.ack_header
.OPT_length
< sizeof(reply
.opt_header
)) return NULL
;
273 if (!(data
= HeapAlloc( GetProcessHeap(), 0, reply
.opt_header
.len
))) return NULL
;
274 buf
.maxlen
= reply
.opt_header
.len
;
275 buf
.buf
= (caddr_t
)data
;
277 if (getmsg( fd
, NULL
, &buf
, &flags
) >= 0 &&
278 reply
.opt_header
.level
== level
&&
279 reply
.opt_header
.name
== name
)
284 HeapFree( GetProcessHeap(), 0, data
);
287 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
289 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
291 DWORD ret
= ERROR_NOT_SUPPORTED
;
293 if (!name
|| !entry
) return ERROR_INVALID_PARAMETER
;
299 if ((fp
= fopen("/proc/net/dev", "r")))
303 int nameLen
= strlen(name
);
305 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
307 while (*ptr
&& isspace(*ptr
)) ptr
++;
308 if (_strnicmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
311 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u",
312 &entry
->dwInOctets
, &entry
->dwInUcastPkts
,
313 &entry
->dwInErrors
, &entry
->dwInDiscards
,
315 &entry
->dwInNUcastPkts
, &entry
->dwOutOctets
,
316 &entry
->dwOutUcastPkts
, &entry
->dwOutErrors
,
317 &entry
->dwOutDiscards
);
325 #elif defined(HAVE_LIBKSTAT)
330 if ((kc
= kstat_open()) &&
331 (ksp
= kstat_lookup( kc
, NULL
, -1, (char *)name
)) &&
332 kstat_read( kc
, ksp
, NULL
) != -1 &&
333 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
335 entry
->dwMtu
= 1500; /* FIXME */
336 entry
->dwSpeed
= min( kstat_get_ui64( ksp
, "ifspeed" ), ~0u );
337 entry
->dwInOctets
= kstat_get_ui32( ksp
, "rbytes" );
338 entry
->dwInNUcastPkts
= kstat_get_ui32( ksp
, "multircv" );
339 entry
->dwInNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstrcv" );
340 entry
->dwInUcastPkts
= kstat_get_ui32( ksp
, "ipackets" ) - entry
->dwInNUcastPkts
;
341 entry
->dwInDiscards
= kstat_get_ui32( ksp
, "norcvbuf" );
342 entry
->dwInErrors
= kstat_get_ui32( ksp
, "ierrors" );
343 entry
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "unknowns" );
344 entry
->dwOutOctets
= kstat_get_ui32( ksp
, "obytes" );
345 entry
->dwOutNUcastPkts
= kstat_get_ui32( ksp
, "multixmt" );
346 entry
->dwOutNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstxmt" );
347 entry
->dwOutUcastPkts
= kstat_get_ui32( ksp
, "opackets" ) - entry
->dwOutNUcastPkts
;
348 entry
->dwOutDiscards
= 0; /* FIXME */
349 entry
->dwOutErrors
= kstat_get_ui32( ksp
, "oerrors" );
350 entry
->dwOutQLen
= kstat_get_ui32( ksp
, "noxmtbuf" );
353 if (kc
) kstat_close( kc
);
355 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
357 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
359 char *buf
= NULL
, *end
;
360 struct if_msghdr
*ifm
;
361 struct if_data ifdata
;
363 if(sysctl(mib
, ARRAY_SIZE(mib
), NULL
, &needed
, NULL
, 0) == -1)
365 ERR ("failed to get size of iflist\n");
368 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
371 ret
= ERROR_OUTOFMEMORY
;
374 if(sysctl(mib
, ARRAY_SIZE(mib
), buf
, &needed
, NULL
, 0) == -1)
376 ERR ("failed to get iflist\n");
379 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
381 ifm
= (struct if_msghdr
*) buf
;
382 if(ifm
->ifm_type
== RTM_IFINFO
)
384 ifdata
= ifm
->ifm_data
;
385 entry
->dwMtu
= ifdata
.ifi_mtu
;
386 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
387 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
388 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
389 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
390 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
391 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
392 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
393 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
394 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
400 HeapFree (GetProcessHeap (), 0, buf
);
403 FIXME( "unimplemented\n" );
409 /******************************************************************
410 * GetIcmpStatistics (IPHLPAPI.@)
412 * Get the ICMP statistics for the local computer.
415 * stats [Out] buffer for ICMP statistics
419 * Failure: error code from winerror.h
421 DWORD WINAPI
GetIcmpStatistics(PMIB_ICMP stats
)
423 DWORD ret
= ERROR_NOT_SUPPORTED
;
425 if (!stats
) return ERROR_INVALID_PARAMETER
;
426 memset( stats
, 0, sizeof(MIB_ICMP
) );
432 if ((fp
= fopen("/proc/net/snmp", "r")))
434 static const char hdr
[] = "Icmp:";
437 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
439 if (_strnicmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
440 /* last line was a header, get another */
441 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
442 if (!_strnicmp(buf
, hdr
, sizeof(hdr
) - 1))
445 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",
446 &stats
->stats
.icmpInStats
.dwMsgs
,
447 &stats
->stats
.icmpInStats
.dwErrors
,
448 &stats
->stats
.icmpInStats
.dwDestUnreachs
,
449 &stats
->stats
.icmpInStats
.dwTimeExcds
,
450 &stats
->stats
.icmpInStats
.dwParmProbs
,
451 &stats
->stats
.icmpInStats
.dwSrcQuenchs
,
452 &stats
->stats
.icmpInStats
.dwRedirects
,
453 &stats
->stats
.icmpInStats
.dwEchoReps
,
454 &stats
->stats
.icmpInStats
.dwTimestamps
,
455 &stats
->stats
.icmpInStats
.dwTimestampReps
,
456 &stats
->stats
.icmpInStats
.dwAddrMasks
,
457 &stats
->stats
.icmpInStats
.dwAddrMaskReps
,
458 &stats
->stats
.icmpOutStats
.dwMsgs
,
459 &stats
->stats
.icmpOutStats
.dwErrors
,
460 &stats
->stats
.icmpOutStats
.dwDestUnreachs
,
461 &stats
->stats
.icmpOutStats
.dwTimeExcds
,
462 &stats
->stats
.icmpOutStats
.dwParmProbs
,
463 &stats
->stats
.icmpOutStats
.dwSrcQuenchs
,
464 &stats
->stats
.icmpOutStats
.dwRedirects
,
465 &stats
->stats
.icmpOutStats
.dwEchoReps
,
466 &stats
->stats
.icmpOutStats
.dwTimestamps
,
467 &stats
->stats
.icmpOutStats
.dwTimestampReps
,
468 &stats
->stats
.icmpOutStats
.dwAddrMasks
,
469 &stats
->stats
.icmpOutStats
.dwAddrMaskReps
);
477 #elif defined(HAVE_LIBKSTAT)
479 static char ip
[] = "ip", icmp
[] = "icmp";
483 if ((kc
= kstat_open()) &&
484 (ksp
= kstat_lookup( kc
, ip
, 0, icmp
)) &&
485 kstat_read( kc
, ksp
, NULL
) != -1 &&
486 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
488 stats
->stats
.icmpInStats
.dwMsgs
= kstat_get_ui32( ksp
, "inMsgs" );
489 stats
->stats
.icmpInStats
.dwErrors
= kstat_get_ui32( ksp
, "inErrors" );
490 stats
->stats
.icmpInStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "inDestUnreachs" );
491 stats
->stats
.icmpInStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "inTimeExcds" );
492 stats
->stats
.icmpInStats
.dwParmProbs
= kstat_get_ui32( ksp
, "inParmProbs" );
493 stats
->stats
.icmpInStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "inSrcQuenchs" );
494 stats
->stats
.icmpInStats
.dwRedirects
= kstat_get_ui32( ksp
, "inRedirects" );
495 stats
->stats
.icmpInStats
.dwEchos
= kstat_get_ui32( ksp
, "inEchos" );
496 stats
->stats
.icmpInStats
.dwEchoReps
= kstat_get_ui32( ksp
, "inEchoReps" );
497 stats
->stats
.icmpInStats
.dwTimestamps
= kstat_get_ui32( ksp
, "inTimestamps" );
498 stats
->stats
.icmpInStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "inTimestampReps" );
499 stats
->stats
.icmpInStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "inAddrMasks" );
500 stats
->stats
.icmpInStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "inAddrMaskReps" );
501 stats
->stats
.icmpOutStats
.dwMsgs
= kstat_get_ui32( ksp
, "outMsgs" );
502 stats
->stats
.icmpOutStats
.dwErrors
= kstat_get_ui32( ksp
, "outErrors" );
503 stats
->stats
.icmpOutStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "outDestUnreachs" );
504 stats
->stats
.icmpOutStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "outTimeExcds" );
505 stats
->stats
.icmpOutStats
.dwParmProbs
= kstat_get_ui32( ksp
, "outParmProbs" );
506 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "outSrcQuenchs" );
507 stats
->stats
.icmpOutStats
.dwRedirects
= kstat_get_ui32( ksp
, "outRedirects" );
508 stats
->stats
.icmpOutStats
.dwEchos
= kstat_get_ui32( ksp
, "outEchos" );
509 stats
->stats
.icmpOutStats
.dwEchoReps
= kstat_get_ui32( ksp
, "outEchoReps" );
510 stats
->stats
.icmpOutStats
.dwTimestamps
= kstat_get_ui32( ksp
, "outTimestamps" );
511 stats
->stats
.icmpOutStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "outTimestampReps" );
512 stats
->stats
.icmpOutStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "outAddrMasks" );
513 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "outAddrMaskReps" );
516 if (kc
) kstat_close( kc
);
518 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && (defined(HAVE_STRUCT_ICMPSTAT_ICPS_INHIST) || defined(HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST))
520 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
521 struct icmpstat icmp_stat
;
522 size_t needed
= sizeof(icmp_stat
);
525 if(sysctl(mib
, ARRAY_SIZE(mib
), &icmp_stat
, &needed
, NULL
, 0) != -1)
527 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_INHIST
529 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
530 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
531 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
533 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
535 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
536 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
537 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
538 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
539 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
540 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
541 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
542 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
543 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
544 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
545 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
548 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST
550 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
551 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
552 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
554 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
556 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
557 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
558 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
559 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
560 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
561 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
562 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
563 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
564 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
565 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
566 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
567 #endif /* HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST */
571 #else /* ICMPCTL_STATS */
572 FIXME( "unimplemented\n" );
577 /******************************************************************
578 * GetIcmpStatisticsEx (IPHLPAPI.@)
580 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
583 * stats [Out] buffer for ICMP statistics
584 * family [In] specifies whether IPv4 or IPv6 statistics are returned
588 * Failure: error code from winerror.h
590 DWORD WINAPI
GetIcmpStatisticsEx(PMIB_ICMP_EX stats
, DWORD family
)
592 DWORD ret
= ERROR_NOT_SUPPORTED
;
595 if (!stats
) return ERROR_INVALID_PARAMETER
;
596 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
597 memset( stats
, 0, sizeof(MIB_ICMP_EX
) );
599 if (family
== WS_AF_INET6
)
605 if ((fp
= fopen("/proc/net/snmp6", "r")))
607 struct icmpstatstruct
{
611 static const struct icmpstatstruct icmpinstatlist
[] = {
612 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH
},
613 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG
},
614 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED
},
615 { "Icmp6InParmProblems", ICMP6_PARAM_PROB
},
616 { "Icmp6InEchos", ICMP6_ECHO_REQUEST
},
617 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY
},
618 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY
},
619 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT
},
620 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION
},
621 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT
},
622 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT
},
623 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT
},
624 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT
},
625 { "Icmp6InRedirects", ND_REDIRECT
},
626 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT
},
628 static const struct icmpstatstruct icmpoutstatlist
[] = {
629 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH
},
630 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG
},
631 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED
},
632 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB
},
633 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST
},
634 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY
},
635 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY
},
636 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT
},
637 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION
},
638 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT
},
639 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT
},
640 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT
},
641 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT
},
642 { "Icmp6OutRedirects", ND_REDIRECT
},
643 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT
},
645 char buf
[512], *ptr
, *value
;
648 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
650 if (!(value
= strchr(buf
, ' ')))
653 /* terminate the valuename */
657 /* and strip leading spaces from value */
659 while (*value
==' ') value
++;
660 if ((ptr
= strchr(value
, '\n')))
663 if (!_strnicmp(buf
, "Icmp6InMsgs", -1))
665 if (sscanf(value
, "%d", &res
)) stats
->icmpInStats
.dwMsgs
= res
;
669 if (!_strnicmp(buf
, "Icmp6InErrors", -1))
671 if (sscanf(value
, "%d", &res
)) stats
->icmpInStats
.dwErrors
= res
;
675 for (i
= 0; i
< ARRAY_SIZE(icmpinstatlist
); i
++)
677 if (!_strnicmp(buf
, icmpinstatlist
[i
].name
, -1))
679 if (sscanf(value
, "%d", &res
))
680 stats
->icmpInStats
.rgdwTypeCount
[icmpinstatlist
[i
].pos
] = res
;
685 if (!_strnicmp(buf
, "Icmp6OutMsgs", -1))
687 if (sscanf(value
, "%d", &res
)) stats
->icmpOutStats
.dwMsgs
= res
;
691 if (!_strnicmp(buf
, "Icmp6OutErrors", -1))
693 if (sscanf(value
, "%d", &res
)) stats
->icmpOutStats
.dwErrors
= res
;
697 for (i
= 0; i
< ARRAY_SIZE(icmpoutstatlist
); i
++)
699 if (!_strnicmp(buf
, icmpoutstatlist
[i
].name
, -1))
701 if (sscanf(value
, "%d", &res
))
702 stats
->icmpOutStats
.rgdwTypeCount
[icmpoutstatlist
[i
].pos
] = res
;
713 FIXME( "unimplemented for IPv6\n" );
718 ret
= GetIcmpStatistics(&ipv4stats
);
721 stats
->icmpInStats
.dwMsgs
= ipv4stats
.stats
.icmpInStats
.dwMsgs
;
722 stats
->icmpInStats
.dwErrors
= ipv4stats
.stats
.icmpInStats
.dwErrors
;
723 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_DST_UNREACH
] = ipv4stats
.stats
.icmpInStats
.dwDestUnreachs
;
724 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_SOURCE_QUENCH
] = ipv4stats
.stats
.icmpInStats
.dwSrcQuenchs
;
725 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_REDIRECT
] = ipv4stats
.stats
.icmpInStats
.dwRedirects
;
726 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_ECHO_REQUEST
] = ipv4stats
.stats
.icmpInStats
.dwEchos
;
727 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_TIME_EXCEEDED
] = ipv4stats
.stats
.icmpInStats
.dwTimeExcds
;
728 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_PARAM_PROB
] = ipv4stats
.stats
.icmpInStats
.dwParmProbs
;
729 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
] = ipv4stats
.stats
.icmpInStats
.dwTimestamps
;
730 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
] = ipv4stats
.stats
.icmpInStats
.dwTimestampReps
;
731 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_MASK_REQUEST
] = ipv4stats
.stats
.icmpInStats
.dwAddrMasks
;
732 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_MASK_REPLY
] = ipv4stats
.stats
.icmpInStats
.dwAddrMaskReps
;
734 stats
->icmpOutStats
.dwMsgs
= ipv4stats
.stats
.icmpOutStats
.dwMsgs
;
735 stats
->icmpOutStats
.dwErrors
= ipv4stats
.stats
.icmpOutStats
.dwErrors
;
736 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_DST_UNREACH
] = ipv4stats
.stats
.icmpOutStats
.dwDestUnreachs
;
737 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_SOURCE_QUENCH
] = ipv4stats
.stats
.icmpOutStats
.dwSrcQuenchs
;
738 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_REDIRECT
] = ipv4stats
.stats
.icmpOutStats
.dwRedirects
;
739 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_ECHO_REQUEST
] = ipv4stats
.stats
.icmpOutStats
.dwEchos
;
740 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_TIME_EXCEEDED
] = ipv4stats
.stats
.icmpOutStats
.dwTimeExcds
;
741 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_PARAM_PROB
] = ipv4stats
.stats
.icmpOutStats
.dwParmProbs
;
742 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
] = ipv4stats
.stats
.icmpOutStats
.dwTimestamps
;
743 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
] = ipv4stats
.stats
.icmpOutStats
.dwTimestampReps
;
744 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_MASK_REQUEST
] = ipv4stats
.stats
.icmpOutStats
.dwAddrMasks
;
745 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_MASK_REPLY
] = ipv4stats
.stats
.icmpOutStats
.dwAddrMaskReps
;
750 /******************************************************************
751 * GetIpStatisticsEx (IPHLPAPI.@)
753 * Get the IPv4 and IPv6 statistics for the local computer.
756 * stats [Out] buffer for IP statistics
757 * family [In] specifies whether IPv4 or IPv6 statistics are returned
761 * Failure: error code from winerror.h
763 DWORD WINAPI
GetIpStatisticsEx(PMIB_IPSTATS stats
, DWORD family
)
765 DWORD ret
= ERROR_NOT_SUPPORTED
;
766 MIB_IPFORWARDTABLE
*fwd_table
;
768 if (!stats
) return ERROR_INVALID_PARAMETER
;
769 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
770 memset( stats
, 0, sizeof(*stats
) );
772 stats
->dwNumIf
= stats
->dwNumAddr
= get_interface_indices( FALSE
, NULL
);
773 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table
, FALSE
, GetProcessHeap(), 0 ))
775 stats
->dwNumRoutes
= fwd_table
->dwNumEntries
;
776 HeapFree( GetProcessHeap(), 0, fwd_table
);
779 if (family
== WS_AF_INET6
)
785 if ((fp
= fopen("/proc/net/snmp6", "r")))
791 { "Ip6InReceives", &stats
->dwInReceives
},
792 { "Ip6InHdrErrors", &stats
->dwInHdrErrors
},
793 { "Ip6InAddrErrors", &stats
->dwInAddrErrors
},
794 { "Ip6OutForwDatagrams", &stats
->dwForwDatagrams
},
795 { "Ip6InUnknownProtos", &stats
->dwInUnknownProtos
},
796 { "Ip6InDiscards", &stats
->dwInDiscards
},
797 { "Ip6InDelivers", &stats
->dwInDelivers
},
798 { "Ip6OutRequests", &stats
->dwOutRequests
},
799 { "Ip6OutDiscards", &stats
->dwOutDiscards
},
800 { "Ip6OutNoRoutes", &stats
->dwOutNoRoutes
},
801 { "Ip6ReasmTimeout", &stats
->dwReasmTimeout
},
802 { "Ip6ReasmReqds", &stats
->dwReasmReqds
},
803 { "Ip6ReasmOKs", &stats
->dwReasmOks
},
804 { "Ip6ReasmFails", &stats
->dwReasmFails
},
805 { "Ip6FragOKs", &stats
->dwFragOks
},
806 { "Ip6FragFails", &stats
->dwFragFails
},
807 { "Ip6FragCreates", &stats
->dwFragCreates
},
808 /* hmm, no routingDiscards, defaultTTL and forwarding? */
810 char buf
[512], *ptr
, *value
;
813 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
815 if (!(value
= strchr(buf
, ' ')))
818 /* terminate the valuename */
822 /* and strip leading spaces from value */
824 while (*value
==' ') value
++;
825 if ((ptr
= strchr(value
, '\n')))
828 for (i
= 0; i
< ARRAY_SIZE(ipstatlist
); i
++)
829 if (!_strnicmp(buf
, ipstatlist
[i
].name
, -1) && sscanf(value
, "%d", &res
))
830 *ipstatlist
[i
].elem
= res
;
837 FIXME( "unimplemented for IPv6\n" );
846 if ((fp
= fopen("/proc/net/snmp", "r")))
848 static const char hdr
[] = "Ip:";
851 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
853 if (_strnicmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
854 /* last line was a header, get another */
855 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
856 if (!_strnicmp(buf
, hdr
, sizeof(hdr
) - 1))
859 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
860 &stats
->u
.dwForwarding
,
861 &stats
->dwDefaultTTL
,
862 &stats
->dwInReceives
,
863 &stats
->dwInHdrErrors
,
864 &stats
->dwInAddrErrors
,
865 &stats
->dwForwDatagrams
,
866 &stats
->dwInUnknownProtos
,
867 &stats
->dwInDiscards
,
868 &stats
->dwInDelivers
,
869 &stats
->dwOutRequests
,
870 &stats
->dwOutDiscards
,
871 &stats
->dwOutNoRoutes
,
872 &stats
->dwReasmTimeout
,
873 &stats
->dwReasmReqds
,
875 &stats
->dwReasmFails
,
878 &stats
->dwFragCreates
);
879 /* hmm, no routingDiscards */
887 #elif defined(HAVE_LIBKSTAT)
889 static char ip
[] = "ip";
893 if ((kc
= kstat_open()) &&
894 (ksp
= kstat_lookup( kc
, ip
, 0, ip
)) &&
895 kstat_read( kc
, ksp
, NULL
) != -1 &&
896 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
898 stats
->u
.dwForwarding
= kstat_get_ui32( ksp
, "forwarding" );
899 stats
->dwDefaultTTL
= kstat_get_ui32( ksp
, "defaultTTL" );
900 stats
->dwInReceives
= kstat_get_ui32( ksp
, "inReceives" );
901 stats
->dwInHdrErrors
= kstat_get_ui32( ksp
, "inHdrErrors" );
902 stats
->dwInAddrErrors
= kstat_get_ui32( ksp
, "inAddrErrors" );
903 stats
->dwForwDatagrams
= kstat_get_ui32( ksp
, "forwDatagrams" );
904 stats
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "inUnknownProtos" );
905 stats
->dwInDiscards
= kstat_get_ui32( ksp
, "inDiscards" );
906 stats
->dwInDelivers
= kstat_get_ui32( ksp
, "inDelivers" );
907 stats
->dwOutRequests
= kstat_get_ui32( ksp
, "outRequests" );
908 stats
->dwRoutingDiscards
= kstat_get_ui32( ksp
, "routingDiscards" );
909 stats
->dwOutDiscards
= kstat_get_ui32( ksp
, "outDiscards" );
910 stats
->dwOutNoRoutes
= kstat_get_ui32( ksp
, "outNoRoutes" );
911 stats
->dwReasmTimeout
= kstat_get_ui32( ksp
, "reasmTimeout" );
912 stats
->dwReasmReqds
= kstat_get_ui32( ksp
, "reasmReqds" );
913 stats
->dwReasmOks
= kstat_get_ui32( ksp
, "reasmOKs" );
914 stats
->dwReasmFails
= kstat_get_ui32( ksp
, "reasmFails" );
915 stats
->dwFragOks
= kstat_get_ui32( ksp
, "fragOKs" );
916 stats
->dwFragFails
= kstat_get_ui32( ksp
, "fragFails" );
917 stats
->dwFragCreates
= kstat_get_ui32( ksp
, "fragCreates" );
920 if (kc
) kstat_close( kc
);
922 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
924 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
925 int ip_ttl
, ip_forwarding
;
926 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
927 struct ipstat ip_stat
;
928 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
929 struct ip_stats ip_stat
;
933 needed
= sizeof(ip_stat
);
934 if(sysctl(mib
, ARRAY_SIZE(mib
), &ip_stat
, &needed
, NULL
, 0) == -1)
936 ERR ("failed to get ipstat\n");
937 return ERROR_NOT_SUPPORTED
;
940 needed
= sizeof(ip_ttl
);
941 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
943 ERR ("failed to get ip Default TTL\n");
944 return ERROR_NOT_SUPPORTED
;
947 needed
= sizeof(ip_forwarding
);
948 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
950 ERR ("failed to get ip forwarding\n");
951 return ERROR_NOT_SUPPORTED
;
954 /* ip.forwarding is 0 or 1 on BSD */
955 stats
->u
.dwForwarding
= ip_forwarding
+1;
956 stats
->dwDefaultTTL
= ip_ttl
;
957 stats
->dwInReceives
= ip_stat
.ips_total
;
958 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
+
959 ip_stat
.ips_badvers
+ ip_stat
.ips_badoptions
;
960 /* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
961 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
+ ip_stat
.ips_badaddr
+ ip_stat
.ips_notmember
;
962 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
963 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
964 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
965 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
966 stats
->dwOutRequests
= ip_stat
.ips_localout
;
967 /*stats->dwRoutingDiscards = 0;*/ /* FIXME */
968 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
969 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
970 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
971 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
972 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
973 stats
->dwReasmFails
= ip_stat
.ips_fragments
- ip_stat
.ips_reassembled
;
974 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
975 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
976 stats
->dwFragCreates
= ip_stat
.ips_ofragments
;
980 FIXME( "unimplemented for IPv4\n" );
985 /******************************************************************
986 * GetIpStatistics (IPHLPAPI.@)
988 * Get the IP statistics for the local computer.
991 * stats [Out] buffer for IP statistics
995 * Failure: error code from winerror.h
997 DWORD WINAPI
GetIpStatistics(PMIB_IPSTATS stats
)
999 return GetIpStatisticsEx(stats
, WS_AF_INET
);
1002 /******************************************************************
1003 * GetTcpStatisticsEx (IPHLPAPI.@)
1005 * Get the IPv4 and IPv6 TCP statistics for the local computer.
1008 * stats [Out] buffer for TCP statistics
1009 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1013 * Failure: error code from winerror.h
1015 DWORD WINAPI
GetTcpStatisticsEx(PMIB_TCPSTATS stats
, DWORD family
)
1017 DWORD ret
= ERROR_NOT_SUPPORTED
;
1019 if (!stats
) return ERROR_INVALID_PARAMETER
;
1020 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
1021 memset( stats
, 0, sizeof(*stats
) );
1023 if (family
== WS_AF_INET6
)
1025 FIXME( "unimplemented for IPv6\n" );
1033 if ((fp
= fopen("/proc/net/snmp", "r")))
1035 static const char hdr
[] = "Tcp:";
1036 MIB_TCPTABLE
*tcp_table
;
1037 char buf
[512], *ptr
;
1039 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1041 if (_strnicmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
1042 /* last line was a header, get another */
1043 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
1044 if (!_strnicmp(buf
, hdr
, sizeof(hdr
) - 1))
1047 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
1048 &stats
->u
.dwRtoAlgorithm
,
1052 &stats
->dwActiveOpens
,
1053 &stats
->dwPassiveOpens
,
1054 &stats
->dwAttemptFails
,
1055 &stats
->dwEstabResets
,
1056 &stats
->dwCurrEstab
,
1059 &stats
->dwRetransSegs
,
1061 &stats
->dwOutRsts
);
1065 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
1067 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
1068 HeapFree( GetProcessHeap(), 0, tcp_table
);
1074 #elif defined(HAVE_LIBKSTAT)
1076 static char tcp
[] = "tcp";
1080 if ((kc
= kstat_open()) &&
1081 (ksp
= kstat_lookup( kc
, tcp
, 0, tcp
)) &&
1082 kstat_read( kc
, ksp
, NULL
) != -1 &&
1083 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
1085 stats
->u
.dwRtoAlgorithm
= kstat_get_ui32( ksp
, "rtoAlgorithm" );
1086 stats
->dwRtoMin
= kstat_get_ui32( ksp
, "rtoMin" );
1087 stats
->dwRtoMax
= kstat_get_ui32( ksp
, "rtoMax" );
1088 stats
->dwMaxConn
= kstat_get_ui32( ksp
, "maxConn" );
1089 stats
->dwActiveOpens
= kstat_get_ui32( ksp
, "activeOpens" );
1090 stats
->dwPassiveOpens
= kstat_get_ui32( ksp
, "passiveOpens" );
1091 stats
->dwAttemptFails
= kstat_get_ui32( ksp
, "attemptFails" );
1092 stats
->dwEstabResets
= kstat_get_ui32( ksp
, "estabResets" );
1093 stats
->dwCurrEstab
= kstat_get_ui32( ksp
, "currEstab" );
1094 stats
->dwInSegs
= kstat_get_ui32( ksp
, "inSegs" );
1095 stats
->dwOutSegs
= kstat_get_ui32( ksp
, "outSegs" );
1096 stats
->dwRetransSegs
= kstat_get_ui32( ksp
, "retransSegs" );
1097 stats
->dwInErrs
= kstat_get_ui32( ksp
, "inErrs" );
1098 stats
->dwOutRsts
= kstat_get_ui32( ksp
, "outRsts" );
1099 stats
->dwNumConns
= kstat_get_ui32( ksp
, "connTableSize" );
1102 if (kc
) kstat_close( kc
);
1104 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
1106 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
1108 #define TCPTV_REXMTMAX 128
1110 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
1112 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
1113 struct tcpstat tcp_stat
;
1114 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
1115 struct tcp_stats tcp_stat
;
1117 size_t needed
= sizeof(tcp_stat
);
1119 if(sysctl(mib
, ARRAY_SIZE(mib
), &tcp_stat
, &needed
, NULL
, 0) != -1)
1121 stats
->u
.RtoAlgorithm
= MIB_TCP_RTO_VANJ
;
1122 stats
->dwRtoMin
= TCPTV_MIN
;
1123 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
1124 stats
->dwMaxConn
= -1;
1125 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
1126 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
1127 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
1128 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
1129 stats
->dwCurrEstab
= 0;
1130 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
1131 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
1132 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
1133 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
1134 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
1135 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
1138 else ERR ("failed to get tcpstat\n");
1141 FIXME( "unimplemented\n" );
1146 /******************************************************************
1147 * GetTcpStatistics (IPHLPAPI.@)
1149 * Get the TCP statistics for the local computer.
1152 * stats [Out] buffer for TCP statistics
1156 * Failure: error code from winerror.h
1158 DWORD WINAPI
GetTcpStatistics(PMIB_TCPSTATS stats
)
1160 return GetTcpStatisticsEx(stats
, WS_AF_INET
);
1163 /******************************************************************
1164 * GetUdpStatistics (IPHLPAPI.@)
1166 * Get the IPv4 and IPv6 UDP statistics for the local computer.
1169 * stats [Out] buffer for UDP statistics
1170 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1174 * Failure: error code from winerror.h
1176 DWORD WINAPI
GetUdpStatisticsEx(PMIB_UDPSTATS stats
, DWORD family
)
1178 DWORD ret
= ERROR_NOT_SUPPORTED
;
1180 if (!stats
) return ERROR_INVALID_PARAMETER
;
1181 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
1182 memset( stats
, 0, sizeof(*stats
) );
1184 stats
->dwNumAddrs
= get_interface_indices( FALSE
, NULL
);
1186 if (family
== WS_AF_INET6
)
1192 if ((fp
= fopen("/proc/net/snmp6", "r")))
1198 { "Udp6InDatagrams", &stats
->dwInDatagrams
},
1199 { "Udp6NoPorts", &stats
->dwNoPorts
},
1200 { "Udp6InErrors", &stats
->dwInErrors
},
1201 { "Udp6OutDatagrams", &stats
->dwOutDatagrams
},
1203 char buf
[512], *ptr
, *value
;
1206 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1208 if (!(value
= strchr(buf
, ' ')))
1211 /* terminate the valuename */
1215 /* and strip leading spaces from value */
1217 while (*value
==' ') value
++;
1218 if ((ptr
= strchr(value
, '\n')))
1221 for (i
= 0; i
< ARRAY_SIZE(udpstatlist
); i
++)
1222 if (!_strnicmp(buf
, udpstatlist
[i
].name
, -1) && sscanf(value
, "%d", &res
))
1223 *udpstatlist
[i
].elem
= res
;
1230 FIXME( "unimplemented for IPv6\n" );
1239 if ((fp
= fopen("/proc/net/snmp", "r")))
1241 static const char hdr
[] = "Udp:";
1242 char buf
[512], *ptr
;
1244 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1246 if (_strnicmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
1247 /* last line was a header, get another */
1248 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
1249 if (!_strnicmp(buf
, hdr
, sizeof(hdr
) - 1))
1252 sscanf( ptr
, "%u %u %u %u %u",
1253 &stats
->dwInDatagrams
, &stats
->dwNoPorts
,
1254 &stats
->dwInErrors
, &stats
->dwOutDatagrams
, &stats
->dwNumAddrs
);
1262 #elif defined(HAVE_LIBKSTAT)
1264 static char udp
[] = "udp";
1267 MIB_UDPTABLE
*udp_table
;
1269 if ((kc
= kstat_open()) &&
1270 (ksp
= kstat_lookup( kc
, udp
, 0, udp
)) &&
1271 kstat_read( kc
, ksp
, NULL
) != -1 &&
1272 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
1274 stats
->dwInDatagrams
= kstat_get_ui32( ksp
, "inDatagrams" );
1275 stats
->dwNoPorts
= 0; /* FIXME */
1276 stats
->dwInErrors
= kstat_get_ui32( ksp
, "inErrors" );
1277 stats
->dwOutDatagrams
= kstat_get_ui32( ksp
, "outDatagrams" );
1278 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
1280 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
1281 HeapFree( GetProcessHeap(), 0, udp_table
);
1285 if (kc
) kstat_close( kc
);
1287 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
1289 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
1290 struct udpstat udp_stat
;
1291 MIB_UDPTABLE
*udp_table
;
1292 size_t needed
= sizeof(udp_stat
);
1294 if(sysctl(mib
, ARRAY_SIZE(mib
), &udp_stat
, &needed
, NULL
, 0) != -1)
1296 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
1297 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
1298 stats
->dwNoPorts
= udp_stat
.udps_noport
;
1299 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
1300 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
1302 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
1303 HeapFree( GetProcessHeap(), 0, udp_table
);
1307 else ERR ("failed to get udpstat\n");
1310 FIXME( "unimplemented for IPv4\n" );
1315 /******************************************************************
1316 * GetUdpStatistics (IPHLPAPI.@)
1318 * Get the UDP statistics for the local computer.
1321 * stats [Out] buffer for UDP statistics
1325 * Failure: error code from winerror.h
1327 DWORD WINAPI
GetUdpStatistics(PMIB_UDPSTATS stats
)
1329 return GetUdpStatisticsEx(stats
, WS_AF_INET
);
1332 static void *append_table_row( HANDLE heap
, DWORD flags
, void *table
, DWORD
*table_size
, DWORD
*table_capacity
,
1333 const void *row
, DWORD row_size
)
1335 DWORD
*num_entries
= table
; /* this must be the first field */
1336 if (*num_entries
== *table_capacity
)
1339 *table_size
+= *table_capacity
* row_size
;
1340 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, *table_size
)))
1342 HeapFree( heap
, 0, table
);
1345 num_entries
= table
= new_table
;
1346 *table_capacity
*= 2;
1348 memcpy( (char *)table
+ *table_size
- (*table_capacity
- *num_entries
) * row_size
, row
, row_size
);
1353 static int compare_ipforward_rows(const void *a
, const void *b
)
1355 const MIB_IPFORWARDROW
*rowA
= a
;
1356 const MIB_IPFORWARDROW
*rowB
= b
;
1359 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
1360 if ((ret
= rowA
->u2
.dwForwardProto
- rowB
->u2
.dwForwardProto
) != 0) return ret
;
1361 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
1362 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
1365 /******************************************************************
1366 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1368 * Get the route table.
1369 * Like GetIpForwardTable(), but allocate the returned table from heap.
1372 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1373 * allocated and returned.
1374 * bOrder [In] whether to sort the table
1375 * heap [In] heap from which the table is allocated
1376 * flags [In] flags to HeapAlloc
1379 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1380 * on failure, NO_ERROR on success.
1382 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, BOOL bOrder
,
1383 HANDLE heap
, DWORD flags
)
1385 MIB_IPFORWARDTABLE
*table
;
1386 MIB_IPFORWARDROW row
;
1387 DWORD ret
= NO_ERROR
, count
= 16, table_size
= FIELD_OFFSET( MIB_IPFORWARDTABLE
, table
[count
] );
1389 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable
, bOrder
, heap
, flags
);
1391 if (!ppIpForwardTable
) return ERROR_INVALID_PARAMETER
;
1393 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
1394 return ERROR_OUTOFMEMORY
;
1396 table
->dwNumEntries
= 0;
1402 if ((fp
= fopen("/proc/net/route", "r")))
1404 char buf
[512], *ptr
;
1407 /* skip header line */
1408 ptr
= fgets(buf
, sizeof(buf
), fp
);
1409 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1411 memset( &row
, 0, sizeof(row
) );
1413 while (!isspace(*ptr
)) ptr
++;
1415 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
1418 row
.dwForwardDest
= strtoul(ptr
, &ptr
, 16);
1419 row
.dwForwardNextHop
= strtoul(ptr
+ 1, &ptr
, 16);
1420 rtf_flags
= strtoul(ptr
+ 1, &ptr
, 16);
1422 if (!(rtf_flags
& RTF_UP
)) row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INVALID
;
1423 else if (rtf_flags
& RTF_GATEWAY
) row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1424 else row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_DIRECT
;
1426 strtoul(ptr
+ 1, &ptr
, 16); /* refcount, skip */
1427 strtoul(ptr
+ 1, &ptr
, 16); /* use, skip */
1428 row
.dwForwardMetric1
= strtoul(ptr
+ 1, &ptr
, 16);
1429 row
.dwForwardMask
= strtoul(ptr
+ 1, &ptr
, 16);
1430 /* FIXME: other protos might be appropriate, e.g. the default
1431 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1432 row
.u2
.ForwardProto
= MIB_IPPROTO_LOCAL
;
1434 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, sizeof(row
) )))
1439 else ret
= ERROR_NOT_SUPPORTED
;
1441 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1444 int fd
, len
, namelen
;
1445 mib2_ipRouteEntry_t
*entry
;
1448 if ((fd
= open_streams_mib( NULL
)) != -1)
1450 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_ROUTE
, &len
)))
1452 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1454 row
.dwForwardDest
= entry
->ipRouteDest
;
1455 row
.dwForwardMask
= entry
->ipRouteMask
;
1456 row
.dwForwardPolicy
= 0;
1457 row
.dwForwardNextHop
= entry
->ipRouteNextHop
;
1458 row
.u1
.dwForwardType
= entry
->ipRouteType
;
1459 row
.u2
.dwForwardProto
= entry
->ipRouteProto
;
1460 row
.dwForwardAge
= entry
->ipRouteAge
;
1461 row
.dwForwardNextHopAS
= 0;
1462 row
.dwForwardMetric1
= entry
->ipRouteMetric1
;
1463 row
.dwForwardMetric2
= entry
->ipRouteMetric2
;
1464 row
.dwForwardMetric3
= entry
->ipRouteMetric3
;
1465 row
.dwForwardMetric4
= entry
->ipRouteMetric4
;
1466 row
.dwForwardMetric5
= entry
->ipRouteMetric5
;
1467 namelen
= min( sizeof(name
) - 1, entry
->ipRouteIfIndex
.o_length
);
1468 memcpy( name
, entry
->ipRouteIfIndex
.o_bytes
, namelen
);
1470 getInterfaceIndexByName( name
, &row
.dwForwardIfIndex
);
1471 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, sizeof(row
) )))
1474 HeapFree( GetProcessHeap(), 0, data
);
1478 else ret
= ERROR_NOT_SUPPORTED
;
1480 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1482 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1484 char *buf
= NULL
, *lim
, *next
, *addrPtr
;
1485 struct rt_msghdr
*rtm
;
1487 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1489 ERR ("sysctl 1 failed!\n");
1490 ret
= ERROR_NOT_SUPPORTED
;
1494 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1497 ret
= ERROR_OUTOFMEMORY
;
1501 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1503 ret
= ERROR_NOT_SUPPORTED
;
1508 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1511 sa_family_t dst_family
= AF_UNSPEC
;
1513 rtm
= (struct rt_msghdr
*)next
;
1515 if (rtm
->rtm_type
!= RTM_GET
)
1517 WARN ("Got unexpected message type 0x%x!\n",
1522 /* Ignore gateway routes which are multicast */
1523 if ((rtm
->rtm_flags
& RTF_GATEWAY
) && (rtm
->rtm_flags
& RTF_MULTICAST
))
1526 memset( &row
, 0, sizeof(row
) );
1527 row
.dwForwardIfIndex
= rtm
->rtm_index
;
1528 row
.u1
.ForwardType
= (rtm
->rtm_flags
& RTF_GATEWAY
) ? MIB_IPROUTE_TYPE_INDIRECT
: MIB_IPROUTE_TYPE_DIRECT
;
1529 row
.dwForwardMetric1
= rtm
->rtm_rmx
.rmx_hopcount
;
1530 row
.u2
.ForwardProto
= MIB_IPPROTO_LOCAL
;
1532 addrPtr
= (char *)(rtm
+ 1);
1534 for (i
= 1; i
; i
<<= 1)
1536 struct sockaddr
*sa
;
1539 if (!(i
& rtm
->rtm_addrs
))
1542 sa
= (struct sockaddr
*)addrPtr
;
1543 if (addrPtr
+ sa
->sa_len
> next
+ rtm
->rtm_msglen
)
1545 ERR ("struct sockaddr extends beyond the route message, %p > %p\n",
1546 addrPtr
+ sa
->sa_len
, next
+ rtm
->rtm_msglen
);
1549 ADVANCE (addrPtr
, sa
);
1551 /* Apple's netstat prints the netmask together with the destination
1552 * and only looks at the destination's address family. The netmask's
1553 * sa_family sometimes contains the non-existent value 0xff. */
1554 switch(i
== RTA_NETMASK
? dst_family
: sa
->sa_family
) {
1556 /* Netmasks (and possibly other addresses) have only enough size
1557 * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has
1558 * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first
1559 * byte of sin_addr). Due to the alignment constraint we can de
1560 * facto read the full 4 bytes of sin_addr (except for the case of
1561 * netmask 0). Don't assume though that the extra bytes are zeroed. */
1562 struct sockaddr_in sin
= {0};
1563 memcpy(&sin
, sa
, sa
->sa_len
);
1564 addr
= sin
.sin_addr
.s_addr
;
1569 if(i
== RTA_GATEWAY
&& row
.u1
.ForwardType
== MIB_IPROUTE_TYPE_DIRECT
) {
1570 /* For direct route we may simply use dest addr as next hop */
1571 C_ASSERT(RTA_DST
< RTA_GATEWAY
);
1572 addr
= row
.dwForwardDest
;
1578 WARN ("Received unsupported sockaddr family 0x%x\n", sa
->sa_family
);
1585 row
.dwForwardDest
= addr
;
1586 dst_family
= sa
->sa_family
;
1588 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
1589 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
1591 WARN ("Unexpected address type 0x%x\n", i
);
1595 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, sizeof(row
) )))
1599 HeapFree( GetProcessHeap (), 0, buf
);
1602 FIXME( "not implemented\n" );
1603 ret
= ERROR_NOT_SUPPORTED
;
1606 if (!table
) return ERROR_OUTOFMEMORY
;
1609 if (bOrder
&& table
->dwNumEntries
)
1610 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipforward_rows
);
1611 *ppIpForwardTable
= table
;
1613 else HeapFree( heap
, flags
, table
);
1614 TRACE( "returning ret %u table %p\n", ret
, table
);
1618 static int compare_ipnet_rows(const void *a
, const void *b
)
1620 const MIB_IPNETROW
*rowA
= a
;
1621 const MIB_IPNETROW
*rowB
= b
;
1623 return ntohl(rowA
->dwAddr
) - ntohl(rowB
->dwAddr
);
1627 /******************************************************************
1628 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1630 * Get the IP-to-physical address mapping table.
1631 * Like GetIpNetTable(), but allocate the returned table from heap.
1634 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1635 * allocated and returned.
1636 * bOrder [In] whether to sort the table
1637 * heap [In] heap from which the table is allocated
1638 * flags [In] flags to HeapAlloc
1641 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1642 * on failure, NO_ERROR on success.
1644 DWORD WINAPI
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE
*ppIpNetTable
, BOOL bOrder
,
1645 HANDLE heap
, DWORD flags
)
1647 MIB_IPNETTABLE
*table
;
1649 DWORD ret
= NO_ERROR
, count
= 16, table_size
= FIELD_OFFSET( MIB_IPNETTABLE
, table
[count
] );
1651 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable
, bOrder
, heap
, flags
);
1653 if (!ppIpNetTable
) return ERROR_INVALID_PARAMETER
;
1655 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
1656 return ERROR_OUTOFMEMORY
;
1658 table
->dwNumEntries
= 0;
1664 if ((fp
= fopen("/proc/net/arp", "r")))
1666 char buf
[512], *ptr
;
1669 /* skip header line */
1670 ptr
= fgets(buf
, sizeof(buf
), fp
);
1671 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1673 memset( &row
, 0, sizeof(row
) );
1675 row
.dwAddr
= inet_addr(ptr
);
1676 while (*ptr
&& !isspace(*ptr
)) ptr
++;
1677 strtoul(ptr
+ 1, &ptr
, 16); /* hw type (skip) */
1678 atf_flags
= strtoul(ptr
+ 1, &ptr
, 16);
1681 if (atf_flags
& ATF_COM
) row
.u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
1685 if (atf_flags
& ATF_PERM
) row
.u
.Type
= MIB_IPNET_TYPE_STATIC
;
1688 row
.u
.Type
= MIB_IPNET_TYPE_OTHER
;
1690 while (*ptr
&& isspace(*ptr
)) ptr
++;
1691 while (*ptr
&& !isspace(*ptr
))
1693 row
.bPhysAddr
[row
.dwPhysAddrLen
++] = strtoul(ptr
, &ptr
, 16);
1696 while (*ptr
&& isspace(*ptr
)) ptr
++;
1697 while (*ptr
&& !isspace(*ptr
)) ptr
++; /* mask (skip) */
1698 while (*ptr
&& isspace(*ptr
)) ptr
++;
1699 getInterfaceIndexByName(ptr
, &row
.dwIndex
);
1701 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, sizeof(row
) )))
1706 else ret
= ERROR_NOT_SUPPORTED
;
1708 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1711 int fd
, len
, namelen
;
1712 mib2_ipNetToMediaEntry_t
*entry
;
1715 if ((fd
= open_streams_mib( NULL
)) != -1)
1717 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_MEDIA
, &len
)))
1719 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1721 row
.dwPhysAddrLen
= min( entry
->ipNetToMediaPhysAddress
.o_length
, MAXLEN_PHYSADDR
);
1722 memcpy( row
.bPhysAddr
, entry
->ipNetToMediaPhysAddress
.o_bytes
, row
.dwPhysAddrLen
);
1723 row
.dwAddr
= entry
->ipNetToMediaNetAddress
;
1724 row
.u
.Type
= entry
->ipNetToMediaType
;
1725 namelen
= min( sizeof(name
) - 1, entry
->ipNetToMediaIfIndex
.o_length
);
1726 memcpy( name
, entry
->ipNetToMediaIfIndex
.o_bytes
, namelen
);
1728 getInterfaceIndexByName( name
, &row
.dwIndex
);
1729 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, sizeof(row
) )))
1732 HeapFree( GetProcessHeap(), 0, data
);
1736 else ret
= ERROR_NOT_SUPPORTED
;
1738 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1740 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1742 char *buf
= NULL
, *lim
, *next
;
1743 struct rt_msghdr
*rtm
;
1744 struct sockaddr_inarp
*sinarp
;
1745 struct sockaddr_dl
*sdl
;
1747 if (sysctl (mib
, ARRAY_SIZE(mib
), NULL
, &needed
, NULL
, 0) == -1)
1749 ERR ("failed to get arp table\n");
1750 ret
= ERROR_NOT_SUPPORTED
;
1754 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1757 ret
= ERROR_OUTOFMEMORY
;
1761 if (sysctl (mib
, ARRAY_SIZE(mib
), buf
, &needed
, NULL
, 0) == -1)
1763 ret
= ERROR_NOT_SUPPORTED
;
1771 rtm
= (struct rt_msghdr
*)next
;
1772 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1773 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1774 if(sdl
->sdl_alen
) /* arp entry */
1776 memset( &row
, 0, sizeof(row
) );
1777 row
.dwAddr
= sinarp
->sin_addr
.s_addr
;
1778 row
.dwIndex
= sdl
->sdl_index
;
1779 row
.dwPhysAddrLen
= min( 8, sdl
->sdl_alen
);
1780 memcpy( row
.bPhysAddr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], row
.dwPhysAddrLen
);
1781 if(rtm
->rtm_rmx
.rmx_expire
== 0) row
.u
.Type
= MIB_IPNET_TYPE_STATIC
;
1782 else if(sinarp
->sin_other
& SIN_PROXY
) row
.u
.Type
= MIB_IPNET_TYPE_OTHER
;
1783 else if(rtm
->rtm_rmx
.rmx_expire
!= 0) row
.u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
1784 else row
.u
.Type
= MIB_IPNET_TYPE_INVALID
;
1786 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, sizeof(row
) )))
1789 next
+= rtm
->rtm_msglen
;
1792 HeapFree( GetProcessHeap (), 0, buf
);
1795 FIXME( "not implemented\n" );
1796 ret
= ERROR_NOT_SUPPORTED
;
1799 if (!table
) return ERROR_OUTOFMEMORY
;
1802 if (bOrder
&& table
->dwNumEntries
)
1803 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipnet_rows
);
1804 *ppIpNetTable
= table
;
1806 else HeapFree( heap
, flags
, table
);
1807 TRACE( "returning ret %u table %p\n", ret
, table
);
1811 static DWORD
get_tcp_table_sizes( TCP_TABLE_CLASS
class, DWORD row_count
, DWORD
*row_size
)
1817 case TCP_TABLE_BASIC_LISTENER
:
1818 case TCP_TABLE_BASIC_CONNECTIONS
:
1819 case TCP_TABLE_BASIC_ALL
:
1821 table_size
= FIELD_OFFSET(MIB_TCPTABLE
, table
[row_count
]);
1822 if (row_size
) *row_size
= sizeof(MIB_TCPROW
);
1825 case TCP_TABLE_OWNER_PID_LISTENER
:
1826 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
1827 case TCP_TABLE_OWNER_PID_ALL
:
1829 table_size
= FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID
, table
[row_count
]);
1830 if (row_size
) *row_size
= sizeof(MIB_TCPROW_OWNER_PID
);
1833 case TCP_TABLE_OWNER_MODULE_LISTENER
:
1834 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
1835 case TCP_TABLE_OWNER_MODULE_ALL
:
1837 table_size
= FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE
, table
[row_count
]);
1838 if (row_size
) *row_size
= sizeof(MIB_TCPROW_OWNER_MODULE
);
1842 ERR("unhandled class %u\n", class);
1848 /* Why not a lookup table? Because the TCPS_* constants are different
1849 on different platforms */
1850 static inline MIB_TCP_STATE
TCPStateToMIBState (int state
)
1854 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1855 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1856 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1857 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1858 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1859 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1860 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1861 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1862 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1863 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1865 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1869 static int compare_tcp_rows(const void *a
, const void *b
)
1871 const MIB_TCPROW
*rowA
= a
;
1872 const MIB_TCPROW
*rowB
= b
;
1875 if ((ret
= ntohl (rowA
->dwLocalAddr
) - ntohl (rowB
->dwLocalAddr
)) != 0) return ret
;
1876 if ((ret
= ntohs ((unsigned short)rowA
->dwLocalPort
) -
1877 ntohs ((unsigned short)rowB
->dwLocalPort
)) != 0) return ret
;
1878 if ((ret
= ntohl (rowA
->dwRemoteAddr
) - ntohl (rowB
->dwRemoteAddr
)) != 0) return ret
;
1879 return ntohs ((unsigned short)rowA
->dwRemotePort
) - ntohs ((unsigned short)rowB
->dwRemotePort
);
1885 unsigned int unix_pid
;
1888 static struct pid_map
*get_pid_map( unsigned int *num_entries
)
1890 struct pid_map
*map
;
1891 unsigned int i
= 0, map_count
= 16, buffer_len
= 4096, process_count
, pos
= 0;
1893 char *buffer
= NULL
, *new_buffer
;
1895 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, buffer_len
))) return NULL
;
1899 SERVER_START_REQ( list_processes
)
1901 wine_server_set_reply( req
, buffer
, buffer_len
);
1902 ret
= wine_server_call( req
);
1903 buffer_len
= reply
->info_size
;
1904 process_count
= reply
->process_count
;
1908 if (ret
!= STATUS_INFO_LENGTH_MISMATCH
) break;
1910 if (!(new_buffer
= HeapReAlloc( GetProcessHeap(), 0, buffer
, buffer_len
)))
1912 HeapFree( GetProcessHeap(), 0, buffer
);
1915 buffer
= new_buffer
;
1918 if (!(map
= HeapAlloc( GetProcessHeap(), 0, map_count
* sizeof(*map
) )))
1920 HeapFree( GetProcessHeap(), 0, buffer
);
1924 for (i
= 0; i
< process_count
; ++i
)
1926 const struct process_info
*process
;
1928 pos
= (pos
+ 7) & ~7;
1929 process
= (const struct process_info
*)(buffer
+ pos
);
1933 struct pid_map
*new_map
;
1935 if (!(new_map
= HeapReAlloc( GetProcessHeap(), 0, map
, map_count
* sizeof(*map
))))
1937 HeapFree( GetProcessHeap(), 0, map
);
1938 HeapFree( GetProcessHeap(), 0, buffer
);
1944 map
[i
].pid
= process
->pid
;
1945 map
[i
].unix_pid
= process
->unix_pid
;
1947 pos
+= sizeof(struct process_info
) + process
->name_len
;
1948 pos
= (pos
+ 7) & ~7;
1949 pos
+= process
->thread_count
* sizeof(struct thread_info
);
1952 HeapFree( GetProcessHeap(), 0, buffer
);
1953 *num_entries
= process_count
;
1957 static unsigned int find_owning_pid( struct pid_map
*map
, unsigned int num_entries
, UINT_PTR inode
)
1960 unsigned int i
, len_socket
;
1963 sprintf( socket
, "socket:[%lu]", inode
);
1964 len_socket
= strlen( socket
);
1965 for (i
= 0; i
< num_entries
; i
++)
1968 struct dirent
*dirent
;
1971 sprintf( dir
, "/proc/%u/fd", map
[i
].unix_pid
);
1972 if ((dirfd
= opendir( dir
)))
1974 while ((dirent
= readdir( dirfd
)))
1976 char link
[sizeof(dirent
->d_name
) + 32], name
[32];
1979 sprintf( link
, "/proc/%u/fd/%s", map
[i
].unix_pid
, dirent
->d_name
);
1980 if ((len
= readlink( link
, name
, sizeof(name
) - 1 )) > 0) name
[len
] = 0;
1981 if (len
== len_socket
&& !strcmp( socket
, name
))
1991 #elif defined(HAVE_LIBPROCSTAT)
1992 struct procstat
*pstat
;
1993 struct kinfo_proc
*proc
;
1994 struct filestat_list
*fds
;
1995 struct filestat
*fd
;
1996 struct sockstat sock
;
1997 unsigned int i
, proc_count
;
1999 pstat
= procstat_open_sysctl();
2000 if (!pstat
) return 0;
2002 for (i
= 0; i
< num_entries
; i
++)
2004 proc
= procstat_getprocs( pstat
, KERN_PROC_PID
, map
[i
].unix_pid
, &proc_count
);
2005 if (!proc
|| proc_count
< 1) continue;
2007 fds
= procstat_getfiles( pstat
, proc
, 0 );
2010 procstat_freeprocs( pstat
, proc
);
2014 STAILQ_FOREACH( fd
, fds
, next
)
2016 char errbuf
[_POSIX2_LINE_MAX
];
2018 if (fd
->fs_type
!= PS_FST_TYPE_SOCKET
) continue;
2020 procstat_get_socket_info( pstat
, fd
, &sock
, errbuf
);
2022 if (sock
.so_pcb
== inode
)
2024 procstat_freefiles( pstat
, fds
);
2025 procstat_freeprocs( pstat
, proc
);
2026 procstat_close( pstat
);
2031 procstat_freefiles( pstat
, fds
);
2032 procstat_freeprocs( pstat
, proc
);
2035 procstat_close( pstat
);
2037 #elif defined(HAVE_PROC_PIDINFO)
2038 struct proc_fdinfo
*fds
;
2039 struct socket_fdinfo sock
;
2040 unsigned int i
, j
, n
;
2042 for (i
= 0; i
< num_entries
; i
++)
2044 int fd_len
= proc_pidinfo( map
[i
].unix_pid
, PROC_PIDLISTFDS
, 0, NULL
, 0 );
2045 if (fd_len
<= 0) continue;
2047 fds
= HeapAlloc( GetProcessHeap(), 0, fd_len
);
2050 proc_pidinfo( map
[i
].unix_pid
, PROC_PIDLISTFDS
, 0, fds
, fd_len
);
2051 n
= fd_len
/ sizeof(struct proc_fdinfo
);
2052 for (j
= 0; j
< n
; j
++)
2054 if (fds
[j
].proc_fdtype
!= PROX_FDTYPE_SOCKET
) continue;
2056 proc_pidfdinfo( map
[i
].unix_pid
, fds
[j
].proc_fd
, PROC_PIDFDSOCKETINFO
, &sock
, sizeof(sock
) );
2057 if (sock
.psi
.soi_pcb
== inode
)
2059 HeapFree( GetProcessHeap(), 0, fds
);
2064 HeapFree( GetProcessHeap(), 0, fds
);
2068 FIXME( "not implemented\n" );
2073 static BOOL
match_class( TCP_TABLE_CLASS
class, MIB_TCP_STATE state
)
2077 case TCP_TABLE_BASIC_ALL
:
2078 case TCP_TABLE_OWNER_PID_ALL
:
2079 case TCP_TABLE_OWNER_MODULE_ALL
:
2082 case TCP_TABLE_BASIC_LISTENER
:
2083 case TCP_TABLE_OWNER_PID_LISTENER
:
2084 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2085 if (state
== MIB_TCP_STATE_LISTEN
) return TRUE
;
2088 case TCP_TABLE_BASIC_CONNECTIONS
:
2089 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2090 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2091 if (state
== MIB_TCP_STATE_ESTAB
) return TRUE
;
2095 ERR( "unhandled class %u\n", class );
2100 DWORD
build_tcp_table( TCP_TABLE_CLASS
class, void **tablep
, BOOL order
, HANDLE heap
, DWORD flags
,
2103 MIB_TCPTABLE
*table
;
2104 MIB_TCPROW_OWNER_MODULE row
;
2105 DWORD ret
= NO_ERROR
, count
= 16, table_size
, row_size
;
2107 if (!(table_size
= get_tcp_table_sizes( class, count
, &row_size
)))
2108 return ERROR_INVALID_PARAMETER
;
2110 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
2111 return ERROR_OUTOFMEMORY
;
2113 table
->dwNumEntries
= 0;
2119 if ((fp
= fopen("/proc/net/tcp", "r")))
2121 char buf
[512], *ptr
;
2122 struct pid_map
*map
= NULL
;
2123 unsigned int num_entries
= 0;
2126 if (class >= TCP_TABLE_OWNER_PID_LISTENER
) map
= get_pid_map( &num_entries
);
2128 /* skip header line */
2129 ptr
= fgets(buf
, sizeof(buf
), fp
);
2130 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
2132 if (sscanf( ptr
, "%*x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d",
2133 &row
.dwLocalAddr
, &row
.dwLocalPort
, &row
.dwRemoteAddr
,
2134 &row
.dwRemotePort
, &row
.dwState
, &inode
) != 6)
2136 row
.dwLocalPort
= htons( row
.dwLocalPort
);
2137 row
.dwRemotePort
= htons( row
.dwRemotePort
);
2138 row
.dwState
= TCPStateToMIBState( row
.dwState
);
2139 if (!match_class( class, row
.dwState
)) continue;
2141 if (class >= TCP_TABLE_OWNER_PID_LISTENER
)
2142 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, inode
);
2143 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER
)
2145 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2146 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2148 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2151 HeapFree( GetProcessHeap(), 0, map
);
2154 else ret
= ERROR_NOT_SUPPORTED
;
2156 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2160 mib2_tcpConnEntry_t
*entry
;
2162 if ((fd
= open_streams_mib( "tcp" )) != -1)
2164 if ((data
= read_mib_entry( fd
, MIB2_TCP
, MIB2_TCP_CONN
, &len
)))
2166 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
2168 row
.dwLocalAddr
= entry
->tcpConnLocalAddress
;
2169 row
.dwLocalPort
= htons( entry
->tcpConnLocalPort
);
2170 row
.dwRemoteAddr
= entry
->tcpConnRemAddress
;
2171 row
.dwRemotePort
= htons( entry
->tcpConnRemPort
);
2172 row
.dwState
= entry
->tcpConnState
;
2173 if (!match_class( class, row
.dwState
)) continue;
2174 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2177 HeapFree( GetProcessHeap(), 0, data
);
2181 else ret
= ERROR_NOT_SUPPORTED
;
2183 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2187 struct xinpgen
*pXIG
, *pOrigXIG
;
2188 struct pid_map
*pMap
= NULL
;
2189 unsigned NumEntries
;
2191 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
2193 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2194 ret
= ERROR_NOT_SUPPORTED
;
2198 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
2201 ret
= ERROR_OUTOFMEMORY
;
2205 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
2207 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2208 ret
= ERROR_NOT_SUPPORTED
;
2212 if (class >= TCP_TABLE_OWNER_PID_LISTENER
) pMap
= get_pid_map( &NumEntries
);
2214 /* Might be nothing here; first entry is just a header it seems */
2215 if (Len
<= sizeof (struct xinpgen
)) goto done
;
2217 pOrigXIG
= (struct xinpgen
*)Buf
;
2220 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
2221 pXIG
->xig_len
> sizeof (struct xinpgen
);
2222 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
2224 #if __FreeBSD_version >= 1200026
2225 struct xtcpcb
*pTCPData
= (struct xtcpcb
*)pXIG
;
2226 struct xinpcb
*pINData
= &pTCPData
->xt_inp
;
2227 struct xsocket
*pSockData
= &pINData
->xi_socket
;
2229 struct tcpcb
*pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
2230 struct inpcb
*pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
2231 struct xsocket
*pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
2234 /* Ignore sockets for other protocols */
2235 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
2238 /* Ignore PCBs that were freed while generating the data */
2239 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
2242 /* we're only interested in IPv4 addresses */
2243 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
2244 (pINData
->inp_vflag
& INP_IPV6
))
2247 /* If all 0's, skip it */
2248 if (!pINData
->inp_laddr
.s_addr
&&
2249 !pINData
->inp_lport
&&
2250 !pINData
->inp_faddr
.s_addr
&&
2251 !pINData
->inp_fport
)
2254 /* Fill in structure details */
2255 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
2256 row
.dwLocalPort
= pINData
->inp_lport
;
2257 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
2258 row
.dwRemotePort
= pINData
->inp_fport
;
2259 row
.dwState
= TCPStateToMIBState (pTCPData
->t_state
);
2260 if (!match_class( class, row
.dwState
)) continue;
2261 if (class >= TCP_TABLE_OWNER_PID_LISTENER
)
2262 row
.dwOwningPid
= find_owning_pid( pMap
, NumEntries
, (UINT_PTR
)pSockData
->so_pcb
);
2263 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER
)
2265 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2266 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2268 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2273 HeapFree( GetProcessHeap(), 0, pMap
);
2274 HeapFree (GetProcessHeap (), 0, Buf
);
2277 FIXME( "not implemented\n" );
2278 ret
= ERROR_NOT_SUPPORTED
;
2281 if (!table
) return ERROR_OUTOFMEMORY
;
2284 if (order
&& table
->dwNumEntries
)
2285 qsort( table
->table
, table
->dwNumEntries
, row_size
, compare_tcp_rows
);
2288 else HeapFree( heap
, flags
, table
);
2289 if (size
) *size
= get_tcp_table_sizes( class, count
, NULL
);
2290 TRACE( "returning ret %u table %p\n", ret
, table
);
2294 /******************************************************************
2295 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
2297 * Get the TCP connection table.
2298 * Like GetTcpTable(), but allocate the returned table from heap.
2301 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2302 * allocated and returned.
2303 * bOrder [In] whether to sort the table
2304 * heap [In] heap from which the table is allocated
2305 * flags [In] flags to HeapAlloc
2308 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2309 * returns otherwise.
2311 DWORD WINAPI
AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE
*ppTcpTable
, BOOL bOrder
,
2312 HANDLE heap
, DWORD flags
)
2314 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable
, bOrder
, heap
, flags
);
2316 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
2317 return build_tcp_table( TCP_TABLE_BASIC_ALL
, (void **)ppTcpTable
, bOrder
, heap
, flags
, NULL
);
2320 /******************************************************************
2321 * AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
2323 * Get the TCP connection table.
2324 * Like GetTcpTable(), but allocate the returned table from heap.
2327 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE_EX is
2328 * allocated and returned.
2329 * bOrder [In] whether to sort the table
2330 * heap [In] heap from which the table is allocated
2331 * flags [In] flags to HeapAlloc
2332 * family [In] address family [AF_INET|AF_INET6]
2335 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2336 * returns otherwise.
2338 DWORD WINAPI
AllocateAndGetTcpExTableFromStack( VOID
**ppTcpTable
, BOOL bOrder
,
2339 HANDLE heap
, DWORD flags
, DWORD family
)
2341 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x, family %u\n",
2342 ppTcpTable
, bOrder
, heap
, flags
, family
);
2344 if (!ppTcpTable
|| !family
)
2345 return ERROR_INVALID_PARAMETER
;
2347 if (family
!= WS_AF_INET
)
2349 FIXME( "family = %u not supported\n", family
);
2350 return ERROR_NOT_SUPPORTED
;
2353 return build_tcp_table( TCP_TABLE_OWNER_PID_ALL
, ppTcpTable
, bOrder
, heap
, flags
, NULL
);
2356 static DWORD
get_udp_table_sizes( UDP_TABLE_CLASS
class, DWORD row_count
, DWORD
*row_size
)
2362 case UDP_TABLE_BASIC
:
2364 table_size
= FIELD_OFFSET(MIB_UDPTABLE
, table
[row_count
]);
2365 if (row_size
) *row_size
= sizeof(MIB_UDPROW
);
2368 case UDP_TABLE_OWNER_PID
:
2370 table_size
= FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID
, table
[row_count
]);
2371 if (row_size
) *row_size
= sizeof(MIB_UDPROW_OWNER_PID
);
2374 case UDP_TABLE_OWNER_MODULE
:
2376 table_size
= FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE
, table
[row_count
]);
2377 if (row_size
) *row_size
= sizeof(MIB_UDPROW_OWNER_MODULE
);
2381 ERR("unhandled class %u\n", class);
2387 static int compare_udp_rows(const void *a
, const void *b
)
2389 const MIB_UDPROW
*rowA
= a
;
2390 const MIB_UDPROW
*rowB
= b
;
2393 if ((ret
= rowA
->dwLocalAddr
- rowB
->dwLocalAddr
) != 0) return ret
;
2394 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
2397 DWORD
build_udp_table( UDP_TABLE_CLASS
class, void **tablep
, BOOL order
, HANDLE heap
, DWORD flags
,
2400 MIB_UDPTABLE
*table
;
2401 MIB_UDPROW_OWNER_MODULE row
;
2402 DWORD ret
= NO_ERROR
, count
= 16, table_size
, row_size
;
2404 if (!(table_size
= get_udp_table_sizes( class, count
, &row_size
)))
2405 return ERROR_INVALID_PARAMETER
;
2407 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
2408 return ERROR_OUTOFMEMORY
;
2410 table
->dwNumEntries
= 0;
2411 memset( &row
, 0, sizeof(row
) );
2417 if ((fp
= fopen( "/proc/net/udp", "r" )))
2419 char buf
[512], *ptr
;
2420 struct pid_map
*map
= NULL
;
2421 unsigned int num_entries
= 0;
2424 if (class >= UDP_TABLE_OWNER_PID
) map
= get_pid_map( &num_entries
);
2426 /* skip header line */
2427 ptr
= fgets( buf
, sizeof(buf
), fp
);
2428 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
2430 if (sscanf( ptr
, "%*u: %x:%x %*s %*s %*s %*s %*s %*s %*s %d",
2431 &row
.dwLocalAddr
, &row
.dwLocalPort
, &inode
) != 3)
2433 row
.dwLocalPort
= htons( row
.dwLocalPort
);
2435 if (class >= UDP_TABLE_OWNER_PID
)
2436 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, inode
);
2437 if (class >= UDP_TABLE_OWNER_MODULE
)
2439 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2441 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2443 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2446 HeapFree( GetProcessHeap(), 0, map
);
2449 else ret
= ERROR_NOT_SUPPORTED
;
2451 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2455 mib2_udpEntry_t
*entry
;
2457 if ((fd
= open_streams_mib( "udp" )) != -1)
2459 if ((data
= read_mib_entry( fd
, MIB2_UDP
, MIB2_UDP_ENTRY
, &len
)))
2461 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
2463 row
.dwLocalAddr
= entry
->udpLocalAddress
;
2464 row
.dwLocalPort
= htons( entry
->udpLocalPort
);
2465 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2468 HeapFree( GetProcessHeap(), 0, data
);
2472 else ret
= ERROR_NOT_SUPPORTED
;
2474 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2478 struct xinpgen
*pXIG
, *pOrigXIG
;
2479 struct pid_map
*pMap
= NULL
;
2480 unsigned NumEntries
;
2482 if (sysctlbyname ("net.inet.udp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
2484 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2485 ret
= ERROR_NOT_SUPPORTED
;
2489 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
2492 ret
= ERROR_OUTOFMEMORY
;
2496 if (sysctlbyname ("net.inet.udp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
2498 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2499 ret
= ERROR_NOT_SUPPORTED
;
2503 if (class >= UDP_TABLE_OWNER_PID
)
2504 pMap
= get_pid_map( &NumEntries
);
2506 /* Might be nothing here; first entry is just a header it seems */
2507 if (Len
<= sizeof (struct xinpgen
)) goto done
;
2509 pOrigXIG
= (struct xinpgen
*)Buf
;
2512 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
2513 pXIG
->xig_len
> sizeof (struct xinpgen
);
2514 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
2516 #if __FreeBSD_version >= 1200026
2517 struct xinpcb
*pINData
= (struct xinpcb
*)pXIG
;
2518 struct xsocket
*pSockData
= &pINData
->xi_socket
;
2520 struct inpcb
*pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
2521 struct xsocket
*pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
2524 /* Ignore sockets for other protocols */
2525 if (pSockData
->xso_protocol
!= IPPROTO_UDP
)
2528 /* Ignore PCBs that were freed while generating the data */
2529 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
2532 /* we're only interested in IPv4 addresses */
2533 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
2534 (pINData
->inp_vflag
& INP_IPV6
))
2537 /* If all 0's, skip it */
2538 if (!pINData
->inp_laddr
.s_addr
&&
2539 !pINData
->inp_lport
)
2542 /* Fill in structure details */
2543 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
2544 row
.dwLocalPort
= pINData
->inp_lport
;
2545 if (class >= UDP_TABLE_OWNER_PID
)
2546 row
.dwOwningPid
= find_owning_pid( pMap
, NumEntries
, (UINT_PTR
)pSockData
->so_pcb
);
2547 if (class >= UDP_TABLE_OWNER_MODULE
)
2549 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2551 row
.SpecificPortBind
= !(pINData
->inp_flags
& INP_ANONPORT
);
2552 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2554 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2559 HeapFree( GetProcessHeap(), 0, pMap
);
2560 HeapFree (GetProcessHeap (), 0, Buf
);
2563 FIXME( "not implemented\n" );
2564 ret
= ERROR_NOT_SUPPORTED
;
2567 if (!table
) return ERROR_OUTOFMEMORY
;
2570 if (order
&& table
->dwNumEntries
)
2571 qsort( table
->table
, table
->dwNumEntries
, row_size
, compare_udp_rows
);
2574 else HeapFree( heap
, flags
, table
);
2575 if (size
) *size
= get_udp_table_sizes( class, count
, NULL
);
2576 TRACE( "returning ret %u table %p\n", ret
, table
);
2580 static DWORD
get_tcp6_table_sizes( TCP_TABLE_CLASS
class, DWORD row_count
, DWORD
*row_size
)
2586 case TCP_TABLE_BASIC_LISTENER
:
2587 case TCP_TABLE_BASIC_CONNECTIONS
:
2588 case TCP_TABLE_BASIC_ALL
:
2590 table_size
= FIELD_OFFSET(MIB_TCP6TABLE
, table
[row_count
]);
2591 if (row_size
) *row_size
= sizeof(MIB_TCP6ROW
);
2594 case TCP_TABLE_OWNER_PID_LISTENER
:
2595 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2596 case TCP_TABLE_OWNER_PID_ALL
:
2598 table_size
= FIELD_OFFSET(MIB_TCP6TABLE_OWNER_PID
, table
[row_count
]);
2599 if (row_size
) *row_size
= sizeof(MIB_TCP6ROW_OWNER_PID
);
2602 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2603 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2604 case TCP_TABLE_OWNER_MODULE_ALL
:
2606 table_size
= FIELD_OFFSET(MIB_TCP6TABLE_OWNER_MODULE
, table
[row_count
]);
2607 if (row_size
) *row_size
= sizeof(MIB_TCP6ROW_OWNER_MODULE
);
2611 ERR("unhandled class %u\n", class);
2617 static int compare_tcp6_basic_rows(const void *a
, const void *b
)
2619 const MIB_TCP6ROW
*rowA
= a
;
2620 const MIB_TCP6ROW
*rowB
= b
;
2623 if ((ret
= memcmp(&rowA
->LocalAddr
, &rowB
->LocalAddr
, sizeof(rowA
->LocalAddr
)) != 0)) return ret
;
2624 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
2625 if ((ret
= rowA
->dwLocalPort
- rowB
->dwLocalPort
) != 0) return ret
;
2626 if ((ret
= memcmp(&rowA
->RemoteAddr
, &rowB
->RemoteAddr
, sizeof(rowA
->RemoteAddr
)) != 0)) return ret
;
2627 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
2628 return rowA
->dwRemotePort
- rowB
->dwRemotePort
;
2631 static int compare_tcp6_owner_rows(const void *a
, const void *b
)
2633 const MIB_TCP6ROW_OWNER_PID
*rowA
= a
;
2634 const MIB_TCP6ROW_OWNER_PID
*rowB
= b
;
2637 if ((ret
= memcmp(&rowA
->ucLocalAddr
, &rowB
->ucLocalAddr
, sizeof(rowA
->ucLocalAddr
)) != 0)) return ret
;
2638 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
2639 if ((ret
= rowA
->dwLocalPort
- rowB
->dwLocalPort
) != 0) return ret
;
2640 if ((ret
= memcmp(&rowA
->ucRemoteAddr
, &rowB
->ucRemoteAddr
, sizeof(rowA
->ucRemoteAddr
)) != 0)) return ret
;
2641 if ((ret
= rowA
->dwRemoteScopeId
- rowB
->dwRemoteScopeId
) != 0) return ret
;
2642 return rowA
->dwRemotePort
- rowB
->dwRemotePort
;
2645 static DWORD
get_udp6_table_sizes( UDP_TABLE_CLASS
class, DWORD row_count
, DWORD
*row_size
)
2651 case UDP_TABLE_BASIC
:
2653 table_size
= FIELD_OFFSET(MIB_UDP6TABLE
, table
[row_count
]);
2654 if (row_size
) *row_size
= sizeof(MIB_UDP6ROW
);
2657 case UDP_TABLE_OWNER_PID
:
2659 table_size
= FIELD_OFFSET(MIB_UDP6TABLE_OWNER_PID
, table
[row_count
]);
2660 if (row_size
) *row_size
= sizeof(MIB_UDP6ROW_OWNER_PID
);
2663 case UDP_TABLE_OWNER_MODULE
:
2665 table_size
= FIELD_OFFSET(MIB_UDP6TABLE_OWNER_MODULE
, table
[row_count
]);
2666 if (row_size
) *row_size
= sizeof(MIB_UDP6ROW_OWNER_MODULE
);
2670 ERR("unhandled class %u\n", class);
2676 static int compare_udp6_rows(const void *a
, const void *b
)
2678 const MIB_UDP6ROW
*rowA
= a
;
2679 const MIB_UDP6ROW
*rowB
= b
;
2682 if ((ret
= memcmp(&rowA
->dwLocalAddr
, &rowB
->dwLocalAddr
, sizeof(rowA
->dwLocalAddr
)) != 0)) return ret
;
2683 if ((ret
= rowA
->dwLocalScopeId
- rowB
->dwLocalScopeId
) != 0) return ret
;
2684 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
2687 #if defined(__linux__) || (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN))
2688 struct ipv6_addr_scope
2694 static struct ipv6_addr_scope
*get_ipv6_addr_scope_table(unsigned int *size
)
2696 struct ipv6_addr_scope
*table
= NULL
;
2697 unsigned int table_size
= 0;
2699 char buf
[512], *ptr
;
2701 #elif defined(HAVE_GETIFADDRS)
2702 struct ifaddrs
*addrs
, *cur
;
2705 if (!(table
= HeapAlloc( GetProcessHeap(), 0, sizeof(table
[0]) )))
2709 if (!(fp
= fopen( "/proc/net/if_inet6", "r" )))
2712 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
2716 struct ipv6_addr_scope
*new_table
;
2717 struct ipv6_addr_scope
*entry
;
2720 if (sscanf( ptr
, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*s %*s %x",
2721 &a
[0], &a
[1], &a
[2], &a
[3], &a
[4], &a
[5], &a
[6], &a
[7], &scope
) != 9)
2725 if (!(new_table
= HeapReAlloc( GetProcessHeap(), 0, table
, table_size
* sizeof(table
[0]) )))
2732 entry
= &table
[table_size
- 1];
2737 entry
->addr
.u
.Word
[i
] = htons(a
[i
]);
2741 entry
->scope
= htons(scope
);
2745 #elif defined(HAVE_GETIFADDRS)
2746 if (getifaddrs(&addrs
) == -1)
2749 for (cur
= addrs
; cur
; cur
= cur
->ifa_next
)
2751 struct sockaddr_in6
*sin6
;
2752 struct ipv6_addr_scope
*new_table
;
2753 struct ipv6_addr_scope
*entry
;
2755 if (cur
->ifa_addr
->sa_family
!= AF_INET6
)
2758 sin6
= (struct sockaddr_in6
*)cur
->ifa_addr
;
2761 if (!(new_table
= HeapReAlloc( GetProcessHeap(), 0, table
, table_size
* sizeof(table
[0]) )))
2768 entry
= &table
[table_size
- 1];
2770 memcpy(&entry
->addr
, &sin6
->sin6_addr
, sizeof(entry
->addr
));
2771 entry
->scope
= sin6
->sin6_scope_id
;
2776 FIXME( "not implemented\n" );
2784 HeapFree( GetProcessHeap(), 0, table
);
2788 static DWORD
find_ipv6_addr_scope(const IN6_ADDR
*addr
, const struct ipv6_addr_scope
*table
, unsigned int size
)
2790 const BYTE multicast_scope_mask
= 0x0F;
2791 const BYTE multicast_scope_shift
= 0;
2794 if (WS_IN6_IS_ADDR_UNSPECIFIED(addr
))
2797 if (WS_IN6_IS_ADDR_MULTICAST(addr
))
2798 return htons((addr
->u
.Byte
[1] & multicast_scope_mask
) >> multicast_scope_shift
);
2805 if (memcmp(&table
[i
].addr
, addr
, sizeof(table
[i
].addr
)) == 0)
2806 return table
[i
].scope
;
2814 DWORD
build_tcp6_table( TCP_TABLE_CLASS
class, void **tablep
, BOOL order
, HANDLE heap
, DWORD flags
,
2817 MIB_TCP6TABLE
*table
;
2818 DWORD ret
= NO_ERROR
, count
= 16, table_size
, row_size
;
2820 if (!(table_size
= get_tcp6_table_sizes( class, count
, &row_size
)))
2821 return ERROR_INVALID_PARAMETER
;
2823 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
2824 return ERROR_OUTOFMEMORY
;
2826 table
->dwNumEntries
= 0;
2830 MIB_TCP6ROW_OWNER_MODULE row
;
2833 if ((fp
= fopen( "/proc/net/tcp6", "r" )))
2835 char buf
[512], *ptr
;
2836 struct pid_map
*map
= NULL
;
2837 unsigned int num_entries
= 0;
2838 struct ipv6_addr_scope
*addr_scopes
;
2839 unsigned int addr_scopes_size
= 0;
2842 addr_scopes
= get_ipv6_addr_scope_table(&addr_scopes_size
);
2844 if (class >= TCP_TABLE_OWNER_PID_LISTENER
) map
= get_pid_map( &num_entries
);
2846 /* skip header line */
2847 ptr
= fgets( buf
, sizeof(buf
), fp
);
2848 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
2850 DWORD
*local_addr
= (DWORD
*)&row
.ucLocalAddr
;
2851 DWORD
*remote_addr
= (DWORD
*)&row
.ucRemoteAddr
;
2853 if (sscanf( ptr
, "%*u: %8x%8x%8x%8x:%x %8x%8x%8x%8x:%x %x %*s %*s %*s %*s %*s %*s %*s %d",
2854 &local_addr
[0], &local_addr
[1], &local_addr
[2], &local_addr
[3], &row
.dwLocalPort
,
2855 &remote_addr
[0], &remote_addr
[1], &remote_addr
[2], &remote_addr
[3], &row
.dwRemotePort
,
2856 &row
.dwState
, &inode
) != 12)
2858 row
.dwState
= TCPStateToMIBState( row
.dwState
);
2859 if (!match_class( class, row
.dwState
)) continue;
2860 row
.dwLocalScopeId
= find_ipv6_addr_scope((const IN6_ADDR
*)&row
.ucLocalAddr
, addr_scopes
, addr_scopes_size
);
2861 row
.dwLocalPort
= htons( row
.dwLocalPort
);
2862 row
.dwRemoteScopeId
= find_ipv6_addr_scope((const IN6_ADDR
*)&row
.ucRemoteAddr
, addr_scopes
, addr_scopes_size
);
2863 row
.dwRemotePort
= htons( row
.dwRemotePort
);
2865 if (class <= TCP_TABLE_BASIC_ALL
)
2867 /* MIB_TCP6ROW has a different field order */
2868 MIB_TCP6ROW basic_row
;
2869 basic_row
.State
= row
.dwState
;
2870 memcpy( &basic_row
.LocalAddr
, &row
.ucLocalAddr
, sizeof(row
.ucLocalAddr
) );
2871 basic_row
.dwLocalScopeId
= row
.dwLocalScopeId
;
2872 basic_row
.dwLocalPort
= row
.dwLocalPort
;
2873 memcpy( &basic_row
.RemoteAddr
, &row
.ucRemoteAddr
, sizeof(row
.ucRemoteAddr
) );
2874 basic_row
.dwRemoteScopeId
= row
.dwRemoteScopeId
;
2875 basic_row
.dwRemotePort
= row
.dwRemotePort
;
2876 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &basic_row
, row_size
)))
2881 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, inode
);
2882 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER
)
2884 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2885 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2887 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
2890 HeapFree( GetProcessHeap(), 0, map
);
2891 HeapFree( GetProcessHeap(), 0, addr_scopes
);
2894 else ret
= ERROR_NOT_SUPPORTED
;
2896 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2898 static const char zero
[sizeof(IN6_ADDR
)] = {0};
2900 MIB_TCP6ROW_OWNER_MODULE row
;
2903 struct xinpgen
*xig
, *orig_xig
;
2904 struct pid_map
*map
= NULL
;
2905 unsigned num_entries
;
2906 struct ipv6_addr_scope
*addr_scopes
= NULL
;
2907 unsigned int addr_scopes_size
= 0;
2909 if (sysctlbyname( "net.inet.tcp.pcblist", NULL
, &len
, NULL
, 0 ) < 0)
2911 ERR( "Failure to read net.inet.tcp.pcblist via sysctlbyname!\n" );
2912 ret
= ERROR_NOT_SUPPORTED
;
2916 buf
= HeapAlloc( GetProcessHeap(), 0, len
);
2919 ret
= ERROR_OUTOFMEMORY
;
2923 if (sysctlbyname( "net.inet.tcp.pcblist", buf
, &len
, NULL
, 0 ) < 0)
2925 ERR( "Failure to read net.inet.tcp.pcblist via sysctlbyname!\n" );
2926 ret
= ERROR_NOT_SUPPORTED
;
2930 addr_scopes
= get_ipv6_addr_scope_table( &addr_scopes_size
);
2933 ret
= ERROR_OUTOFMEMORY
;
2937 if (class >= TCP_TABLE_OWNER_PID_LISTENER
) map
= get_pid_map( &num_entries
);
2939 /* Might be nothing here; first entry is just a header it seems */
2940 if (len
<= sizeof (struct xinpgen
)) goto done
;
2942 orig_xig
= (struct xinpgen
*)buf
;
2945 for (xig
= (struct xinpgen
*)((char *)xig
+ xig
->xig_len
);
2946 xig
->xig_len
> sizeof (struct xinpgen
);
2947 xig
= (struct xinpgen
*)((char *)xig
+ xig
->xig_len
))
2949 #if __FreeBSD_version >= 1200026
2950 struct xtcpcb
*tcp
= (struct xtcpcb
*)xig
;
2951 struct xinpcb
*in
= &tcp
->xt_inp
;
2952 struct xsocket
*sock
= &in
->xi_socket
;
2954 struct tcpcb
*tcp
= &((struct xtcpcb
*)xig
)->xt_tp
;
2955 struct inpcb
*in
= &((struct xtcpcb
*)xig
)->xt_inp
;
2956 struct xsocket
*sock
= &((struct xtcpcb
*)xig
)->xt_socket
;
2959 /* Ignore sockets for other protocols */
2960 if (sock
->xso_protocol
!= IPPROTO_TCP
)
2963 /* Ignore PCBs that were freed while generating the data */
2964 if (in
->inp_gencnt
> orig_xig
->xig_gen
)
2967 /* we're only interested in IPv6 addresses */
2968 if (!(in
->inp_vflag
& INP_IPV6
) ||
2969 (in
->inp_vflag
& INP_IPV4
))
2972 /* If all 0's, skip it */
2973 if (!memcmp( &in
->in6p_laddr
, zero
, sizeof(zero
) ) && !in
->inp_lport
&&
2974 !memcmp( &in
->in6p_faddr
, zero
, sizeof(zero
) ) && !in
->inp_fport
)
2977 /* Fill in structure details */
2978 memcpy( &row
.ucLocalAddr
, &in
->in6p_laddr
.s6_addr
, sizeof(row
.ucLocalAddr
) );
2979 row
.dwLocalPort
= in
->inp_lport
;
2980 row
.dwLocalScopeId
= find_ipv6_addr_scope( (const IN6_ADDR
*)&row
.ucLocalAddr
, addr_scopes
, addr_scopes_size
);
2981 memcpy( &row
.ucRemoteAddr
, &in
->in6p_faddr
.s6_addr
, sizeof(row
.ucRemoteAddr
) );
2982 row
.dwRemotePort
= in
->inp_fport
;
2983 row
.dwRemoteScopeId
= find_ipv6_addr_scope( (const IN6_ADDR
*)&row
.ucRemoteAddr
, addr_scopes
, addr_scopes_size
);
2984 row
.dwState
= TCPStateToMIBState( tcp
->t_state
);
2985 if (!match_class( class, row
.dwState
)) continue;
2987 if (class <= TCP_TABLE_BASIC_ALL
)
2989 /* MIB_TCP6ROW has a different field order */
2990 MIB_TCP6ROW basic_row
;
2991 basic_row
.State
= row
.dwState
;
2992 memcpy( &basic_row
.LocalAddr
, &row
.ucLocalAddr
, sizeof(row
.ucLocalAddr
) );
2993 basic_row
.dwLocalScopeId
= row
.dwLocalScopeId
;
2994 basic_row
.dwLocalPort
= row
.dwLocalPort
;
2995 memcpy( &basic_row
.RemoteAddr
, &row
.ucRemoteAddr
, sizeof(row
.ucRemoteAddr
) );
2996 basic_row
.dwRemoteScopeId
= row
.dwRemoteScopeId
;
2997 basic_row
.dwRemotePort
= row
.dwRemotePort
;
2998 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &basic_row
, row_size
)))
3003 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, (UINT_PTR
)sock
->so_pcb
);
3004 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER
)
3006 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
3007 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
3009 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
3014 HeapFree( GetProcessHeap(), 0, map
);
3015 HeapFree( GetProcessHeap(), 0, buf
);
3016 HeapFree( GetProcessHeap(), 0, addr_scopes
);
3019 FIXME( "not implemented\n" );
3020 ret
= ERROR_NOT_SUPPORTED
;
3023 if (!table
) return ERROR_OUTOFMEMORY
;
3026 if (order
&& table
->dwNumEntries
)
3028 qsort( table
->table
, table
->dwNumEntries
, row_size
,
3029 class <= TCP_TABLE_BASIC_ALL
? compare_tcp6_basic_rows
: compare_tcp6_owner_rows
);
3033 else HeapFree( heap
, flags
, table
);
3034 if (size
) *size
= get_tcp6_table_sizes( class, count
, NULL
);
3035 TRACE( "returning ret %u table %p\n", ret
, table
);
3039 DWORD
build_udp6_table( UDP_TABLE_CLASS
class, void **tablep
, BOOL order
, HANDLE heap
, DWORD flags
,
3042 MIB_UDP6TABLE
*table
;
3043 MIB_UDP6ROW_OWNER_MODULE row
;
3044 DWORD ret
= NO_ERROR
, count
= 16, table_size
, row_size
;
3046 if (!(table_size
= get_udp6_table_sizes( class, count
, &row_size
)))
3047 return ERROR_INVALID_PARAMETER
;
3049 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
3050 return ERROR_OUTOFMEMORY
;
3052 table
->dwNumEntries
= 0;
3053 memset( &row
, 0, sizeof(row
) );
3059 if ((fp
= fopen( "/proc/net/udp6", "r" )))
3061 char buf
[512], *ptr
;
3062 struct pid_map
*map
= NULL
;
3063 unsigned int num_entries
= 0;
3064 struct ipv6_addr_scope
*addr_scopes
;
3065 unsigned int addr_scopes_size
= 0;
3068 addr_scopes
= get_ipv6_addr_scope_table(&addr_scopes_size
);
3070 if (class >= UDP_TABLE_OWNER_PID
) map
= get_pid_map( &num_entries
);
3072 /* skip header line */
3073 ptr
= fgets( buf
, sizeof(buf
), fp
);
3074 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
3076 DWORD
*local_addr
= (DWORD
*)&row
.ucLocalAddr
;
3078 if (sscanf( ptr
, "%*u: %8x%8x%8x%8x:%x %*s %*s %*s %*s %*s %*s %*s %d",
3079 &local_addr
[0], &local_addr
[1], &local_addr
[2], &local_addr
[3],
3080 &row
.dwLocalPort
, &inode
) != 6)
3082 row
.dwLocalScopeId
= find_ipv6_addr_scope((const IN6_ADDR
*)&row
.ucLocalAddr
, addr_scopes
, addr_scopes_size
);
3083 row
.dwLocalPort
= htons( row
.dwLocalPort
);
3085 if (class >= UDP_TABLE_OWNER_PID
)
3086 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, inode
);
3087 if (class >= UDP_TABLE_OWNER_MODULE
)
3089 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
3091 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
3093 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
3096 HeapFree( GetProcessHeap(), 0, map
);
3097 HeapFree( GetProcessHeap(), 0, addr_scopes
);
3100 else ret
= ERROR_NOT_SUPPORTED
;
3102 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
3104 static const char zero
[sizeof(IN6_ADDR
)] = {0};
3108 struct xinpgen
*xig
, *orig_xig
;
3109 struct pid_map
*map
= NULL
;
3110 unsigned num_entries
;
3111 struct ipv6_addr_scope
*addr_scopes
= NULL
;
3112 unsigned int addr_scopes_size
= 0;
3114 if (sysctlbyname( "net.inet.udp.pcblist", NULL
, &len
, NULL
, 0 ) < 0)
3116 ERR( "Failure to read net.inet.udp.pcblist via sysctlbyname!\n" );
3117 ret
= ERROR_NOT_SUPPORTED
;
3121 buf
= HeapAlloc( GetProcessHeap(), 0, len
);
3124 ret
= ERROR_OUTOFMEMORY
;
3128 if (sysctlbyname( "net.inet.udp.pcblist", buf
, &len
, NULL
, 0 ) < 0)
3130 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
3131 ret
= ERROR_NOT_SUPPORTED
;
3135 addr_scopes
= get_ipv6_addr_scope_table( &addr_scopes_size
);
3138 ret
= ERROR_OUTOFMEMORY
;
3142 if (class >= UDP_TABLE_OWNER_PID
) map
= get_pid_map( &num_entries
);
3144 /* Might be nothing here; first entry is just a header it seems */
3145 if (len
<= sizeof (struct xinpgen
)) goto done
;
3147 orig_xig
= (struct xinpgen
*)buf
;
3150 for (xig
= (struct xinpgen
*)((char *)xig
+ xig
->xig_len
);
3151 xig
->xig_len
> sizeof (struct xinpgen
);
3152 xig
= (struct xinpgen
*)((char *)xig
+ xig
->xig_len
))
3154 #if __FreeBSD_version >= 1200026
3155 struct xinpcb
*in
= (struct xinpcb
*)xig
;
3156 struct xsocket
*sock
= &in
->xi_socket
;
3158 struct inpcb
*in
= &((struct xinpcb
*)xig
)->xi_inp
;
3159 struct xsocket
*sock
= &((struct xinpcb
*)xig
)->xi_socket
;
3162 /* Ignore sockets for other protocols */
3163 if (sock
->xso_protocol
!= IPPROTO_UDP
)
3166 /* Ignore PCBs that were freed while generating the data */
3167 if (in
->inp_gencnt
> orig_xig
->xig_gen
)
3170 /* we're only interested in IPv6 addresses */
3171 if (!(in
->inp_vflag
& INP_IPV6
) ||
3172 (in
->inp_vflag
& INP_IPV4
))
3175 /* If all 0's, skip it */
3176 if (!memcmp( &in
->in6p_laddr
.s6_addr
, zero
, sizeof(zero
) ) && !in
->inp_lport
)
3179 /* Fill in structure details */
3180 memcpy(row
.ucLocalAddr
, &in
->in6p_laddr
.s6_addr
, sizeof(row
.ucLocalAddr
));
3181 row
.dwLocalPort
= in
->inp_lport
;
3182 row
.dwLocalScopeId
= find_ipv6_addr_scope((const IN6_ADDR
*)&row
.ucLocalAddr
, addr_scopes
, addr_scopes_size
);
3183 if (class >= UDP_TABLE_OWNER_PID
)
3184 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, (UINT_PTR
)sock
->so_pcb
);
3185 if (class >= UDP_TABLE_OWNER_MODULE
)
3187 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
3189 row
.SpecificPortBind
= !(in
->inp_flags
& INP_ANONPORT
);
3190 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
3192 if (!(table
= append_table_row( heap
, flags
, table
, &table_size
, &count
, &row
, row_size
)))
3197 HeapFree( GetProcessHeap(), 0, map
);
3198 HeapFree( GetProcessHeap(), 0, buf
);
3199 HeapFree( GetProcessHeap(), 0, addr_scopes
);
3202 FIXME( "not implemented\n" );
3203 ret
= ERROR_NOT_SUPPORTED
;
3206 if (!table
) return ERROR_OUTOFMEMORY
;
3209 if (order
&& table
->dwNumEntries
)
3210 qsort( table
->table
, table
->dwNumEntries
, row_size
, compare_udp6_rows
);
3213 else HeapFree( heap
, flags
, table
);
3214 if (size
) *size
= get_udp6_table_sizes( class, count
, NULL
);
3215 TRACE( "returning ret %u table %p\n", ret
, table
);
3219 /******************************************************************
3220 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
3222 * Get the UDP listener table.
3223 * Like GetUdpTable(), but allocate the returned table from heap.
3226 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
3227 * allocated and returned.
3228 * bOrder [In] whether to sort the table
3229 * heap [In] heap from which the table is allocated
3230 * flags [In] flags to HeapAlloc
3233 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
3234 * returns otherwise.
3236 DWORD WINAPI
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE
*ppUdpTable
, BOOL bOrder
,
3237 HANDLE heap
, DWORD flags
)
3239 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable
, bOrder
, heap
, flags
);
3241 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
3242 return build_udp_table( UDP_TABLE_BASIC
, (void **)ppUdpTable
, bOrder
, heap
, flags
, NULL
);