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>
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>
36 #ifdef HAVE_SYS_SOCKETVAR_H
37 #include <sys/socketvar.h>
39 #ifdef HAVE_SYS_TIMEOUT_H
40 #include <sys/timeout.h>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #ifdef HAVE_NETINET_IN_SYSTM_H
46 #include <netinet/in_systm.h>
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
54 #ifdef HAVE_NET_IF_DL_H
55 #include <net/if_dl.h>
57 #ifdef HAVE_NET_IF_TYPES_H
58 #include <net/if_types.h>
60 #ifdef HAVE_NET_ROUTE_H
61 #include <net/route.h>
63 #ifdef HAVE_NET_IF_ARP_H
64 #include <net/if_arp.h>
66 #ifdef HAVE_NETINET_IF_ETHER_H
67 #include <netinet/if_ether.h>
69 #ifdef HAVE_NETINET_IF_INARP_H
70 #include <netinet/if_inarp.h>
72 #ifdef HAVE_NETINET_IP_H
73 #include <netinet/ip.h>
75 #ifdef HAVE_NETINET_TCP_H
76 #include <netinet/tcp.h>
78 #ifdef HAVE_NETINET_IP_VAR_H
79 #include <netinet/ip_var.h>
81 #ifdef HAVE_NETINET_TCP_FSM_H
82 #include <netinet/tcp_fsm.h>
84 #ifdef HAVE_NETINET_IN_PCB_H
85 #include <netinet/in_pcb.h>
87 #ifdef HAVE_NETINET_TCP_TIMER_H
88 #include <netinet/tcp_timer.h>
90 #ifdef HAVE_NETINET_TCP_VAR_H
91 #include <netinet/tcp_var.h>
93 #ifdef HAVE_NETINET_IP_ICMP_H
94 #include <netinet/ip_icmp.h>
96 #ifdef HAVE_NETINET_ICMP_VAR_H
97 #include <netinet/icmp_var.h>
99 #ifdef HAVE_NETINET_UDP_H
100 #include <netinet/udp.h>
102 #ifdef HAVE_NETINET_UDP_VAR_H
103 #include <netinet/udp_var.h>
105 #ifdef HAVE_SYS_PROTOSW_H
106 #include <sys/protosw.h>
108 #ifdef HAVE_SYS_SYSCTL_H
109 #include <sys/sysctl.h>
114 #ifdef HAVE_INET_MIB2_H
115 #include <inet/mib2.h>
117 #ifdef HAVE_STROPTS_H
120 #ifdef HAVE_SYS_TIHDR_H
121 #include <sys/tihdr.h>
126 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
129 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
135 #include "wine/debug.h"
137 #ifndef HAVE_NETINET_TCP_FSM_H
138 #define TCPS_ESTABLISHED 1
139 #define TCPS_SYN_SENT 2
140 #define TCPS_SYN_RECEIVED 3
141 #define TCPS_FIN_WAIT_1 4
142 #define TCPS_FIN_WAIT_2 5
143 #define TCPS_TIME_WAIT 6
144 #define TCPS_CLOSED 7
145 #define TCPS_CLOSE_WAIT 8
146 #define TCPS_LAST_ACK 9
147 #define TCPS_LISTEN 10
148 #define TCPS_CLOSING 11
151 #ifndef RTF_MULTICAST
152 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
156 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
159 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
162 static DWORD
kstat_get_ui32( kstat_t
*ksp
, const char *name
)
165 kstat_named_t
*data
= ksp
->ks_data
;
167 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
168 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui32
;
172 static ULONGLONG
kstat_get_ui64( kstat_t
*ksp
, const char *name
)
175 kstat_named_t
*data
= ksp
->ks_data
;
177 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
178 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui64
;
183 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
184 static int open_streams_mib( const char *proto
)
190 struct T_optmgmt_req req_header
;
191 struct opthdr opt_header
;
194 if ((fd
= open( "/dev/arp", O_RDWR
)) == -1)
196 WARN( "could not open /dev/arp: %s\n", strerror(errno
) );
199 if (proto
) ioctl( fd
, I_PUSH
, proto
);
201 request
.req_header
.PRIM_type
= T_SVR4_OPTMGMT_REQ
;
202 request
.req_header
.OPT_length
= sizeof(request
.opt_header
);
203 request
.req_header
.OPT_offset
= FIELD_OFFSET( struct request
, opt_header
);
204 request
.req_header
.MGMT_flags
= T_CURRENT
;
205 request
.opt_header
.level
= MIB2_IP
;
206 request
.opt_header
.name
= 0;
207 request
.opt_header
.len
= 0;
209 buf
.len
= sizeof(request
);
210 buf
.buf
= (caddr_t
)&request
;
211 if (putmsg( fd
, &buf
, NULL
, 0 ) == -1)
213 WARN( "putmsg: %s\n", strerror(errno
) );
220 static void *read_mib_entry( int fd
, int level
, int name
, int *len
)
228 struct T_optmgmt_ack ack_header
;
229 struct opthdr opt_header
;
234 buf
.maxlen
= sizeof(reply
);
235 buf
.buf
= (caddr_t
)&reply
;
236 if ((ret
= getmsg( fd
, &buf
, NULL
, &flags
)) < 0) return NULL
;
237 if (!(ret
& MOREDATA
)) return NULL
;
238 if (reply
.ack_header
.PRIM_type
!= T_OPTMGMT_ACK
) return NULL
;
239 if (buf
.len
< sizeof(reply
.ack_header
)) return NULL
;
240 if (reply
.ack_header
.OPT_length
< sizeof(reply
.opt_header
)) return NULL
;
242 if (!(data
= HeapAlloc( GetProcessHeap(), 0, reply
.opt_header
.len
))) return NULL
;
243 buf
.maxlen
= reply
.opt_header
.len
;
244 buf
.buf
= (caddr_t
)data
;
246 if (getmsg( fd
, NULL
, &buf
, &flags
) >= 0 &&
247 reply
.opt_header
.level
== level
&&
248 reply
.opt_header
.name
== name
)
253 HeapFree( GetProcessHeap(), 0, data
);
256 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
258 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
260 DWORD ret
= ERROR_NOT_SUPPORTED
;
262 if (!name
|| !entry
) return ERROR_INVALID_PARAMETER
;
268 if ((fp
= fopen("/proc/net/dev", "r")))
272 int nameLen
= strlen(name
);
274 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
276 while (*ptr
&& isspace(*ptr
)) ptr
++;
277 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
280 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u",
281 &entry
->dwInOctets
, &entry
->dwInUcastPkts
,
282 &entry
->dwInErrors
, &entry
->dwInDiscards
,
284 &entry
->dwInNUcastPkts
, &entry
->dwOutOctets
,
285 &entry
->dwOutUcastPkts
, &entry
->dwOutErrors
,
286 &entry
->dwOutDiscards
);
294 #elif defined(HAVE_LIBKSTAT)
299 if ((kc
= kstat_open()) &&
300 (ksp
= kstat_lookup( kc
, NULL
, -1, (char *)name
)) &&
301 kstat_read( kc
, ksp
, NULL
) != -1 &&
302 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
304 entry
->dwMtu
= 1500; /* FIXME */
305 entry
->dwSpeed
= min( kstat_get_ui64( ksp
, "ifspeed" ), ~0u );
306 entry
->dwInOctets
= kstat_get_ui32( ksp
, "rbytes" );
307 entry
->dwInNUcastPkts
= kstat_get_ui32( ksp
, "multircv" );
308 entry
->dwInNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstrcv" );
309 entry
->dwInUcastPkts
= kstat_get_ui32( ksp
, "ipackets" ) - entry
->dwInNUcastPkts
;
310 entry
->dwInDiscards
= kstat_get_ui32( ksp
, "norcvbuf" );
311 entry
->dwInErrors
= kstat_get_ui32( ksp
, "ierrors" );
312 entry
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "unknowns" );
313 entry
->dwOutOctets
= kstat_get_ui32( ksp
, "obytes" );
314 entry
->dwOutNUcastPkts
= kstat_get_ui32( ksp
, "multixmt" );
315 entry
->dwOutNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstxmt" );
316 entry
->dwOutUcastPkts
= kstat_get_ui32( ksp
, "opackets" ) - entry
->dwOutNUcastPkts
;
317 entry
->dwOutDiscards
= 0; /* FIXME */
318 entry
->dwOutErrors
= kstat_get_ui32( ksp
, "oerrors" );
319 entry
->dwOutQLen
= kstat_get_ui32( ksp
, "noxmtbuf" );
322 if (kc
) kstat_close( kc
);
324 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
326 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
327 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
330 char *buf
= NULL
, *end
;
331 struct if_msghdr
*ifm
;
332 struct if_data ifdata
;
334 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
336 ERR ("failed to get size of iflist\n");
339 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
342 ret
= ERROR_OUTOFMEMORY
;
345 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
347 ERR ("failed to get iflist\n");
350 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
352 ifm
= (struct if_msghdr
*) buf
;
353 if(ifm
->ifm_type
== RTM_IFINFO
)
355 ifdata
= ifm
->ifm_data
;
356 entry
->dwMtu
= ifdata
.ifi_mtu
;
357 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
358 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
359 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
360 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
361 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
362 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
363 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
364 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
365 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
371 HeapFree (GetProcessHeap (), 0, buf
);
374 FIXME( "unimplemented\n" );
380 /******************************************************************
381 * GetIcmpStatistics (IPHLPAPI.@)
383 * Get the ICMP statistics for the local computer.
386 * stats [Out] buffer for ICMP statistics
390 * Failure: error code from winerror.h
392 DWORD WINAPI
GetIcmpStatistics(PMIB_ICMP stats
)
394 DWORD ret
= ERROR_NOT_SUPPORTED
;
396 if (!stats
) return ERROR_INVALID_PARAMETER
;
397 memset( stats
, 0, sizeof(MIB_ICMP
) );
403 if ((fp
= fopen("/proc/net/snmp", "r")))
405 static const char hdr
[] = "Icmp:";
408 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
410 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
411 /* last line was a header, get another */
412 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
413 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
416 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",
417 &stats
->stats
.icmpInStats
.dwMsgs
,
418 &stats
->stats
.icmpInStats
.dwErrors
,
419 &stats
->stats
.icmpInStats
.dwDestUnreachs
,
420 &stats
->stats
.icmpInStats
.dwTimeExcds
,
421 &stats
->stats
.icmpInStats
.dwParmProbs
,
422 &stats
->stats
.icmpInStats
.dwSrcQuenchs
,
423 &stats
->stats
.icmpInStats
.dwRedirects
,
424 &stats
->stats
.icmpInStats
.dwEchoReps
,
425 &stats
->stats
.icmpInStats
.dwTimestamps
,
426 &stats
->stats
.icmpInStats
.dwTimestampReps
,
427 &stats
->stats
.icmpInStats
.dwAddrMasks
,
428 &stats
->stats
.icmpInStats
.dwAddrMaskReps
,
429 &stats
->stats
.icmpOutStats
.dwMsgs
,
430 &stats
->stats
.icmpOutStats
.dwErrors
,
431 &stats
->stats
.icmpOutStats
.dwDestUnreachs
,
432 &stats
->stats
.icmpOutStats
.dwTimeExcds
,
433 &stats
->stats
.icmpOutStats
.dwParmProbs
,
434 &stats
->stats
.icmpOutStats
.dwSrcQuenchs
,
435 &stats
->stats
.icmpOutStats
.dwRedirects
,
436 &stats
->stats
.icmpOutStats
.dwEchoReps
,
437 &stats
->stats
.icmpOutStats
.dwTimestamps
,
438 &stats
->stats
.icmpOutStats
.dwTimestampReps
,
439 &stats
->stats
.icmpOutStats
.dwAddrMasks
,
440 &stats
->stats
.icmpOutStats
.dwAddrMaskReps
);
448 #elif defined(HAVE_LIBKSTAT)
450 static char ip
[] = "ip", icmp
[] = "icmp";
454 if ((kc
= kstat_open()) &&
455 (ksp
= kstat_lookup( kc
, ip
, 0, icmp
)) &&
456 kstat_read( kc
, ksp
, NULL
) != -1 &&
457 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
459 stats
->stats
.icmpInStats
.dwMsgs
= kstat_get_ui32( ksp
, "inMsgs" );
460 stats
->stats
.icmpInStats
.dwErrors
= kstat_get_ui32( ksp
, "inErrors" );
461 stats
->stats
.icmpInStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "inDestUnreachs" );
462 stats
->stats
.icmpInStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "inTimeExcds" );
463 stats
->stats
.icmpInStats
.dwParmProbs
= kstat_get_ui32( ksp
, "inParmProbs" );
464 stats
->stats
.icmpInStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "inSrcQuenchs" );
465 stats
->stats
.icmpInStats
.dwRedirects
= kstat_get_ui32( ksp
, "inRedirects" );
466 stats
->stats
.icmpInStats
.dwEchos
= kstat_get_ui32( ksp
, "inEchos" );
467 stats
->stats
.icmpInStats
.dwEchoReps
= kstat_get_ui32( ksp
, "inEchoReps" );
468 stats
->stats
.icmpInStats
.dwTimestamps
= kstat_get_ui32( ksp
, "inTimestamps" );
469 stats
->stats
.icmpInStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "inTimestampReps" );
470 stats
->stats
.icmpInStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "inAddrMasks" );
471 stats
->stats
.icmpInStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "inAddrMaskReps" );
472 stats
->stats
.icmpOutStats
.dwMsgs
= kstat_get_ui32( ksp
, "outMsgs" );
473 stats
->stats
.icmpOutStats
.dwErrors
= kstat_get_ui32( ksp
, "outErrors" );
474 stats
->stats
.icmpOutStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "outDestUnreachs" );
475 stats
->stats
.icmpOutStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "outTimeExcds" );
476 stats
->stats
.icmpOutStats
.dwParmProbs
= kstat_get_ui32( ksp
, "outParmProbs" );
477 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "outSrcQuenchs" );
478 stats
->stats
.icmpOutStats
.dwRedirects
= kstat_get_ui32( ksp
, "outRedirects" );
479 stats
->stats
.icmpOutStats
.dwEchos
= kstat_get_ui32( ksp
, "outEchos" );
480 stats
->stats
.icmpOutStats
.dwEchoReps
= kstat_get_ui32( ksp
, "outEchoReps" );
481 stats
->stats
.icmpOutStats
.dwTimestamps
= kstat_get_ui32( ksp
, "outTimestamps" );
482 stats
->stats
.icmpOutStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "outTimestampReps" );
483 stats
->stats
.icmpOutStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "outAddrMasks" );
484 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "outAddrMaskReps" );
487 if (kc
) kstat_close( kc
);
489 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
491 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
492 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
493 struct icmpstat icmp_stat
;
494 size_t needed
= sizeof(icmp_stat
);
497 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) != -1)
500 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
501 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
502 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
504 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
506 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
507 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
508 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
509 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
510 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
511 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
512 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
513 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
514 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
515 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
516 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
518 #ifdef HAVE_ICPS_OUTHIST
520 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
521 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
522 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
524 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
526 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
527 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
528 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
529 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
530 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
531 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
532 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
533 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
534 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
535 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
536 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
537 #endif /* ICPS_OUTHIST */
541 #else /* ICMPCTL_STATS */
542 FIXME( "unimplemented\n" );
548 /******************************************************************
549 * GetIpStatistics (IPHLPAPI.@)
551 * Get the IP statistics for the local computer.
554 * stats [Out] buffer for IP statistics
558 * Failure: error code from winerror.h
560 DWORD WINAPI
GetIpStatistics(PMIB_IPSTATS stats
)
562 DWORD ret
= ERROR_NOT_SUPPORTED
;
563 MIB_IPFORWARDTABLE
*fwd_table
;
565 if (!stats
) return ERROR_INVALID_PARAMETER
;
566 memset( stats
, 0, sizeof(*stats
) );
568 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
569 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table
, FALSE
, GetProcessHeap(), 0 ))
571 stats
->dwNumRoutes
= fwd_table
->dwNumEntries
;
572 HeapFree( GetProcessHeap(), 0, fwd_table
);
579 if ((fp
= fopen("/proc/net/snmp", "r")))
581 static const char hdr
[] = "Ip:";
584 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
586 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
587 /* last line was a header, get another */
588 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
589 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
592 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
593 &stats
->dwForwarding
,
594 &stats
->dwDefaultTTL
,
595 &stats
->dwInReceives
,
596 &stats
->dwInHdrErrors
,
597 &stats
->dwInAddrErrors
,
598 &stats
->dwForwDatagrams
,
599 &stats
->dwInUnknownProtos
,
600 &stats
->dwInDiscards
,
601 &stats
->dwInDelivers
,
602 &stats
->dwOutRequests
,
603 &stats
->dwOutDiscards
,
604 &stats
->dwOutNoRoutes
,
605 &stats
->dwReasmTimeout
,
606 &stats
->dwReasmReqds
,
608 &stats
->dwReasmFails
,
611 &stats
->dwFragCreates
);
612 /* hmm, no routingDiscards */
620 #elif defined(HAVE_LIBKSTAT)
622 static char ip
[] = "ip";
626 if ((kc
= kstat_open()) &&
627 (ksp
= kstat_lookup( kc
, ip
, 0, ip
)) &&
628 kstat_read( kc
, ksp
, NULL
) != -1 &&
629 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
631 stats
->dwForwarding
= kstat_get_ui32( ksp
, "forwarding" );
632 stats
->dwDefaultTTL
= kstat_get_ui32( ksp
, "defaultTTL" );
633 stats
->dwInReceives
= kstat_get_ui32( ksp
, "inReceives" );
634 stats
->dwInHdrErrors
= kstat_get_ui32( ksp
, "inHdrErrors" );
635 stats
->dwInAddrErrors
= kstat_get_ui32( ksp
, "inAddrErrors" );
636 stats
->dwForwDatagrams
= kstat_get_ui32( ksp
, "forwDatagrams" );
637 stats
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "inUnknownProtos" );
638 stats
->dwInDiscards
= kstat_get_ui32( ksp
, "inDiscards" );
639 stats
->dwInDelivers
= kstat_get_ui32( ksp
, "inDelivers" );
640 stats
->dwOutRequests
= kstat_get_ui32( ksp
, "outRequests" );
641 stats
->dwRoutingDiscards
= kstat_get_ui32( ksp
, "routingDiscards" );
642 stats
->dwOutDiscards
= kstat_get_ui32( ksp
, "outDiscards" );
643 stats
->dwOutNoRoutes
= kstat_get_ui32( ksp
, "outNoRoutes" );
644 stats
->dwReasmTimeout
= kstat_get_ui32( ksp
, "reasmTimeout" );
645 stats
->dwReasmReqds
= kstat_get_ui32( ksp
, "reasmReqds" );
646 stats
->dwReasmOks
= kstat_get_ui32( ksp
, "reasmOKs" );
647 stats
->dwReasmFails
= kstat_get_ui32( ksp
, "reasmFails" );
648 stats
->dwFragOks
= kstat_get_ui32( ksp
, "fragOKs" );
649 stats
->dwFragFails
= kstat_get_ui32( ksp
, "fragFails" );
650 stats
->dwFragCreates
= kstat_get_ui32( ksp
, "fragCreates" );
653 if (kc
) kstat_close( kc
);
655 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
657 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
658 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
659 int ip_ttl
, ip_forwarding
;
660 struct ipstat ip_stat
;
663 needed
= sizeof(ip_stat
);
664 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
666 ERR ("failed to get ipstat\n");
667 return ERROR_NOT_SUPPORTED
;
670 needed
= sizeof(ip_ttl
);
671 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
673 ERR ("failed to get ip Default TTL\n");
674 return ERROR_NOT_SUPPORTED
;
677 needed
= sizeof(ip_forwarding
);
678 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
680 ERR ("failed to get ip forwarding\n");
681 return ERROR_NOT_SUPPORTED
;
684 stats
->dwForwarding
= ip_forwarding
;
685 stats
->dwDefaultTTL
= ip_ttl
;
686 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
687 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
688 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
689 stats
->dwInReceives
= ip_stat
.ips_total
;
690 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
691 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
692 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
693 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
694 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
695 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
696 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
697 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
698 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
699 stats
->dwOutRequests
= ip_stat
.ips_localout
;
700 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
704 FIXME( "unimplemented\n" );
710 /******************************************************************
711 * GetTcpStatistics (IPHLPAPI.@)
713 * Get the TCP statistics for the local computer.
716 * stats [Out] buffer for TCP statistics
720 * Failure: error code from winerror.h
722 DWORD WINAPI
GetTcpStatistics(PMIB_TCPSTATS stats
)
724 DWORD ret
= ERROR_NOT_SUPPORTED
;
726 if (!stats
) return ERROR_INVALID_PARAMETER
;
727 memset( stats
, 0, sizeof(*stats
) );
733 if ((fp
= fopen("/proc/net/snmp", "r")))
735 static const char hdr
[] = "Tcp:";
736 MIB_TCPTABLE
*tcp_table
;
739 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
741 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
742 /* last line was a header, get another */
743 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
744 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
747 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
748 &stats
->dwRtoAlgorithm
,
752 &stats
->dwActiveOpens
,
753 &stats
->dwPassiveOpens
,
754 &stats
->dwAttemptFails
,
755 &stats
->dwEstabResets
,
759 &stats
->dwRetransSegs
,
765 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
767 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
768 HeapFree( GetProcessHeap(), 0, tcp_table
);
774 #elif defined(HAVE_LIBKSTAT)
776 static char tcp
[] = "tcp";
780 if ((kc
= kstat_open()) &&
781 (ksp
= kstat_lookup( kc
, tcp
, 0, tcp
)) &&
782 kstat_read( kc
, ksp
, NULL
) != -1 &&
783 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
785 stats
->dwRtoAlgorithm
= kstat_get_ui32( ksp
, "rtoAlgorithm" );
786 stats
->dwRtoMin
= kstat_get_ui32( ksp
, "rtoMin" );
787 stats
->dwRtoMax
= kstat_get_ui32( ksp
, "rtoMax" );
788 stats
->dwMaxConn
= kstat_get_ui32( ksp
, "maxConn" );
789 stats
->dwActiveOpens
= kstat_get_ui32( ksp
, "activeOpens" );
790 stats
->dwPassiveOpens
= kstat_get_ui32( ksp
, "passiveOpens" );
791 stats
->dwAttemptFails
= kstat_get_ui32( ksp
, "attemptFails" );
792 stats
->dwEstabResets
= kstat_get_ui32( ksp
, "estabResets" );
793 stats
->dwCurrEstab
= kstat_get_ui32( ksp
, "currEstab" );
794 stats
->dwInSegs
= kstat_get_ui32( ksp
, "inSegs" );
795 stats
->dwOutSegs
= kstat_get_ui32( ksp
, "outSegs" );
796 stats
->dwRetransSegs
= kstat_get_ui32( ksp
, "retransSegs" );
797 stats
->dwInErrs
= kstat_get_ui32( ksp
, "inErrs" );
798 stats
->dwOutRsts
= kstat_get_ui32( ksp
, "outRsts" );
799 stats
->dwNumConns
= kstat_get_ui32( ksp
, "connTableSize" );
802 if (kc
) kstat_close( kc
);
804 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
806 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
808 #define TCPTV_REXMTMAX 128
810 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
811 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
813 struct tcpstat tcp_stat
;
814 size_t needed
= sizeof(tcp_stat
);
816 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) != -1)
818 stats
->dwRtoAlgorithm
= MIB_TCP_RTO_VANJ
;
819 stats
->dwRtoMin
= TCPTV_MIN
;
820 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
821 stats
->dwMaxConn
= -1;
822 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
823 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
824 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
825 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
826 stats
->dwCurrEstab
= 0;
827 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
828 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
829 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
830 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
831 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
832 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
835 else ERR ("failed to get tcpstat\n");
838 FIXME( "unimplemented\n" );
844 /******************************************************************
845 * GetUdpStatistics (IPHLPAPI.@)
847 * Get the UDP statistics for the local computer.
850 * stats [Out] buffer for UDP statistics
854 * Failure: error code from winerror.h
856 DWORD WINAPI
GetUdpStatistics(PMIB_UDPSTATS stats
)
858 DWORD ret
= ERROR_NOT_SUPPORTED
;
860 if (!stats
) return ERROR_INVALID_PARAMETER
;
861 memset( stats
, 0, sizeof(*stats
) );
867 if ((fp
= fopen("/proc/net/snmp", "r")))
869 static const char hdr
[] = "Udp:";
872 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
874 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
875 /* last line was a header, get another */
876 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
877 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
880 sscanf( ptr
, "%u %u %u %u %u",
881 &stats
->dwInDatagrams
, &stats
->dwNoPorts
,
882 &stats
->dwInErrors
, &stats
->dwOutDatagrams
, &stats
->dwNumAddrs
);
890 #elif defined(HAVE_LIBKSTAT)
892 static char udp
[] = "udp";
895 MIB_UDPTABLE
*udp_table
;
897 if ((kc
= kstat_open()) &&
898 (ksp
= kstat_lookup( kc
, udp
, 0, udp
)) &&
899 kstat_read( kc
, ksp
, NULL
) != -1 &&
900 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
902 stats
->dwInDatagrams
= kstat_get_ui32( ksp
, "inDatagrams" );
903 stats
->dwNoPorts
= 0; /* FIXME */
904 stats
->dwInErrors
= kstat_get_ui32( ksp
, "inErrors" );
905 stats
->dwOutDatagrams
= kstat_get_ui32( ksp
, "outDatagrams" );
906 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
908 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
909 HeapFree( GetProcessHeap(), 0, udp_table
);
913 if (kc
) kstat_close( kc
);
915 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
917 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
918 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
919 struct udpstat udp_stat
;
920 MIB_UDPTABLE
*udp_table
;
921 size_t needed
= sizeof(udp_stat
);
923 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) != -1)
925 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
926 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
927 stats
->dwNoPorts
= udp_stat
.udps_noport
;
928 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
929 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
931 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
932 HeapFree( GetProcessHeap(), 0, udp_table
);
936 else ERR ("failed to get udpstat\n");
939 FIXME( "unimplemented\n" );
945 static MIB_IPFORWARDTABLE
*append_ipforward_row( HANDLE heap
, DWORD flags
, MIB_IPFORWARDTABLE
*table
,
946 DWORD
*count
, const MIB_IPFORWARDROW
*row
)
948 if (table
->dwNumEntries
>= *count
)
950 MIB_IPFORWARDTABLE
*new_table
;
951 DWORD new_count
= table
->dwNumEntries
* 2;
953 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
954 FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[new_count
] ))))
956 HeapFree( heap
, 0, table
);
962 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
966 static int compare_ipforward_rows(const void *a
, const void *b
)
968 const MIB_IPFORWARDROW
*rowA
= a
;
969 const MIB_IPFORWARDROW
*rowB
= b
;
972 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
973 if ((ret
= rowA
->dwForwardProto
- rowB
->dwForwardProto
) != 0) return ret
;
974 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
975 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
978 /******************************************************************
979 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
981 * Get the route table.
982 * Like GetIpForwardTable(), but allocate the returned table from heap.
985 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
986 * allocated and returned.
987 * bOrder [In] whether to sort the table
988 * heap [In] heap from which the table is allocated
989 * flags [In] flags to HeapAlloc
992 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
993 * on failure, NO_ERROR on success.
995 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, BOOL bOrder
,
996 HANDLE heap
, DWORD flags
)
998 MIB_IPFORWARDTABLE
*table
;
999 MIB_IPFORWARDROW row
;
1000 DWORD ret
= NO_ERROR
, count
= 16;
1002 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable
, bOrder
, heap
, flags
);
1004 if (!ppIpForwardTable
) return ERROR_INVALID_PARAMETER
;
1006 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[count
] ))))
1007 return ERROR_OUTOFMEMORY
;
1009 table
->dwNumEntries
= 0;
1015 if ((fp
= fopen("/proc/net/route", "r")))
1017 char buf
[512], *ptr
;
1020 /* skip header line */
1021 ptr
= fgets(buf
, sizeof(buf
), fp
);
1022 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1024 memset( &row
, 0, sizeof(row
) );
1026 while (!isspace(*ptr
)) ptr
++;
1028 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
1031 row
.dwForwardDest
= strtoul(ptr
, &ptr
, 16);
1032 row
.dwForwardNextHop
= strtoul(ptr
+ 1, &ptr
, 16);
1033 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1035 if (!(flags
& RTF_UP
)) row
.dwForwardType
= MIB_IPROUTE_TYPE_INVALID
;
1036 else if (flags
& RTF_GATEWAY
) row
.dwForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1037 else row
.dwForwardType
= MIB_IPROUTE_TYPE_DIRECT
;
1039 strtoul(ptr
+ 1, &ptr
, 16); /* refcount, skip */
1040 strtoul(ptr
+ 1, &ptr
, 16); /* use, skip */
1041 row
.dwForwardMetric1
= strtoul(ptr
+ 1, &ptr
, 16);
1042 row
.dwForwardMask
= strtoul(ptr
+ 1, &ptr
, 16);
1043 /* FIXME: other protos might be appropriate, e.g. the default
1044 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1045 row
.dwForwardProto
= MIB_IPPROTO_LOCAL
;
1047 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1052 else ret
= ERROR_NOT_SUPPORTED
;
1054 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1057 int fd
, len
, namelen
;
1058 mib2_ipRouteEntry_t
*entry
;
1061 if ((fd
= open_streams_mib( NULL
)) != -1)
1063 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_ROUTE
, &len
)))
1065 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1067 row
.dwForwardDest
= entry
->ipRouteDest
;
1068 row
.dwForwardMask
= entry
->ipRouteMask
;
1069 row
.dwForwardPolicy
= 0;
1070 row
.dwForwardNextHop
= entry
->ipRouteNextHop
;
1071 row
.dwForwardType
= entry
->ipRouteType
;
1072 row
.dwForwardProto
= entry
->ipRouteProto
;
1073 row
.dwForwardAge
= entry
->ipRouteAge
;
1074 row
.dwForwardNextHopAS
= 0;
1075 row
.dwForwardMetric1
= entry
->ipRouteMetric1
;
1076 row
.dwForwardMetric2
= entry
->ipRouteMetric2
;
1077 row
.dwForwardMetric3
= entry
->ipRouteMetric3
;
1078 row
.dwForwardMetric4
= entry
->ipRouteMetric4
;
1079 row
.dwForwardMetric5
= entry
->ipRouteMetric5
;
1080 namelen
= min( sizeof(name
) - 1, entry
->ipRouteIfIndex
.o_length
);
1081 memcpy( name
, entry
->ipRouteIfIndex
.o_bytes
, namelen
);
1083 getInterfaceIndexByName( name
, &row
.dwForwardIfIndex
);
1084 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
))) break;
1086 HeapFree( GetProcessHeap(), 0, data
);
1090 else ret
= ERROR_NOT_SUPPORTED
;
1092 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1094 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1096 char *buf
= NULL
, *lim
, *next
, *addrPtr
;
1097 struct rt_msghdr
*rtm
;
1099 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1101 ERR ("sysctl 1 failed!\n");
1102 ret
= ERROR_NOT_SUPPORTED
;
1106 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1109 ret
= ERROR_OUTOFMEMORY
;
1113 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1115 ret
= ERROR_NOT_SUPPORTED
;
1120 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1124 rtm
= (struct rt_msghdr
*)next
;
1126 if (rtm
->rtm_type
!= RTM_GET
)
1128 WARN ("Got unexpected message type 0x%x!\n",
1133 /* Ignore all entries except for gateway routes which aren't
1135 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1136 (rtm
->rtm_flags
& RTF_MULTICAST
))
1139 memset( &row
, 0, sizeof(row
) );
1140 row
.dwForwardIfIndex
= rtm
->rtm_index
;
1141 row
.dwForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1142 row
.dwForwardMetric1
= rtm
->rtm_rmx
.rmx_hopcount
;
1143 row
.dwForwardProto
= MIB_IPPROTO_LOCAL
;
1145 addrPtr
= (char *)(rtm
+ 1);
1147 for (i
= 1; i
; i
<<= 1)
1149 struct sockaddr
*sa
;
1152 if (!(i
& rtm
->rtm_addrs
))
1155 sa
= (struct sockaddr
*)addrPtr
;
1156 ADVANCE (addrPtr
, sa
);
1158 /* default routes are encoded by length-zero sockaddr */
1159 if (sa
->sa_len
== 0)
1161 else if (sa
->sa_family
!= AF_INET
)
1163 WARN ("Received unsupported sockaddr family 0x%x\n",
1169 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1171 addr
= sin
->sin_addr
.s_addr
;
1176 case RTA_DST
: row
.dwForwardDest
= addr
; break;
1177 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
1178 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
1180 WARN ("Unexpected address type 0x%x\n", i
);
1184 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1188 HeapFree( GetProcessHeap (), 0, buf
);
1191 FIXME( "not implemented\n" );
1192 ret
= ERROR_NOT_SUPPORTED
;
1195 if (!table
) return ERROR_OUTOFMEMORY
;
1198 if (bOrder
&& table
->dwNumEntries
)
1199 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipforward_rows
);
1200 *ppIpForwardTable
= table
;
1202 else HeapFree( heap
, flags
, table
);
1203 TRACE( "returning ret %u table %p\n", ret
, table
);
1207 static MIB_IPNETTABLE
*append_ipnet_row( HANDLE heap
, DWORD flags
, MIB_IPNETTABLE
*table
,
1208 DWORD
*count
, const MIB_IPNETROW
*row
)
1210 if (table
->dwNumEntries
>= *count
)
1212 MIB_IPNETTABLE
*new_table
;
1213 DWORD new_count
= table
->dwNumEntries
* 2;
1215 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
1216 FIELD_OFFSET(MIB_IPNETTABLE
, table
[new_count
] ))))
1218 HeapFree( heap
, 0, table
);
1224 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1228 static int compare_ipnet_rows(const void *a
, const void *b
)
1230 const MIB_IPNETROW
*rowA
= a
;
1231 const MIB_IPNETROW
*rowB
= b
;
1233 return ntohl(rowA
->dwAddr
) - ntohl(rowB
->dwAddr
);
1237 /******************************************************************
1238 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1240 * Get the IP-to-physical address mapping table.
1241 * Like GetIpNetTable(), but allocate the returned table from heap.
1244 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1245 * allocated and returned.
1246 * bOrder [In] whether to sort the table
1247 * heap [In] heap from which the table is allocated
1248 * flags [In] flags to HeapAlloc
1251 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1252 * on failure, NO_ERROR on success.
1254 DWORD WINAPI
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE
*ppIpNetTable
, BOOL bOrder
,
1255 HANDLE heap
, DWORD flags
)
1257 MIB_IPNETTABLE
*table
;
1259 DWORD ret
= NO_ERROR
, count
= 16;
1261 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable
, bOrder
, heap
, flags
);
1263 if (!ppIpNetTable
) return ERROR_INVALID_PARAMETER
;
1265 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPNETTABLE
, table
[count
] ))))
1266 return ERROR_OUTOFMEMORY
;
1268 table
->dwNumEntries
= 0;
1274 if ((fp
= fopen("/proc/net/arp", "r")))
1276 char buf
[512], *ptr
;
1279 /* skip header line */
1280 ptr
= fgets(buf
, sizeof(buf
), fp
);
1281 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1283 memset( &row
, 0, sizeof(row
) );
1285 row
.dwAddr
= inet_addr(ptr
);
1286 while (*ptr
&& !isspace(*ptr
)) ptr
++;
1287 strtoul(ptr
+ 1, &ptr
, 16); /* hw type (skip) */
1288 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1291 if (flags
& ATF_COM
) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1295 if (flags
& ATF_PERM
) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
1298 row
.dwType
= MIB_IPNET_TYPE_OTHER
;
1300 while (*ptr
&& isspace(*ptr
)) ptr
++;
1301 while (*ptr
&& !isspace(*ptr
))
1303 row
.bPhysAddr
[row
.dwPhysAddrLen
++] = strtoul(ptr
, &ptr
, 16);
1306 while (*ptr
&& isspace(*ptr
)) ptr
++;
1307 while (*ptr
&& !isspace(*ptr
)) ptr
++; /* mask (skip) */
1308 while (*ptr
&& isspace(*ptr
)) ptr
++;
1309 getInterfaceIndexByName(ptr
, &row
.dwIndex
);
1311 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1316 else ret
= ERROR_NOT_SUPPORTED
;
1318 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1321 int fd
, len
, namelen
;
1322 mib2_ipNetToMediaEntry_t
*entry
;
1325 if ((fd
= open_streams_mib( NULL
)) != -1)
1327 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_MEDIA
, &len
)))
1329 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1331 row
.dwPhysAddrLen
= min( entry
->ipNetToMediaPhysAddress
.o_length
, MAXLEN_PHYSADDR
);
1332 memcpy( row
.bPhysAddr
, entry
->ipNetToMediaPhysAddress
.o_bytes
, row
.dwPhysAddrLen
);
1333 row
.dwAddr
= entry
->ipNetToMediaNetAddress
;
1334 row
.dwType
= entry
->ipNetToMediaType
;
1335 namelen
= min( sizeof(name
) - 1, entry
->ipNetToMediaIfIndex
.o_length
);
1336 memcpy( name
, entry
->ipNetToMediaIfIndex
.o_bytes
, namelen
);
1338 getInterfaceIndexByName( name
, &row
.dwIndex
);
1339 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
))) break;
1341 HeapFree( GetProcessHeap(), 0, data
);
1345 else ret
= ERROR_NOT_SUPPORTED
;
1347 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1349 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1350 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1352 char *buf
= NULL
, *lim
, *next
;
1353 struct rt_msghdr
*rtm
;
1354 struct sockaddr_inarp
*sinarp
;
1355 struct sockaddr_dl
*sdl
;
1357 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1359 ERR ("failed to get arp table\n");
1360 ret
= ERROR_NOT_SUPPORTED
;
1364 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1367 ret
= ERROR_OUTOFMEMORY
;
1371 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1373 ret
= ERROR_NOT_SUPPORTED
;
1381 rtm
= (struct rt_msghdr
*)next
;
1382 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1383 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1384 if(sdl
->sdl_alen
) /* arp entry */
1386 memset( &row
, 0, sizeof(row
) );
1387 row
.dwAddr
= sinarp
->sin_addr
.s_addr
;
1388 row
.dwIndex
= sdl
->sdl_index
;
1389 row
.dwPhysAddrLen
= min( 8, sdl
->sdl_alen
);
1390 memcpy( row
.bPhysAddr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], row
.dwPhysAddrLen
);
1391 if(rtm
->rtm_rmx
.rmx_expire
== 0) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
1392 else if(sinarp
->sin_other
& SIN_PROXY
) row
.dwType
= MIB_IPNET_TYPE_OTHER
;
1393 else if(rtm
->rtm_rmx
.rmx_expire
!= 0) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1394 else row
.dwType
= MIB_IPNET_TYPE_INVALID
;
1396 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1399 next
+= rtm
->rtm_msglen
;
1402 HeapFree( GetProcessHeap (), 0, buf
);
1405 FIXME( "not implemented\n" );
1406 ret
= ERROR_NOT_SUPPORTED
;
1409 if (!table
) return ERROR_OUTOFMEMORY
;
1412 if (bOrder
&& table
->dwNumEntries
)
1413 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipnet_rows
);
1414 *ppIpNetTable
= table
;
1416 else HeapFree( heap
, flags
, table
);
1417 TRACE( "returning ret %u table %p\n", ret
, table
);
1422 static MIB_UDPTABLE
*append_udp_row( HANDLE heap
, DWORD flags
, MIB_UDPTABLE
*table
,
1423 DWORD
*count
, const MIB_UDPROW
*row
)
1425 if (table
->dwNumEntries
>= *count
)
1427 MIB_UDPTABLE
*new_table
;
1428 DWORD new_count
= table
->dwNumEntries
* 2;
1430 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_UDPTABLE
, table
[new_count
] ))))
1432 HeapFree( heap
, 0, table
);
1438 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1442 static int compare_udp_rows(const void *a
, const void *b
)
1444 const MIB_UDPROW
*rowA
= a
;
1445 const MIB_UDPROW
*rowB
= b
;
1448 if ((ret
= rowA
->dwLocalAddr
- rowB
->dwLocalAddr
) != 0) return ret
;
1449 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
1453 /******************************************************************
1454 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1456 * Get the UDP listener table.
1457 * Like GetUdpTable(), but allocate the returned table from heap.
1460 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1461 * allocated and returned.
1462 * bOrder [In] whether to sort the table
1463 * heap [In] heap from which the table is allocated
1464 * flags [In] flags to HeapAlloc
1467 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1468 * returns otherwise.
1470 DWORD WINAPI
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE
*ppUdpTable
, BOOL bOrder
,
1471 HANDLE heap
, DWORD flags
)
1473 MIB_UDPTABLE
*table
;
1475 DWORD ret
= NO_ERROR
, count
= 16;
1477 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable
, bOrder
, heap
, flags
);
1479 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
1481 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_UDPTABLE
, table
[count
] ))))
1482 return ERROR_OUTOFMEMORY
;
1484 table
->dwNumEntries
= 0;
1490 if ((fp
= fopen("/proc/net/udp", "r")))
1492 char buf
[512], *ptr
;
1495 /* skip header line */
1496 ptr
= fgets(buf
, sizeof(buf
), fp
);
1497 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1499 if (sscanf( ptr
, "%u: %x:%x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
) != 3)
1501 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1502 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
)))
1507 else ret
= ERROR_NOT_SUPPORTED
;
1509 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1513 mib2_udpEntry_t
*entry
;
1515 if ((fd
= open_streams_mib( "udp" )) != -1)
1517 if ((data
= read_mib_entry( fd
, MIB2_UDP
, MIB2_UDP_ENTRY
, &len
)))
1519 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1521 row
.dwLocalAddr
= entry
->udpLocalAddress
;
1522 row
.dwLocalPort
= htons( entry
->udpLocalPort
);
1523 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
))) break;
1525 HeapFree( GetProcessHeap(), 0, data
);
1529 else ret
= ERROR_NOT_SUPPORTED
;
1531 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1535 struct xinpgen
*pXIG
, *pOrigXIG
;
1537 if (sysctlbyname ("net.inet.udp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1539 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1540 ret
= ERROR_NOT_SUPPORTED
;
1544 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1547 ret
= ERROR_OUTOFMEMORY
;
1551 if (sysctlbyname ("net.inet.udp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1553 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1554 ret
= ERROR_NOT_SUPPORTED
;
1558 /* Might be nothing here; first entry is just a header it seems */
1559 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1561 pOrigXIG
= (struct xinpgen
*)Buf
;
1564 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1565 pXIG
->xig_len
> sizeof (struct xinpgen
);
1566 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1568 struct inpcb
*pINData
;
1569 struct xsocket
*pSockData
;
1571 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
1572 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
1574 /* Ignore sockets for other protocols */
1575 if (pSockData
->xso_protocol
!= IPPROTO_UDP
)
1578 /* Ignore PCBs that were freed while generating the data */
1579 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1582 /* we're only interested in IPv4 addresses */
1583 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1584 (pINData
->inp_vflag
& INP_IPV6
))
1587 /* If all 0's, skip it */
1588 if (!pINData
->inp_laddr
.s_addr
&&
1589 !pINData
->inp_lport
)
1592 /* Fill in structure details */
1593 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1594 row
.dwLocalPort
= pINData
->inp_lport
;
1595 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
))) break;
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_udp_rows
);
1611 *ppUdpTable
= table
;
1613 else HeapFree( heap
, flags
, table
);
1614 TRACE( "returning ret %u table %p\n", ret
, table
);
1619 static MIB_TCPTABLE
*append_tcp_row( HANDLE heap
, DWORD flags
, MIB_TCPTABLE
*table
,
1620 DWORD
*count
, const MIB_TCPROW
*row
)
1622 if (table
->dwNumEntries
>= *count
)
1624 MIB_TCPTABLE
*new_table
;
1625 DWORD new_count
= table
->dwNumEntries
* 2;
1627 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_TCPTABLE
, table
[new_count
] ))))
1629 HeapFree( heap
, 0, table
);
1635 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1640 /* Why not a lookup table? Because the TCPS_* constants are different
1641 on different platforms */
1642 static inline DWORD
TCPStateToMIBState (int state
)
1646 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1647 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1648 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1649 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1650 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1651 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1652 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1653 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1654 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1655 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1657 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1662 static int compare_tcp_rows(const void *a
, const void *b
)
1664 const MIB_TCPROW
*rowA
= a
;
1665 const MIB_TCPROW
*rowB
= b
;
1668 if ((ret
= ntohl (rowA
->dwLocalAddr
) - ntohl (rowB
->dwLocalAddr
)) != 0) return ret
;
1669 if ((ret
= ntohs ((unsigned short)rowA
->dwLocalPort
) -
1670 ntohs ((unsigned short)rowB
->dwLocalPort
)) != 0) return ret
;
1671 if ((ret
= ntohl (rowA
->dwRemoteAddr
) - ntohl (rowB
->dwRemoteAddr
)) != 0) return ret
;
1672 return ntohs ((unsigned short)rowA
->dwRemotePort
) - ntohs ((unsigned short)rowB
->dwRemotePort
);
1676 /******************************************************************
1677 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1679 * Get the TCP connection table.
1680 * Like GetTcpTable(), but allocate the returned table from heap.
1683 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1684 * allocated and returned.
1685 * bOrder [In] whether to sort the table
1686 * heap [In] heap from which the table is allocated
1687 * flags [In] flags to HeapAlloc
1690 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1691 * returns otherwise.
1693 DWORD WINAPI
AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE
*ppTcpTable
, BOOL bOrder
,
1694 HANDLE heap
, DWORD flags
)
1696 MIB_TCPTABLE
*table
;
1698 DWORD ret
= NO_ERROR
, count
= 16;
1700 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable
, bOrder
, heap
, flags
);
1702 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
1704 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_TCPTABLE
, table
[count
] ))))
1705 return ERROR_OUTOFMEMORY
;
1707 table
->dwNumEntries
= 0;
1713 if ((fp
= fopen("/proc/net/tcp", "r")))
1715 char buf
[512], *ptr
;
1718 /* skip header line */
1719 ptr
= fgets(buf
, sizeof(buf
), fp
);
1720 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1722 if (sscanf( ptr
, "%x: %x:%x %x:%x %x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
,
1723 &row
.dwRemoteAddr
, &row
.dwRemotePort
, &row
.dwState
) != 6)
1725 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1726 row
.dwRemotePort
= htons( row
.dwRemotePort
);
1727 row
.dwState
= TCPStateToMIBState( row
.dwState
);
1728 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
)))
1733 else ret
= ERROR_NOT_SUPPORTED
;
1735 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1739 mib2_tcpConnEntry_t
*entry
;
1741 if ((fd
= open_streams_mib( "tcp" )) != -1)
1743 if ((data
= read_mib_entry( fd
, MIB2_TCP
, MIB2_TCP_CONN
, &len
)))
1745 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1747 row
.dwLocalAddr
= entry
->tcpConnLocalAddress
;
1748 row
.dwLocalPort
= htons( entry
->tcpConnLocalPort
);
1749 row
.dwRemoteAddr
= entry
->tcpConnRemAddress
;
1750 row
.dwRemotePort
= htons( entry
->tcpConnRemPort
);
1751 row
.dwState
= entry
->tcpConnState
;
1752 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1754 HeapFree( GetProcessHeap(), 0, data
);
1758 else ret
= ERROR_NOT_SUPPORTED
;
1760 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1764 struct xinpgen
*pXIG
, *pOrigXIG
;
1766 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1768 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1769 ret
= ERROR_NOT_SUPPORTED
;
1773 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1776 ret
= ERROR_OUTOFMEMORY
;
1780 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1782 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1783 ret
= ERROR_NOT_SUPPORTED
;
1787 /* Might be nothing here; first entry is just a header it seems */
1788 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1790 pOrigXIG
= (struct xinpgen
*)Buf
;
1793 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1794 pXIG
->xig_len
> sizeof (struct xinpgen
);
1795 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1797 struct tcpcb
*pTCPData
= NULL
;
1798 struct inpcb
*pINData
;
1799 struct xsocket
*pSockData
;
1801 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1802 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1803 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1805 /* Ignore sockets for other protocols */
1806 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1809 /* Ignore PCBs that were freed while generating the data */
1810 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1813 /* we're only interested in IPv4 addresses */
1814 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1815 (pINData
->inp_vflag
& INP_IPV6
))
1818 /* If all 0's, skip it */
1819 if (!pINData
->inp_laddr
.s_addr
&&
1820 !pINData
->inp_lport
&&
1821 !pINData
->inp_faddr
.s_addr
&&
1822 !pINData
->inp_fport
)
1825 /* Fill in structure details */
1826 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1827 row
.dwLocalPort
= pINData
->inp_lport
;
1828 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
1829 row
.dwRemotePort
= pINData
->inp_fport
;
1830 row
.dwState
= TCPStateToMIBState (pTCPData
->t_state
);
1831 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1835 HeapFree (GetProcessHeap (), 0, Buf
);
1838 FIXME( "not implemented\n" );
1839 ret
= ERROR_NOT_SUPPORTED
;
1842 if (!table
) return ERROR_OUTOFMEMORY
;
1845 if (bOrder
&& table
->dwNumEntries
)
1846 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_tcp_rows
);
1847 *ppTcpTable
= table
;
1849 else HeapFree( heap
, flags
, table
);
1850 TRACE( "returning ret %u table %p\n", ret
, table
);