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