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