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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This file is implemented on the IOCTL_TCP_QUERY_INFORMATION_EX ioctl on
24 #include "iphlpapi_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
30 #ifndef TCPS_ESTABLISHED
31 # define TCPS_ESTABLISHED TCP_ESTABLISHED
34 # define TCPS_SYN_SENT TCP_SYN_SENT
36 #ifndef TCPS_SYN_RECEIVED
37 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
39 #ifndef TCPS_FIN_WAIT_1
40 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
42 #ifndef TCPS_FIN_WAIT_2
43 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
45 #ifndef TCPS_TIME_WAIT
46 # define TCPS_TIME_WAIT TCP_TIME_WAIT
49 # define TCPS_CLOSED TCP_CLOSE
51 #ifndef TCPS_CLOSE_WAIT
52 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
55 # define TCPS_LAST_ACK TCP_LAST_ACK
58 # define TCPS_LISTEN TCP_LISTEN
61 # define TCPS_CLOSING TCP_CLOSING
64 BOOL
isIpEntity( HANDLE tcpFile
, TDIEntityID
*ent
) {
65 DWORD entityType
, returnedLen
;
67 TCP_REQUEST_QUERY_INFORMATION_EX req
;
69 req
.ID
.toi_class
= INFO_CLASS_GENERIC
;
70 req
.ID
.toi_type
= INFO_TYPE_PROVIDER
;
71 req
.ID
.toi_id
= ENTITY_TYPE_ID
;
72 req
.ID
.toi_entity
= *ent
;
77 IOCTL_TCP_QUERY_INFORMATION_EX
,
85 TRACE("Ent: %04x:d -> %04x\n",
86 ent
->tei_entity
, ent
->tei_instance
, entityType
);
88 return NT_SUCCESS(status
) && entityType
== CL_NL_IP
;
91 NTSTATUS
getNthIpEntity( HANDLE tcpFile
, DWORD index
, TDIEntityID
*ent
) {
92 DWORD numEntities
= 0;
94 TDIEntityID
*entitySet
= 0;
95 NTSTATUS status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
98 if( !NT_SUCCESS(status
) )
101 for( i
= 0; i
< numEntities
; i
++ ) {
102 if( isIpEntity( tcpFile
, &entitySet
[i
] ) ) {
103 TRACE("Entity %d is an IP Entity\n", i
);
104 if( numRoutes
== index
) break;
109 if( numRoutes
== index
&& i
< numEntities
) {
110 TRACE("Index %d is entity #%d - %04x:%08x\n", index
, i
,
111 entitySet
[i
].tei_entity
, entitySet
[i
].tei_instance
);
112 memcpy( ent
, &entitySet
[i
], sizeof(*ent
) );
113 tdiFreeThingSet( entitySet
);
114 return STATUS_SUCCESS
;
116 tdiFreeThingSet( entitySet
);
117 return STATUS_UNSUCCESSFUL
;
121 NTSTATUS tdiGetMibForIpEntity
122 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPSNMPInfo
*entry
) {
123 TCP_REQUEST_QUERY_INFORMATION_EX req
= TCP_REQUEST_QUERY_INFORMATION_INIT
;
124 NTSTATUS status
= STATUS_SUCCESS
;
127 memset( entry
, 0, sizeof( *entry
) );
129 TRACE("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n",
130 (DWORD
)tcpFile
, ent
->tei_instance
);
132 req
.ID
.toi_class
= INFO_CLASS_PROTOCOL
;
133 req
.ID
.toi_type
= INFO_TYPE_PROVIDER
;
134 req
.ID
.toi_id
= IP_MIB_STATS_ID
;
135 req
.ID
.toi_entity
= *ent
;
137 status
= DeviceIoControl( tcpFile
,
138 IOCTL_TCP_QUERY_INFORMATION_EX
,
146 TRACE("TdiGetMibForIpEntity() => {\n"
147 " ipsi_forwarding ............ %d\n"
148 " ipsi_defaultttl ............ %d\n"
149 " ipsi_inreceives ............ %d\n"
150 " ipsi_indelivers ............ %d\n"
151 " ipsi_outrequests ........... %d\n"
152 " ipsi_routingdiscards ....... %d\n"
153 " ipsi_outdiscards ........... %d\n"
154 " ipsi_outnoroutes ........... %d\n"
155 " ipsi_numif ................. %d\n"
156 " ipsi_numaddr ............... %d\n"
157 " ipsi_numroutes ............. %d\n"
159 entry
->ipsi_forwarding
,
160 entry
->ipsi_defaultttl
,
161 entry
->ipsi_inreceives
,
162 entry
->ipsi_indelivers
,
163 entry
->ipsi_outrequests
,
164 entry
->ipsi_routingdiscards
,
165 entry
->ipsi_outdiscards
,
166 entry
->ipsi_outnoroutes
,
169 entry
->ipsi_numroutes
,
175 NTSTATUS tdiGetRoutesForIpEntity
176 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPRouteEntry
**routes
, PDWORD numRoutes
) {
177 NTSTATUS status
= STATUS_SUCCESS
;
179 TRACE("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
180 (DWORD
)tcpFile
, ent
->tei_instance
);
182 status
= tdiGetSetOfThings( tcpFile
,
185 IP_MIB_ROUTETABLE_ENTRY_ID
,
189 sizeof(IPRouteEntry
),
196 NTSTATUS tdiGetIpAddrsForIpEntity
197 ( HANDLE tcpFile
, TDIEntityID
*ent
, IPAddrEntry
**addrs
, PDWORD numAddrs
) {
200 TRACE("TdiGetIpAddrsForIpEntity(tcpFile %x,entityId %x)\n",
201 (DWORD
)tcpFile
, ent
->tei_instance
);
203 status
= tdiGetSetOfThings( tcpFile
,
206 IP_MIB_ADDRTABLE_ENTRY_ID
,
217 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
220 return ERROR_INVALID_PARAMETER
;
222 return ERROR_INVALID_PARAMETER
;
227 DWORD
getInterfaceStatsByIndex(DWORD index
, PMIB_IFROW entry
)
229 return ERROR_INVALID_PARAMETER
;
232 DWORD
getICMPStats(MIB_ICMP
*stats
)
237 return ERROR_INVALID_PARAMETER
;
239 memset(stats
, 0, sizeof(MIB_ICMP
));
240 /* get most of these stats from /proc/net/snmp, no error if can't */
241 fp
= fopen("/proc/net/snmp", "r");
243 const char hdr
[] = "Icmp:";
244 char buf
[512] = { 0 }, *ptr
;
247 ptr
= fgets(buf
, sizeof(buf
), fp
);
248 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
250 /* last line was a header, get another */
251 ptr
= fgets(buf
, sizeof(buf
), fp
);
252 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
257 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
261 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
265 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
269 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
273 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
277 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
281 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
285 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
289 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
293 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
297 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
301 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
305 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
309 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
313 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
317 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
321 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
325 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
329 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
333 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
337 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
341 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
345 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
349 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
359 DWORD
getIPStats(PMIB_IPSTATS stats
, DWORD family
)
362 return ERROR_INVALID_PARAMETER
;
366 DWORD
getTCPStats(MIB_TCPSTATS
*stats
, DWORD family
)
369 return ERROR_INVALID_PARAMETER
;
373 DWORD
getUDPStats(MIB_UDPSTATS
*stats
, DWORD family
)
376 return ERROR_INVALID_PARAMETER
;
380 static DWORD
getNumWithOneHeader(const char *filename
)
385 DWORD
getNumRoutes(void)
387 DWORD numEntities
, numRoutes
= 0;
388 TDIEntityID
*entitySet
;
395 status
= openTcpFile( &tcpFile
);
397 if( !NT_SUCCESS(status
) ) {
398 TRACE("failure: %08x\n", (int)status
);
402 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
404 if( !NT_SUCCESS(status
) ) {
405 TRACE("failure: %08x\n", (int)status
);
406 closeTcpFile( tcpFile
);
410 for( i
= 0; i
< numEntities
; i
++ ) {
411 if( isIpEntity( tcpFile
, &entitySet
[i
] ) ) {
413 memset( &isnmp
, 0, sizeof( isnmp
) );
414 status
= tdiGetMibForIpEntity( tcpFile
, &entitySet
[i
], &isnmp
);
415 if( !NT_SUCCESS(status
) ) {
416 tdiFreeThingSet( entitySet
);
417 closeTcpFile( tcpFile
);
420 numRoutes
+= isnmp
.ipsi_numroutes
;
424 TRACE("numRoutes: %d\n", (int)numRoutes
);
426 closeTcpFile( tcpFile
);
431 VOID
HexDump( PCHAR Data
, DWORD Len
) {
434 for( i
= 0; i
< Len
; i
++ ) {
436 if( i
) fprintf(stderr
,"\n");
437 fprintf(stderr
,"%08x:", i
);
439 fprintf( stderr
, " %02x", Data
[i
] & 0xff );
441 fprintf(stderr
,"\n");
444 RouteTable
*getRouteTable(void)
446 RouteTable
*out_route_table
;
447 DWORD numRoutes
= getNumRoutes(), routesAdded
= 0;
451 NTSTATUS status
= openTcpFile( &tcpFile
);
454 if( !NT_SUCCESS(status
) )
457 TRACE("GETTING ROUTE TABLE\n");
459 out_route_table
= HeapAlloc( GetProcessHeap(), 0,
461 (sizeof(RouteEntry
) * (numRoutes
- 1)) );
462 if (!out_route_table
) {
463 closeTcpFile(tcpFile
);
467 out_route_table
->numRoutes
= numRoutes
;
469 for( i
= 0; routesAdded
< numRoutes
; i
++ ) {
471 IPRouteEntry
*route_set
;
473 getNthIpEntity( tcpFile
, i
, &ent
);
474 tdiGetMibForIpEntity( tcpFile
, &ent
, &snmpInfo
);
476 TRACE( "%d routes in instance %d\n", snmpInfo
.ipsi_numroutes
, i
);
478 tdiGetRoutesForIpEntity( tcpFile
, &ent
, &route_set
, &numRoutes
);
481 closeTcpFile( tcpFile
);
482 HeapFree( GetProcessHeap(), 0, out_route_table
);
486 TRACE("Route set returned\n");
489 sizeof( IPRouteEntry
) *
490 snmpInfo
.ipsi_numroutes
);
493 for( j
= 0; j
< snmpInfo
.ipsi_numroutes
; j
++ ) {
494 int routeNum
= j
+ routesAdded
;
495 out_route_table
->routes
[routeNum
].dest
=
496 route_set
[j
].ire_dest
;
497 out_route_table
->routes
[routeNum
].mask
=
498 route_set
[j
].ire_mask
;
499 out_route_table
->routes
[routeNum
].gateway
=
501 out_route_table
->routes
[routeNum
].ifIndex
=
502 route_set
[j
].ire_index
;
503 out_route_table
->routes
[routeNum
].metric
=
504 route_set
[j
].ire_metric1
;
507 if( route_set
) tdiFreeThingSet( route_set
);
509 routesAdded
+= snmpInfo
.ipsi_numroutes
;
512 closeTcpFile( tcpFile
);
514 TRACE("Return: %08x, %08x\n", status
, out_route_table
);
516 return out_route_table
;
519 DWORD
getNumArpEntries(void)
522 TDIEntityID
*entitySet
= NULL
;
524 int i
, totalNumber
= 0;
526 PMIB_IPNETROW IpArpTable
= NULL
;
531 status
= openTcpFile( &tcpFile
);
533 if( !NT_SUCCESS(status
) ) {
534 TRACE("failure: %08x\n", (int)status
);
538 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
540 for( i
= 0; i
< numEntities
; i
++ ) {
541 if( isInterface( &entitySet
[i
] ) &&
542 hasArp( tcpFile
, &entitySet
[i
] ) &&
543 !isLoopback( tcpFile
, &entitySet
[i
] ) ) {
545 status
= tdiGetSetOfThings( tcpFile
,
548 IP_MIB_ARPTABLE_ENTRY_ID
,
550 entitySet
[i
].tei_instance
,
552 sizeof(MIB_IPNETROW
),
553 (PVOID
*)&IpArpTable
,
556 if( status
== STATUS_SUCCESS
) totalNumber
+= returnSize
;
558 tdiFreeThingSet( IpArpTable
);
564 closeTcpFile( tcpFile
);
565 if( IpArpTable
) tdiFreeThingSet( IpArpTable
);
566 if( entitySet
) tdiFreeThingSet( entitySet
);
570 PMIB_IPNETTABLE
getArpTable(void)
572 DWORD numEntities
, returnSize
;
573 TDIEntityID
*entitySet
;
575 int i
, totalNumber
, TmpIdx
, CurrIdx
= 0;
577 PMIB_IPNETTABLE IpArpTable
= NULL
;
578 PMIB_IPNETROW AdapterArpTable
= NULL
;
582 totalNumber
= getNumArpEntries();
584 status
= openTcpFile( &tcpFile
);
586 if( !NT_SUCCESS(status
) ) {
587 TRACE("failure: %08x\n", (int)status
);
591 IpArpTable
= HeapAlloc
592 ( GetProcessHeap(), 0,
593 sizeof(DWORD
) + (sizeof(MIB_IPNETROW
) * totalNumber
) );
595 closeTcpFile(tcpFile
);
599 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
601 for( i
= 0; i
< numEntities
; i
++ ) {
602 if( isInterface( &entitySet
[i
] ) &&
603 hasArp( tcpFile
, &entitySet
[i
] ) &&
604 !isLoopback( tcpFile
, &entitySet
[i
] ) ) {
606 status
= tdiGetSetOfThings( tcpFile
,
609 IP_MIB_ARPTABLE_ENTRY_ID
,
611 entitySet
[i
].tei_instance
,
613 sizeof(MIB_IPNETROW
),
614 (PVOID
*)&AdapterArpTable
,
617 if( status
== STATUS_SUCCESS
) {
618 for( TmpIdx
= 0; TmpIdx
< returnSize
; TmpIdx
++, CurrIdx
++ )
619 IpArpTable
->table
[CurrIdx
] = AdapterArpTable
[TmpIdx
];
622 if( AdapterArpTable
) tdiFreeThingSet( AdapterArpTable
);
626 closeTcpFile( tcpFile
);
628 tdiFreeThingSet( entitySet
);
629 IpArpTable
->dwNumEntries
= CurrIdx
;
634 DWORD
getNumUdpEntries(void)
636 return getNumWithOneHeader("/proc/net/udp");
639 PMIB_UDPTABLE
getUdpTable(void)
641 DWORD numEntries
= getNumUdpEntries();
644 ret
= (PMIB_UDPTABLE
)calloc(1, sizeof(MIB_UDPTABLE
) +
645 (numEntries
- 1) * sizeof(MIB_UDPROW
));
649 /* get from /proc/net/udp, no error if can't */
650 fp
= fopen("/proc/net/udp", "r");
652 char buf
[512] = { 0 }, *ptr
;
654 /* skip header line */
655 ptr
= fgets(buf
, sizeof(buf
), fp
);
656 while (ptr
&& ret
->dwNumEntries
< numEntries
) {
657 ptr
= fgets(buf
, sizeof(buf
), fp
);
662 strtoul(ptr
, &endPtr
, 16); /* skip */
667 ret
->table
[ret
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
, &endPtr
,
673 ret
->table
[ret
->dwNumEntries
].dwLocalPort
= strtoul(ptr
, &endPtr
,
686 DWORD
getNumTcpEntries(void)
688 return getNumWithOneHeader("/proc/net/tcp");
691 PMIB_TCPTABLE
getTcpTable(void)