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 && _strnicmp(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 && _strnicmp(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 
338   if (family != AF_INET && family != AF_INET6)
339     return ERROR_INVALID_PARAMETER;
340 
341   return NO_ERROR;
342 }
343 
344 DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family)
345 {
346   if (!stats)
347     return ERROR_INVALID_PARAMETER;
348 
349   if (family != AF_INET && family != AF_INET6)
350     return ERROR_INVALID_PARAMETER;
351 
352   return NO_ERROR;
353 }
354 
355 DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family)
356 {
357   if (!stats)
358     return ERROR_INVALID_PARAMETER;
359 
360   if (family != AF_INET && family != AF_INET6)
361     return ERROR_INVALID_PARAMETER;
362 
363   return NO_ERROR;
364 }
365 
366 DWORD getNumRoutes(void)
367 {
368     DWORD numEntities, numRoutes = 0;
369     TDIEntityID *entitySet;
370     HANDLE tcpFile;
371     int i;
372     NTSTATUS status;
373 
374     TRACE("called.\n");
375 
376     status = openTcpFile(&tcpFile, FILE_READ_DATA);
377     if (!NT_SUCCESS(status))
378     {
379         ERR("openTcpFile returned 0x%08lx\n", status);
380         return 0;
381     }
382 
383     status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
384     if (!NT_SUCCESS(status)) {
385         ERR("tdiGetEntityIDSet returned 0x%08lx\n", status);
386         closeTcpFile( tcpFile );
387         return 0;
388     }
389 
390     for (i = 0; i < numEntities; i++) {
391         if (isIpEntity(tcpFile, &entitySet[i])) {
392             IPSNMPInfo isnmp;
393             memset(&isnmp, 0, sizeof(isnmp));
394             status = tdiGetMibForIpEntity(tcpFile, &entitySet[i], &isnmp);
395             if (!NT_SUCCESS(status)) {
396                 ERR("tdiGetMibForIpEntity returned 0x%08lx, for i = %d\n", status, i);
397                 numRoutes = 0;
398                 break;
399             }
400             numRoutes += isnmp.ipsi_numroutes;
401         }
402     }
403 
404     TRACE("numRoutes = %lu\n", numRoutes);
405 
406     tdiFreeThingSet(entitySet);
407     closeTcpFile(tcpFile);
408 
409     return numRoutes;
410 }
411 
412 VOID HexDump( PCHAR Data, DWORD Len ) {
413     int i;
414 
415     for( i = 0; i < Len; i++ ) {
416         if( !(i & 0xf) ) {
417             if( i ) fprintf(stderr,"\n");
418             fprintf(stderr,"%08x:", i);
419         }
420         fprintf( stderr, " %02x", Data[i] & 0xff );
421     }
422     fprintf(stderr,"\n");
423 }
424 
425 RouteTable *getRouteTable(void)
426 {
427     RouteTable *out_route_table;
428     DWORD numRoutes = getNumRoutes(), routesAdded = 0;
429     TDIEntityID ent;
430     HANDLE tcpFile;
431     NTSTATUS status = openTcpFile(&tcpFile, FILE_READ_DATA);
432     int i;
433 
434     if (!NT_SUCCESS(status))
435         return 0;
436 
437     TRACE("GETTING ROUTE TABLE\n");
438 
439     out_route_table = HeapAlloc(GetProcessHeap(), 0,
440                                 sizeof(RouteTable) +
441                                 (sizeof(RouteEntry) * (numRoutes - 1)));
442     if (!out_route_table) {
443         closeTcpFile(tcpFile);
444         return NULL;
445     }
446 
447     out_route_table->numRoutes = numRoutes;
448 
449     for (i = 0; routesAdded < out_route_table->numRoutes; i++) {
450         int j;
451         IPRouteEntry *route_set;
452 
453         getNthIpEntity(tcpFile, i, &ent);
454 
455         tdiGetRoutesForIpEntity(tcpFile, &ent, &route_set, &numRoutes);
456         if (!route_set) {
457             closeTcpFile(tcpFile);
458             HeapFree(GetProcessHeap(), 0, out_route_table);
459             return 0;
460         }
461 
462         TRACE("%lu routes in instance %d\n", numRoutes, i);
463 #if 0
464         HexDump(route_set,
465                 sizeof(IPRouteEntry) *
466                 snmpInfo.ipsi_numroutes);
467 #endif
468 
469         for (j = 0; j < numRoutes; j++) {
470             int routeNum = j + routesAdded;
471             out_route_table->routes[routeNum].dest =
472                 route_set[j].ire_dest;
473             out_route_table->routes[routeNum].mask =
474                 route_set[j].ire_mask;
475             out_route_table->routes[routeNum].gateway =
476                 route_set[j].ire_gw;
477             out_route_table->routes[routeNum].ifIndex =
478                 route_set[j].ire_index;
479             out_route_table->routes[routeNum].metric =
480                 route_set[j].ire_metric1;
481         }
482 
483         if (route_set) tdiFreeThingSet(route_set);
484 
485         routesAdded += numRoutes;
486     }
487 
488     closeTcpFile(tcpFile);
489     TRACE("status = 0x%08lx, out_route_table = 0x%p\n", status, out_route_table);
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, FILE_READ_DATA);
506     if (!NT_SUCCESS(status))
507     {
508         ERR("openTcpFile returned 0x%08lx\n", 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]) && hasArp(tcpFile, &entitySet[i]))
516         {
517             status = tdiGetSetOfThings(tcpFile,
518                 INFO_CLASS_PROTOCOL,
519                 INFO_TYPE_PROVIDER,
520                 IP_MIB_ARPTABLE_ENTRY_ID,
521                 AT_ENTITY,
522                 entitySet[i].tei_instance,
523                 0,
524                 sizeof(MIB_IPNETROW),
525                 (PVOID *)&IpArpTable,
526                 &returnSize);
527 
528             if (status == STATUS_SUCCESS) totalNumber += returnSize;
529             if (IpArpTable) {
530                 tdiFreeThingSet(IpArpTable);
531                 IpArpTable = NULL;
532             }
533         }
534     }
535 
536     closeTcpFile(tcpFile);
537     if (entitySet) tdiFreeThingSet(entitySet);
538     return totalNumber;
539 }
540 
541 PMIB_IPNETTABLE getArpTable(void)
542 {
543     DWORD numEntities, returnSize;
544     TDIEntityID *entitySet;
545     HANDLE tcpFile;
546     int i, totalNumber, TmpIdx, CurrIdx = 0;
547     NTSTATUS status;
548     PMIB_IPNETTABLE IpArpTable = NULL;
549     PMIB_IPNETROW AdapterArpTable = NULL;
550 
551     TRACE("called.\n");
552 
553     totalNumber = getNumArpEntries();
554 
555     status = openTcpFile(&tcpFile, FILE_READ_DATA);
556     if (!NT_SUCCESS(status))
557     {
558         ERR("openTcpFile returned 0x%08lx\n", status);
559         return 0;
560     }
561 
562     IpArpTable = HeapAlloc(GetProcessHeap(), 0,
563         sizeof(DWORD) + (sizeof(MIB_IPNETROW) * totalNumber));
564     if (!IpArpTable) {
565         closeTcpFile(tcpFile);
566         return NULL;
567     }
568 
569     status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
570 
571     for (i = 0; i < numEntities; i++) {
572         if (isInterface(&entitySet[i]) && hasArp(tcpFile, &entitySet[i]))
573         {
574             status = tdiGetSetOfThings(tcpFile,
575                 INFO_CLASS_PROTOCOL,
576                 INFO_TYPE_PROVIDER,
577                 IP_MIB_ARPTABLE_ENTRY_ID,
578                 AT_ENTITY,
579                 entitySet[i].tei_instance,
580                 0,
581                 sizeof(MIB_IPNETROW),
582                 (PVOID *)&AdapterArpTable,
583                 &returnSize);
584 
585             if (status == STATUS_SUCCESS) {
586                 for (TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++)
587                     IpArpTable->table[CurrIdx] = AdapterArpTable[TmpIdx];
588                 tdiFreeThingSet(AdapterArpTable);
589             }
590         }
591     }
592 
593     closeTcpFile(tcpFile);
594     tdiFreeThingSet(entitySet);
595     IpArpTable->dwNumEntries = CurrIdx;
596     return IpArpTable;
597 }
598 
599 struct _TABLE_CALL
600 {
601     DWORD TOIID;
602     SIZE_T UdpSize;
603     SIZE_T TcpSize;
604     SIZE_T UdpOffset;
605     SIZE_T TcpOffset;
606 } UdpTcpTableCall[] = {
607     {IP_MIB_ARPTABLE_ENTRY_ID, sizeof(MIB_UDPROW), sizeof(MIB_TCPROW), FIELD_OFFSET(MIB_UDPTABLE, table), FIELD_OFFSET(MIB_TCPTABLE, table)},
608     {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)},
609     {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)},
610 };
611 
612 #define Add2Ptr(PTR, INC) (PVOID)((ULONG_PTR)(PTR) + (INC))
613 
614 DWORD getNumUdpEntries(void)
615 {
616     DWORD numEntities;
617     TDIEntityID *entitySet = NULL;
618     HANDLE tcpFile;
619     int i, totalNumber = 0;
620     NTSTATUS status;
621     PMIB_UDPROW IpUdpTable = NULL;
622     DWORD returnSize;
623 
624     TRACE("called.\n");
625 
626     status = openTcpFile(&tcpFile, FILE_READ_DATA);
627     if (!NT_SUCCESS(status))
628     {
629         ERR("openTcpFile returned 0x%08lx\n", status);
630         return 0;
631     }
632 
633     status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
634 
635     for (i = 0; i < numEntities; i++) {
636         if (entitySet[i].tei_entity == CL_TL_ENTITY && hasArp(tcpFile, &entitySet[i]))
637         {
638             status = tdiGetSetOfThings(tcpFile,
639                 INFO_CLASS_PROTOCOL,
640                 INFO_TYPE_PROVIDER,
641                 IP_MIB_ARPTABLE_ENTRY_ID,
642                 CL_TL_ENTITY,
643                 entitySet[i].tei_instance,
644                 0,
645                 sizeof(MIB_UDPROW),
646                 (PVOID *)&IpUdpTable,
647                 &returnSize);
648 
649             if (status == STATUS_SUCCESS) totalNumber += returnSize;
650             if (IpUdpTable) {
651                 tdiFreeThingSet(IpUdpTable);
652                 IpUdpTable = NULL;
653             }
654         }
655     }
656 
657     closeTcpFile(tcpFile);
658     if (entitySet) tdiFreeThingSet(entitySet);
659     return totalNumber;
660 }
661 
662 PVOID getUdpTable(CLASS_TABLE Class)
663 {
664     DWORD numEntities, returnSize;
665     TDIEntityID *entitySet;
666     HANDLE tcpFile;
667     int i, totalNumber, TmpIdx, CurrIdx = 0;
668     NTSTATUS status;
669     PMIB_UDPTABLE IpUdpTable = NULL;
670     PVOID AdapterUdpTable = NULL;
671 
672     TRACE("called.\n");
673 
674     totalNumber = getNumUdpEntries();
675 
676     status = openTcpFile(&tcpFile, FILE_READ_DATA);
677     if (!NT_SUCCESS(status))
678     {
679         ERR("openTcpFile returned 0x%08lx\n", status);
680         return 0;
681     }
682 
683     IpUdpTable = HeapAlloc(GetProcessHeap(), 0,
684         UdpTcpTableCall[Class].UdpOffset + (UdpTcpTableCall[Class].UdpSize * totalNumber));
685     if (!IpUdpTable) {
686         closeTcpFile(tcpFile);
687         return NULL;
688     }
689 
690     status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
691 
692     for (i = 0; i < numEntities; i++) {
693         if (entitySet[i].tei_entity == CL_TL_ENTITY && hasArp(tcpFile, &entitySet[i]))
694         {
695             status = tdiGetSetOfThings(tcpFile,
696                 INFO_CLASS_PROTOCOL,
697                 INFO_TYPE_PROVIDER,
698                 UdpTcpTableCall[Class].TOIID,
699                 CL_TL_ENTITY,
700                 entitySet[i].tei_instance,
701                 0,
702                 UdpTcpTableCall[Class].UdpSize,
703                 &AdapterUdpTable,
704                 &returnSize);
705 
706             if (status == STATUS_SUCCESS) {
707                 for (TmpIdx = 0; TmpIdx < returnSize; TmpIdx++, CurrIdx++)
708                     CopyMemory(Add2Ptr(IpUdpTable, UdpTcpTableCall[Class].UdpOffset + UdpTcpTableCall[Class].UdpSize * CurrIdx),
709                                Add2Ptr(AdapterUdpTable, UdpTcpTableCall[Class].UdpSize * TmpIdx),
710                                UdpTcpTableCall[Class].UdpSize);
711                 tdiFreeThingSet(AdapterUdpTable);
712             }
713         }
714     }
715 
716     closeTcpFile(tcpFile);
717     tdiFreeThingSet(entitySet);
718     IpUdpTable->dwNumEntries = CurrIdx;
719     return IpUdpTable;
720 }
721 
722 DWORD getNumTcpEntries(void)
723 {
724     DWORD numEntities;
725     TDIEntityID *entitySet = NULL;
726     HANDLE tcpFile;
727     int i, totalNumber = 0;
728     NTSTATUS status;
729     PMIB_TCPROW IpTcpTable = NULL;
730     DWORD returnSize;
731 
732     TRACE("called.\n");
733 
734     status = openTcpFile(&tcpFile, FILE_READ_DATA);
735     if (!NT_SUCCESS(status))
736     {
737         ERR("openTcpFile returned 0x%08lx\n", status);
738         return 0;
739     }
740 
741     status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
742 
743     for (i = 0; i < numEntities; i++) {
744         if (entitySet[i].tei_entity == CO_TL_ENTITY && hasArp(tcpFile, &entitySet[i]))
745         {
746             status = tdiGetSetOfThings(tcpFile,
747                 INFO_CLASS_PROTOCOL,
748                 INFO_TYPE_PROVIDER,
749                 IP_MIB_ARPTABLE_ENTRY_ID,
750                 CO_TL_ENTITY,
751                 entitySet[i].tei_instance,
752                 0,
753                 sizeof(MIB_TCPROW),
754                 (PVOID *)&IpTcpTable,
755                 &returnSize);
756 
757             if (status == STATUS_SUCCESS) totalNumber += returnSize;
758             if (IpTcpTable) {
759                 tdiFreeThingSet(IpTcpTable);
760                 IpTcpTable = NULL;
761             }
762         }
763     }
764 
765     closeTcpFile(tcpFile);
766     if (entitySet) tdiFreeThingSet(entitySet);
767     return totalNumber;
768 }
769 
770 PVOID getTcpTable(CLASS_TABLE Class)
771 {
772     DWORD numEntities, returnSize;
773     TDIEntityID *entitySet;
774     HANDLE tcpFile;
775     int i, totalNumber, TmpIdx, CurrIdx = 0;
776     NTSTATUS status;
777     PMIB_TCPTABLE IpTcpTable = NULL;
778     PVOID AdapterTcpTable = NULL;
779 
780     TRACE("called.\n");
781 
782     totalNumber = getNumTcpEntries();
783 
784     status = openTcpFile(&tcpFile, FILE_READ_DATA);
785     if (!NT_SUCCESS(status))
786     {
787         ERR("openTcpFile returned 0x%08lx\n", status);
788         return 0;
789     }
790 
791     IpTcpTable = HeapAlloc(GetProcessHeap(), 0,
792         UdpTcpTableCall[Class].TcpOffset + (UdpTcpTableCall[Class].TcpSize * totalNumber));
793     if (!IpTcpTable) {
794         closeTcpFile(tcpFile);
795         return NULL;
796     }
797 
798     status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
799 
800     for (i = 0; i < numEntities; i++) {
801         if (entitySet[i].tei_entity == CO_TL_ENTITY && 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     tdiFreeThingSet(entitySet);
826     IpTcpTable->dwNumEntries = CurrIdx;
827     return IpTcpTable;
828 }
829