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