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