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 %d 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 %x,entityId %x)\n",
104 (DWORD
)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() => {\n"
121 " ipsi_forwarding ............ %d\n"
122 " ipsi_defaultttl ............ %d\n"
123 " ipsi_inreceives ............ %d\n"
124 " ipsi_indelivers ............ %d\n"
125 " ipsi_outrequests ........... %d\n"
126 " ipsi_routingdiscards ....... %d\n"
127 " ipsi_outdiscards ........... %d\n"
128 " ipsi_outnoroutes ........... %d\n"
129 " ipsi_numif ................. %d\n"
130 " ipsi_numaddr ............... %d\n"
131 " ipsi_numroutes ............. %d\n"
133 entry
->ipsi_forwarding
,
134 entry
->ipsi_defaultttl
,
135 entry
->ipsi_inreceives
,
136 entry
->ipsi_indelivers
,
137 entry
->ipsi_outrequests
,
138 entry
->ipsi_routingdiscards
,
139 entry
->ipsi_outdiscards
,
140 entry
->ipsi_outnoroutes
,
143 entry
->ipsi_numroutes
,
149 NTSTATUS tdiGetRoutesForIpEntity
150 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPRouteEntry
**routes
, PDWORD numRoutes
) {
151 NTSTATUS status
= STATUS_SUCCESS
;
153 TRACE("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
154 (DWORD
)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 %x,entityId %x)\n",
175 (DWORD
)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 static DWORD
getNumWithOneHeader(const char *filename
)
359 DWORD
getNumRoutes(void)
361 DWORD numEntities
, numRoutes
= 0;
362 TDIEntityID
*entitySet
;
369 status
= openTcpFile( &tcpFile
);
371 if( !NT_SUCCESS(status
) ) {
372 TRACE("failure: %08x\n", (int)status
);
376 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
378 if( !NT_SUCCESS(status
) ) {
379 TRACE("failure: %08x\n", (int)status
);
380 closeTcpFile( tcpFile
);
384 for( i
= 0; i
< numEntities
; i
++ ) {
385 if( isIpEntity( tcpFile
, &entitySet
[i
] ) ) {
387 memset( &isnmp
, 0, sizeof( isnmp
) );
388 status
= tdiGetMibForIpEntity( tcpFile
, &entitySet
[i
], &isnmp
);
389 if( !NT_SUCCESS(status
) ) {
390 tdiFreeThingSet( entitySet
);
391 closeTcpFile( tcpFile
);
394 numRoutes
+= isnmp
.ipsi_numroutes
;
398 TRACE("numRoutes: %d\n", (int)numRoutes
);
400 closeTcpFile( tcpFile
);
405 VOID
HexDump( PCHAR Data
, DWORD Len
) {
408 for( i
= 0; i
< Len
; i
++ ) {
410 if( i
) fprintf(stderr
,"\n");
411 fprintf(stderr
,"%08x:", i
);
413 fprintf( stderr
, " %02x", Data
[i
] & 0xff );
415 fprintf(stderr
,"\n");
418 RouteTable
*getRouteTable(void)
420 RouteTable
*out_route_table
;
421 DWORD numRoutes
= getNumRoutes(), routesAdded
= 0;
424 NTSTATUS status
= openTcpFile( &tcpFile
);
427 if( !NT_SUCCESS(status
) )
430 TRACE("GETTING ROUTE TABLE\n");
432 out_route_table
= HeapAlloc( GetProcessHeap(), 0,
434 (sizeof(RouteEntry
) * (numRoutes
- 1)) );
435 if (!out_route_table
) {
436 closeTcpFile(tcpFile
);
440 out_route_table
->numRoutes
= numRoutes
;
442 for( i
= 0; routesAdded
< out_route_table
->numRoutes
; i
++ ) {
444 IPRouteEntry
*route_set
;
446 getNthIpEntity( tcpFile
, i
, &ent
);
448 tdiGetRoutesForIpEntity( tcpFile
, &ent
, &route_set
, &numRoutes
);
451 closeTcpFile( tcpFile
);
452 HeapFree( GetProcessHeap(), 0, out_route_table
);
456 TRACE( "%d routes in instance %d\n", numRoutes
, i
);
459 sizeof( IPRouteEntry
) *
460 snmpInfo
.ipsi_numroutes
);
463 for( j
= 0; j
< numRoutes
; j
++ ) {
464 int routeNum
= j
+ routesAdded
;
465 out_route_table
->routes
[routeNum
].dest
=
466 route_set
[j
].ire_dest
;
467 out_route_table
->routes
[routeNum
].mask
=
468 route_set
[j
].ire_mask
;
469 out_route_table
->routes
[routeNum
].gateway
=
471 out_route_table
->routes
[routeNum
].ifIndex
=
472 route_set
[j
].ire_index
;
473 out_route_table
->routes
[routeNum
].metric
=
474 route_set
[j
].ire_metric1
;
477 if( route_set
) tdiFreeThingSet( route_set
);
479 routesAdded
+= numRoutes
;
482 closeTcpFile( tcpFile
);
484 TRACE("Return: %08x, %08x\n", status
, out_route_table
);
486 return out_route_table
;
489 DWORD
getNumArpEntries(void)
492 TDIEntityID
*entitySet
= NULL
;
494 int i
, totalNumber
= 0;
496 PMIB_IPNETROW IpArpTable
= NULL
;
501 status
= openTcpFile( &tcpFile
);
503 if( !NT_SUCCESS(status
) ) {
504 TRACE("failure: %08x\n", (int)status
);
508 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
510 for( i
= 0; i
< numEntities
; i
++ ) {
511 if( isInterface( &entitySet
[i
] ) &&
512 hasArp( tcpFile
, &entitySet
[i
] ) ) {
514 status
= tdiGetSetOfThings( tcpFile
,
517 IP_MIB_ARPTABLE_ENTRY_ID
,
519 entitySet
[i
].tei_instance
,
521 sizeof(MIB_IPNETROW
),
522 (PVOID
*)&IpArpTable
,
525 if( status
== STATUS_SUCCESS
) totalNumber
+= returnSize
;
527 tdiFreeThingSet( IpArpTable
);
533 closeTcpFile( tcpFile
);
534 if( IpArpTable
) tdiFreeThingSet( IpArpTable
);
535 if( entitySet
) tdiFreeThingSet( entitySet
);
539 PMIB_IPNETTABLE
getArpTable(void)
541 DWORD numEntities
, returnSize
;
542 TDIEntityID
*entitySet
;
544 int i
, totalNumber
, TmpIdx
, CurrIdx
= 0;
546 PMIB_IPNETTABLE IpArpTable
= NULL
;
547 PMIB_IPNETROW AdapterArpTable
= NULL
;
551 totalNumber
= getNumArpEntries();
553 status
= openTcpFile( &tcpFile
);
555 if( !NT_SUCCESS(status
) ) {
556 TRACE("failure: %08x\n", (int)status
);
560 IpArpTable
= HeapAlloc
561 ( GetProcessHeap(), 0,
562 sizeof(DWORD
) + (sizeof(MIB_IPNETROW
) * totalNumber
) );
564 closeTcpFile(tcpFile
);
568 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
570 for( i
= 0; i
< numEntities
; i
++ ) {
571 if( isInterface( &entitySet
[i
] ) &&
572 hasArp( tcpFile
, &entitySet
[i
] ) ) {
574 status
= tdiGetSetOfThings( tcpFile
,
577 IP_MIB_ARPTABLE_ENTRY_ID
,
579 entitySet
[i
].tei_instance
,
581 sizeof(MIB_IPNETROW
),
582 (PVOID
*)&AdapterArpTable
,
585 if( status
== STATUS_SUCCESS
) {
586 for( TmpIdx
= 0; TmpIdx
< returnSize
; TmpIdx
++, CurrIdx
++ )
587 IpArpTable
->table
[CurrIdx
] = AdapterArpTable
[TmpIdx
];
588 tdiFreeThingSet( AdapterArpTable
);
593 closeTcpFile( tcpFile
);
595 tdiFreeThingSet( entitySet
);
596 IpArpTable
->dwNumEntries
= CurrIdx
;
601 DWORD
getNumUdpEntries(void)
603 return getNumWithOneHeader("/proc/net/udp");
606 PMIB_UDPTABLE
getUdpTable(void)
608 DWORD numEntries
= getNumUdpEntries();
611 ret
= (PMIB_UDPTABLE
)calloc(1, sizeof(MIB_UDPTABLE
) +
612 (numEntries
- 1) * sizeof(MIB_UDPROW
));
616 /* get from /proc/net/udp, no error if can't */
617 fp
= fopen("/proc/net/udp", "r");
619 char buf
[512] = { 0 }, *ptr
;
621 /* skip header line */
622 ptr
= fgets(buf
, sizeof(buf
), fp
);
623 while (ptr
&& ret
->dwNumEntries
< numEntries
) {
624 ptr
= fgets(buf
, sizeof(buf
), fp
);
629 strtoul(ptr
, &endPtr
, 16); /* skip */
634 ret
->table
[ret
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
, &endPtr
,
640 ret
->table
[ret
->dwNumEntries
].dwLocalPort
= strtoul(ptr
, &endPtr
,
653 DWORD
getNumTcpEntries(void)
655 return getNumWithOneHeader("/proc/net/tcp");
658 PMIB_TCPTABLE
getTcpTable(void)