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