xref: /reactos/dll/win32/iphlpapi/ifenum_reactos.c (revision 58aee30e)
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 
41 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
42 
43 /* Functions */
44 
45 /* I'm a bit skittish about maintaining this info in memory, as I'd rather
46  * not add any mutex or critical section blockers to these functions.  I've
47  * encountered far too many windows functions that contribute to deadlock
48  * by not announcing themselves. */
49 void interfaceMapInit(void)
50 {
51     /* For now, nothing */
52 }
53 
54 void interfaceMapFree(void)
55 {
56     /* Ditto. */
57 }
58 
59 NTSTATUS tdiGetMibForIfEntity
60 ( HANDLE tcpFile, TDIEntityID *ent, IFEntrySafelySized *entry ) {
61     TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
62     NTSTATUS status = STATUS_SUCCESS;
63     DWORD returnSize;
64 
65     WARN("TdiGetMibForIfEntity(tcpFile %p,entityId %p)\n",
66            tcpFile, ent->tei_instance);
67 
68     req.ID.toi_class                = INFO_CLASS_PROTOCOL;
69     req.ID.toi_type                 = INFO_TYPE_PROVIDER;
70     req.ID.toi_id                   = IF_MIB_STATS_ID;
71     req.ID.toi_entity               = *ent;
72 
73     status = DeviceIoControl( tcpFile,
74                               IOCTL_TCP_QUERY_INFORMATION_EX,
75                               &req,
76                               sizeof(req),
77                               entry,
78                               sizeof(*entry),
79                               &returnSize,
80                               NULL );
81 
82     if(!status)
83     {
84             WARN("IOCTL Failed\n");
85             return STATUS_UNSUCCESSFUL;
86     }
87 
88     TRACE("TdiGetMibForIfEntity() => {\n"
89            "  if_index ....................... %x\n"
90            "  if_type ........................ %x\n"
91            "  if_mtu ......................... %d\n"
92            "  if_speed ....................... %x\n"
93            "  if_physaddrlen ................. %d\n",
94            entry->ent.if_index,
95            entry->ent.if_type,
96            entry->ent.if_mtu,
97            entry->ent.if_speed,
98            entry->ent.if_physaddrlen);
99     TRACE("  if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n"
100            "  if_descr ....................... %s\n",
101            entry->ent.if_physaddr[0] & 0xff,
102            entry->ent.if_physaddr[1] & 0xff,
103            entry->ent.if_physaddr[2] & 0xff,
104            entry->ent.if_physaddr[3] & 0xff,
105            entry->ent.if_physaddr[4] & 0xff,
106            entry->ent.if_physaddr[5] & 0xff,
107            entry->ent.if_descr);
108     TRACE("} status %08x\n",status);
109 
110     return STATUS_SUCCESS;
111 }
112 
113 BOOL isInterface( TDIEntityID *if_maybe ) {
114     return
115         if_maybe->tei_entity == IF_ENTITY;
116 }
117 
118 BOOL isLoopback( HANDLE tcpFile, TDIEntityID *loop_maybe ) {
119     IFEntrySafelySized entryInfo;
120     NTSTATUS status;
121 
122     status = tdiGetMibForIfEntity( tcpFile,
123                                    loop_maybe,
124                                    &entryInfo );
125 
126     return NT_SUCCESS(status) &&
127            (entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
128 }
129 
130 BOOL hasArp( HANDLE tcpFile, TDIEntityID *arp_maybe ) {
131     TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
132     NTSTATUS status = STATUS_SUCCESS;
133     DWORD returnSize, type;
134 
135     req.ID.toi_class                = INFO_CLASS_GENERIC;
136     req.ID.toi_type                 = INFO_TYPE_PROVIDER;
137     req.ID.toi_id                   = ENTITY_TYPE_ID;
138     req.ID.toi_entity.tei_entity    = AT_ENTITY;
139     req.ID.toi_entity.tei_instance  = arp_maybe->tei_instance;
140 
141     status = DeviceIoControl( tcpFile,
142                               IOCTL_TCP_QUERY_INFORMATION_EX,
143                               &req,
144                               sizeof(req),
145                               &type,
146                               sizeof(type),
147                               &returnSize,
148                               NULL );
149     if( !NT_SUCCESS(status) ) return FALSE;
150 
151     return (type & AT_ARP);
152 }
153 
154 static NTSTATUS getInterfaceInfoSet( HANDLE tcpFile,
155                                      IFInfo **infoSet,
156                                      PDWORD numInterfaces ) {
157     DWORD numEntities;
158     TDIEntityID *entIDSet = NULL;
159     NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entIDSet, &numEntities );
160     IFInfo *infoSetInt = 0;
161     int curInterf = 0, i;
162 
163     if (!NT_SUCCESS(status)) {
164         ERR("getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n", status);
165         return status;
166     }
167 
168     infoSetInt = HeapAlloc( GetProcessHeap(), 0,
169                             sizeof(IFInfo) * numEntities );
170 
171     if( infoSetInt ) {
172         for( i = 0; i < numEntities; i++ ) {
173             if( isInterface( &entIDSet[i] ) ) {
174                 infoSetInt[curInterf].entity_id = entIDSet[i];
175                 status = tdiGetMibForIfEntity
176                     ( tcpFile,
177                       &entIDSet[i],
178                       &infoSetInt[curInterf].if_info );
179                 TRACE("tdiGetMibForIfEntity: %08x\n", status);
180                 if( NT_SUCCESS(status) ) {
181                     DWORD numAddrs;
182                     IPAddrEntry *addrs;
183                     TDIEntityID ip_ent;
184                     int j;
185 
186                     status = getNthIpEntity( tcpFile, curInterf, &ip_ent );
187                     if( NT_SUCCESS(status) )
188                         status = tdiGetIpAddrsForIpEntity
189                             ( tcpFile, &ip_ent, &addrs, &numAddrs );
190                     for( j = 0; NT_SUCCESS(status) && j < numAddrs; j++ ) {
191                         TRACE("ADDR %d: index %d (target %d)\n", j, addrs[j].iae_index, infoSetInt[curInterf].if_info.ent.if_index);
192                         if( addrs[j].iae_index ==
193                             infoSetInt[curInterf].if_info.ent.if_index ) {
194                             memcpy( &infoSetInt[curInterf].ip_addr,
195                                     &addrs[j],
196                                     sizeof( addrs[j] ) );
197                             curInterf++;
198                             break;
199                         }
200                     }
201                     if ( NT_SUCCESS(status) )
202                         tdiFreeThingSet(addrs);
203                 }
204             }
205         }
206 
207         tdiFreeThingSet(entIDSet);
208 
209         if (NT_SUCCESS(status)) {
210             *infoSet = infoSetInt;
211             *numInterfaces = curInterf;
212         } else {
213             HeapFree(GetProcessHeap(), 0, infoSetInt);
214         }
215 
216         return status;
217     } else {
218         tdiFreeThingSet(entIDSet);
219         return STATUS_INSUFFICIENT_RESOURCES;
220     }
221 }
222 
223 static DWORD getNumInterfacesInt(BOOL onlyNonLoopback)
224 {
225     DWORD numEntities, numInterfaces = 0;
226     TDIEntityID *entitySet;
227     HANDLE tcpFile;
228     NTSTATUS status;
229     int i;
230 
231     status = openTcpFile( &tcpFile, FILE_READ_DATA );
232 
233     if( !NT_SUCCESS(status) ) {
234         WARN("getNumInterfaces: failed %08x\n", status );
235         return 0;
236     }
237 
238     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
239 
240     if( !NT_SUCCESS(status) ) {
241         WARN("getNumInterfaces: failed %08x\n", status );
242         closeTcpFile( tcpFile );
243         return 0;
244     }
245 
246     for( i = 0; i < numEntities; i++ ) {
247         if( isInterface( &entitySet[i] ) &&
248             (!onlyNonLoopback ||
249              (onlyNonLoopback && !isLoopback( tcpFile, &entitySet[i] ))) )
250             numInterfaces++;
251     }
252 
253     TRACE("getNumInterfaces: success: %d %d %08x\n",
254            onlyNonLoopback, numInterfaces, status );
255 
256     closeTcpFile( tcpFile );
257 
258     tdiFreeThingSet( entitySet );
259 
260     return numInterfaces;
261 }
262 
263 DWORD getNumInterfaces(void)
264 {
265     return getNumInterfacesInt( FALSE );
266 }
267 
268 DWORD getNumNonLoopbackInterfaces(void)
269 {
270     return getNumInterfacesInt( TRUE );
271 }
272 
273 DWORD getNthInterfaceEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
274     DWORD numEntities = 0;
275     DWORD numInterfaces = 0;
276     TDIEntityID *entitySet = 0;
277     NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
278     int i;
279 
280     if( !NT_SUCCESS(status) )
281         return status;
282 
283     for( i = 0; i < numEntities; i++ ) {
284         if( isInterface( &entitySet[i] ) ) {
285             if( numInterfaces == index ) break;
286             else numInterfaces++;
287         }
288     }
289 
290     TRACE("Index %d is entity #%d - %04x:%08x\n", index, i,
291            entitySet[i].tei_entity, entitySet[i].tei_instance );
292 
293     if( numInterfaces == index && i < numEntities ) {
294         memcpy( ent, &entitySet[i], sizeof(*ent) );
295         tdiFreeThingSet( entitySet );
296         return STATUS_SUCCESS;
297     } else {
298         tdiFreeThingSet( entitySet );
299         return STATUS_UNSUCCESSFUL;
300     }
301 }
302 
303 NTSTATUS getInterfaceInfoByIndex( HANDLE tcpFile, DWORD index, IFInfo *info ) {
304     IFInfo *ifInfo;
305     DWORD numInterfaces;
306     NTSTATUS status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
307     int i;
308 
309     if( NT_SUCCESS(status) )
310     {
311         for( i = 0; i < numInterfaces; i++ ) {
312             if( ifInfo[i].if_info.ent.if_index == index ) {
313                 memcpy( info, &ifInfo[i], sizeof(*info) );
314                 break;
315             }
316         }
317 
318         HeapFree(GetProcessHeap(), 0, ifInfo);
319 
320         return i < numInterfaces ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
321     }
322 
323     return status;
324 }
325 
326 NTSTATUS getInterfaceInfoByName( HANDLE tcpFile, char *name, IFInfo *info ) {
327     IFInfo *ifInfo;
328     DWORD numInterfaces;
329     int i;
330     NTSTATUS status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
331 
332     if( NT_SUCCESS(status) )
333     {
334         for( i = 0; i < numInterfaces; i++ ) {
335             if( !strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name) ) {
336                 memcpy( info, &ifInfo[i], sizeof(*info) );
337                 break;
338             }
339         }
340 
341         HeapFree(GetProcessHeap(), 0,ifInfo);
342 
343         return i < numInterfaces ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
344     }
345 
346     return status;
347 }
348 
349 /* Note that the result of this operation must be freed later */
350 
351 const char *getInterfaceNameByIndex(DWORD index)
352 {
353     IFInfo ifInfo;
354     HANDLE tcpFile;
355     char *interfaceName = 0, *adapter_name = 0;
356     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
357 
358     if( NT_SUCCESS(status) ) {
359         status = getInterfaceInfoByIndex( tcpFile, index, &ifInfo );
360 
361         if( NT_SUCCESS(status) ) {
362             adapter_name = (char *)ifInfo.if_info.ent.if_descr;
363 
364             interfaceName = HeapAlloc( GetProcessHeap(), 0,
365                                        strlen(adapter_name) + 1 );
366             if (!interfaceName) return NULL;
367 
368             strcpy( interfaceName, adapter_name );
369         }
370 
371         closeTcpFile( tcpFile );
372     }
373 
374     return interfaceName;
375 }
376 
377 void consumeInterfaceName(const char *name) {
378     HeapFree( GetProcessHeap(), 0, (char *)name );
379 }
380 
381 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
382 {
383     IFInfo ifInfo;
384     HANDLE tcpFile;
385     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
386 
387     if( NT_SUCCESS(status) ) {
388         status = getInterfaceInfoByName( tcpFile, (char *)name, &ifInfo );
389 
390         if( NT_SUCCESS(status) ) {
391             *index = ifInfo.if_info.ent.if_index;
392         }
393 
394         closeTcpFile( tcpFile );
395     }
396 
397     return status;
398 }
399 
400 InterfaceIndexTable *getInterfaceIndexTableInt( BOOL nonLoopbackOnly ) {
401   DWORD numInterfaces, curInterface = 0;
402   int i;
403   IFInfo *ifInfo;
404   InterfaceIndexTable *ret = 0;
405   HANDLE tcpFile;
406   NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
407 
408   if( NT_SUCCESS(status) ) {
409       status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
410 
411       TRACE("InterfaceInfoSet: %08x, %04x:%08x\n",
412              status,
413              ifInfo->entity_id.tei_entity,
414              ifInfo->entity_id.tei_instance);
415 
416       if( NT_SUCCESS(status) ) {
417           ret = (InterfaceIndexTable *)
418               calloc(1,
419                      sizeof(InterfaceIndexTable) +
420                      (numInterfaces - 1) * sizeof(DWORD));
421 
422           if (ret) {
423               ret->numAllocated = numInterfaces;
424               TRACE("NumInterfaces = %d\n", numInterfaces);
425 
426               for( i = 0; i < numInterfaces; i++ ) {
427                   TRACE("Examining interface %d\n", i);
428                   if( !nonLoopbackOnly ||
429                       !isLoopback( tcpFile, &ifInfo[i].entity_id ) ) {
430                       TRACE("Interface %d matches (%d)\n", i, curInterface);
431                       ret->indexes[curInterface++] =
432                           ifInfo[i].if_info.ent.if_index;
433                   }
434               }
435 
436               ret->numIndexes = curInterface;
437           }
438 
439           tdiFreeThingSet( ifInfo );
440       }
441       closeTcpFile( tcpFile );
442   }
443 
444   return ret;
445 }
446 
447 InterfaceIndexTable *getInterfaceIndexTable(void) {
448     return getInterfaceIndexTableInt( FALSE );
449 }
450 
451 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) {
452     return getInterfaceIndexTableInt( TRUE );
453 }
454 
455 DWORD getInterfaceIPAddrByName(const char *name)
456 {
457     return INADDR_ANY;
458 }
459 
460 NTSTATUS getIPAddrEntryForIf(HANDLE tcpFile,
461                              char *name,
462                              DWORD index,
463                              IFInfo *ifInfo) {
464     NTSTATUS status =
465         name ?
466         getInterfaceInfoByName( tcpFile, name, ifInfo ) :
467         getInterfaceInfoByIndex( tcpFile, index, ifInfo );
468 
469     if (!NT_SUCCESS(status)) {
470         ERR("getIPAddrEntryForIf returning %lx\n", status);
471     }
472 
473     return status;
474 }
475 
476 DWORD getAddrByIndexOrName( char *name, DWORD index, IPHLPAddrType addrType ) {
477     IFInfo ifInfo;
478     HANDLE tcpFile;
479     NTSTATUS status = STATUS_SUCCESS;
480     DWORD addrOut = INADDR_ANY;
481 
482     status = openTcpFile( &tcpFile, FILE_READ_DATA );
483 
484     if( NT_SUCCESS(status) ) {
485         status = getIPAddrEntryForIf( tcpFile, name, index, &ifInfo );
486         if( NT_SUCCESS(status) ) {
487             switch( addrType ) {
488             case IPAAddr:  addrOut = ifInfo.ip_addr.iae_addr; break;
489             case IPABcast: addrOut = ifInfo.ip_addr.iae_bcastaddr; break;
490             case IPAMask:  addrOut = ifInfo.ip_addr.iae_mask; break;
491             case IFMtu:    addrOut = ifInfo.if_info.ent.if_mtu; break;
492             case IFStatus: addrOut = ifInfo.if_info.ent.if_operstatus; break;
493             }
494         }
495         closeTcpFile( tcpFile );
496     }
497 
498     return addrOut;
499 }
500 
501 DWORD getInterfaceIPAddrByIndex(DWORD index) {
502     return getAddrByIndexOrName( 0, index, IPAAddr );
503 }
504 
505 DWORD getInterfaceBCastAddrByName(const char *name) {
506     return getAddrByIndexOrName( (char *)name, 0, IPABcast );
507 }
508 
509 DWORD getInterfaceBCastAddrByIndex(DWORD index) {
510     return getAddrByIndexOrName( 0, index, IPABcast );
511 }
512 
513 DWORD getInterfaceMaskByName(const char *name) {
514     return getAddrByIndexOrName( (char *)name, 0, IPAMask );
515 }
516 
517 DWORD getInterfaceMaskByIndex(DWORD index) {
518     return getAddrByIndexOrName( 0, index, IPAMask );
519 }
520 
521 void getInterfacePhysicalFromInfo( IFInfo *info,
522                                    PDWORD len, PBYTE addr, PDWORD type ) {
523     *len = info->if_info.ent.if_physaddrlen;
524     memcpy( addr, info->if_info.ent.if_physaddr, *len );
525     *type = info->if_info.ent.if_type;
526 }
527 
528 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
529                                  PDWORD type)
530 {
531     HANDLE tcpFile;
532     IFInfo info;
533     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
534 
535     if( NT_SUCCESS(status) ) {
536         status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
537         if( NT_SUCCESS(status) )
538             getInterfacePhysicalFromInfo( &info, len, addr, type );
539         closeTcpFile( tcpFile );
540     }
541 
542     return status;
543 }
544 
545 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
546  PDWORD type)
547 {
548     HANDLE tcpFile;
549     IFInfo info;
550     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
551 
552     if( NT_SUCCESS(status) ) {
553         status = getInterfaceInfoByIndex( tcpFile, index, &info );
554         if( NT_SUCCESS(status) )
555             getInterfacePhysicalFromInfo( &info, len, addr, type );
556         closeTcpFile( tcpFile );
557     }
558 
559     return status;
560 }
561 
562 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) {
563     *mtu = getAddrByIndexOrName( (char *)name, 0, IFMtu );
564     return STATUS_SUCCESS;
565 }
566 
567 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu) {
568     *mtu = getAddrByIndexOrName( 0, index, IFMtu );
569     return STATUS_SUCCESS;
570 }
571 
572 DWORD getInterfaceStatusByName(const char *name, PDWORD status) {
573     *status = getAddrByIndexOrName( (char *)name, 0, IFStatus );
574     return STATUS_SUCCESS;
575 }
576 
577 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
578 {
579     *status = getAddrByIndexOrName( 0, index, IFStatus );
580     return STATUS_SUCCESS;
581 }
582 
583 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
584 {
585     HANDLE tcpFile;
586     IFInfo info;
587     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
588 
589     TRACE("Called.\n");
590 
591     if( NT_SUCCESS(status) ) {
592         status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
593 
594         if( NT_SUCCESS(status) ) {
595             memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
596                     &info.if_info,
597                     sizeof(info.if_info) );
598         }
599 
600         TRACE("entry->bDescr = %s\n", entry->bDescr);
601 
602         closeTcpFile( tcpFile );
603     }
604 
605     return status;
606 }
607 
608 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
609 {
610     HANDLE tcpFile;
611     IFInfo info;
612     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
613 
614     TRACE("Called.\n");
615 
616     if( NT_SUCCESS(status) ) {
617         status = getInterfaceInfoByIndex( tcpFile, index, &info );
618 
619         if( NT_SUCCESS(status) ) {
620             memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
621                     &info.if_info,
622                     sizeof(info.if_info) );
623         }
624 
625         closeTcpFile( tcpFile );
626     }
627 
628     return status;
629 }
630 
631 char *toIPAddressString(unsigned int addr, char string[16])
632 {
633     struct in_addr iAddr;
634 
635     iAddr.s_addr = addr;
636 
637     if (string)
638         strncpy(string, inet_ntoa(iAddr), 16);
639 
640     return inet_ntoa(iAddr);
641 }
642 
643 NTSTATUS addIPAddress( IPAddr Address, IPMask Mask, DWORD IfIndex,
644                        PULONG NteContext, PULONG NteInstance )
645 {
646   HANDLE tcpFile;
647   NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA );
648   IP_SET_DATA Data;
649   IO_STATUS_BLOCK Iosb;
650 
651   TRACE("Called.\n");
652 
653   if( !NT_SUCCESS(status) ) return status;
654 
655   Data.NteContext = IfIndex;
656   Data.NewAddress = Address;
657   Data.NewNetmask = Mask;
658 
659   status = NtDeviceIoControlFile( tcpFile,
660                                   NULL,
661                                   NULL,
662                                   NULL,
663                                   &Iosb,
664                                   IOCTL_SET_IP_ADDRESS,
665                                   &Data,
666                                   sizeof(Data),
667                                   &Data,
668                                   sizeof(Data) );
669 
670   closeTcpFile( tcpFile );
671 
672   if( NT_SUCCESS(status) ) {
673       *NteContext = Iosb.Information;
674       *NteInstance = Data.NewAddress;
675   }
676 
677   if (!NT_SUCCESS(status)) {
678       ERR("addIPAddress for if %d returning 0x%lx\n", IfIndex, status);
679   }
680 
681   return status;
682 
683 }
684 
685 NTSTATUS deleteIpAddress( ULONG NteContext )
686 {
687   HANDLE tcpFile;
688   NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA );
689   IO_STATUS_BLOCK Iosb;
690 
691   TRACE("Called.\n");
692 
693   if( !NT_SUCCESS(status) ) return status;
694 
695   status = NtDeviceIoControlFile( tcpFile,
696                                   NULL,
697                                   NULL,
698                                   NULL,
699                                   &Iosb,
700                                   IOCTL_DELETE_IP_ADDRESS,
701                                   &NteContext,
702                                   sizeof(USHORT),
703                                   NULL,
704                                   0 );
705 
706   closeTcpFile( tcpFile );
707 
708   if (!NT_SUCCESS(status)) {
709       ERR("deleteIpAddress(%lu) returning 0x%lx\n", NteContext, status);
710   }
711 
712   return status;
713 }
714