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))
132 #define NONAMELESSUNION
136 #include "wine/debug.h"
138 #ifndef HAVE_NETINET_TCP_FSM_H
139 #define TCPS_ESTABLISHED 1
140 #define TCPS_SYN_SENT 2
141 #define TCPS_SYN_RECEIVED 3
142 #define TCPS_FIN_WAIT_1 4
143 #define TCPS_FIN_WAIT_2 5
144 #define TCPS_TIME_WAIT 6
145 #define TCPS_CLOSED 7
146 #define TCPS_CLOSE_WAIT 8
147 #define TCPS_LAST_ACK 9
148 #define TCPS_LISTEN 10
149 #define TCPS_CLOSING 11
152 #ifndef RTF_MULTICAST
153 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
157 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
160 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
163 static DWORD
kstat_get_ui32( kstat_t
*ksp
, const char *name
)
166 kstat_named_t
*data
= ksp
->ks_data
;
168 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
169 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui32
;
173 static ULONGLONG
kstat_get_ui64( kstat_t
*ksp
, const char *name
)
176 kstat_named_t
*data
= ksp
->ks_data
;
178 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
179 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui64
;
184 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
185 static int open_streams_mib( const char *proto
)
191 struct T_optmgmt_req req_header
;
192 struct opthdr opt_header
;
195 if ((fd
= open( "/dev/arp", O_RDWR
)) == -1)
197 WARN( "could not open /dev/arp: %s\n", strerror(errno
) );
200 if (proto
) ioctl( fd
, I_PUSH
, proto
);
202 request
.req_header
.PRIM_type
= T_SVR4_OPTMGMT_REQ
;
203 request
.req_header
.OPT_length
= sizeof(request
.opt_header
);
204 request
.req_header
.OPT_offset
= FIELD_OFFSET( struct request
, opt_header
);
205 request
.req_header
.MGMT_flags
= T_CURRENT
;
206 request
.opt_header
.level
= MIB2_IP
;
207 request
.opt_header
.name
= 0;
208 request
.opt_header
.len
= 0;
210 buf
.len
= sizeof(request
);
211 buf
.buf
= (caddr_t
)&request
;
212 if (putmsg( fd
, &buf
, NULL
, 0 ) == -1)
214 WARN( "putmsg: %s\n", strerror(errno
) );
221 static void *read_mib_entry( int fd
, int level
, int name
, int *len
)
229 struct T_optmgmt_ack ack_header
;
230 struct opthdr opt_header
;
235 buf
.maxlen
= sizeof(reply
);
236 buf
.buf
= (caddr_t
)&reply
;
237 if ((ret
= getmsg( fd
, &buf
, NULL
, &flags
)) < 0) return NULL
;
238 if (!(ret
& MOREDATA
)) return NULL
;
239 if (reply
.ack_header
.PRIM_type
!= T_OPTMGMT_ACK
) return NULL
;
240 if (buf
.len
< sizeof(reply
.ack_header
)) return NULL
;
241 if (reply
.ack_header
.OPT_length
< sizeof(reply
.opt_header
)) return NULL
;
243 if (!(data
= HeapAlloc( GetProcessHeap(), 0, reply
.opt_header
.len
))) return NULL
;
244 buf
.maxlen
= reply
.opt_header
.len
;
245 buf
.buf
= (caddr_t
)data
;
247 if (getmsg( fd
, NULL
, &buf
, &flags
) >= 0 &&
248 reply
.opt_header
.level
== level
&&
249 reply
.opt_header
.name
== name
)
254 HeapFree( GetProcessHeap(), 0, data
);
257 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
259 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
261 DWORD ret
= ERROR_NOT_SUPPORTED
;
263 if (!name
|| !entry
) return ERROR_INVALID_PARAMETER
;
269 if ((fp
= fopen("/proc/net/dev", "r")))
273 int nameLen
= strlen(name
);
275 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
277 while (*ptr
&& isspace(*ptr
)) ptr
++;
278 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
281 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u",
282 &entry
->dwInOctets
, &entry
->dwInUcastPkts
,
283 &entry
->dwInErrors
, &entry
->dwInDiscards
,
285 &entry
->dwInNUcastPkts
, &entry
->dwOutOctets
,
286 &entry
->dwOutUcastPkts
, &entry
->dwOutErrors
,
287 &entry
->dwOutDiscards
);
295 #elif defined(HAVE_LIBKSTAT)
300 if ((kc
= kstat_open()) &&
301 (ksp
= kstat_lookup( kc
, NULL
, -1, (char *)name
)) &&
302 kstat_read( kc
, ksp
, NULL
) != -1 &&
303 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
305 entry
->dwMtu
= 1500; /* FIXME */
306 entry
->dwSpeed
= min( kstat_get_ui64( ksp
, "ifspeed" ), ~0u );
307 entry
->dwInOctets
= kstat_get_ui32( ksp
, "rbytes" );
308 entry
->dwInNUcastPkts
= kstat_get_ui32( ksp
, "multircv" );
309 entry
->dwInNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstrcv" );
310 entry
->dwInUcastPkts
= kstat_get_ui32( ksp
, "ipackets" ) - entry
->dwInNUcastPkts
;
311 entry
->dwInDiscards
= kstat_get_ui32( ksp
, "norcvbuf" );
312 entry
->dwInErrors
= kstat_get_ui32( ksp
, "ierrors" );
313 entry
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "unknowns" );
314 entry
->dwOutOctets
= kstat_get_ui32( ksp
, "obytes" );
315 entry
->dwOutNUcastPkts
= kstat_get_ui32( ksp
, "multixmt" );
316 entry
->dwOutNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstxmt" );
317 entry
->dwOutUcastPkts
= kstat_get_ui32( ksp
, "opackets" ) - entry
->dwOutNUcastPkts
;
318 entry
->dwOutDiscards
= 0; /* FIXME */
319 entry
->dwOutErrors
= kstat_get_ui32( ksp
, "oerrors" );
320 entry
->dwOutQLen
= kstat_get_ui32( ksp
, "noxmtbuf" );
323 if (kc
) kstat_close( kc
);
325 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
327 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
328 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
331 char *buf
= NULL
, *end
;
332 struct if_msghdr
*ifm
;
333 struct if_data ifdata
;
335 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
337 ERR ("failed to get size of iflist\n");
340 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
343 ret
= ERROR_OUTOFMEMORY
;
346 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
348 ERR ("failed to get iflist\n");
351 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
353 ifm
= (struct if_msghdr
*) buf
;
354 if(ifm
->ifm_type
== RTM_IFINFO
)
356 ifdata
= ifm
->ifm_data
;
357 entry
->dwMtu
= ifdata
.ifi_mtu
;
358 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
359 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
360 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
361 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
362 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
363 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
364 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
365 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
366 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
372 HeapFree (GetProcessHeap (), 0, buf
);
375 FIXME( "unimplemented\n" );
381 /******************************************************************
382 * GetIcmpStatistics (IPHLPAPI.@)
384 * Get the ICMP statistics for the local computer.
387 * stats [Out] buffer for ICMP statistics
391 * Failure: error code from winerror.h
393 DWORD WINAPI
GetIcmpStatistics(PMIB_ICMP stats
)
395 DWORD ret
= ERROR_NOT_SUPPORTED
;
397 if (!stats
) return ERROR_INVALID_PARAMETER
;
398 memset( stats
, 0, sizeof(MIB_ICMP
) );
404 if ((fp
= fopen("/proc/net/snmp", "r")))
406 static const char hdr
[] = "Icmp:";
409 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
411 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
412 /* last line was a header, get another */
413 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
414 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
417 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",
418 &stats
->stats
.icmpInStats
.dwMsgs
,
419 &stats
->stats
.icmpInStats
.dwErrors
,
420 &stats
->stats
.icmpInStats
.dwDestUnreachs
,
421 &stats
->stats
.icmpInStats
.dwTimeExcds
,
422 &stats
->stats
.icmpInStats
.dwParmProbs
,
423 &stats
->stats
.icmpInStats
.dwSrcQuenchs
,
424 &stats
->stats
.icmpInStats
.dwRedirects
,
425 &stats
->stats
.icmpInStats
.dwEchoReps
,
426 &stats
->stats
.icmpInStats
.dwTimestamps
,
427 &stats
->stats
.icmpInStats
.dwTimestampReps
,
428 &stats
->stats
.icmpInStats
.dwAddrMasks
,
429 &stats
->stats
.icmpInStats
.dwAddrMaskReps
,
430 &stats
->stats
.icmpOutStats
.dwMsgs
,
431 &stats
->stats
.icmpOutStats
.dwErrors
,
432 &stats
->stats
.icmpOutStats
.dwDestUnreachs
,
433 &stats
->stats
.icmpOutStats
.dwTimeExcds
,
434 &stats
->stats
.icmpOutStats
.dwParmProbs
,
435 &stats
->stats
.icmpOutStats
.dwSrcQuenchs
,
436 &stats
->stats
.icmpOutStats
.dwRedirects
,
437 &stats
->stats
.icmpOutStats
.dwEchoReps
,
438 &stats
->stats
.icmpOutStats
.dwTimestamps
,
439 &stats
->stats
.icmpOutStats
.dwTimestampReps
,
440 &stats
->stats
.icmpOutStats
.dwAddrMasks
,
441 &stats
->stats
.icmpOutStats
.dwAddrMaskReps
);
449 #elif defined(HAVE_LIBKSTAT)
451 static char ip
[] = "ip", icmp
[] = "icmp";
455 if ((kc
= kstat_open()) &&
456 (ksp
= kstat_lookup( kc
, ip
, 0, icmp
)) &&
457 kstat_read( kc
, ksp
, NULL
) != -1 &&
458 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
460 stats
->stats
.icmpInStats
.dwMsgs
= kstat_get_ui32( ksp
, "inMsgs" );
461 stats
->stats
.icmpInStats
.dwErrors
= kstat_get_ui32( ksp
, "inErrors" );
462 stats
->stats
.icmpInStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "inDestUnreachs" );
463 stats
->stats
.icmpInStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "inTimeExcds" );
464 stats
->stats
.icmpInStats
.dwParmProbs
= kstat_get_ui32( ksp
, "inParmProbs" );
465 stats
->stats
.icmpInStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "inSrcQuenchs" );
466 stats
->stats
.icmpInStats
.dwRedirects
= kstat_get_ui32( ksp
, "inRedirects" );
467 stats
->stats
.icmpInStats
.dwEchos
= kstat_get_ui32( ksp
, "inEchos" );
468 stats
->stats
.icmpInStats
.dwEchoReps
= kstat_get_ui32( ksp
, "inEchoReps" );
469 stats
->stats
.icmpInStats
.dwTimestamps
= kstat_get_ui32( ksp
, "inTimestamps" );
470 stats
->stats
.icmpInStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "inTimestampReps" );
471 stats
->stats
.icmpInStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "inAddrMasks" );
472 stats
->stats
.icmpInStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "inAddrMaskReps" );
473 stats
->stats
.icmpOutStats
.dwMsgs
= kstat_get_ui32( ksp
, "outMsgs" );
474 stats
->stats
.icmpOutStats
.dwErrors
= kstat_get_ui32( ksp
, "outErrors" );
475 stats
->stats
.icmpOutStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "outDestUnreachs" );
476 stats
->stats
.icmpOutStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "outTimeExcds" );
477 stats
->stats
.icmpOutStats
.dwParmProbs
= kstat_get_ui32( ksp
, "outParmProbs" );
478 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "outSrcQuenchs" );
479 stats
->stats
.icmpOutStats
.dwRedirects
= kstat_get_ui32( ksp
, "outRedirects" );
480 stats
->stats
.icmpOutStats
.dwEchos
= kstat_get_ui32( ksp
, "outEchos" );
481 stats
->stats
.icmpOutStats
.dwEchoReps
= kstat_get_ui32( ksp
, "outEchoReps" );
482 stats
->stats
.icmpOutStats
.dwTimestamps
= kstat_get_ui32( ksp
, "outTimestamps" );
483 stats
->stats
.icmpOutStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "outTimestampReps" );
484 stats
->stats
.icmpOutStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "outAddrMasks" );
485 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "outAddrMaskReps" );
488 if (kc
) kstat_close( kc
);
490 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
492 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
493 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
494 struct icmpstat icmp_stat
;
495 size_t needed
= sizeof(icmp_stat
);
498 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) != -1)
501 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
502 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
503 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
505 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
507 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
508 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
509 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
510 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
511 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
512 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
513 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
514 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
515 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
516 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
517 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
519 #ifdef HAVE_ICPS_OUTHIST
521 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
522 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
523 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
525 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
527 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
528 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
529 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
530 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
531 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
532 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
533 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
534 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
535 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
536 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
537 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
538 #endif /* ICPS_OUTHIST */
542 #else /* ICMPCTL_STATS */
543 FIXME( "unimplemented\n" );
549 /******************************************************************
550 * GetIpStatistics (IPHLPAPI.@)
552 * Get the IP statistics for the local computer.
555 * stats [Out] buffer for IP statistics
559 * Failure: error code from winerror.h
561 DWORD WINAPI
GetIpStatistics(PMIB_IPSTATS stats
)
563 DWORD ret
= ERROR_NOT_SUPPORTED
;
564 MIB_IPFORWARDTABLE
*fwd_table
;
566 if (!stats
) return ERROR_INVALID_PARAMETER
;
567 memset( stats
, 0, sizeof(*stats
) );
569 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
570 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table
, FALSE
, GetProcessHeap(), 0 ))
572 stats
->dwNumRoutes
= fwd_table
->dwNumEntries
;
573 HeapFree( GetProcessHeap(), 0, fwd_table
);
580 if ((fp
= fopen("/proc/net/snmp", "r")))
582 static const char hdr
[] = "Ip:";
585 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
587 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
588 /* last line was a header, get another */
589 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
590 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
593 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
594 &stats
->u
.dwForwarding
,
595 &stats
->dwDefaultTTL
,
596 &stats
->dwInReceives
,
597 &stats
->dwInHdrErrors
,
598 &stats
->dwInAddrErrors
,
599 &stats
->dwForwDatagrams
,
600 &stats
->dwInUnknownProtos
,
601 &stats
->dwInDiscards
,
602 &stats
->dwInDelivers
,
603 &stats
->dwOutRequests
,
604 &stats
->dwOutDiscards
,
605 &stats
->dwOutNoRoutes
,
606 &stats
->dwReasmTimeout
,
607 &stats
->dwReasmReqds
,
609 &stats
->dwReasmFails
,
612 &stats
->dwFragCreates
);
613 /* hmm, no routingDiscards */
621 #elif defined(HAVE_LIBKSTAT)
623 static char ip
[] = "ip";
627 if ((kc
= kstat_open()) &&
628 (ksp
= kstat_lookup( kc
, ip
, 0, ip
)) &&
629 kstat_read( kc
, ksp
, NULL
) != -1 &&
630 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
632 stats
->u
.dwForwarding
= kstat_get_ui32( ksp
, "forwarding" );
633 stats
->dwDefaultTTL
= kstat_get_ui32( ksp
, "defaultTTL" );
634 stats
->dwInReceives
= kstat_get_ui32( ksp
, "inReceives" );
635 stats
->dwInHdrErrors
= kstat_get_ui32( ksp
, "inHdrErrors" );
636 stats
->dwInAddrErrors
= kstat_get_ui32( ksp
, "inAddrErrors" );
637 stats
->dwForwDatagrams
= kstat_get_ui32( ksp
, "forwDatagrams" );
638 stats
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "inUnknownProtos" );
639 stats
->dwInDiscards
= kstat_get_ui32( ksp
, "inDiscards" );
640 stats
->dwInDelivers
= kstat_get_ui32( ksp
, "inDelivers" );
641 stats
->dwOutRequests
= kstat_get_ui32( ksp
, "outRequests" );
642 stats
->dwRoutingDiscards
= kstat_get_ui32( ksp
, "routingDiscards" );
643 stats
->dwOutDiscards
= kstat_get_ui32( ksp
, "outDiscards" );
644 stats
->dwOutNoRoutes
= kstat_get_ui32( ksp
, "outNoRoutes" );
645 stats
->dwReasmTimeout
= kstat_get_ui32( ksp
, "reasmTimeout" );
646 stats
->dwReasmReqds
= kstat_get_ui32( ksp
, "reasmReqds" );
647 stats
->dwReasmOks
= kstat_get_ui32( ksp
, "reasmOKs" );
648 stats
->dwReasmFails
= kstat_get_ui32( ksp
, "reasmFails" );
649 stats
->dwFragOks
= kstat_get_ui32( ksp
, "fragOKs" );
650 stats
->dwFragFails
= kstat_get_ui32( ksp
, "fragFails" );
651 stats
->dwFragCreates
= kstat_get_ui32( ksp
, "fragCreates" );
654 if (kc
) kstat_close( kc
);
656 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
658 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
659 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
660 int ip_ttl
, ip_forwarding
;
661 struct ipstat ip_stat
;
664 needed
= sizeof(ip_stat
);
665 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
667 ERR ("failed to get ipstat\n");
668 return ERROR_NOT_SUPPORTED
;
671 needed
= sizeof(ip_ttl
);
672 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
674 ERR ("failed to get ip Default TTL\n");
675 return ERROR_NOT_SUPPORTED
;
678 needed
= sizeof(ip_forwarding
);
679 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
681 ERR ("failed to get ip forwarding\n");
682 return ERROR_NOT_SUPPORTED
;
685 stats
->u
.dwForwarding
= ip_forwarding
;
686 stats
->dwDefaultTTL
= ip_ttl
;
687 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
688 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
689 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
690 stats
->dwInReceives
= ip_stat
.ips_total
;
691 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
692 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
693 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
694 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
695 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
696 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
697 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
698 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
699 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
700 stats
->dwOutRequests
= ip_stat
.ips_localout
;
701 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
705 FIXME( "unimplemented\n" );
711 /******************************************************************
712 * GetTcpStatistics (IPHLPAPI.@)
714 * Get the TCP statistics for the local computer.
717 * stats [Out] buffer for TCP statistics
721 * Failure: error code from winerror.h
723 DWORD WINAPI
GetTcpStatistics(PMIB_TCPSTATS stats
)
725 DWORD ret
= ERROR_NOT_SUPPORTED
;
727 if (!stats
) return ERROR_INVALID_PARAMETER
;
728 memset( stats
, 0, sizeof(*stats
) );
734 if ((fp
= fopen("/proc/net/snmp", "r")))
736 static const char hdr
[] = "Tcp:";
737 MIB_TCPTABLE
*tcp_table
;
740 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
742 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
743 /* last line was a header, get another */
744 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
745 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
748 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
749 &stats
->u
.dwRtoAlgorithm
,
753 &stats
->dwActiveOpens
,
754 &stats
->dwPassiveOpens
,
755 &stats
->dwAttemptFails
,
756 &stats
->dwEstabResets
,
760 &stats
->dwRetransSegs
,
766 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
768 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
769 HeapFree( GetProcessHeap(), 0, tcp_table
);
775 #elif defined(HAVE_LIBKSTAT)
777 static char tcp
[] = "tcp";
781 if ((kc
= kstat_open()) &&
782 (ksp
= kstat_lookup( kc
, tcp
, 0, tcp
)) &&
783 kstat_read( kc
, ksp
, NULL
) != -1 &&
784 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
786 stats
->u
.dwRtoAlgorithm
= kstat_get_ui32( ksp
, "rtoAlgorithm" );
787 stats
->dwRtoMin
= kstat_get_ui32( ksp
, "rtoMin" );
788 stats
->dwRtoMax
= kstat_get_ui32( ksp
, "rtoMax" );
789 stats
->dwMaxConn
= kstat_get_ui32( ksp
, "maxConn" );
790 stats
->dwActiveOpens
= kstat_get_ui32( ksp
, "activeOpens" );
791 stats
->dwPassiveOpens
= kstat_get_ui32( ksp
, "passiveOpens" );
792 stats
->dwAttemptFails
= kstat_get_ui32( ksp
, "attemptFails" );
793 stats
->dwEstabResets
= kstat_get_ui32( ksp
, "estabResets" );
794 stats
->dwCurrEstab
= kstat_get_ui32( ksp
, "currEstab" );
795 stats
->dwInSegs
= kstat_get_ui32( ksp
, "inSegs" );
796 stats
->dwOutSegs
= kstat_get_ui32( ksp
, "outSegs" );
797 stats
->dwRetransSegs
= kstat_get_ui32( ksp
, "retransSegs" );
798 stats
->dwInErrs
= kstat_get_ui32( ksp
, "inErrs" );
799 stats
->dwOutRsts
= kstat_get_ui32( ksp
, "outRsts" );
800 stats
->dwNumConns
= kstat_get_ui32( ksp
, "connTableSize" );
803 if (kc
) kstat_close( kc
);
805 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
807 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
809 #define TCPTV_REXMTMAX 128
811 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
812 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
814 struct tcpstat tcp_stat
;
815 size_t needed
= sizeof(tcp_stat
);
817 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) != -1)
819 stats
->u
.RtoAlgorithm
= MIB_TCP_RTO_VANJ
;
820 stats
->dwRtoMin
= TCPTV_MIN
;
821 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
822 stats
->dwMaxConn
= -1;
823 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
824 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
825 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
826 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
827 stats
->dwCurrEstab
= 0;
828 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
829 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
830 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
831 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
832 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
833 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
836 else ERR ("failed to get tcpstat\n");
839 FIXME( "unimplemented\n" );
845 /******************************************************************
846 * GetUdpStatistics (IPHLPAPI.@)
848 * Get the UDP statistics for the local computer.
851 * stats [Out] buffer for UDP statistics
855 * Failure: error code from winerror.h
857 DWORD WINAPI
GetUdpStatistics(PMIB_UDPSTATS stats
)
859 DWORD ret
= ERROR_NOT_SUPPORTED
;
861 if (!stats
) return ERROR_INVALID_PARAMETER
;
862 memset( stats
, 0, sizeof(*stats
) );
868 if ((fp
= fopen("/proc/net/snmp", "r")))
870 static const char hdr
[] = "Udp:";
873 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
875 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
876 /* last line was a header, get another */
877 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
878 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
881 sscanf( ptr
, "%u %u %u %u %u",
882 &stats
->dwInDatagrams
, &stats
->dwNoPorts
,
883 &stats
->dwInErrors
, &stats
->dwOutDatagrams
, &stats
->dwNumAddrs
);
891 #elif defined(HAVE_LIBKSTAT)
893 static char udp
[] = "udp";
896 MIB_UDPTABLE
*udp_table
;
898 if ((kc
= kstat_open()) &&
899 (ksp
= kstat_lookup( kc
, udp
, 0, udp
)) &&
900 kstat_read( kc
, ksp
, NULL
) != -1 &&
901 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
903 stats
->dwInDatagrams
= kstat_get_ui32( ksp
, "inDatagrams" );
904 stats
->dwNoPorts
= 0; /* FIXME */
905 stats
->dwInErrors
= kstat_get_ui32( ksp
, "inErrors" );
906 stats
->dwOutDatagrams
= kstat_get_ui32( ksp
, "outDatagrams" );
907 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
909 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
910 HeapFree( GetProcessHeap(), 0, udp_table
);
914 if (kc
) kstat_close( kc
);
916 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
918 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
919 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
920 struct udpstat udp_stat
;
921 MIB_UDPTABLE
*udp_table
;
922 size_t needed
= sizeof(udp_stat
);
924 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) != -1)
926 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
927 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
928 stats
->dwNoPorts
= udp_stat
.udps_noport
;
929 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
930 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
932 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
933 HeapFree( GetProcessHeap(), 0, udp_table
);
937 else ERR ("failed to get udpstat\n");
940 FIXME( "unimplemented\n" );
946 static MIB_IPFORWARDTABLE
*append_ipforward_row( HANDLE heap
, DWORD flags
, MIB_IPFORWARDTABLE
*table
,
947 DWORD
*count
, const MIB_IPFORWARDROW
*row
)
949 if (table
->dwNumEntries
>= *count
)
951 MIB_IPFORWARDTABLE
*new_table
;
952 DWORD new_count
= table
->dwNumEntries
* 2;
954 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
955 FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[new_count
] ))))
957 HeapFree( heap
, 0, table
);
963 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
967 static int compare_ipforward_rows(const void *a
, const void *b
)
969 const MIB_IPFORWARDROW
*rowA
= a
;
970 const MIB_IPFORWARDROW
*rowB
= b
;
973 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
974 if ((ret
= rowA
->u2
.dwForwardProto
- rowB
->u2
.dwForwardProto
) != 0) return ret
;
975 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
976 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
979 /******************************************************************
980 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
982 * Get the route table.
983 * Like GetIpForwardTable(), but allocate the returned table from heap.
986 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
987 * allocated and returned.
988 * bOrder [In] whether to sort the table
989 * heap [In] heap from which the table is allocated
990 * flags [In] flags to HeapAlloc
993 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
994 * on failure, NO_ERROR on success.
996 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, BOOL bOrder
,
997 HANDLE heap
, DWORD flags
)
999 MIB_IPFORWARDTABLE
*table
;
1000 MIB_IPFORWARDROW row
;
1001 DWORD ret
= NO_ERROR
, count
= 16;
1003 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable
, bOrder
, heap
, flags
);
1005 if (!ppIpForwardTable
) return ERROR_INVALID_PARAMETER
;
1007 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[count
] ))))
1008 return ERROR_OUTOFMEMORY
;
1010 table
->dwNumEntries
= 0;
1016 if ((fp
= fopen("/proc/net/route", "r")))
1018 char buf
[512], *ptr
;
1021 /* skip header line */
1022 ptr
= fgets(buf
, sizeof(buf
), fp
);
1023 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1025 memset( &row
, 0, sizeof(row
) );
1027 while (!isspace(*ptr
)) ptr
++;
1029 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
1032 row
.dwForwardDest
= strtoul(ptr
, &ptr
, 16);
1033 row
.dwForwardNextHop
= strtoul(ptr
+ 1, &ptr
, 16);
1034 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1036 if (!(flags
& RTF_UP
)) row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INVALID
;
1037 else if (flags
& RTF_GATEWAY
) row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1038 else row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_DIRECT
;
1040 strtoul(ptr
+ 1, &ptr
, 16); /* refcount, skip */
1041 strtoul(ptr
+ 1, &ptr
, 16); /* use, skip */
1042 row
.dwForwardMetric1
= strtoul(ptr
+ 1, &ptr
, 16);
1043 row
.dwForwardMask
= strtoul(ptr
+ 1, &ptr
, 16);
1044 /* FIXME: other protos might be appropriate, e.g. the default
1045 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1046 row
.u2
.ForwardProto
= MIB_IPPROTO_LOCAL
;
1048 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1053 else ret
= ERROR_NOT_SUPPORTED
;
1055 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1058 int fd
, len
, namelen
;
1059 mib2_ipRouteEntry_t
*entry
;
1062 if ((fd
= open_streams_mib( NULL
)) != -1)
1064 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_ROUTE
, &len
)))
1066 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1068 row
.dwForwardDest
= entry
->ipRouteDest
;
1069 row
.dwForwardMask
= entry
->ipRouteMask
;
1070 row
.dwForwardPolicy
= 0;
1071 row
.dwForwardNextHop
= entry
->ipRouteNextHop
;
1072 row
.u1
.dwForwardType
= entry
->ipRouteType
;
1073 row
.u2
.dwForwardProto
= entry
->ipRouteProto
;
1074 row
.dwForwardAge
= entry
->ipRouteAge
;
1075 row
.dwForwardNextHopAS
= 0;
1076 row
.dwForwardMetric1
= entry
->ipRouteMetric1
;
1077 row
.dwForwardMetric2
= entry
->ipRouteMetric2
;
1078 row
.dwForwardMetric3
= entry
->ipRouteMetric3
;
1079 row
.dwForwardMetric4
= entry
->ipRouteMetric4
;
1080 row
.dwForwardMetric5
= entry
->ipRouteMetric5
;
1081 namelen
= min( sizeof(name
) - 1, entry
->ipRouteIfIndex
.o_length
);
1082 memcpy( name
, entry
->ipRouteIfIndex
.o_bytes
, namelen
);
1084 getInterfaceIndexByName( name
, &row
.dwForwardIfIndex
);
1085 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
))) break;
1087 HeapFree( GetProcessHeap(), 0, data
);
1091 else ret
= ERROR_NOT_SUPPORTED
;
1093 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1095 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1097 char *buf
= NULL
, *lim
, *next
, *addrPtr
;
1098 struct rt_msghdr
*rtm
;
1100 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1102 ERR ("sysctl 1 failed!\n");
1103 ret
= ERROR_NOT_SUPPORTED
;
1107 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1110 ret
= ERROR_OUTOFMEMORY
;
1114 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1116 ret
= ERROR_NOT_SUPPORTED
;
1121 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1125 rtm
= (struct rt_msghdr
*)next
;
1127 if (rtm
->rtm_type
!= RTM_GET
)
1129 WARN ("Got unexpected message type 0x%x!\n",
1134 /* Ignore all entries except for gateway routes which aren't
1136 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1137 (rtm
->rtm_flags
& RTF_MULTICAST
))
1140 memset( &row
, 0, sizeof(row
) );
1141 row
.dwForwardIfIndex
= rtm
->rtm_index
;
1142 row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1143 row
.dwForwardMetric1
= rtm
->rtm_rmx
.rmx_hopcount
;
1144 row
.u2
.ForwardProto
= MIB_IPPROTO_LOCAL
;
1146 addrPtr
= (char *)(rtm
+ 1);
1148 for (i
= 1; i
; i
<<= 1)
1150 struct sockaddr
*sa
;
1153 if (!(i
& rtm
->rtm_addrs
))
1156 sa
= (struct sockaddr
*)addrPtr
;
1157 ADVANCE (addrPtr
, sa
);
1159 /* default routes are encoded by length-zero sockaddr */
1160 if (sa
->sa_len
== 0)
1162 else if (sa
->sa_family
!= AF_INET
)
1164 WARN ("Received unsupported sockaddr family 0x%x\n",
1170 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1172 addr
= sin
->sin_addr
.s_addr
;
1177 case RTA_DST
: row
.dwForwardDest
= addr
; break;
1178 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
1179 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
1181 WARN ("Unexpected address type 0x%x\n", i
);
1185 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1189 HeapFree( GetProcessHeap (), 0, buf
);
1192 FIXME( "not implemented\n" );
1193 ret
= ERROR_NOT_SUPPORTED
;
1196 if (!table
) return ERROR_OUTOFMEMORY
;
1199 if (bOrder
&& table
->dwNumEntries
)
1200 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipforward_rows
);
1201 *ppIpForwardTable
= table
;
1203 else HeapFree( heap
, flags
, table
);
1204 TRACE( "returning ret %u table %p\n", ret
, table
);
1208 static MIB_IPNETTABLE
*append_ipnet_row( HANDLE heap
, DWORD flags
, MIB_IPNETTABLE
*table
,
1209 DWORD
*count
, const MIB_IPNETROW
*row
)
1211 if (table
->dwNumEntries
>= *count
)
1213 MIB_IPNETTABLE
*new_table
;
1214 DWORD new_count
= table
->dwNumEntries
* 2;
1216 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
1217 FIELD_OFFSET(MIB_IPNETTABLE
, table
[new_count
] ))))
1219 HeapFree( heap
, 0, table
);
1225 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1229 static int compare_ipnet_rows(const void *a
, const void *b
)
1231 const MIB_IPNETROW
*rowA
= a
;
1232 const MIB_IPNETROW
*rowB
= b
;
1234 return ntohl(rowA
->dwAddr
) - ntohl(rowB
->dwAddr
);
1238 /******************************************************************
1239 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1241 * Get the IP-to-physical address mapping table.
1242 * Like GetIpNetTable(), but allocate the returned table from heap.
1245 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1246 * allocated and returned.
1247 * bOrder [In] whether to sort the table
1248 * heap [In] heap from which the table is allocated
1249 * flags [In] flags to HeapAlloc
1252 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1253 * on failure, NO_ERROR on success.
1255 DWORD WINAPI
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE
*ppIpNetTable
, BOOL bOrder
,
1256 HANDLE heap
, DWORD flags
)
1258 MIB_IPNETTABLE
*table
;
1260 DWORD ret
= NO_ERROR
, count
= 16;
1262 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable
, bOrder
, heap
, flags
);
1264 if (!ppIpNetTable
) return ERROR_INVALID_PARAMETER
;
1266 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPNETTABLE
, table
[count
] ))))
1267 return ERROR_OUTOFMEMORY
;
1269 table
->dwNumEntries
= 0;
1275 if ((fp
= fopen("/proc/net/arp", "r")))
1277 char buf
[512], *ptr
;
1280 /* skip header line */
1281 ptr
= fgets(buf
, sizeof(buf
), fp
);
1282 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1284 memset( &row
, 0, sizeof(row
) );
1286 row
.dwAddr
= inet_addr(ptr
);
1287 while (*ptr
&& !isspace(*ptr
)) ptr
++;
1288 strtoul(ptr
+ 1, &ptr
, 16); /* hw type (skip) */
1289 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1292 if (flags
& ATF_COM
) row
.u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
1296 if (flags
& ATF_PERM
) row
.u
.Type
= MIB_IPNET_TYPE_STATIC
;
1299 row
.u
.Type
= MIB_IPNET_TYPE_OTHER
;
1301 while (*ptr
&& isspace(*ptr
)) ptr
++;
1302 while (*ptr
&& !isspace(*ptr
))
1304 row
.bPhysAddr
[row
.dwPhysAddrLen
++] = strtoul(ptr
, &ptr
, 16);
1307 while (*ptr
&& isspace(*ptr
)) ptr
++;
1308 while (*ptr
&& !isspace(*ptr
)) ptr
++; /* mask (skip) */
1309 while (*ptr
&& isspace(*ptr
)) ptr
++;
1310 getInterfaceIndexByName(ptr
, &row
.dwIndex
);
1312 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1317 else ret
= ERROR_NOT_SUPPORTED
;
1319 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1322 int fd
, len
, namelen
;
1323 mib2_ipNetToMediaEntry_t
*entry
;
1326 if ((fd
= open_streams_mib( NULL
)) != -1)
1328 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_MEDIA
, &len
)))
1330 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1332 row
.dwPhysAddrLen
= min( entry
->ipNetToMediaPhysAddress
.o_length
, MAXLEN_PHYSADDR
);
1333 memcpy( row
.bPhysAddr
, entry
->ipNetToMediaPhysAddress
.o_bytes
, row
.dwPhysAddrLen
);
1334 row
.dwAddr
= entry
->ipNetToMediaNetAddress
;
1335 row
.u
.Type
= entry
->ipNetToMediaType
;
1336 namelen
= min( sizeof(name
) - 1, entry
->ipNetToMediaIfIndex
.o_length
);
1337 memcpy( name
, entry
->ipNetToMediaIfIndex
.o_bytes
, namelen
);
1339 getInterfaceIndexByName( name
, &row
.dwIndex
);
1340 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
))) break;
1342 HeapFree( GetProcessHeap(), 0, data
);
1346 else ret
= ERROR_NOT_SUPPORTED
;
1348 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1350 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1351 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1353 char *buf
= NULL
, *lim
, *next
;
1354 struct rt_msghdr
*rtm
;
1355 struct sockaddr_inarp
*sinarp
;
1356 struct sockaddr_dl
*sdl
;
1358 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1360 ERR ("failed to get arp table\n");
1361 ret
= ERROR_NOT_SUPPORTED
;
1365 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1368 ret
= ERROR_OUTOFMEMORY
;
1372 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1374 ret
= ERROR_NOT_SUPPORTED
;
1382 rtm
= (struct rt_msghdr
*)next
;
1383 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1384 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1385 if(sdl
->sdl_alen
) /* arp entry */
1387 memset( &row
, 0, sizeof(row
) );
1388 row
.dwAddr
= sinarp
->sin_addr
.s_addr
;
1389 row
.dwIndex
= sdl
->sdl_index
;
1390 row
.dwPhysAddrLen
= min( 8, sdl
->sdl_alen
);
1391 memcpy( row
.bPhysAddr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], row
.dwPhysAddrLen
);
1392 if(rtm
->rtm_rmx
.rmx_expire
== 0) row
.u
.Type
= MIB_IPNET_TYPE_STATIC
;
1393 else if(sinarp
->sin_other
& SIN_PROXY
) row
.u
.Type
= MIB_IPNET_TYPE_OTHER
;
1394 else if(rtm
->rtm_rmx
.rmx_expire
!= 0) row
.u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
1395 else row
.u
.Type
= MIB_IPNET_TYPE_INVALID
;
1397 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1400 next
+= rtm
->rtm_msglen
;
1403 HeapFree( GetProcessHeap (), 0, buf
);
1406 FIXME( "not implemented\n" );
1407 ret
= ERROR_NOT_SUPPORTED
;
1410 if (!table
) return ERROR_OUTOFMEMORY
;
1413 if (bOrder
&& table
->dwNumEntries
)
1414 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipnet_rows
);
1415 *ppIpNetTable
= table
;
1417 else HeapFree( heap
, flags
, table
);
1418 TRACE( "returning ret %u table %p\n", ret
, table
);
1423 static MIB_UDPTABLE
*append_udp_row( HANDLE heap
, DWORD flags
, MIB_UDPTABLE
*table
,
1424 DWORD
*count
, const MIB_UDPROW
*row
)
1426 if (table
->dwNumEntries
>= *count
)
1428 MIB_UDPTABLE
*new_table
;
1429 DWORD new_count
= table
->dwNumEntries
* 2;
1431 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_UDPTABLE
, table
[new_count
] ))))
1433 HeapFree( heap
, 0, table
);
1439 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1443 static int compare_udp_rows(const void *a
, const void *b
)
1445 const MIB_UDPROW
*rowA
= a
;
1446 const MIB_UDPROW
*rowB
= b
;
1449 if ((ret
= rowA
->dwLocalAddr
- rowB
->dwLocalAddr
) != 0) return ret
;
1450 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
1454 /******************************************************************
1455 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1457 * Get the UDP listener table.
1458 * Like GetUdpTable(), but allocate the returned table from heap.
1461 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1462 * allocated and returned.
1463 * bOrder [In] whether to sort the table
1464 * heap [In] heap from which the table is allocated
1465 * flags [In] flags to HeapAlloc
1468 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1469 * returns otherwise.
1471 DWORD WINAPI
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE
*ppUdpTable
, BOOL bOrder
,
1472 HANDLE heap
, DWORD flags
)
1474 MIB_UDPTABLE
*table
;
1476 DWORD ret
= NO_ERROR
, count
= 16;
1478 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable
, bOrder
, heap
, flags
);
1480 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
1482 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_UDPTABLE
, table
[count
] ))))
1483 return ERROR_OUTOFMEMORY
;
1485 table
->dwNumEntries
= 0;
1491 if ((fp
= fopen("/proc/net/udp", "r")))
1493 char buf
[512], *ptr
;
1496 /* skip header line */
1497 ptr
= fgets(buf
, sizeof(buf
), fp
);
1498 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1500 if (sscanf( ptr
, "%u: %x:%x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
) != 3)
1502 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1503 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
)))
1508 else ret
= ERROR_NOT_SUPPORTED
;
1510 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1514 mib2_udpEntry_t
*entry
;
1516 if ((fd
= open_streams_mib( "udp" )) != -1)
1518 if ((data
= read_mib_entry( fd
, MIB2_UDP
, MIB2_UDP_ENTRY
, &len
)))
1520 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1522 row
.dwLocalAddr
= entry
->udpLocalAddress
;
1523 row
.dwLocalPort
= htons( entry
->udpLocalPort
);
1524 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
))) break;
1526 HeapFree( GetProcessHeap(), 0, data
);
1530 else ret
= ERROR_NOT_SUPPORTED
;
1532 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1536 struct xinpgen
*pXIG
, *pOrigXIG
;
1538 if (sysctlbyname ("net.inet.udp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1540 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1541 ret
= ERROR_NOT_SUPPORTED
;
1545 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1548 ret
= ERROR_OUTOFMEMORY
;
1552 if (sysctlbyname ("net.inet.udp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1554 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
1555 ret
= ERROR_NOT_SUPPORTED
;
1559 /* Might be nothing here; first entry is just a header it seems */
1560 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1562 pOrigXIG
= (struct xinpgen
*)Buf
;
1565 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1566 pXIG
->xig_len
> sizeof (struct xinpgen
);
1567 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1569 struct inpcb
*pINData
;
1570 struct xsocket
*pSockData
;
1572 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
1573 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
1575 /* Ignore sockets for other protocols */
1576 if (pSockData
->xso_protocol
!= IPPROTO_UDP
)
1579 /* Ignore PCBs that were freed while generating the data */
1580 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1583 /* we're only interested in IPv4 addresses */
1584 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1585 (pINData
->inp_vflag
& INP_IPV6
))
1588 /* If all 0's, skip it */
1589 if (!pINData
->inp_laddr
.s_addr
&&
1590 !pINData
->inp_lport
)
1593 /* Fill in structure details */
1594 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1595 row
.dwLocalPort
= pINData
->inp_lport
;
1596 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
))) break;
1600 HeapFree (GetProcessHeap (), 0, Buf
);
1603 FIXME( "not implemented\n" );
1604 ret
= ERROR_NOT_SUPPORTED
;
1607 if (!table
) return ERROR_OUTOFMEMORY
;
1610 if (bOrder
&& table
->dwNumEntries
)
1611 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_udp_rows
);
1612 *ppUdpTable
= table
;
1614 else HeapFree( heap
, flags
, table
);
1615 TRACE( "returning ret %u table %p\n", ret
, table
);
1620 static MIB_TCPTABLE
*append_tcp_row( HANDLE heap
, DWORD flags
, MIB_TCPTABLE
*table
,
1621 DWORD
*count
, const MIB_TCPROW
*row
)
1623 if (table
->dwNumEntries
>= *count
)
1625 MIB_TCPTABLE
*new_table
;
1626 DWORD new_count
= table
->dwNumEntries
* 2;
1628 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_TCPTABLE
, table
[new_count
] ))))
1630 HeapFree( heap
, 0, table
);
1636 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1641 /* Why not a lookup table? Because the TCPS_* constants are different
1642 on different platforms */
1643 static inline MIB_TCP_STATE
TCPStateToMIBState (int state
)
1647 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1648 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1649 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1650 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1651 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1652 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1653 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1654 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1655 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1656 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1658 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1663 static int compare_tcp_rows(const void *a
, const void *b
)
1665 const MIB_TCPROW
*rowA
= a
;
1666 const MIB_TCPROW
*rowB
= b
;
1669 if ((ret
= ntohl (rowA
->dwLocalAddr
) - ntohl (rowB
->dwLocalAddr
)) != 0) return ret
;
1670 if ((ret
= ntohs ((unsigned short)rowA
->dwLocalPort
) -
1671 ntohs ((unsigned short)rowB
->dwLocalPort
)) != 0) return ret
;
1672 if ((ret
= ntohl (rowA
->dwRemoteAddr
) - ntohl (rowB
->dwRemoteAddr
)) != 0) return ret
;
1673 return ntohs ((unsigned short)rowA
->dwRemotePort
) - ntohs ((unsigned short)rowB
->dwRemotePort
);
1677 /******************************************************************
1678 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1680 * Get the TCP connection table.
1681 * Like GetTcpTable(), but allocate the returned table from heap.
1684 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1685 * allocated and returned.
1686 * bOrder [In] whether to sort the table
1687 * heap [In] heap from which the table is allocated
1688 * flags [In] flags to HeapAlloc
1691 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1692 * returns otherwise.
1694 DWORD WINAPI
AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE
*ppTcpTable
, BOOL bOrder
,
1695 HANDLE heap
, DWORD flags
)
1697 MIB_TCPTABLE
*table
;
1699 DWORD ret
= NO_ERROR
, count
= 16;
1701 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable
, bOrder
, heap
, flags
);
1703 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
1705 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_TCPTABLE
, table
[count
] ))))
1706 return ERROR_OUTOFMEMORY
;
1708 table
->dwNumEntries
= 0;
1714 if ((fp
= fopen("/proc/net/tcp", "r")))
1716 char buf
[512], *ptr
;
1719 /* skip header line */
1720 ptr
= fgets(buf
, sizeof(buf
), fp
);
1721 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1723 if (sscanf( ptr
, "%x: %x:%x %x:%x %x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
,
1724 &row
.dwRemoteAddr
, &row
.dwRemotePort
, &row
.u
.dwState
) != 6)
1726 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1727 row
.dwRemotePort
= htons( row
.dwRemotePort
);
1728 row
.u
.State
= TCPStateToMIBState( row
.u
.dwState
);
1729 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
)))
1734 else ret
= ERROR_NOT_SUPPORTED
;
1736 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1740 mib2_tcpConnEntry_t
*entry
;
1742 if ((fd
= open_streams_mib( "tcp" )) != -1)
1744 if ((data
= read_mib_entry( fd
, MIB2_TCP
, MIB2_TCP_CONN
, &len
)))
1746 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1748 row
.dwLocalAddr
= entry
->tcpConnLocalAddress
;
1749 row
.dwLocalPort
= htons( entry
->tcpConnLocalPort
);
1750 row
.dwRemoteAddr
= entry
->tcpConnRemAddress
;
1751 row
.dwRemotePort
= htons( entry
->tcpConnRemPort
);
1752 row
.u
.dwState
= entry
->tcpConnState
;
1753 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1755 HeapFree( GetProcessHeap(), 0, data
);
1759 else ret
= ERROR_NOT_SUPPORTED
;
1761 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1765 struct xinpgen
*pXIG
, *pOrigXIG
;
1767 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1769 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1770 ret
= ERROR_NOT_SUPPORTED
;
1774 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1777 ret
= ERROR_OUTOFMEMORY
;
1781 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1783 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1784 ret
= ERROR_NOT_SUPPORTED
;
1788 /* Might be nothing here; first entry is just a header it seems */
1789 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1791 pOrigXIG
= (struct xinpgen
*)Buf
;
1794 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1795 pXIG
->xig_len
> sizeof (struct xinpgen
);
1796 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1798 struct tcpcb
*pTCPData
= NULL
;
1799 struct inpcb
*pINData
;
1800 struct xsocket
*pSockData
;
1802 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1803 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1804 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1806 /* Ignore sockets for other protocols */
1807 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1810 /* Ignore PCBs that were freed while generating the data */
1811 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1814 /* we're only interested in IPv4 addresses */
1815 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1816 (pINData
->inp_vflag
& INP_IPV6
))
1819 /* If all 0's, skip it */
1820 if (!pINData
->inp_laddr
.s_addr
&&
1821 !pINData
->inp_lport
&&
1822 !pINData
->inp_faddr
.s_addr
&&
1823 !pINData
->inp_fport
)
1826 /* Fill in structure details */
1827 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1828 row
.dwLocalPort
= pINData
->inp_lport
;
1829 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
1830 row
.dwRemotePort
= pINData
->inp_fport
;
1831 row
.u
.State
= TCPStateToMIBState (pTCPData
->t_state
);
1832 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1836 HeapFree (GetProcessHeap (), 0, Buf
);
1839 FIXME( "not implemented\n" );
1840 ret
= ERROR_NOT_SUPPORTED
;
1843 if (!table
) return ERROR_OUTOFMEMORY
;
1846 if (bOrder
&& table
->dwNumEntries
)
1847 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_tcp_rows
);
1848 *ppTcpTable
= table
;
1850 else HeapFree( heap
, flags
, table
);
1851 TRACE( "returning ret %u table %p\n", ret
, table
);