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