- Fix some typos from my last commit
[reactos.git] / reactos / dll / win32 / iphlpapi / ipstats_reactos.c
1 /* Copyright (C) 2003 Art Yerkes
2 * A reimplementation of ifenum.c by Juan Lang
3 *
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.
8 *
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.
13 *
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
17 *
18 * This file is implemented on the IOCTL_TCP_QUERY_INFORMATION_EX ioctl on
19 * tcpip.sys
20 */
21
22 #include <stdio.h>
23
24 #include "iphlpapi_private.h"
25 #include "ipstats.h"
26 #include "ifenum.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
29
30 #ifndef TCPS_ESTABLISHED
31 # define TCPS_ESTABLISHED TCP_ESTABLISHED
32 #endif
33 #ifndef TCPS_SYN_SENT
34 # define TCPS_SYN_SENT TCP_SYN_SENT
35 #endif
36 #ifndef TCPS_SYN_RECEIVED
37 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
38 #endif
39 #ifndef TCPS_FIN_WAIT_1
40 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
41 #endif
42 #ifndef TCPS_FIN_WAIT_2
43 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
44 #endif
45 #ifndef TCPS_TIME_WAIT
46 # define TCPS_TIME_WAIT TCP_TIME_WAIT
47 #endif
48 #ifndef TCPS_CLOSED
49 # define TCPS_CLOSED TCP_CLOSE
50 #endif
51 #ifndef TCPS_CLOSE_WAIT
52 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
53 #endif
54 #ifndef TCPS_LAST_ACK
55 # define TCPS_LAST_ACK TCP_LAST_ACK
56 #endif
57 #ifndef TCPS_LISTEN
58 # define TCPS_LISTEN TCP_LISTEN
59 #endif
60 #ifndef TCPS_CLOSING
61 # define TCPS_CLOSING TCP_CLOSING
62 #endif
63
64 BOOL isIpEntity( HANDLE tcpFile, TDIEntityID *ent ) {
65 return (ent->tei_entity == CL_NL_ENTITY ||
66 ent->tei_entity == CO_NL_ENTITY);
67 }
68
69 NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
70 DWORD numEntities = 0;
71 DWORD numRoutes = 0;
72 TDIEntityID *entitySet = 0;
73 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
74 int i;
75
76 if( !NT_SUCCESS(status) )
77 return status;
78
79 for( i = 0; i < numEntities; i++ ) {
80 if( isIpEntity( tcpFile, &entitySet[i] ) ) {
81 TRACE("Entity %d is an IP Entity\n", i);
82 if( numRoutes == index ) break;
83 else numRoutes++;
84 }
85 }
86
87 if( numRoutes == index && i < numEntities ) {
88 TRACE("Index %d is entity #%d - %04x:%08x\n", index, i,
89 entitySet[i].tei_entity, entitySet[i].tei_instance );
90 memcpy( ent, &entitySet[i], sizeof(*ent) );
91 tdiFreeThingSet( entitySet );
92 return STATUS_SUCCESS;
93 } else {
94 tdiFreeThingSet( entitySet );
95 return STATUS_UNSUCCESSFUL;
96 }
97 }
98
99 NTSTATUS tdiGetMibForIpEntity
100 ( HANDLE tcpFile, TDIEntityID *ent, IPSNMPInfo *entry ) {
101 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
102 NTSTATUS status = STATUS_SUCCESS;
103 DWORD returnSize;
104
105 memset( entry, 0, sizeof( *entry ) );
106
107 TRACE("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n",
108 (DWORD)tcpFile, ent->tei_instance);
109
110 req.ID.toi_class = INFO_CLASS_PROTOCOL;
111 req.ID.toi_type = INFO_TYPE_PROVIDER;
112 req.ID.toi_id = IP_MIB_STATS_ID;
113 req.ID.toi_entity = *ent;
114
115 status = DeviceIoControl( tcpFile,
116 IOCTL_TCP_QUERY_INFORMATION_EX,
117 &req,
118 sizeof(req),
119 entry,
120 sizeof(*entry),
121 &returnSize,
122 NULL );
123
124 TRACE("TdiGetMibForIpEntity() => {\n"
125 " ipsi_forwarding ............ %d\n"
126 " ipsi_defaultttl ............ %d\n"
127 " ipsi_inreceives ............ %d\n"
128 " ipsi_indelivers ............ %d\n"
129 " ipsi_outrequests ........... %d\n"
130 " ipsi_routingdiscards ....... %d\n"
131 " ipsi_outdiscards ........... %d\n"
132 " ipsi_outnoroutes ........... %d\n"
133 " ipsi_numif ................. %d\n"
134 " ipsi_numaddr ............... %d\n"
135 " ipsi_numroutes ............. %d\n"
136 "} status %08x\n",
137 entry->ipsi_forwarding,
138 entry->ipsi_defaultttl,
139 entry->ipsi_inreceives,
140 entry->ipsi_indelivers,
141 entry->ipsi_outrequests,
142 entry->ipsi_routingdiscards,
143 entry->ipsi_outdiscards,
144 entry->ipsi_outnoroutes,
145 entry->ipsi_numif,
146 entry->ipsi_numaddr,
147 entry->ipsi_numroutes,
148 status);
149
150 return status;
151 }
152
153 NTSTATUS tdiGetRoutesForIpEntity
154 ( HANDLE tcpFile, TDIEntityID *ent, IPRouteEntry **routes, PDWORD numRoutes ) {
155 NTSTATUS status = STATUS_SUCCESS;
156
157 TRACE("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
158 (DWORD)tcpFile, ent->tei_instance);
159
160 status = tdiGetSetOfThings( tcpFile,
161 INFO_CLASS_PROTOCOL,
162 INFO_TYPE_PROVIDER,
163 IP_MIB_ARPTABLE_ENTRY_ID,
164 CL_NL_ENTITY,
165 ent->tei_instance,
166 0,
167 sizeof(IPRouteEntry),
168 (PVOID *)routes,
169 numRoutes);
170
171 return status;
172 }
173
174 NTSTATUS tdiGetIpAddrsForIpEntity
175 ( HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs, PDWORD numAddrs ) {
176 NTSTATUS status;
177
178 TRACE("TdiGetIpAddrsForIpEntity(tcpFile %x,entityId %x)\n",
179 (DWORD)tcpFile, ent->tei_instance);
180
181 status = tdiGetSetOfThings( tcpFile,
182 INFO_CLASS_PROTOCOL,
183 INFO_TYPE_PROVIDER,
184 IP_MIB_ADDRTABLE_ENTRY_ID,
185 CL_NL_ENTITY,
186 ent->tei_instance,
187 0,
188 sizeof(IPAddrEntry),
189 (PVOID *)addrs,
190 numAddrs );
191
192 return status;
193 }
194
195 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
196 {
197 if (!name)
198 return ERROR_INVALID_PARAMETER;
199 if (!entry)
200 return ERROR_INVALID_PARAMETER;
201
202 return NO_ERROR;
203 }
204
205 DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry)
206 {
207 return ERROR_INVALID_PARAMETER;
208 }
209
210 DWORD getICMPStats(MIB_ICMP *stats)
211 {
212 FILE *fp;
213
214 if (!stats)
215 return ERROR_INVALID_PARAMETER;
216
217 memset(stats, 0, sizeof(MIB_ICMP));
218 /* get most of these stats from /proc/net/snmp, no error if can't */
219 fp = fopen("/proc/net/snmp", "r");
220 if (fp) {
221 const char hdr[] = "Icmp:";
222 char buf[512] = { 0 }, *ptr;
223
224 do {
225 ptr = fgets(buf, sizeof(buf), fp);
226 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
227 if (ptr) {
228 /* last line was a header, get another */
229 ptr = fgets(buf, sizeof(buf), fp);
230 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
231 char *endPtr;
232
233 ptr += sizeof(hdr);
234 if (ptr && *ptr) {
235 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
236 ptr = endPtr;
237 }
238 if (ptr && *ptr) {
239 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
240 ptr = endPtr;
241 }
242 if (ptr && *ptr) {
243 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
244 ptr = endPtr;
245 }
246 if (ptr && *ptr) {
247 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
248 ptr = endPtr;
249 }
250 if (ptr && *ptr) {
251 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
252 ptr = endPtr;
253 }
254 if (ptr && *ptr) {
255 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
256 ptr = endPtr;
257 }
258 if (ptr && *ptr) {
259 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
260 ptr = endPtr;
261 }
262 if (ptr && *ptr) {
263 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
264 ptr = endPtr;
265 }
266 if (ptr && *ptr) {
267 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
268 ptr = endPtr;
269 }
270 if (ptr && *ptr) {
271 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
272 ptr = endPtr;
273 }
274 if (ptr && *ptr) {
275 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
276 ptr = endPtr;
277 }
278 if (ptr && *ptr) {
279 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
280 ptr = endPtr;
281 }
282 if (ptr && *ptr) {
283 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
284 ptr = endPtr;
285 }
286 if (ptr && *ptr) {
287 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
288 ptr = endPtr;
289 }
290 if (ptr && *ptr) {
291 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
292 ptr = endPtr;
293 }
294 if (ptr && *ptr) {
295 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
296 ptr = endPtr;
297 }
298 if (ptr && *ptr) {
299 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
300 ptr = endPtr;
301 }
302 if (ptr && *ptr) {
303 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
304 ptr = endPtr;
305 }
306 if (ptr && *ptr) {
307 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
308 ptr = endPtr;
309 }
310 if (ptr && *ptr) {
311 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
312 ptr = endPtr;
313 }
314 if (ptr && *ptr) {
315 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
316 ptr = endPtr;
317 }
318 if (ptr && *ptr) {
319 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
320 ptr = endPtr;
321 }
322 if (ptr && *ptr) {
323 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
324 ptr = endPtr;
325 }
326 if (ptr && *ptr) {
327 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
328 ptr = endPtr;
329 }
330 }
331 }
332 fclose(fp);
333 }
334 return NO_ERROR;
335 }
336
337 DWORD getIPStats(PMIB_IPSTATS stats, DWORD family)
338 {
339 if (!stats)
340 return ERROR_INVALID_PARAMETER;
341 return NO_ERROR;
342 }
343
344 DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family)
345 {
346 if (!stats)
347 return ERROR_INVALID_PARAMETER;
348 return NO_ERROR;
349 }
350
351 DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family)
352 {
353 if (!stats)
354 return ERROR_INVALID_PARAMETER;
355 return NO_ERROR;
356 }
357
358 static DWORD getNumWithOneHeader(const char *filename)
359 {
360 return 0;
361 }
362
363 DWORD getNumRoutes(void)
364 {
365 DWORD numEntities, numRoutes = 0;
366 TDIEntityID *entitySet;
367 HANDLE tcpFile;
368 int i;
369 NTSTATUS status;
370
371 TRACE("called.\n");
372
373 status = openTcpFile( &tcpFile );
374
375 if( !NT_SUCCESS(status) ) {
376 TRACE("failure: %08x\n", (int)status );
377 return 0;
378 }
379
380 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
381
382 if( !NT_SUCCESS(status) ) {
383 TRACE("failure: %08x\n", (int)status );
384 closeTcpFile( tcpFile );
385 return 0;
386 }
387
388 for( i = 0; i < numEntities; i++ ) {
389 if( isIpEntity( tcpFile, &entitySet[i] ) ) {
390 IPSNMPInfo isnmp;
391 memset( &isnmp, 0, sizeof( isnmp ) );
392 status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp );
393 if( !NT_SUCCESS(status) ) {
394 tdiFreeThingSet( entitySet );
395 closeTcpFile( tcpFile );
396 return status;
397 }
398 numRoutes += isnmp.ipsi_numroutes;
399 }
400 }
401
402 TRACE("numRoutes: %d\n", (int)numRoutes);
403
404 closeTcpFile( tcpFile );
405
406 return numRoutes;
407 }
408
409 VOID HexDump( PCHAR Data, DWORD Len ) {
410 int i;
411
412 for( i = 0; i < Len; i++ ) {
413 if( !(i & 0xf) ) {
414 if( i ) fprintf(stderr,"\n");
415 fprintf(stderr,"%08x:", i);
416 }
417 fprintf( stderr, " %02x", Data[i] & 0xff );
418 }
419 fprintf(stderr,"\n");
420 }
421
422 RouteTable *getRouteTable(void)
423 {
424 RouteTable *out_route_table;
425 DWORD numRoutes = getNumRoutes(), routesAdded = 0;
426 TDIEntityID ent;
427 HANDLE tcpFile;
428 NTSTATUS status = openTcpFile( &tcpFile );
429 int i;
430
431 if( !NT_SUCCESS(status) )
432 return 0;
433
434 TRACE("GETTING ROUTE TABLE\n");
435
436 out_route_table = HeapAlloc( GetProcessHeap(), 0,
437 sizeof(RouteTable) +
438 (sizeof(RouteEntry) * (numRoutes - 1)) );
439 if (!out_route_table) {
440 closeTcpFile(tcpFile);
441 return NULL;
442 }
443
444 out_route_table->numRoutes = numRoutes;
445
446 for( i = 0; routesAdded < out_route_table->numRoutes; i++ ) {
447 int j;
448 IPRouteEntry *route_set;
449
450 getNthIpEntity( tcpFile, i, &ent );
451
452 tdiGetRoutesForIpEntity( tcpFile, &ent, &route_set, &numRoutes );
453
454 if( !route_set ) {
455 closeTcpFile( tcpFile );
456 HeapFree( GetProcessHeap(), 0, out_route_table );
457 return 0;
458 }
459
460 TRACE( "%d routes in instance %d\n", numRoutes, i );
461 #if 0
462 HexDump( route_set,
463 sizeof( IPRouteEntry ) *
464 snmpInfo.ipsi_numroutes );
465 #endif
466
467 for( j = 0; j < numRoutes; j++ ) {
468 int routeNum = j + routesAdded;
469 out_route_table->routes[routeNum].dest =
470 route_set[j].ire_dest;
471 out_route_table->routes[routeNum].mask =
472 route_set[j].ire_mask;
473 out_route_table->routes[routeNum].gateway =
474 route_set[j].ire_gw;
475 out_route_table->routes[routeNum].ifIndex =
476 route_set[j].ire_index;
477 out_route_table->routes[routeNum].metric =
478 route_set[j].ire_metric1;
479 }
480
481 if( route_set ) tdiFreeThingSet( route_set );
482
483 routesAdded += numRoutes;
484 }
485
486 closeTcpFile( tcpFile );
487
488 TRACE("Return: %08x, %08x\n", status, out_route_table);
489
490 return out_route_table;
491 }
492
493 DWORD getNumArpEntries(void)
494 {
495 DWORD numEntities;
496 TDIEntityID *entitySet = NULL;
497 HANDLE tcpFile;
498 int i, totalNumber = 0;
499 NTSTATUS status;
500 PMIB_IPNETROW IpArpTable = NULL;
501 DWORD returnSize;
502
503 TRACE("called.\n");
504
505 status = openTcpFile( &tcpFile );
506
507 if( !NT_SUCCESS(status) ) {
508 TRACE("failure: %08x\n", (int)status );
509 return 0;
510 }
511
512 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
513
514 for( i = 0; i < numEntities; i++ ) {
515 if( isInterface( &entitySet[i] ) &&
516 hasArp( tcpFile, &entitySet[i] ) &&
517 !isLoopback( tcpFile, &entitySet[i] ) ) {
518
519 status = tdiGetSetOfThings( tcpFile,
520 INFO_CLASS_PROTOCOL,
521 INFO_TYPE_PROVIDER,
522 IP_MIB_ARPTABLE_ENTRY_ID,
523 AT_ENTITY,
524 entitySet[i].tei_instance,
525 0,
526 sizeof(MIB_IPNETROW),
527 (PVOID *)&IpArpTable,
528 &returnSize );
529
530 if( status == STATUS_SUCCESS ) totalNumber += returnSize;
531 if( IpArpTable ) {
532 tdiFreeThingSet( IpArpTable );
533 IpArpTable = NULL;
534 }
535 }
536 }
537
538 closeTcpFile( tcpFile );
539 if( IpArpTable ) tdiFreeThingSet( IpArpTable );
540 if( entitySet ) tdiFreeThingSet( entitySet );
541 return totalNumber;
542 }
543
544 PMIB_IPNETTABLE getArpTable(void)
545 {
546 DWORD numEntities, returnSize;
547 TDIEntityID *entitySet;
548 HANDLE tcpFile;
549 int i, totalNumber, TmpIdx, CurrIdx = 0;
550 NTSTATUS status;
551 PMIB_IPNETTABLE IpArpTable = NULL;
552 PMIB_IPNETROW AdapterArpTable = NULL;
553
554 TRACE("called.\n");
555
556 totalNumber = getNumArpEntries();
557
558 status = openTcpFile( &tcpFile );
559
560 if( !NT_SUCCESS(status) ) {
561 TRACE("failure: %08x\n", (int)status );
562 return 0;
563 }
564
565 IpArpTable = HeapAlloc
566 ( GetProcessHeap(), 0,
567 sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber) );
568 if (!IpArpTable) {
569 closeTcpFile(tcpFile);
570 return NULL;
571 }
572
573 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
574
575 for( i = 0; i < numEntities; i++ ) {
576 if( isInterface( &entitySet[i] ) &&
577 hasArp( tcpFile, &entitySet[i] ) &&
578 !isLoopback( tcpFile, &entitySet[i] ) ) {
579
580 status = tdiGetSetOfThings( tcpFile,
581 INFO_CLASS_PROTOCOL,
582 INFO_TYPE_PROVIDER,
583 IP_MIB_ARPTABLE_ENTRY_ID,
584 AT_ENTITY,
585 entitySet[i].tei_instance,
586 0,
587 sizeof(MIB_IPNETROW),
588 (PVOID *)&AdapterArpTable,
589 &returnSize );
590
591 if( status == STATUS_SUCCESS ) {
592 for( TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++ )
593 IpArpTable->table[CurrIdx] = AdapterArpTable[TmpIdx];
594 }
595
596 if( AdapterArpTable ) tdiFreeThingSet( AdapterArpTable );
597 }
598 }
599
600 closeTcpFile( tcpFile );
601
602 tdiFreeThingSet( entitySet );
603 IpArpTable->dwNumEntries = CurrIdx;
604
605 return IpArpTable;
606 }
607
608 DWORD getNumUdpEntries(void)
609 {
610 return getNumWithOneHeader("/proc/net/udp");
611 }
612
613 PMIB_UDPTABLE getUdpTable(void)
614 {
615 DWORD numEntries = getNumUdpEntries();
616 PMIB_UDPTABLE ret;
617
618 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
619 (numEntries - 1) * sizeof(MIB_UDPROW));
620 if (ret) {
621 FILE *fp;
622
623 /* get from /proc/net/udp, no error if can't */
624 fp = fopen("/proc/net/udp", "r");
625 if (fp) {
626 char buf[512] = { 0 }, *ptr;
627
628 /* skip header line */
629 ptr = fgets(buf, sizeof(buf), fp);
630 while (ptr && ret->dwNumEntries < numEntries) {
631 ptr = fgets(buf, sizeof(buf), fp);
632 if (ptr) {
633 char *endPtr;
634
635 if (ptr && *ptr) {
636 strtoul(ptr, &endPtr, 16); /* skip */
637 ptr = endPtr;
638 }
639 if (ptr && *ptr) {
640 ptr++;
641 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
642 16);
643 ptr = endPtr;
644 }
645 if (ptr && *ptr) {
646 ptr++;
647 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
648 16);
649 ptr = endPtr;
650 }
651 ret->dwNumEntries++;
652 }
653 }
654 fclose(fp);
655 }
656 }
657 return ret;
658 }
659
660 DWORD getNumTcpEntries(void)
661 {
662 return getNumWithOneHeader("/proc/net/tcp");
663 }
664
665 PMIB_TCPTABLE getTcpTable(void)
666 {
667 return 0;
668 }