Create a branch for network fixes.
[reactos.git] / dll / win32 / iphlpapi / ifenum_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 * Implementation notes
19 * - Our bretheren use IOCTL_TCP_QUERY_INFORMATION_EX to get information
20 * from tcpip.sys and IOCTL_TCP_SET_INFORMATION_EX to set info (such as
21 * the route table). These ioctls mirror WsControl exactly in usage.
22 * - This iphlpapi does not rely on any reactos-only features.
23 * - This implementation is meant to be largely correct. I am not, however,
24 * paying any attention to performance. It can be done faster, and
25 * someone should definately optimize this code when speed is more of a
26 * priority than it is now.
27 *
28 * Edited implementation notes from the original -- Basically edited to add
29 * information and prune things which are not accurate about this file.
30 * Interface index fun:
31 * - Windows may rely on an index being cleared in the topmost 8 bits in some
32 * APIs; see GetFriendlyIfIndex and the mention of "backward compatible"
33 * indexes. It isn't clear which APIs might fail with non-backward-compatible
34 * indexes, but I'll keep them bits clear just in case.
35 * FIXME:
36 * - We don't support IPv6 addresses here yet -- I moved the upper edge
37 * functions into iphlpv6.c (arty)
38 */
39 #include "iphlpapi_private.h"
40 #include "ifenum.h"
41 #include <assert.h>
42
43 //#define NDEBUG
44 #include "debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
47
48 /* Globals */
49 const PWCHAR TcpFileName = L"\\Device\\Tcp";
50
51 /* Functions */
52
53 /* I'm a bit skittish about maintaining this info in memory, as I'd rather
54 * not add any mutex or critical section blockers to these functions. I've
55 * encountered far too many windows functions that contribute to deadlock
56 * by not announcing themselves. */
57 void interfaceMapInit(void)
58 {
59 /* For now, nothing */
60 }
61
62 void interfaceMapFree(void)
63 {
64 /* Ditto. */
65 }
66
67 NTSTATUS openTcpFile(PHANDLE tcpFile) {
68 UNICODE_STRING fileName;
69 OBJECT_ATTRIBUTES objectAttributes;
70 IO_STATUS_BLOCK ioStatusBlock;
71 NTSTATUS status;
72
73 TRACE("called.\n");
74
75 /* Shamelessly ripped from CreateFileW */
76 RtlInitUnicodeString( &fileName, TcpFileName );
77
78 InitializeObjectAttributes( &objectAttributes,
79 &fileName,
80 OBJ_CASE_INSENSITIVE,
81 NULL,
82 NULL );
83
84 status = ZwCreateFile( tcpFile,
85 SYNCHRONIZE | GENERIC_EXECUTE |
86 GENERIC_READ | GENERIC_WRITE,
87 &objectAttributes,
88 &ioStatusBlock,
89 NULL,
90 FILE_ATTRIBUTE_NORMAL,
91 FILE_SHARE_READ | FILE_SHARE_WRITE,
92 FILE_OPEN_IF,
93 FILE_SYNCHRONOUS_IO_NONALERT,
94 0,
95 0 );
96
97 /* String does not need to be freed: it points to the constant
98 * string we provided */
99
100 if (!NT_SUCCESS(status)) {
101 ERR("openTcpFile for <%wZ> failed: 0x%lx\n", &fileName, status);
102 *tcpFile = INVALID_HANDLE_VALUE;
103 }
104
105 return status;
106 }
107
108 void closeTcpFile( HANDLE h ) {
109 TRACE("called.\n");
110 ASSERT(h != INVALID_HANDLE_VALUE);
111 ZwClose( h );
112 }
113
114 /* A generic thing-getting function which interacts in the right way with
115 * TDI. This may seem oblique, but I'm using it to reduce code and hopefully
116 * make this thing easier to debug.
117 *
118 * The things returned can be any of:
119 * TDIEntityID
120 * TDIObjectID
121 * IFEntry
122 * IPSNMPInfo
123 * IPAddrEntry
124 * IPInterfaceInfo
125 */
126 NTSTATUS tdiGetSetOfThings( HANDLE tcpFile,
127 DWORD toiClass,
128 DWORD toiType,
129 DWORD toiId,
130 DWORD teiEntity,
131 DWORD teiInstance,
132 DWORD fixedPart,
133 DWORD entrySize,
134 PVOID *tdiEntitySet,
135 PDWORD numEntries ) {
136 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
137 PVOID entitySet = 0;
138 NTSTATUS status = STATUS_SUCCESS;
139 DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES,
140 arraySize = entrySize * MAX_TDI_ENTITIES;
141
142 TRACE("TdiGetSetOfThings(tcpFile %x,toiClass %x,toiType %x,toiId %x,"
143 "teiEntity %x,fixedPart %d,entrySize %d)\n",
144 (int)tcpFile,
145 (int)toiClass,
146 (int)toiType,
147 (int)toiId,
148 (int)teiEntity,
149 (int)fixedPart,
150 (int)entrySize );
151
152 req.ID.toi_class = toiClass;
153 req.ID.toi_type = toiType;
154 req.ID.toi_id = toiId;
155 req.ID.toi_entity.tei_entity = teiEntity;
156 req.ID.toi_entity.tei_instance = teiInstance;
157
158 /* There's a subtle problem here...
159 * If an interface is added at this exact instant, (as if by a PCMCIA
160 * card insertion), the array will still not have enough entries after
161 * have allocated it after the first DeviceIoControl call.
162 *
163 * We'll get around this by repeating until the number of interfaces
164 * stabilizes.
165 */
166 do {
167 assert( !entitySet ); /* We must not have an entity set allocated */
168 status = DeviceIoControl( tcpFile,
169 IOCTL_TCP_QUERY_INFORMATION_EX,
170 &req,
171 sizeof(req),
172 0,
173 0,
174 &allocationSizeForEntityArray,
175 NULL );
176
177 if(!NT_SUCCESS(status))
178 {
179 ERR("IOCTL Failed\n");
180 return STATUS_UNSUCCESSFUL;
181 }
182
183 arraySize = allocationSizeForEntityArray;
184 entitySet = HeapAlloc( GetProcessHeap(), 0, arraySize );
185
186 if( !entitySet ) {
187 status = STATUS_INSUFFICIENT_RESOURCES;
188 WARN("TdiGetSetOfThings() => %08x\n", (int)status);
189 return status;
190 }
191
192 status = DeviceIoControl( tcpFile,
193 IOCTL_TCP_QUERY_INFORMATION_EX,
194 &req,
195 sizeof(req),
196 entitySet,
197 arraySize,
198 &allocationSizeForEntityArray,
199 NULL );
200
201 /* This is why we have the loop -- we might have added an adapter */
202 if( arraySize == allocationSizeForEntityArray )
203 break;
204
205 HeapFree( GetProcessHeap(), 0, entitySet );
206 entitySet = 0;
207
208 if(!status)
209 {
210 WARN("IOCTL Failed\n");
211 return STATUS_UNSUCCESSFUL;
212 }
213
214 WARN("TdiGetSetOfThings(): Array changed size: %d -> %d.\n",
215 arraySize, allocationSizeForEntityArray );
216 } while( TRUE ); /* We break if the array we received was the size we
217 * expected. Therefore, we got here because it wasn't */
218
219 *numEntries = (arraySize - fixedPart) / entrySize;
220 *tdiEntitySet = entitySet;
221
222 WARN("TdiGetSetOfThings() => Success: %d things @ %08x\n",
223 (int)*numEntries, (int)entitySet);
224
225 return STATUS_SUCCESS;
226 }
227
228 VOID tdiFreeThingSet( PVOID things ) {
229 HeapFree( GetProcessHeap(), 0, things );
230 }
231
232 NTSTATUS tdiGetMibForIfEntity
233 ( HANDLE tcpFile, TDIEntityID *ent, IFEntrySafelySized *entry ) {
234 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
235 NTSTATUS status = STATUS_SUCCESS;
236 DWORD returnSize;
237
238 WARN("TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n",
239 (int)tcpFile, (int)ent->tei_instance);
240
241 req.ID.toi_class = INFO_CLASS_PROTOCOL;
242 req.ID.toi_type = INFO_TYPE_PROVIDER;
243 req.ID.toi_id = IF_MIB_STATS_ID;
244 req.ID.toi_entity = *ent;
245
246 status = DeviceIoControl( tcpFile,
247 IOCTL_TCP_QUERY_INFORMATION_EX,
248 &req,
249 sizeof(req),
250 entry,
251 sizeof(*entry),
252 &returnSize,
253 NULL );
254
255 if(!status)
256 {
257 WARN("IOCTL Failed\n");
258 return STATUS_UNSUCCESSFUL;
259 }
260
261 TRACE("TdiGetMibForIfEntity() => {\n"
262 " if_index ....................... %x\n"
263 " if_type ........................ %x\n"
264 " if_mtu ......................... %d\n"
265 " if_speed ....................... %x\n"
266 " if_physaddrlen ................. %d\n",
267 entry->ent.if_index,
268 entry->ent.if_type,
269 entry->ent.if_mtu,
270 entry->ent.if_speed,
271 entry->ent.if_physaddrlen);
272 TRACE(" if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n"
273 " if_descr ....................... %s\n",
274 entry->ent.if_physaddr[0] & 0xff,
275 entry->ent.if_physaddr[1] & 0xff,
276 entry->ent.if_physaddr[2] & 0xff,
277 entry->ent.if_physaddr[3] & 0xff,
278 entry->ent.if_physaddr[4] & 0xff,
279 entry->ent.if_physaddr[5] & 0xff,
280 entry->ent.if_descr);
281 TRACE("} status %08x\n",status);
282
283 return status;
284 }
285
286 NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile,
287 TDIEntityID **entitySet,
288 PDWORD numEntities ) {
289 NTSTATUS status = tdiGetSetOfThings( tcpFile,
290 INFO_CLASS_GENERIC,
291 INFO_TYPE_PROVIDER,
292 ENTITY_LIST_ID,
293 GENERIC_ENTITY,
294 0,
295 0,
296 sizeof(TDIEntityID),
297 (PVOID *)entitySet,
298 numEntities );
299 if( NT_SUCCESS(status) ) {
300 int i;
301
302 for( i = 0; i < *numEntities; i++ ) {
303 TRACE("%-4d: %04x:%08x\n",
304 i,
305 (*entitySet)[i].tei_entity,
306 (*entitySet)[i].tei_instance );
307 }
308 }
309
310 return status;
311 }
312
313 BOOL isInterface( TDIEntityID *if_maybe ) {
314 return
315 if_maybe->tei_entity == IF_ENTITY;
316 }
317
318 static BOOL isLoopback( HANDLE tcpFile, TDIEntityID *loop_maybe ) {
319 IFEntrySafelySized entryInfo;
320 NTSTATUS status;
321
322 status = tdiGetMibForIfEntity( tcpFile,
323 loop_maybe,
324 &entryInfo );
325
326 return NT_SUCCESS(status) && (!entryInfo.ent.if_type ||
327 entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
328 }
329
330 NTSTATUS tdiGetEntityType( HANDLE tcpFile, TDIEntityID *ent, PULONG type ) {
331 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
332 NTSTATUS status = STATUS_SUCCESS;
333 DWORD returnSize;
334
335 TRACE("TdiGetEntityType(tcpFile %x,entityId %x)\n",
336 (DWORD)tcpFile, ent->tei_instance);
337
338 req.ID.toi_class = INFO_CLASS_GENERIC;
339 req.ID.toi_type = INFO_TYPE_PROVIDER;
340 req.ID.toi_id = ENTITY_TYPE_ID;
341 req.ID.toi_entity.tei_entity = ent->tei_entity;
342 req.ID.toi_entity.tei_instance = ent->tei_instance;
343
344 status = DeviceIoControl( tcpFile,
345 IOCTL_TCP_QUERY_INFORMATION_EX,
346 &req,
347 sizeof(req),
348 type,
349 sizeof(*type),
350 &returnSize,
351 NULL );
352
353 TRACE("TdiGetEntityType() => %08x %08x\n", *type, status);
354
355 return (status ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
356 }
357
358 BOOL hasArp( HANDLE tcpFile, TDIEntityID *arp_maybe ) {
359 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
360 NTSTATUS status = STATUS_SUCCESS;
361 DWORD returnSize, type;
362
363 req.ID.toi_class = INFO_CLASS_GENERIC;
364 req.ID.toi_type = INFO_TYPE_PROVIDER;
365 req.ID.toi_id = ENTITY_TYPE_ID;
366 req.ID.toi_entity.tei_entity = AT_ENTITY;
367 req.ID.toi_entity.tei_instance = arp_maybe->tei_instance;
368
369 status = DeviceIoControl( tcpFile,
370 IOCTL_TCP_QUERY_INFORMATION_EX,
371 &req,
372 sizeof(req),
373 &type,
374 sizeof(type),
375 &returnSize,
376 NULL );
377
378 if( !NT_SUCCESS(status) ) return FALSE;
379 return type == AT_ENTITY;
380 }
381
382 static NTSTATUS getInterfaceInfoSet( HANDLE tcpFile,
383 IFInfo **infoSet,
384 PDWORD numInterfaces ) {
385 DWORD numEntities;
386 TDIEntityID *entIDSet = 0;
387 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entIDSet, &numEntities );
388 IFInfo *infoSetInt = 0;
389 BOOL interfaceInfoComplete;
390 int curInterf = 0, i;
391
392 if (!NT_SUCCESS(status)) {
393 ERR("getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n", status);
394 return status;
395 }
396
397 infoSetInt = HeapAlloc( GetProcessHeap(), 0,
398 sizeof(IFInfo) * numEntities );
399
400 if( infoSetInt ) {
401 for( i = 0; i < numEntities; i++ ) {
402 if( isInterface( &entIDSet[i] ) ) {
403 infoSetInt[curInterf].entity_id = entIDSet[i];
404 status = tdiGetMibForIfEntity
405 ( tcpFile,
406 &entIDSet[i],
407 &infoSetInt[curInterf].if_info );
408 TRACE("tdiGetMibForIfEntity: %08x\n", status);
409 if( NT_SUCCESS(status) ) {
410 DWORD numAddrs;
411 IPAddrEntry *addrs;
412 TDIEntityID ip_ent;
413 int j;
414
415 interfaceInfoComplete = FALSE;
416 status = getNthIpEntity( tcpFile, 0, &ip_ent );
417 if( NT_SUCCESS(status) )
418 status = tdiGetIpAddrsForIpEntity
419 ( tcpFile, &ip_ent, &addrs, &numAddrs );
420 for( j = 0; j < numAddrs && NT_SUCCESS(status); j++ ) {
421 TRACE("ADDR %d: index %d (target %d)\n", j, addrs[j].iae_index, infoSetInt[curInterf].if_info.ent.if_index);
422 if( addrs[j].iae_index ==
423 infoSetInt[curInterf].if_info.ent.if_index ) {
424 memcpy( &infoSetInt[curInterf].ip_addr,
425 &addrs[j],
426 sizeof( addrs[j] ) );
427 curInterf++;
428 break;
429 }
430 }
431 }
432 }
433 }
434
435 if (NT_SUCCESS(status)) {
436 *infoSet = infoSetInt;
437 *numInterfaces = curInterf;
438 } else {
439 HeapFree(GetProcessHeap(), 0, infoSetInt);
440 }
441
442 return status;
443 } else {
444 return STATUS_INSUFFICIENT_RESOURCES;
445 }
446 }
447
448 static DWORD getNumInterfacesInt(BOOL onlyNonLoopback)
449 {
450 DWORD numEntities, numInterfaces = 0;
451 TDIEntityID *entitySet;
452 HANDLE tcpFile;
453 NTSTATUS status;
454 int i;
455
456 status = openTcpFile( &tcpFile );
457
458 if( !NT_SUCCESS(status) ) {
459 WARN("getNumInterfaces: failed %08x\n", status );
460 return 0;
461 }
462
463 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
464
465 if( !NT_SUCCESS(status) ) {
466 WARN("getNumInterfaces: failed %08x\n", status );
467 closeTcpFile( tcpFile );
468 return 0;
469 }
470
471 for( i = 0; i < numEntities; i++ ) {
472 if( isInterface( &entitySet[i] ) &&
473 (!onlyNonLoopback ||
474 (onlyNonLoopback && !isLoopback( tcpFile, &entitySet[i] ))) )
475 numInterfaces++;
476 }
477
478 TRACE("getNumInterfaces: success: %d %d %08x\n",
479 onlyNonLoopback, numInterfaces, status );
480
481 closeTcpFile( tcpFile );
482
483 tdiFreeThingSet( entitySet );
484
485 return numInterfaces;
486 }
487
488 DWORD getNumInterfaces(void)
489 {
490 return getNumInterfacesInt( FALSE );
491 }
492
493 DWORD getNumNonLoopbackInterfaces(void)
494 {
495 return getNumInterfacesInt( TRUE );
496 }
497
498 DWORD getNthInterfaceEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
499 DWORD numEntities = 0;
500 DWORD numInterfaces = 0;
501 TDIEntityID *entitySet = 0;
502 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
503 int i;
504
505 if( !NT_SUCCESS(status) )
506 return status;
507
508 for( i = 0; i < numEntities; i++ ) {
509 if( isInterface( &entitySet[i] ) ) {
510 if( numInterfaces == index ) break;
511 else numInterfaces++;
512 }
513 }
514
515 TRACE("Index %d is entity #%d - %04x:%08x\n", index, i,
516 entitySet[i].tei_entity, entitySet[i].tei_instance );
517
518 if( numInterfaces == index && i < numEntities ) {
519 memcpy( ent, &entitySet[i], sizeof(*ent) );
520 tdiFreeThingSet( entitySet );
521 return STATUS_SUCCESS;
522 } else {
523 tdiFreeThingSet( entitySet );
524 return STATUS_UNSUCCESSFUL;
525 }
526 }
527
528 NTSTATUS getInterfaceInfoByIndex( HANDLE tcpFile, DWORD index, IFInfo *info ) {
529 IFInfo *ifInfo;
530 DWORD numInterfaces;
531 NTSTATUS status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
532 int i;
533
534 if( NT_SUCCESS(status) )
535 for( i = 0; i < numInterfaces; i++ ) {
536 if( ifInfo[i].if_info.ent.if_index == index ) {
537 memcpy( info, &ifInfo[i], sizeof(*info) );
538 break;
539 }
540 }
541
542 if( NT_SUCCESS(status) )
543 return i < numInterfaces ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
544 else
545 return status;
546 }
547
548 NTSTATUS getInterfaceInfoByName( HANDLE tcpFile, char *name, IFInfo *info ) {
549 IFInfo *ifInfo;
550 DWORD numInterfaces;
551 int i;
552 NTSTATUS status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
553
554 if( NT_SUCCESS(status) )
555 for( i = 0; i < numInterfaces; i++ ) {
556 if( !strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name) ) {
557 memcpy( info, &ifInfo[i], sizeof(*info) );
558 break;
559 }
560 }
561
562 if( NT_SUCCESS(status) )
563 return i < numInterfaces ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
564 else
565 return status;
566 }
567
568 /* Note that the result of this operation must be freed later */
569
570 const char *getInterfaceNameByIndex(DWORD index)
571 {
572 IFInfo ifInfo;
573 HANDLE tcpFile;
574 char *interfaceName = 0, *adapter_name = 0;
575 NTSTATUS status = openTcpFile( &tcpFile );
576
577 if( NT_SUCCESS(status) ) {
578 status = getInterfaceInfoByIndex( tcpFile, index, &ifInfo );
579
580 if( NT_SUCCESS(status) ) {
581 adapter_name = (char *)ifInfo.if_info.ent.if_descr;
582
583 interfaceName = HeapAlloc( GetProcessHeap(), 0,
584 strlen(adapter_name) + 1 );
585 strcpy( interfaceName, adapter_name );
586 }
587
588 closeTcpFile( tcpFile );
589 }
590
591 return interfaceName;
592 }
593
594 void consumeInterfaceName(const char *name) {
595 HeapFree( GetProcessHeap(), 0, (char *)name );
596 }
597
598 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
599 {
600 IFInfo ifInfo;
601 HANDLE tcpFile;
602 NTSTATUS status = openTcpFile( &tcpFile );
603
604 if( NT_SUCCESS(status) ) {
605 status = getInterfaceInfoByName( tcpFile, (char *)name, &ifInfo );
606
607 if( NT_SUCCESS(status) ) {
608 *index = ifInfo.if_info.ent.if_index;
609 }
610
611 closeTcpFile( tcpFile );
612 }
613
614 return status;
615 }
616
617 InterfaceIndexTable *getInterfaceIndexTableInt( BOOL nonLoopbackOnly ) {
618 DWORD numInterfaces, curInterface = 0;
619 int i;
620 IFInfo *ifInfo;
621 InterfaceIndexTable *ret = 0;
622 HANDLE tcpFile;
623 NTSTATUS status = openTcpFile( &tcpFile );
624
625 if( NT_SUCCESS(status) ) {
626 status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
627
628 TRACE("InterfaceInfoSet: %08x, %04x:%08x\n",
629 status,
630 ifInfo->entity_id.tei_entity,
631 ifInfo->entity_id.tei_instance);
632
633 if( NT_SUCCESS(status) ) {
634 ret = (InterfaceIndexTable *)
635 calloc(1,
636 sizeof(InterfaceIndexTable) +
637 (numInterfaces - 1) * sizeof(DWORD));
638
639 if (ret) {
640 ret->numAllocated = numInterfaces;
641 TRACE("NumInterfaces = %d\n", numInterfaces);
642
643 for( i = 0; i < numInterfaces; i++ ) {
644 TRACE("Examining interface %d\n", i);
645 if( !nonLoopbackOnly ||
646 !isLoopback( tcpFile, &ifInfo[i].entity_id ) ) {
647 TRACE("Interface %d matches (%d)\n", i, curInterface);
648 ret->indexes[curInterface++] =
649 ifInfo[i].if_info.ent.if_index;
650 }
651 }
652
653 ret->numIndexes = curInterface;
654 }
655
656 tdiFreeThingSet( ifInfo );
657 }
658 closeTcpFile( tcpFile );
659 }
660
661 return ret;
662 }
663
664 InterfaceIndexTable *getInterfaceIndexTable(void) {
665 return getInterfaceIndexTableInt( FALSE );
666 }
667
668 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) {
669 return getInterfaceIndexTableInt( TRUE );
670 }
671
672 DWORD getInterfaceIPAddrByName(const char *name)
673 {
674 return INADDR_ANY;
675 }
676
677 NTSTATUS getIPAddrEntryForIf(HANDLE tcpFile,
678 char *name,
679 DWORD index,
680 IFInfo *ifInfo) {
681 NTSTATUS status =
682 name ?
683 getInterfaceInfoByName( tcpFile, name, ifInfo ) :
684 getInterfaceInfoByIndex( tcpFile, index, ifInfo );
685
686 if (!NT_SUCCESS(status)) {
687 ERR("getIPAddrEntryForIf returning %lx\n", status);
688 }
689
690 return status;
691 }
692
693 DWORD getAddrByIndexOrName( char *name, DWORD index, IPHLPAddrType addrType ) {
694 IFInfo ifInfo;
695 HANDLE tcpFile;
696 NTSTATUS status = STATUS_SUCCESS;
697 DWORD addrOut = INADDR_ANY;
698
699 status = openTcpFile( &tcpFile );
700
701 if( NT_SUCCESS(status) ) {
702 status = getIPAddrEntryForIf( tcpFile, name, index, &ifInfo );
703 if( NT_SUCCESS(status) ) {
704 switch( addrType ) {
705 case IPAAddr: addrOut = ifInfo.ip_addr.iae_addr; break;
706 case IPABcast: addrOut = ifInfo.ip_addr.iae_bcastaddr; break;
707 case IPAMask: addrOut = ifInfo.ip_addr.iae_mask; break;
708 case IFMtu: addrOut = ifInfo.if_info.ent.if_mtu; break;
709 case IFStatus: addrOut = ifInfo.if_info.ent.if_operstatus; break;
710 }
711 }
712 closeTcpFile( tcpFile );
713 }
714
715 return addrOut;
716 }
717
718 DWORD getInterfaceIPAddrByIndex(DWORD index) {
719 return getAddrByIndexOrName( 0, index, IPAAddr );
720 }
721
722 DWORD getInterfaceBCastAddrByName(const char *name) {
723 return getAddrByIndexOrName( (char *)name, 0, IPABcast );
724 }
725
726 DWORD getInterfaceBCastAddrByIndex(DWORD index) {
727 return getAddrByIndexOrName( 0, index, IPABcast );
728 }
729
730 DWORD getInterfaceMaskByName(const char *name) {
731 return getAddrByIndexOrName( (char *)name, 0, IPAMask );
732 }
733
734 DWORD getInterfaceMaskByIndex(DWORD index) {
735 return getAddrByIndexOrName( 0, index, IPAMask );
736 }
737
738 void getInterfacePhysicalFromInfo( IFInfo *info,
739 PDWORD len, PBYTE addr, PDWORD type ) {
740 *len = info->if_info.ent.if_physaddrlen;
741 memcpy( addr, info->if_info.ent.if_physaddr, *len );
742 *type = info->if_info.ent.if_type;
743 }
744
745 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
746 PDWORD type)
747 {
748 HANDLE tcpFile;
749 IFInfo info;
750 NTSTATUS status = openTcpFile( &tcpFile );
751
752 if( NT_SUCCESS(status) ) {
753 status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
754 if( NT_SUCCESS(status) )
755 getInterfacePhysicalFromInfo( &info, len, addr, type );
756 closeTcpFile( tcpFile );
757 }
758
759 return status;
760 }
761
762 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
763 PDWORD type)
764 {
765 HANDLE tcpFile;
766 IFInfo info;
767 NTSTATUS status = openTcpFile( &tcpFile );
768
769 if( NT_SUCCESS(status) ) {
770 status = getInterfaceInfoByIndex( tcpFile, index, &info );
771 if( NT_SUCCESS(status) )
772 getInterfacePhysicalFromInfo( &info, len, addr, type );
773 closeTcpFile( tcpFile );
774 }
775
776 return status;
777 }
778
779 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) {
780 *mtu = getAddrByIndexOrName( (char *)name, 0, IFMtu );
781 return STATUS_SUCCESS;
782 }
783
784 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu) {
785 *mtu = getAddrByIndexOrName( 0, index, IFMtu );
786 return STATUS_SUCCESS;
787 }
788
789 DWORD getInterfaceStatusByName(const char *name, PDWORD status) {
790 *status = getAddrByIndexOrName( (char *)name, 0, IFStatus );
791 return STATUS_SUCCESS;
792 }
793
794 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
795 {
796 *status = getAddrByIndexOrName( 0, index, IFStatus );
797 return STATUS_SUCCESS;
798 }
799
800 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
801 {
802 HANDLE tcpFile;
803 IFInfo info;
804 NTSTATUS status = openTcpFile( &tcpFile );
805
806 TRACE("Called.\n");
807
808 if( NT_SUCCESS(status) ) {
809 status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
810
811 if( NT_SUCCESS(status) ) {
812 memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
813 &info.if_info,
814 sizeof(info.if_info) );
815 }
816
817 TRACE("entry->bDescr = %s\n", entry->bDescr);
818
819 closeTcpFile( tcpFile );
820 }
821
822 return status;
823 }
824
825 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
826 {
827 HANDLE tcpFile;
828 IFInfo info;
829 NTSTATUS status = openTcpFile( &tcpFile );
830
831 TRACE("Called.\n");
832
833 if( NT_SUCCESS(status) ) {
834 status = getInterfaceInfoByIndex( tcpFile, index, &info );
835
836 if( NT_SUCCESS(status) ) {
837 memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
838 &info.if_info,
839 sizeof(info.if_info) );
840 }
841
842 closeTcpFile( tcpFile );
843 }
844
845 return status;
846 }
847
848 char *toIPAddressString(unsigned int addr, char string[16])
849 {
850 if (string) {
851 struct in_addr iAddr;
852
853 iAddr.s_addr = addr;
854 /* extra-anal, just to make auditors happy */
855 strncpy(string, inet_ntoa(iAddr), 16);
856 string[16] = '\0';
857 }
858 return string;
859 }
860
861 NTSTATUS addIPAddress( IPAddr Address, IPMask Mask, DWORD IfIndex,
862 PULONG NteContext, PULONG NteInstance )
863 {
864 HANDLE tcpFile;
865 NTSTATUS status = openTcpFile( &tcpFile );
866 IP_SET_DATA Data;
867 IO_STATUS_BLOCK Iosb;
868
869 TRACE("Called.\n");
870
871 if( !NT_SUCCESS(status) ) return status;
872
873 Data.NteContext = IfIndex;
874 Data.NewAddress = Address;
875 Data.NewNetmask = Mask;
876
877 status = NtDeviceIoControlFile( tcpFile,
878 NULL,
879 NULL,
880 NULL,
881 &Iosb,
882 IOCTL_SET_IP_ADDRESS,
883 &Data,
884 sizeof(Data),
885 &Data,
886 sizeof(Data) );
887
888 closeTcpFile( tcpFile );
889
890 if( NT_SUCCESS(status) ) {
891 *NteContext = Iosb.Information;
892 *NteInstance = Data.NewAddress;
893 }
894
895 if (!NT_SUCCESS(status)) {
896 ERR("addIPAddress for if %d returning 0x%lx\n", IfIndex, status);
897 }
898
899 return status;
900
901 }
902
903 NTSTATUS deleteIpAddress( ULONG NteContext )
904 {
905 HANDLE tcpFile;
906 NTSTATUS status = openTcpFile( &tcpFile );
907 IO_STATUS_BLOCK Iosb;
908
909 TRACE("Called.\n");
910
911 if( !NT_SUCCESS(status) ) return status;
912
913 status = NtDeviceIoControlFile( tcpFile,
914 NULL,
915 NULL,
916 NULL,
917 &Iosb,
918 IOCTL_DELETE_IP_ADDRESS,
919 &NteContext,
920 sizeof(USHORT),
921 NULL,
922 0 );
923
924 closeTcpFile( tcpFile );
925
926 if (!NT_SUCCESS(status)) {
927 ERR("deleteIpAddress(%lu) returning 0x%lx\n", NteContext, status);
928 }
929
930 return status;
931 }