xref: /reactos/dll/win32/iphlpapi/ifenum_reactos.c (revision b5218987)
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_descrlen,
108            entry->ent.if_descr);
109     TRACE("} status %08x\n",status);
110 
111     return STATUS_SUCCESS;
112 }
113 
114 BOOL isInterface( TDIEntityID *if_maybe ) {
115     return
116         if_maybe->tei_entity == IF_ENTITY;
117 }
118 
119 BOOL isLoopback( HANDLE tcpFile, TDIEntityID *loop_maybe ) {
120     IFEntrySafelySized entryInfo;
121     NTSTATUS status;
122 
123     status = tdiGetMibForIfEntity( tcpFile,
124                                    loop_maybe,
125                                    &entryInfo );
126 
127     return NT_SUCCESS(status) &&
128            (entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
129 }
130 
131 BOOL hasArp( HANDLE tcpFile, TDIEntityID *arp_maybe ) {
132     TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
133     NTSTATUS status = STATUS_SUCCESS;
134     DWORD returnSize, type;
135 
136     req.ID.toi_class                = INFO_CLASS_GENERIC;
137     req.ID.toi_type                 = INFO_TYPE_PROVIDER;
138     req.ID.toi_id                   = ENTITY_TYPE_ID;
139     req.ID.toi_entity.tei_entity    = AT_ENTITY;
140     req.ID.toi_entity.tei_instance  = arp_maybe->tei_instance;
141 
142     status = DeviceIoControl( tcpFile,
143                               IOCTL_TCP_QUERY_INFORMATION_EX,
144                               &req,
145                               sizeof(req),
146                               &type,
147                               sizeof(type),
148                               &returnSize,
149                               NULL );
150     if( !NT_SUCCESS(status) ) return FALSE;
151 
152     return (type & AT_ARP);
153 }
154 
155 static NTSTATUS getInterfaceInfoSet( HANDLE tcpFile,
156                                      IFInfo **infoSet,
157                                      PDWORD numInterfaces ) {
158     DWORD numEntities;
159     TDIEntityID *entIDSet = NULL;
160     NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entIDSet, &numEntities );
161     IFInfo *infoSetInt = 0;
162     int curInterf = 0, i;
163 
164     if (!NT_SUCCESS(status)) {
165         ERR("getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n", status);
166         return status;
167     }
168 
169     infoSetInt = HeapAlloc( GetProcessHeap(), 0,
170                             sizeof(IFInfo) * numEntities );
171 
172     if( infoSetInt ) {
173         for( i = 0; i < numEntities; i++ ) {
174             if( isInterface( &entIDSet[i] ) ) {
175                 infoSetInt[curInterf].entity_id = entIDSet[i];
176                 status = tdiGetMibForIfEntity
177                     ( tcpFile,
178                       &entIDSet[i],
179                       &infoSetInt[curInterf].if_info );
180                 TRACE("tdiGetMibForIfEntity: %08x\n", status);
181                 if( NT_SUCCESS(status) ) {
182                     DWORD numAddrs;
183                     IPAddrEntry *addrs;
184                     TDIEntityID ip_ent;
185                     int j;
186 
187                     status = getNthIpEntity( tcpFile, curInterf, &ip_ent );
188                     if( NT_SUCCESS(status) )
189                         status = tdiGetIpAddrsForIpEntity
190                             ( tcpFile, &ip_ent, &addrs, &numAddrs );
191                     for( j = 0; NT_SUCCESS(status) && j < numAddrs; j++ ) {
192                         TRACE("ADDR %d: index %d (target %d)\n", j, addrs[j].iae_index, infoSetInt[curInterf].if_info.ent.if_index);
193                         if( addrs[j].iae_index ==
194                             infoSetInt[curInterf].if_info.ent.if_index ) {
195                             memcpy( &infoSetInt[curInterf].ip_addr,
196                                     &addrs[j],
197                                     sizeof( addrs[j] ) );
198                             curInterf++;
199                             break;
200                         }
201                     }
202                     if ( NT_SUCCESS(status) )
203                         tdiFreeThingSet(addrs);
204                 }
205             }
206         }
207 
208         tdiFreeThingSet(entIDSet);
209 
210         if (NT_SUCCESS(status)) {
211             *infoSet = infoSetInt;
212             *numInterfaces = curInterf;
213         } else {
214             HeapFree(GetProcessHeap(), 0, infoSetInt);
215         }
216 
217         return status;
218     } else {
219         tdiFreeThingSet(entIDSet);
220         return STATUS_INSUFFICIENT_RESOURCES;
221     }
222 }
223 
224 static DWORD getNumInterfacesInt(BOOL onlyNonLoopback)
225 {
226     DWORD numEntities, numInterfaces = 0;
227     TDIEntityID *entitySet;
228     HANDLE tcpFile;
229     NTSTATUS status;
230     int i;
231 
232     status = openTcpFile( &tcpFile, FILE_READ_DATA );
233 
234     if( !NT_SUCCESS(status) ) {
235         WARN("getNumInterfaces: failed %08x\n", status );
236         return 0;
237     }
238 
239     status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
240 
241     if( !NT_SUCCESS(status) ) {
242         WARN("getNumInterfaces: failed %08x\n", status );
243         closeTcpFile( tcpFile );
244         return 0;
245     }
246 
247     for( i = 0; i < numEntities; i++ ) {
248         if( isInterface( &entitySet[i] ) &&
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( !strncmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name, ifInfo[i].if_info.ent.if_descrlen) ) {
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 = NULL;
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             interfaceName = HeapAlloc( GetProcessHeap(), 0,
363                                        ifInfo.if_info.ent.if_descrlen + 1 );
364             if( interfaceName ) {
365               memcpy(interfaceName, ifInfo.if_info.ent.if_descr, ifInfo.if_info.ent.if_descrlen);
366               interfaceName[ifInfo.if_info.ent.if_descrlen] = '\0';
367             }
368         }
369 
370         closeTcpFile( tcpFile );
371     }
372 
373     return interfaceName;
374 }
375 
376 void consumeInterfaceName(const char *name) {
377     HeapFree( GetProcessHeap(), 0, (char *)name );
378 }
379 
380 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
381 {
382     IFInfo ifInfo;
383     HANDLE tcpFile;
384     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
385 
386     if( NT_SUCCESS(status) ) {
387         status = getInterfaceInfoByName( tcpFile, (char *)name, &ifInfo );
388 
389         if( NT_SUCCESS(status) ) {
390             *index = ifInfo.if_info.ent.if_index;
391         }
392 
393         closeTcpFile( tcpFile );
394     }
395 
396     return status;
397 }
398 
399 InterfaceIndexTable *getInterfaceIndexTableInt( BOOL nonLoopbackOnly ) {
400   DWORD numInterfaces, curInterface = 0;
401   int i;
402   IFInfo *ifInfo;
403   InterfaceIndexTable *ret = 0;
404   HANDLE tcpFile;
405   NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
406 
407   if( NT_SUCCESS(status) ) {
408       status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
409 
410       TRACE("InterfaceInfoSet: %08x, %04x:%08x\n",
411              status,
412              ifInfo->entity_id.tei_entity,
413              ifInfo->entity_id.tei_instance);
414 
415       if( NT_SUCCESS(status) ) {
416           ret = (InterfaceIndexTable *)
417               calloc(1,
418                      sizeof(InterfaceIndexTable) +
419                      (numInterfaces - 1) * sizeof(DWORD));
420 
421           if (ret) {
422               ret->numAllocated = numInterfaces;
423               TRACE("NumInterfaces = %d\n", numInterfaces);
424 
425               for( i = 0; i < numInterfaces; i++ ) {
426                   TRACE("Examining interface %d\n", i);
427                   if( !nonLoopbackOnly ||
428                       !isLoopback( tcpFile, &ifInfo[i].entity_id ) ) {
429                       TRACE("Interface %d matches (%d)\n", i, curInterface);
430                       ret->indexes[curInterface++] =
431                           ifInfo[i].if_info.ent.if_index;
432                   }
433               }
434 
435               ret->numIndexes = curInterface;
436           }
437 
438           tdiFreeThingSet( ifInfo );
439       }
440       closeTcpFile( tcpFile );
441   }
442 
443   return ret;
444 }
445 
446 InterfaceIndexTable *getInterfaceIndexTable(void) {
447     return getInterfaceIndexTableInt( FALSE );
448 }
449 
450 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) {
451     return getInterfaceIndexTableInt( TRUE );
452 }
453 
454 DWORD getInterfaceIPAddrByName(const char *name)
455 {
456     return INADDR_ANY;
457 }
458 
459 NTSTATUS getIPAddrEntryForIf(HANDLE tcpFile,
460                              char *name,
461                              DWORD index,
462                              IFInfo *ifInfo) {
463     NTSTATUS status =
464         name ?
465         getInterfaceInfoByName( tcpFile, name, ifInfo ) :
466         getInterfaceInfoByIndex( tcpFile, index, ifInfo );
467 
468     if (!NT_SUCCESS(status)) {
469         ERR("getIPAddrEntryForIf returning %lx\n", status);
470     }
471 
472     return status;
473 }
474 
475 DWORD getAddrByIndexOrName( char *name, DWORD index, IPHLPAddrType addrType ) {
476     IFInfo ifInfo;
477     HANDLE tcpFile;
478     NTSTATUS status = STATUS_SUCCESS;
479     DWORD addrOut = INADDR_ANY;
480 
481     status = openTcpFile( &tcpFile, FILE_READ_DATA );
482 
483     if( NT_SUCCESS(status) ) {
484         status = getIPAddrEntryForIf( tcpFile, name, index, &ifInfo );
485         if( NT_SUCCESS(status) ) {
486             switch( addrType ) {
487             case IPAAddr:  addrOut = ifInfo.ip_addr.iae_addr; break;
488             case IPABcast: addrOut = ifInfo.ip_addr.iae_bcastaddr; break;
489             case IPAMask:  addrOut = ifInfo.ip_addr.iae_mask; break;
490             case IFMtu:    addrOut = ifInfo.if_info.ent.if_mtu; break;
491             case IFStatus: addrOut = ifInfo.if_info.ent.if_operstatus; break;
492             }
493         }
494         closeTcpFile( tcpFile );
495     }
496 
497     return addrOut;
498 }
499 
500 DWORD getInterfaceIPAddrByIndex(DWORD index) {
501     return getAddrByIndexOrName( 0, index, IPAAddr );
502 }
503 
504 DWORD getInterfaceBCastAddrByName(const char *name) {
505     return getAddrByIndexOrName( (char *)name, 0, IPABcast );
506 }
507 
508 DWORD getInterfaceBCastAddrByIndex(DWORD index) {
509     return getAddrByIndexOrName( 0, index, IPABcast );
510 }
511 
512 DWORD getInterfaceMaskByName(const char *name) {
513     return getAddrByIndexOrName( (char *)name, 0, IPAMask );
514 }
515 
516 DWORD getInterfaceMaskByIndex(DWORD index) {
517     return getAddrByIndexOrName( 0, index, IPAMask );
518 }
519 
520 void getInterfacePhysicalFromInfo( IFInfo *info,
521                                    PDWORD len, PBYTE addr, PDWORD type ) {
522     *len = info->if_info.ent.if_physaddrlen;
523     memcpy( addr, info->if_info.ent.if_physaddr, *len );
524     *type = info->if_info.ent.if_type;
525 }
526 
527 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
528                                  PDWORD type)
529 {
530     HANDLE tcpFile;
531     IFInfo info;
532     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
533 
534     if( NT_SUCCESS(status) ) {
535         status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
536         if( NT_SUCCESS(status) )
537             getInterfacePhysicalFromInfo( &info, len, addr, type );
538         closeTcpFile( tcpFile );
539     }
540 
541     return status;
542 }
543 
544 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
545  PDWORD type)
546 {
547     HANDLE tcpFile;
548     IFInfo info;
549     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
550 
551     if( NT_SUCCESS(status) ) {
552         status = getInterfaceInfoByIndex( tcpFile, index, &info );
553         if( NT_SUCCESS(status) )
554             getInterfacePhysicalFromInfo( &info, len, addr, type );
555         closeTcpFile( tcpFile );
556     }
557 
558     return status;
559 }
560 
561 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) {
562     *mtu = getAddrByIndexOrName( (char *)name, 0, IFMtu );
563     return STATUS_SUCCESS;
564 }
565 
566 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu) {
567     *mtu = getAddrByIndexOrName( 0, index, IFMtu );
568     return STATUS_SUCCESS;
569 }
570 
571 DWORD getInterfaceStatusByName(const char *name, PDWORD status) {
572     *status = getAddrByIndexOrName( (char *)name, 0, IFStatus );
573     return STATUS_SUCCESS;
574 }
575 
576 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
577 {
578     *status = getAddrByIndexOrName( 0, index, IFStatus );
579     return STATUS_SUCCESS;
580 }
581 
582 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
583 {
584     HANDLE tcpFile;
585     IFInfo info;
586     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
587 
588     TRACE("Called.\n");
589 
590     if( NT_SUCCESS(status) ) {
591         status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
592 
593         if( NT_SUCCESS(status) ) {
594             memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
595                     &info.if_info,
596                     sizeof(info.if_info) );
597         }
598 
599         TRACE("entry->bDescr = %s\n", entry->bDescr);
600 
601         closeTcpFile( tcpFile );
602     }
603 
604     return status;
605 }
606 
607 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
608 {
609     HANDLE tcpFile;
610     IFInfo info;
611     NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA );
612 
613     TRACE("Called.\n");
614 
615     if( NT_SUCCESS(status) ) {
616         status = getInterfaceInfoByIndex( tcpFile, index, &info );
617 
618         if( NT_SUCCESS(status) ) {
619             memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
620                     &info.if_info,
621                     sizeof(info.if_info) );
622         }
623 
624         closeTcpFile( tcpFile );
625     }
626 
627     return status;
628 }
629 
630 char *toIPAddressString(unsigned int addr, char string[16])
631 {
632     struct in_addr iAddr;
633 
634     iAddr.s_addr = addr;
635 
636     if (string)
637         strncpy(string, inet_ntoa(iAddr), 16);
638 
639     return inet_ntoa(iAddr);
640 }
641 
642 NTSTATUS addIPAddress( IPAddr Address, IPMask Mask, DWORD IfIndex,
643                        PULONG NteContext, PULONG NteInstance )
644 {
645   HANDLE tcpFile;
646   NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA );
647   IP_SET_DATA Data;
648   IO_STATUS_BLOCK Iosb;
649 
650   TRACE("Called.\n");
651 
652   if( !NT_SUCCESS(status) ) return status;
653 
654   Data.NteContext = IfIndex;
655   Data.NewAddress = Address;
656   Data.NewNetmask = Mask;
657 
658   status = NtDeviceIoControlFile( tcpFile,
659                                   NULL,
660                                   NULL,
661                                   NULL,
662                                   &Iosb,
663                                   IOCTL_SET_IP_ADDRESS,
664                                   &Data,
665                                   sizeof(Data),
666                                   &Data,
667                                   sizeof(Data) );
668 
669   closeTcpFile( tcpFile );
670 
671   if( NT_SUCCESS(status) ) {
672       *NteContext = Iosb.Information;
673       *NteInstance = Data.NewAddress;
674   }
675 
676   if (!NT_SUCCESS(status)) {
677       ERR("addIPAddress for if %d returning 0x%lx\n", IfIndex, status);
678   }
679 
680   return status;
681 
682 }
683 
684 NTSTATUS deleteIpAddress( ULONG NteContext )
685 {
686   HANDLE tcpFile;
687   NTSTATUS status = openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA );
688   IO_STATUS_BLOCK Iosb;
689 
690   TRACE("Called.\n");
691 
692   if( !NT_SUCCESS(status) ) return status;
693 
694   status = NtDeviceIoControlFile( tcpFile,
695                                   NULL,
696                                   NULL,
697                                   NULL,
698                                   &Iosb,
699                                   IOCTL_DELETE_IP_ADDRESS,
700                                   &NteContext,
701                                   sizeof(USHORT),
702                                   NULL,
703                                   0 );
704 
705   closeTcpFile( tcpFile );
706 
707   if (!NT_SUCCESS(status)) {
708       ERR("deleteIpAddress(%lu) returning 0x%lx\n", NteContext, status);
709   }
710 
711   return status;
712 }
713