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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 
24 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
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     return (ent->tei_entity == CL_NL_ENTITY ||
62             ent->tei_entity == CO_NL_ENTITY);
63 }
64 
65 NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
66     DWORD numEntities = 0;
67     DWORD numRoutes = 0;
68     TDIEntityID *entitySet = 0;
69     NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
70     int i;
71 
72     if( !NT_SUCCESS(status) )
73         return status;
74 
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;
79             else numRoutes++;
80         }
81     }
82 
83     if( numRoutes == index && i < numEntities ) {
84         TRACE("Index %lu 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;
89     } else {
90         tdiFreeThingSet( entitySet );
91         return STATUS_UNSUCCESSFUL;
92     }
93 }
94 
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;
99     DWORD returnSize;
100 
101     memset( entry, 0, sizeof( *entry ) );
102 
103     TRACE("TdiGetMibForIpEntity(tcpFile 0x%p, entityId 0x%x)\n",
104           tcpFile, ent->tei_instance);
105 
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;
110 
111     status = DeviceIoControl( tcpFile,
112                               IOCTL_TCP_QUERY_INFORMATION_EX,
113                               &req,
114                               sizeof(req),
115                               entry,
116                               sizeof(*entry),
117                               &returnSize,
118                               NULL );
119 
120     TRACE("TdiGetMibForIpEntity() => status = 0x%08lx, entry = {\n"
121            "  ipsi_forwarding ............ %lu\n"
122            "  ipsi_defaultttl ............ %lu\n"
123            "  ipsi_inreceives ............ %lu\n"
124            "  ipsi_indelivers ............ %lu\n"
125            "  ipsi_outrequests ........... %lu\n"
126            "  ipsi_routingdiscards ....... %lu\n"
127            "  ipsi_outdiscards ........... %lu\n"
128            "  ipsi_outnoroutes ........... %lu\n"
129            "  ipsi_numif ................. %lu\n"
130            "  ipsi_numaddr ............... %lu\n"
131            "  ipsi_numroutes ............. %lu\n"
132            "}\n",
133           status,
134           entry->ipsi_forwarding,
135           entry->ipsi_defaultttl,
136           entry->ipsi_inreceives,
137           entry->ipsi_indelivers,
138           entry->ipsi_outrequests,
139           entry->ipsi_routingdiscards,
140           entry->ipsi_outdiscards,
141           entry->ipsi_outnoroutes,
142           entry->ipsi_numif,
143           entry->ipsi_numaddr,
144           entry->ipsi_numroutes);
145 
146     return status;
147 }
148 
149 NTSTATUS tdiGetRoutesForIpEntity
150 ( HANDLE tcpFile, TDIEntityID *ent, IPRouteEntry **routes, PDWORD numRoutes ) {
151     NTSTATUS status = STATUS_SUCCESS;
152 
153     TRACE("TdiGetRoutesForIpEntity(tcpFile 0x%p, entityId 0x%x)\n",
154           tcpFile, ent->tei_instance);
155 
156     status = tdiGetSetOfThings( tcpFile,
157                                 INFO_CLASS_PROTOCOL,
158                                 INFO_TYPE_PROVIDER,
159                                 IP_MIB_ARPTABLE_ENTRY_ID,
160                                 CL_NL_ENTITY,
161 				ent->tei_instance,
162                                 0,
163                                 sizeof(IPRouteEntry),
164                                 (PVOID *)routes,
165                                 numRoutes);
166 
167     return status;
168 }
169 
170 NTSTATUS tdiGetIpAddrsForIpEntity
171 ( HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs, PDWORD numAddrs ) {
172     NTSTATUS status;
173 
174     TRACE("TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%x)\n",
175           tcpFile, ent->tei_instance);
176 
177     status = tdiGetSetOfThings( tcpFile,
178                                 INFO_CLASS_PROTOCOL,
179                                 INFO_TYPE_PROVIDER,
180                                 IP_MIB_ADDRTABLE_ENTRY_ID,
181                                 CL_NL_ENTITY,
182 				ent->tei_instance,
183                                 0,
184                                 sizeof(IPAddrEntry),
185                                 (PVOID *)addrs,
186                                 numAddrs );
187 
188     return status;
189 }
190 
191 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
192 {
193   if (!name)
194     return ERROR_INVALID_PARAMETER;
195   if (!entry)
196     return ERROR_INVALID_PARAMETER;
197 
198   return NO_ERROR;
199 }
200 
201 DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry)
202 {
203     return ERROR_INVALID_PARAMETER;
204 }
205 
206 DWORD getICMPStats(MIB_ICMP *stats)
207 {
208   FILE *fp;
209 
210   if (!stats)
211     return ERROR_INVALID_PARAMETER;
212 
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");
216   if (fp) {
217     const char hdr[] = "Icmp:";
218     char buf[512] = { 0 }, *ptr;
219 
220     do {
221       ptr = fgets(buf, sizeof(buf), fp);
222     } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
223     if (ptr) {
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) {
227         char *endPtr;
228 
229         ptr += sizeof(hdr);
230         if (ptr && *ptr) {
231           stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
232           ptr = endPtr;
233         }
234         if (ptr && *ptr) {
235           stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
236           ptr = endPtr;
237         }
238         if (ptr && *ptr) {
239           stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
240           ptr = endPtr;
241         }
242         if (ptr && *ptr) {
243           stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
244           ptr = endPtr;
245         }
246         if (ptr && *ptr) {
247           stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
248           ptr = endPtr;
249         }
250         if (ptr && *ptr) {
251           stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
252           ptr = endPtr;
253         }
254         if (ptr && *ptr) {
255           stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
256           ptr = endPtr;
257         }
258         if (ptr && *ptr) {
259           stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
260           ptr = endPtr;
261         }
262         if (ptr && *ptr) {
263           stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
264           ptr = endPtr;
265         }
266         if (ptr && *ptr) {
267           stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
268           ptr = endPtr;
269         }
270         if (ptr && *ptr) {
271           stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
272           ptr = endPtr;
273         }
274         if (ptr && *ptr) {
275           stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
276           ptr = endPtr;
277         }
278         if (ptr && *ptr) {
279           stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
280           ptr = endPtr;
281         }
282         if (ptr && *ptr) {
283           stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
284           ptr = endPtr;
285         }
286         if (ptr && *ptr) {
287           stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
288           ptr = endPtr;
289         }
290         if (ptr && *ptr) {
291           stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
292           ptr = endPtr;
293         }
294         if (ptr && *ptr) {
295           stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
296           ptr = endPtr;
297         }
298         if (ptr && *ptr) {
299           stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
300           ptr = endPtr;
301         }
302         if (ptr && *ptr) {
303           stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
304           ptr = endPtr;
305         }
306         if (ptr && *ptr) {
307           stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
308           ptr = endPtr;
309         }
310         if (ptr && *ptr) {
311           stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
312           ptr = endPtr;
313         }
314         if (ptr && *ptr) {
315           stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
316           ptr = endPtr;
317         }
318         if (ptr && *ptr) {
319           stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
320           ptr = endPtr;
321         }
322         if (ptr && *ptr) {
323           stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
324           ptr = endPtr;
325         }
326       }
327     }
328     fclose(fp);
329   }
330   return NO_ERROR;
331 }
332 
333 DWORD getIPStats(PMIB_IPSTATS stats, DWORD family)
334 {
335   if (!stats)
336     return ERROR_INVALID_PARAMETER;
337   return NO_ERROR;
338 }
339 
340 DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family)
341 {
342   if (!stats)
343     return ERROR_INVALID_PARAMETER;
344   return NO_ERROR;
345 }
346 
347 DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family)
348 {
349   if (!stats)
350     return ERROR_INVALID_PARAMETER;
351   return NO_ERROR;
352 }
353 
354 DWORD getNumRoutes(void)
355 {
356     DWORD numEntities, numRoutes = 0;
357     TDIEntityID *entitySet;
358     HANDLE tcpFile;
359     int i;
360     NTSTATUS status;
361 
362     TRACE("called.\n");
363 
364     status = openTcpFile( &tcpFile, FILE_READ_DATA );
365     if( !NT_SUCCESS(status) ) {
366         ERR("openTcpFile returned 0x%08lx\n", status);
367         return 0;
368     }
369 
370     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
371     if( !NT_SUCCESS(status) ) {
372         ERR("tdiGetEntityIDSet returned 0x%08lx\n", status);
373         closeTcpFile( tcpFile );
374         return 0;
375     }
376 
377     for( i = 0; i < numEntities; i++ ) {
378         if( isIpEntity( tcpFile, &entitySet[i] ) ) {
379             IPSNMPInfo isnmp;
380             memset( &isnmp, 0, sizeof( isnmp ) );
381             status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp );
382             if( !NT_SUCCESS(status) ) {
383                 ERR("tdiGetMibForIpEntity returned 0x%08lx, for i = %d", status, i);
384                 numRoutes = 0;
385                 break;
386             }
387             numRoutes += isnmp.ipsi_numroutes;
388         }
389     }
390 
391     TRACE("numRoutes = %lu\n", numRoutes);
392 
393     tdiFreeThingSet( entitySet );
394     closeTcpFile( tcpFile );
395 
396     return numRoutes;
397 }
398 
399 VOID HexDump( PCHAR Data, DWORD Len ) {
400     int i;
401 
402     for( i = 0; i < Len; i++ ) {
403         if( !(i & 0xf) ) {
404             if( i ) fprintf(stderr,"\n");
405             fprintf(stderr,"%08x:", i);
406         }
407         fprintf( stderr, " %02x", Data[i] & 0xff );
408     }
409     fprintf(stderr,"\n");
410 }
411 
412 RouteTable *getRouteTable(void)
413 {
414     RouteTable *out_route_table;
415     DWORD numRoutes = getNumRoutes(), routesAdded = 0;
416     TDIEntityID ent;
417     HANDLE tcpFile;
418     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
419     int i;
420 
421     if( !NT_SUCCESS(status) )
422         return 0;
423 
424     TRACE("GETTING ROUTE TABLE\n");
425 
426     out_route_table = HeapAlloc( GetProcessHeap(), 0,
427                                  sizeof(RouteTable) +
428                                  (sizeof(RouteEntry) * (numRoutes - 1)) );
429     if (!out_route_table) {
430         closeTcpFile(tcpFile);
431         return NULL;
432     }
433 
434     out_route_table->numRoutes = numRoutes;
435 
436     for( i = 0; routesAdded < out_route_table->numRoutes; i++ ) {
437         int j;
438         IPRouteEntry *route_set;
439 
440         getNthIpEntity( tcpFile, i, &ent );
441 
442         tdiGetRoutesForIpEntity( tcpFile, &ent, &route_set, &numRoutes );
443 
444         if( !route_set ) {
445             closeTcpFile( tcpFile );
446             HeapFree( GetProcessHeap(), 0, out_route_table );
447             return 0;
448         }
449 
450         TRACE("%lu routes in instance %d\n", numRoutes, i);
451 #if 0
452         HexDump( route_set,
453                  sizeof( IPRouteEntry ) *
454                  snmpInfo.ipsi_numroutes );
455 #endif
456 
457         for( j = 0; j < numRoutes; j++ ) {
458             int routeNum = j + routesAdded;
459             out_route_table->routes[routeNum].dest =
460                 route_set[j].ire_dest;
461             out_route_table->routes[routeNum].mask =
462                 route_set[j].ire_mask;
463             out_route_table->routes[routeNum].gateway =
464                 route_set[j].ire_gw;
465             out_route_table->routes[routeNum].ifIndex =
466                 route_set[j].ire_index;
467             out_route_table->routes[routeNum].metric =
468                 route_set[j].ire_metric1;
469         }
470 
471         if( route_set ) tdiFreeThingSet( route_set );
472 
473         routesAdded += numRoutes;
474     }
475 
476     closeTcpFile( tcpFile );
477 
478     TRACE("status = 0x%08lx, out_route_table = 0x%p\n", status, out_route_table);
479 
480     return out_route_table;
481 }
482 
483 DWORD getNumArpEntries(void)
484 {
485     DWORD numEntities;
486     TDIEntityID *entitySet = NULL;
487     HANDLE tcpFile;
488     int i, totalNumber = 0;
489     NTSTATUS status;
490     PMIB_IPNETROW IpArpTable = NULL;
491     DWORD returnSize;
492 
493     TRACE("called.\n");
494 
495     status = openTcpFile( &tcpFile, FILE_READ_DATA );
496     if( !NT_SUCCESS(status) ) {
497         ERR("openTcpFile returned 0x%08lx\n", status);
498         return 0;
499     }
500 
501     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
502 
503     for( i = 0; i < numEntities; i++ ) {
504         if( isInterface( &entitySet[i] ) &&
505 	    hasArp( tcpFile, &entitySet[i] ) ) {
506 
507 	    status = tdiGetSetOfThings( tcpFile,
508 					INFO_CLASS_PROTOCOL,
509 					INFO_TYPE_PROVIDER,
510 					IP_MIB_ARPTABLE_ENTRY_ID,
511 					AT_ENTITY,
512 					entitySet[i].tei_instance,
513 					0,
514 					sizeof(MIB_IPNETROW),
515 					(PVOID *)&IpArpTable,
516 					&returnSize );
517 
518 	    if( status == STATUS_SUCCESS ) totalNumber += returnSize;
519 		if( IpArpTable ) {
520 			tdiFreeThingSet( IpArpTable );
521 			IpArpTable = NULL;
522 		}
523 	}
524     }
525 
526     closeTcpFile( tcpFile );
527     if( IpArpTable ) tdiFreeThingSet( IpArpTable );
528     if( entitySet ) tdiFreeThingSet( entitySet );
529     return totalNumber;
530 }
531 
532 PMIB_IPNETTABLE getArpTable(void)
533 {
534     DWORD numEntities, returnSize;
535     TDIEntityID *entitySet;
536     HANDLE tcpFile;
537     int i, totalNumber, TmpIdx, CurrIdx = 0;
538     NTSTATUS status;
539     PMIB_IPNETTABLE IpArpTable = NULL;
540     PMIB_IPNETROW AdapterArpTable = NULL;
541 
542     TRACE("called.\n");
543 
544     totalNumber = getNumArpEntries();
545 
546     status = openTcpFile( &tcpFile, FILE_READ_DATA );
547     if( !NT_SUCCESS(status) ) {
548         ERR("openTcpFile returned 0x%08lx\n", status);
549         return 0;
550     }
551 
552     IpArpTable = HeapAlloc
553 	( GetProcessHeap(), 0,
554 	  sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber) );
555     if (!IpArpTable) {
556         closeTcpFile(tcpFile);
557         return NULL;
558     }
559 
560     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
561 
562     for( i = 0; i < numEntities; i++ ) {
563         if( isInterface( &entitySet[i] ) &&
564 	    hasArp( tcpFile, &entitySet[i] ) ) {
565 
566 	    status = tdiGetSetOfThings( tcpFile,
567 					INFO_CLASS_PROTOCOL,
568 					INFO_TYPE_PROVIDER,
569 					IP_MIB_ARPTABLE_ENTRY_ID,
570 					AT_ENTITY,
571 					entitySet[i].tei_instance,
572 					0,
573 					sizeof(MIB_IPNETROW),
574 					(PVOID *)&AdapterArpTable,
575 					&returnSize );
576 
577             if( status == STATUS_SUCCESS ) {
578                 for( TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++ )
579                     IpArpTable->table[CurrIdx] = AdapterArpTable[TmpIdx];
580                 tdiFreeThingSet( AdapterArpTable );
581             }
582         }
583     }
584 
585     closeTcpFile( tcpFile );
586 
587     tdiFreeThingSet( entitySet );
588     IpArpTable->dwNumEntries = CurrIdx;
589 
590     return IpArpTable;
591 }
592 
593 struct _TABLE_CALL
594 {
595     DWORD TOIID;
596     SIZE_T UdpSize;
597     SIZE_T TcpSize;
598     SIZE_T UdpOffset;
599     SIZE_T TcpOffset;
600 } UdpTcpTableCall[] = {
601     {IP_MIB_ARPTABLE_ENTRY_ID, sizeof(MIB_UDPROW), sizeof(MIB_TCPROW), FIELD_OFFSET(MIB_UDPTABLE, table), FIELD_OFFSET(MIB_TCPTABLE, table)},
602     {IP_MIB_ADDRTABLE_ENTRY_ID, sizeof(MIB_UDPROW_OWNER_PID), sizeof(MIB_TCPROW_OWNER_PID), FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table), FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table)},
603     {IP_SPECIFIC_MODULE_ENTRY_ID, sizeof(MIB_UDPROW_OWNER_MODULE), sizeof(MIB_TCPROW_OWNER_MODULE), FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table), FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table)},
604 };
605 
606 #define Add2Ptr(PTR, INC) (PVOID)((ULONG_PTR)(PTR) + (INC))
607 
608 DWORD getNumUdpEntries(void)
609 {
610     DWORD numEntities;
611     TDIEntityID *entitySet = NULL;
612     HANDLE tcpFile;
613     int i, totalNumber = 0;
614     NTSTATUS status;
615     PMIB_UDPROW IpUdpTable = NULL;
616     DWORD returnSize;
617 
618     TRACE("called.\n");
619 
620     status = openTcpFile( &tcpFile, FILE_READ_DATA );
621     if( !NT_SUCCESS(status) ) {
622         ERR("openTcpFile returned 0x%08lx\n", status);
623         return 0;
624     }
625 
626     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
627 
628     for( i = 0; i < numEntities; i++ ) {
629         if( entitySet[i].tei_entity == CL_TL_ENTITY &&
630 	    hasArp( tcpFile, &entitySet[i] ) ) {
631 
632 	    status = tdiGetSetOfThings( tcpFile,
633 					INFO_CLASS_PROTOCOL,
634 					INFO_TYPE_PROVIDER,
635 					IP_MIB_ARPTABLE_ENTRY_ID,
636 					CL_TL_ENTITY,
637 					entitySet[i].tei_instance,
638 					0,
639 					sizeof(MIB_UDPROW),
640 					(PVOID *)&IpUdpTable,
641 					&returnSize );
642 
643 	    if( status == STATUS_SUCCESS ) totalNumber += returnSize;
644 		if( IpUdpTable ) {
645 			tdiFreeThingSet( IpUdpTable );
646 			IpUdpTable = NULL;
647 		}
648 	}
649     }
650 
651     closeTcpFile( tcpFile );
652     if( IpUdpTable ) tdiFreeThingSet( IpUdpTable );
653     if( entitySet ) tdiFreeThingSet( entitySet );
654     return totalNumber;
655 }
656 
657 PVOID getUdpTable(CLASS_TABLE Class)
658 {
659     DWORD numEntities, returnSize;
660     TDIEntityID *entitySet;
661     HANDLE tcpFile;
662     int i, totalNumber, TmpIdx, CurrIdx = 0;
663     NTSTATUS status;
664     PMIB_UDPTABLE IpUdpTable = NULL;
665     PVOID AdapterUdpTable = NULL;
666 
667     TRACE("called.\n");
668 
669     totalNumber = getNumUdpEntries();
670 
671     status = openTcpFile( &tcpFile, FILE_READ_DATA );
672     if( !NT_SUCCESS(status) ) {
673         ERR("openTcpFile returned 0x%08lx\n", status);
674         return 0;
675     }
676 
677     IpUdpTable = HeapAlloc
678 	( GetProcessHeap(), 0,
679 	  UdpTcpTableCall[Class].UdpOffset + (UdpTcpTableCall[Class].UdpSize * totalNumber) );
680     if (!IpUdpTable) {
681         closeTcpFile(tcpFile);
682         return NULL;
683     }
684 
685     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
686 
687     for( i = 0; i < numEntities; i++ ) {
688         if( entitySet[i].tei_entity == CL_TL_ENTITY &&
689 	    hasArp( tcpFile, &entitySet[i] ) ) {
690 
691 	    status = tdiGetSetOfThings( tcpFile,
692 					INFO_CLASS_PROTOCOL,
693 					INFO_TYPE_PROVIDER,
694 					UdpTcpTableCall[Class].TOIID,
695 					CL_TL_ENTITY,
696 					entitySet[i].tei_instance,
697 					0,
698 					UdpTcpTableCall[Class].UdpSize,
699 					&AdapterUdpTable,
700 					&returnSize );
701 
702             if( status == STATUS_SUCCESS ) {
703                 for( TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++ )
704                     CopyMemory(Add2Ptr(IpUdpTable, UdpTcpTableCall[Class].UdpOffset + UdpTcpTableCall[Class].UdpSize * CurrIdx),
705                                Add2Ptr(AdapterUdpTable, UdpTcpTableCall[Class].UdpSize * TmpIdx),
706                                UdpTcpTableCall[Class].UdpSize);
707                 tdiFreeThingSet( AdapterUdpTable );
708             }
709         }
710     }
711 
712     closeTcpFile( tcpFile );
713 
714     tdiFreeThingSet( entitySet );
715     IpUdpTable->dwNumEntries = CurrIdx;
716 
717     return IpUdpTable;
718 }
719 
720 DWORD getNumTcpEntries(void)
721 {
722     DWORD numEntities;
723     TDIEntityID *entitySet = NULL;
724     HANDLE tcpFile;
725     int i, totalNumber = 0;
726     NTSTATUS status;
727     PMIB_TCPROW IpTcpTable = NULL;
728     DWORD returnSize;
729 
730     TRACE("called.\n");
731 
732     status = openTcpFile( &tcpFile, FILE_READ_DATA );
733     if( !NT_SUCCESS(status) ) {
734         ERR("openTcpFile returned 0x%08lx\n", status);
735         return 0;
736     }
737 
738     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
739 
740     for( i = 0; i < numEntities; i++ ) {
741         if( entitySet[i].tei_entity == CO_TL_ENTITY &&
742 	    hasArp( tcpFile, &entitySet[i] ) ) {
743 
744 	    status = tdiGetSetOfThings( tcpFile,
745 					INFO_CLASS_PROTOCOL,
746 					INFO_TYPE_PROVIDER,
747 					IP_MIB_ARPTABLE_ENTRY_ID,
748 					CO_TL_ENTITY,
749 					entitySet[i].tei_instance,
750 					0,
751 					sizeof(MIB_TCPROW),
752 					(PVOID *)&IpTcpTable,
753 					&returnSize );
754 
755 	    if( status == STATUS_SUCCESS ) totalNumber += returnSize;
756 		if( IpTcpTable ) {
757 			tdiFreeThingSet( IpTcpTable );
758 			IpTcpTable = NULL;
759 		}
760 	}
761     }
762 
763     closeTcpFile( tcpFile );
764     if( IpTcpTable ) tdiFreeThingSet( IpTcpTable );
765     if( entitySet ) tdiFreeThingSet( entitySet );
766     return totalNumber;
767 }
768 
769 PVOID getTcpTable(CLASS_TABLE Class)
770 {
771     DWORD numEntities, returnSize;
772     TDIEntityID *entitySet;
773     HANDLE tcpFile;
774     int i, totalNumber, TmpIdx, CurrIdx = 0;
775     NTSTATUS status;
776     PMIB_TCPTABLE IpTcpTable = NULL;
777     PVOID AdapterTcpTable = NULL;
778 
779     TRACE("called.\n");
780 
781     totalNumber = getNumTcpEntries();
782 
783     status = openTcpFile( &tcpFile, FILE_READ_DATA );
784     if( !NT_SUCCESS(status) ) {
785         ERR("openTcpFile returned 0x%08lx\n", status);
786         return 0;
787     }
788 
789     IpTcpTable = HeapAlloc
790 	( GetProcessHeap(), 0,
791 	  UdpTcpTableCall[Class].TcpOffset + (UdpTcpTableCall[Class].TcpSize * totalNumber) );
792     if (!IpTcpTable) {
793         closeTcpFile(tcpFile);
794         return NULL;
795     }
796 
797     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
798 
799     for( i = 0; i < numEntities; i++ ) {
800         if( entitySet[i].tei_entity == CO_TL_ENTITY &&
801 	    hasArp( tcpFile, &entitySet[i] ) ) {
802 
803 	    status = tdiGetSetOfThings( tcpFile,
804 					INFO_CLASS_PROTOCOL,
805 					INFO_TYPE_PROVIDER,
806 					UdpTcpTableCall[Class].TOIID,
807 					CO_TL_ENTITY,
808 					entitySet[i].tei_instance,
809 					0,
810 					UdpTcpTableCall[Class].TcpSize,
811 					&AdapterTcpTable,
812 					&returnSize );
813 
814             if( status == STATUS_SUCCESS ) {
815                 for( TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++ )
816                     CopyMemory(Add2Ptr(IpTcpTable, UdpTcpTableCall[Class].TcpOffset + UdpTcpTableCall[Class].TcpSize * CurrIdx),
817                                Add2Ptr(AdapterTcpTable, UdpTcpTableCall[Class].TcpSize * TmpIdx),
818                                UdpTcpTableCall[Class].TcpSize);
819                 tdiFreeThingSet( AdapterTcpTable );
820             }
821         }
822     }
823 
824     closeTcpFile( tcpFile );
825 
826     tdiFreeThingSet( entitySet );
827     IpTcpTable->dwNumEntries = CurrIdx;
828 
829     return IpTcpTable;
830 }
831