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