1 /* Copyright (C) 2003 Art Yerkes
2 * A reimplementation of ifenum.c by Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 * This file is implemented on the IOCTL_TCP_QUERY_INFORMATION_EX ioctl on
22 #include "iphlpapi_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
26 #ifndef TCPS_ESTABLISHED
27 # define TCPS_ESTABLISHED TCP_ESTABLISHED
30 # define TCPS_SYN_SENT TCP_SYN_SENT
32 #ifndef TCPS_SYN_RECEIVED
33 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
35 #ifndef TCPS_FIN_WAIT_1
36 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
38 #ifndef TCPS_FIN_WAIT_2
39 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
41 #ifndef TCPS_TIME_WAIT
42 # define TCPS_TIME_WAIT TCP_TIME_WAIT
45 # define TCPS_CLOSED TCP_CLOSE
47 #ifndef TCPS_CLOSE_WAIT
48 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
51 # define TCPS_LAST_ACK TCP_LAST_ACK
54 # define TCPS_LISTEN TCP_LISTEN
57 # define TCPS_CLOSING TCP_CLOSING
60 BOOL
isIpEntity( HANDLE tcpFile
, TDIEntityID
*ent
) {
61 return (ent
->tei_entity
== CL_NL_ENTITY
||
62 ent
->tei_entity
== CO_NL_ENTITY
);
65 NTSTATUS
getNthIpEntity( HANDLE tcpFile
, DWORD index
, TDIEntityID
*ent
) {
66 DWORD numEntities
= 0;
68 TDIEntityID
*entitySet
= 0;
69 NTSTATUS status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
72 if( !NT_SUCCESS(status
) )
75 for( i
= 0; i
< numEntities
; i
++ ) {
76 if( isIpEntity( tcpFile
, &entitySet
[i
] ) ) {
77 TRACE("Entity %d is an IP Entity\n", i
);
78 if( numRoutes
== index
) break;
83 if( numRoutes
== index
&& i
< numEntities
) {
84 TRACE("Index %lu is entity #%d - %04x:%08x\n", index
, i
,
85 entitySet
[i
].tei_entity
, entitySet
[i
].tei_instance
);
86 memcpy( ent
, &entitySet
[i
], sizeof(*ent
) );
87 tdiFreeThingSet( entitySet
);
88 return STATUS_SUCCESS
;
90 tdiFreeThingSet( entitySet
);
91 return STATUS_UNSUCCESSFUL
;
95 NTSTATUS tdiGetMibForIpEntity
96 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPSNMPInfo
*entry
) {
97 TCP_REQUEST_QUERY_INFORMATION_EX req
= TCP_REQUEST_QUERY_INFORMATION_INIT
;
98 NTSTATUS status
= STATUS_SUCCESS
;
101 memset( entry
, 0, sizeof( *entry
) );
103 TRACE("TdiGetMibForIpEntity(tcpFile 0x%p, entityId 0x%x)\n",
104 tcpFile
, ent
->tei_instance
);
106 req
.ID
.toi_class
= INFO_CLASS_PROTOCOL
;
107 req
.ID
.toi_type
= INFO_TYPE_PROVIDER
;
108 req
.ID
.toi_id
= IP_MIB_STATS_ID
;
109 req
.ID
.toi_entity
= *ent
;
111 status
= DeviceIoControl( tcpFile
,
112 IOCTL_TCP_QUERY_INFORMATION_EX
,
120 TRACE("TdiGetMibForIpEntity() => status = 0x%08lx, entry = {\n"
121 " ipsi_forwarding ............ %lu\n"
122 " ipsi_defaultttl ............ %lu\n"
123 " ipsi_inreceives ............ %lu\n"
124 " ipsi_indelivers ............ %lu\n"
125 " ipsi_outrequests ........... %lu\n"
126 " ipsi_routingdiscards ....... %lu\n"
127 " ipsi_outdiscards ........... %lu\n"
128 " ipsi_outnoroutes ........... %lu\n"
129 " ipsi_numif ................. %lu\n"
130 " ipsi_numaddr ............... %lu\n"
131 " ipsi_numroutes ............. %lu\n"
134 entry
->ipsi_forwarding
,
135 entry
->ipsi_defaultttl
,
136 entry
->ipsi_inreceives
,
137 entry
->ipsi_indelivers
,
138 entry
->ipsi_outrequests
,
139 entry
->ipsi_routingdiscards
,
140 entry
->ipsi_outdiscards
,
141 entry
->ipsi_outnoroutes
,
144 entry
->ipsi_numroutes
);
149 NTSTATUS tdiGetRoutesForIpEntity
150 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPRouteEntry
**routes
, PDWORD numRoutes
) {
151 NTSTATUS status
= STATUS_SUCCESS
;
153 TRACE("TdiGetRoutesForIpEntity(tcpFile 0x%p, entityId 0x%x)\n",
154 tcpFile
, ent
->tei_instance
);
156 status
= tdiGetSetOfThings( tcpFile
,
159 IP_MIB_ARPTABLE_ENTRY_ID
,
163 sizeof(IPRouteEntry
),
170 NTSTATUS tdiGetIpAddrsForIpEntity
171 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPAddrEntry
**addrs
, PDWORD numAddrs
) {
174 TRACE("TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%x)\n",
175 tcpFile
, ent
->tei_instance
);
177 status
= tdiGetSetOfThings( tcpFile
,
180 IP_MIB_ADDRTABLE_ENTRY_ID
,
191 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
194 return ERROR_INVALID_PARAMETER
;
196 return ERROR_INVALID_PARAMETER
;
201 DWORD
getInterfaceStatsByIndex(DWORD index
, PMIB_IFROW entry
)
203 return ERROR_INVALID_PARAMETER
;
206 DWORD
getICMPStats(MIB_ICMP
*stats
)
211 return ERROR_INVALID_PARAMETER
;
213 memset(stats
, 0, sizeof(MIB_ICMP
));
214 /* get most of these stats from /proc/net/snmp, no error if can't */
215 fp
= fopen("/proc/net/snmp", "r");
217 const char hdr
[] = "Icmp:";
218 char buf
[512] = { 0 }, *ptr
;
221 ptr
= fgets(buf
, sizeof(buf
), fp
);
222 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
224 /* last line was a header, get another */
225 ptr
= fgets(buf
, sizeof(buf
), fp
);
226 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
231 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
235 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
239 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
243 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
247 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
251 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
255 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
259 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
263 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
267 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
271 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
275 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
279 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
283 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
287 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
291 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
295 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
299 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
303 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
307 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
311 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
315 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
319 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
323 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
333 DWORD
getIPStats(PMIB_IPSTATS stats
, DWORD family
)
336 return ERROR_INVALID_PARAMETER
;
340 DWORD
getTCPStats(MIB_TCPSTATS
*stats
, DWORD family
)
343 return ERROR_INVALID_PARAMETER
;
347 DWORD
getUDPStats(MIB_UDPSTATS
*stats
, DWORD family
)
350 return ERROR_INVALID_PARAMETER
;
354 DWORD
getNumRoutes(void)
356 DWORD numEntities
, numRoutes
= 0;
357 TDIEntityID
*entitySet
;
364 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
365 if( !NT_SUCCESS(status
) ) {
366 ERR("openTcpFile returned 0x%08lx\n", status
);
370 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
371 if( !NT_SUCCESS(status
) ) {
372 ERR("tdiGetEntityIDSet returned 0x%08lx\n", status
);
373 closeTcpFile( tcpFile
);
377 for( i
= 0; i
< numEntities
; i
++ ) {
378 if( isIpEntity( tcpFile
, &entitySet
[i
] ) ) {
380 memset( &isnmp
, 0, sizeof( isnmp
) );
381 status
= tdiGetMibForIpEntity( tcpFile
, &entitySet
[i
], &isnmp
);
382 if( !NT_SUCCESS(status
) ) {
383 ERR("tdiGetMibForIpEntity returned 0x%08lx, for i = %d", status
, i
);
387 numRoutes
+= isnmp
.ipsi_numroutes
;
391 TRACE("numRoutes = %lu\n", numRoutes
);
393 tdiFreeThingSet( entitySet
);
394 closeTcpFile( tcpFile
);
399 VOID
HexDump( PCHAR Data
, DWORD Len
) {
402 for( i
= 0; i
< Len
; i
++ ) {
404 if( i
) fprintf(stderr
,"\n");
405 fprintf(stderr
,"%08x:", i
);
407 fprintf( stderr
, " %02x", Data
[i
] & 0xff );
409 fprintf(stderr
,"\n");
412 RouteTable
*getRouteTable(void)
414 RouteTable
*out_route_table
;
415 DWORD numRoutes
= getNumRoutes(), routesAdded
= 0;
418 NTSTATUS status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
421 if( !NT_SUCCESS(status
) )
424 TRACE("GETTING ROUTE TABLE\n");
426 out_route_table
= HeapAlloc( GetProcessHeap(), 0,
428 (sizeof(RouteEntry
) * (numRoutes
- 1)) );
429 if (!out_route_table
) {
430 closeTcpFile(tcpFile
);
434 out_route_table
->numRoutes
= numRoutes
;
436 for( i
= 0; routesAdded
< out_route_table
->numRoutes
; i
++ ) {
438 IPRouteEntry
*route_set
;
440 getNthIpEntity( tcpFile
, i
, &ent
);
442 tdiGetRoutesForIpEntity( tcpFile
, &ent
, &route_set
, &numRoutes
);
445 closeTcpFile( tcpFile
);
446 HeapFree( GetProcessHeap(), 0, out_route_table
);
450 TRACE("%lu routes in instance %d\n", numRoutes
, i
);
453 sizeof( IPRouteEntry
) *
454 snmpInfo
.ipsi_numroutes
);
457 for( j
= 0; j
< numRoutes
; j
++ ) {
458 int routeNum
= j
+ routesAdded
;
459 out_route_table
->routes
[routeNum
].dest
=
460 route_set
[j
].ire_dest
;
461 out_route_table
->routes
[routeNum
].mask
=
462 route_set
[j
].ire_mask
;
463 out_route_table
->routes
[routeNum
].gateway
=
465 out_route_table
->routes
[routeNum
].ifIndex
=
466 route_set
[j
].ire_index
;
467 out_route_table
->routes
[routeNum
].metric
=
468 route_set
[j
].ire_metric1
;
471 if( route_set
) tdiFreeThingSet( route_set
);
473 routesAdded
+= numRoutes
;
476 closeTcpFile( tcpFile
);
478 TRACE("status = 0x%08lx, out_route_table = 0x%p\n", status
, out_route_table
);
480 return out_route_table
;
483 DWORD
getNumArpEntries(void)
486 TDIEntityID
*entitySet
= NULL
;
488 int i
, totalNumber
= 0;
490 PMIB_IPNETROW IpArpTable
= NULL
;
495 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
496 if( !NT_SUCCESS(status
) ) {
497 ERR("openTcpFile returned 0x%08lx\n", status
);
501 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
503 for( i
= 0; i
< numEntities
; i
++ ) {
504 if( isInterface( &entitySet
[i
] ) &&
505 hasArp( tcpFile
, &entitySet
[i
] ) ) {
507 status
= tdiGetSetOfThings( tcpFile
,
510 IP_MIB_ARPTABLE_ENTRY_ID
,
512 entitySet
[i
].tei_instance
,
514 sizeof(MIB_IPNETROW
),
515 (PVOID
*)&IpArpTable
,
518 if( status
== STATUS_SUCCESS
) totalNumber
+= returnSize
;
520 tdiFreeThingSet( IpArpTable
);
526 closeTcpFile( tcpFile
);
527 if( IpArpTable
) tdiFreeThingSet( IpArpTable
);
528 if( entitySet
) tdiFreeThingSet( entitySet
);
532 PMIB_IPNETTABLE
getArpTable(void)
534 DWORD numEntities
, returnSize
;
535 TDIEntityID
*entitySet
;
537 int i
, totalNumber
, TmpIdx
, CurrIdx
= 0;
539 PMIB_IPNETTABLE IpArpTable
= NULL
;
540 PMIB_IPNETROW AdapterArpTable
= NULL
;
544 totalNumber
= getNumArpEntries();
546 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
547 if( !NT_SUCCESS(status
) ) {
548 ERR("openTcpFile returned 0x%08lx\n", status
);
552 IpArpTable
= HeapAlloc
553 ( GetProcessHeap(), 0,
554 sizeof(DWORD
) + (sizeof(MIB_IPNETROW
) * totalNumber
) );
556 closeTcpFile(tcpFile
);
560 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
562 for( i
= 0; i
< numEntities
; i
++ ) {
563 if( isInterface( &entitySet
[i
] ) &&
564 hasArp( tcpFile
, &entitySet
[i
] ) ) {
566 status
= tdiGetSetOfThings( tcpFile
,
569 IP_MIB_ARPTABLE_ENTRY_ID
,
571 entitySet
[i
].tei_instance
,
573 sizeof(MIB_IPNETROW
),
574 (PVOID
*)&AdapterArpTable
,
577 if( status
== STATUS_SUCCESS
) {
578 for( TmpIdx
= 0; TmpIdx
< returnSize
; TmpIdx
++, CurrIdx
++ )
579 IpArpTable
->table
[CurrIdx
] = AdapterArpTable
[TmpIdx
];
580 tdiFreeThingSet( AdapterArpTable
);
585 closeTcpFile( tcpFile
);
587 tdiFreeThingSet( entitySet
);
588 IpArpTable
->dwNumEntries
= CurrIdx
;
593 DWORD
getNumUdpEntries(void)
596 TDIEntityID
*entitySet
= NULL
;
598 int i
, totalNumber
= 0;
600 PMIB_UDPROW IpUdpTable
= NULL
;
605 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
606 if( !NT_SUCCESS(status
) ) {
607 ERR("openTcpFile returned 0x%08lx\n", status
);
611 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
613 for( i
= 0; i
< numEntities
; i
++ ) {
614 if( isInterface( &entitySet
[i
] ) &&
615 hasArp( tcpFile
, &entitySet
[i
] ) ) {
617 status
= tdiGetSetOfThings( tcpFile
,
620 IP_MIB_ARPTABLE_ENTRY_ID
,
622 entitySet
[i
].tei_instance
,
625 (PVOID
*)&IpUdpTable
,
628 if( status
== STATUS_SUCCESS
) totalNumber
+= returnSize
;
630 tdiFreeThingSet( IpUdpTable
);
636 closeTcpFile( tcpFile
);
637 if( IpUdpTable
) tdiFreeThingSet( IpUdpTable
);
638 if( entitySet
) tdiFreeThingSet( entitySet
);
642 PMIB_UDPTABLE
getUdpTable(void)
644 DWORD numEntities
, returnSize
;
645 TDIEntityID
*entitySet
;
647 int i
, totalNumber
, TmpIdx
, CurrIdx
= 0;
649 PMIB_UDPTABLE IpUdpTable
= NULL
;
650 PMIB_UDPROW AdapterUdpTable
= NULL
;
654 totalNumber
= getNumTcpEntries();
656 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
657 if( !NT_SUCCESS(status
) ) {
658 ERR("openTcpFile returned 0x%08lx\n", status
);
662 IpUdpTable
= HeapAlloc
663 ( GetProcessHeap(), 0,
664 sizeof(DWORD
) + (sizeof(MIB_UDPROW
) * totalNumber
) );
666 closeTcpFile(tcpFile
);
670 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
672 for( i
= 0; i
< numEntities
; i
++ ) {
673 if( isInterface( &entitySet
[i
] ) &&
674 hasArp( tcpFile
, &entitySet
[i
] ) ) {
676 status
= tdiGetSetOfThings( tcpFile
,
679 IP_MIB_ARPTABLE_ENTRY_ID
,
681 entitySet
[i
].tei_instance
,
684 (PVOID
*)&AdapterUdpTable
,
687 if( status
== STATUS_SUCCESS
) {
688 for( TmpIdx
= 0; TmpIdx
< returnSize
; TmpIdx
++, CurrIdx
++ )
689 IpUdpTable
->table
[CurrIdx
] = AdapterUdpTable
[TmpIdx
];
690 tdiFreeThingSet( AdapterUdpTable
);
695 closeTcpFile( tcpFile
);
697 tdiFreeThingSet( entitySet
);
698 IpUdpTable
->dwNumEntries
= CurrIdx
;
703 DWORD
getNumTcpEntries(void)
706 TDIEntityID
*entitySet
= NULL
;
708 int i
, totalNumber
= 0;
710 PMIB_TCPROW IpTcpTable
= NULL
;
715 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
716 if( !NT_SUCCESS(status
) ) {
717 ERR("openTcpFile returned 0x%08lx\n", status
);
721 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
723 for( i
= 0; i
< numEntities
; i
++ ) {
724 if( isInterface( &entitySet
[i
] ) &&
725 hasArp( tcpFile
, &entitySet
[i
] ) ) {
727 status
= tdiGetSetOfThings( tcpFile
,
730 IP_MIB_ARPTABLE_ENTRY_ID
,
732 entitySet
[i
].tei_instance
,
735 (PVOID
*)&IpTcpTable
,
738 if( status
== STATUS_SUCCESS
) totalNumber
+= returnSize
;
740 tdiFreeThingSet( IpTcpTable
);
746 closeTcpFile( tcpFile
);
747 if( IpTcpTable
) tdiFreeThingSet( IpTcpTable
);
748 if( entitySet
) tdiFreeThingSet( entitySet
);
752 PMIB_TCPTABLE
getTcpTable(void)
754 DWORD numEntities
, returnSize
;
755 TDIEntityID
*entitySet
;
757 int i
, totalNumber
, TmpIdx
, CurrIdx
= 0;
759 PMIB_TCPTABLE IpTcpTable
= NULL
;
760 PMIB_TCPROW AdapterTcpTable
= NULL
;
764 totalNumber
= getNumTcpEntries();
766 status
= openTcpFile( &tcpFile
, FILE_READ_DATA
);
767 if( !NT_SUCCESS(status
) ) {
768 ERR("openTcpFile returned 0x%08lx\n", status
);
772 IpTcpTable
= HeapAlloc
773 ( GetProcessHeap(), 0,
774 sizeof(DWORD
) + (sizeof(MIB_TCPROW
) * totalNumber
) );
776 closeTcpFile(tcpFile
);
780 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
782 for( i
= 0; i
< numEntities
; i
++ ) {
783 if( isInterface( &entitySet
[i
] ) &&
784 hasArp( tcpFile
, &entitySet
[i
] ) ) {
786 status
= tdiGetSetOfThings( tcpFile
,
789 IP_MIB_ARPTABLE_ENTRY_ID
,
791 entitySet
[i
].tei_instance
,
794 (PVOID
*)&AdapterTcpTable
,
797 if( status
== STATUS_SUCCESS
) {
798 for( TmpIdx
= 0; TmpIdx
< returnSize
; TmpIdx
++, CurrIdx
++ )
799 IpTcpTable
->table
[CurrIdx
] = AdapterTcpTable
[TmpIdx
];
800 tdiFreeThingSet( AdapterTcpTable
);
805 closeTcpFile( tcpFile
);
807 tdiFreeThingSet( entitySet
);
808 IpTcpTable
->dwNumEntries
= CurrIdx
;