Sync with trunk r63270.
[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
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 %x,entityId %x)\n",
66 (int)tcpFile, (int)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 = 0;
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; j < numAddrs && NT_SUCCESS(status); 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 }
202 }
203 }
204
205 tdiFreeThingSet(entIDSet);
206
207 if (NT_SUCCESS(status)) {
208 *infoSet = infoSetInt;
209 *numInterfaces = curInterf;
210 } else {
211 HeapFree(GetProcessHeap(), 0, infoSetInt);
212 }
213
214 return status;
215 } else {
216 return STATUS_INSUFFICIENT_RESOURCES;
217 }
218 }
219
220 static DWORD getNumInterfacesInt(BOOL onlyNonLoopback)
221 {
222 DWORD numEntities, numInterfaces = 0;
223 TDIEntityID *entitySet;
224 HANDLE tcpFile;
225 NTSTATUS status;
226 int i;
227
228 status = openTcpFile( &tcpFile );
229
230 if( !NT_SUCCESS(status) ) {
231 WARN("getNumInterfaces: failed %08x\n", status );
232 return 0;
233 }
234
235 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
236
237 if( !NT_SUCCESS(status) ) {
238 WARN("getNumInterfaces: failed %08x\n", status );
239 closeTcpFile( tcpFile );
240 return 0;
241 }
242
243 for( i = 0; i < numEntities; i++ ) {
244 if( isInterface( &entitySet[i] ) &&
245 (!onlyNonLoopback ||
246 (onlyNonLoopback && !isLoopback( tcpFile, &entitySet[i] ))) )
247 numInterfaces++;
248 }
249
250 TRACE("getNumInterfaces: success: %d %d %08x\n",
251 onlyNonLoopback, numInterfaces, status );
252
253 closeTcpFile( tcpFile );
254
255 tdiFreeThingSet( entitySet );
256
257 return numInterfaces;
258 }
259
260 DWORD getNumInterfaces(void)
261 {
262 return getNumInterfacesInt( FALSE );
263 }
264
265 DWORD getNumNonLoopbackInterfaces(void)
266 {
267 return getNumInterfacesInt( TRUE );
268 }
269
270 DWORD getNthInterfaceEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
271 DWORD numEntities = 0;
272 DWORD numInterfaces = 0;
273 TDIEntityID *entitySet = 0;
274 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
275 int i;
276
277 if( !NT_SUCCESS(status) )
278 return status;
279
280 for( i = 0; i < numEntities; i++ ) {
281 if( isInterface( &entitySet[i] ) ) {
282 if( numInterfaces == index ) break;
283 else numInterfaces++;
284 }
285 }
286
287 TRACE("Index %d is entity #%d - %04x:%08x\n", index, i,
288 entitySet[i].tei_entity, entitySet[i].tei_instance );
289
290 if( numInterfaces == index && i < numEntities ) {
291 memcpy( ent, &entitySet[i], sizeof(*ent) );
292 tdiFreeThingSet( entitySet );
293 return STATUS_SUCCESS;
294 } else {
295 tdiFreeThingSet( entitySet );
296 return STATUS_UNSUCCESSFUL;
297 }
298 }
299
300 NTSTATUS getInterfaceInfoByIndex( HANDLE tcpFile, DWORD index, IFInfo *info ) {
301 IFInfo *ifInfo;
302 DWORD numInterfaces;
303 NTSTATUS status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
304 int i;
305
306 if( NT_SUCCESS(status) )
307 {
308 for( i = 0; i < numInterfaces; i++ ) {
309 if( ifInfo[i].if_info.ent.if_index == index ) {
310 memcpy( info, &ifInfo[i], sizeof(*info) );
311 break;
312 }
313 }
314
315 HeapFree(GetProcessHeap(), 0, ifInfo);
316
317 return i < numInterfaces ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
318 }
319
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 {
331 for( i = 0; i < numInterfaces; i++ ) {
332 if( !strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name) ) {
333 memcpy( info, &ifInfo[i], sizeof(*info) );
334 break;
335 }
336 }
337
338 HeapFree(GetProcessHeap(), 0,ifInfo);
339
340 return i < numInterfaces ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
341 }
342
343 return status;
344 }
345
346 /* Note that the result of this operation must be freed later */
347
348 const char *getInterfaceNameByIndex(DWORD index)
349 {
350 IFInfo ifInfo;
351 HANDLE tcpFile;
352 char *interfaceName = 0, *adapter_name = 0;
353 NTSTATUS status = openTcpFile( &tcpFile );
354
355 if( NT_SUCCESS(status) ) {
356 status = getInterfaceInfoByIndex( tcpFile, index, &ifInfo );
357
358 if( NT_SUCCESS(status) ) {
359 adapter_name = (char *)ifInfo.if_info.ent.if_descr;
360
361 interfaceName = HeapAlloc( GetProcessHeap(), 0,
362 strlen(adapter_name) + 1 );
363 if (!interfaceName) return NULL;
364
365 strcpy( interfaceName, adapter_name );
366 }
367
368 closeTcpFile( tcpFile );
369 }
370
371 return interfaceName;
372 }
373
374 void consumeInterfaceName(const char *name) {
375 HeapFree( GetProcessHeap(), 0, (char *)name );
376 }
377
378 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
379 {
380 IFInfo ifInfo;
381 HANDLE tcpFile;
382 NTSTATUS status = openTcpFile( &tcpFile );
383
384 if( NT_SUCCESS(status) ) {
385 status = getInterfaceInfoByName( tcpFile, (char *)name, &ifInfo );
386
387 if( NT_SUCCESS(status) ) {
388 *index = ifInfo.if_info.ent.if_index;
389 }
390
391 closeTcpFile( tcpFile );
392 }
393
394 return status;
395 }
396
397 InterfaceIndexTable *getInterfaceIndexTableInt( BOOL nonLoopbackOnly ) {
398 DWORD numInterfaces, curInterface = 0;
399 int i;
400 IFInfo *ifInfo;
401 InterfaceIndexTable *ret = 0;
402 HANDLE tcpFile;
403 NTSTATUS status = openTcpFile( &tcpFile );
404
405 if( NT_SUCCESS(status) ) {
406 status = getInterfaceInfoSet( tcpFile, &ifInfo, &numInterfaces );
407
408 TRACE("InterfaceInfoSet: %08x, %04x:%08x\n",
409 status,
410 ifInfo->entity_id.tei_entity,
411 ifInfo->entity_id.tei_instance);
412
413 if( NT_SUCCESS(status) ) {
414 ret = (InterfaceIndexTable *)
415 calloc(1,
416 sizeof(InterfaceIndexTable) +
417 (numInterfaces - 1) * sizeof(DWORD));
418
419 if (ret) {
420 ret->numAllocated = numInterfaces;
421 TRACE("NumInterfaces = %d\n", numInterfaces);
422
423 for( i = 0; i < numInterfaces; i++ ) {
424 TRACE("Examining interface %d\n", i);
425 if( !nonLoopbackOnly ||
426 !isLoopback( tcpFile, &ifInfo[i].entity_id ) ) {
427 TRACE("Interface %d matches (%d)\n", i, curInterface);
428 ret->indexes[curInterface++] =
429 ifInfo[i].if_info.ent.if_index;
430 }
431 }
432
433 ret->numIndexes = curInterface;
434 }
435
436 tdiFreeThingSet( ifInfo );
437 }
438 closeTcpFile( tcpFile );
439 }
440
441 return ret;
442 }
443
444 InterfaceIndexTable *getInterfaceIndexTable(void) {
445 return getInterfaceIndexTableInt( FALSE );
446 }
447
448 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) {
449 return getInterfaceIndexTableInt( TRUE );
450 }
451
452 DWORD getInterfaceIPAddrByName(const char *name)
453 {
454 return INADDR_ANY;
455 }
456
457 NTSTATUS getIPAddrEntryForIf(HANDLE tcpFile,
458 char *name,
459 DWORD index,
460 IFInfo *ifInfo) {
461 NTSTATUS status =
462 name ?
463 getInterfaceInfoByName( tcpFile, name, ifInfo ) :
464 getInterfaceInfoByIndex( tcpFile, index, ifInfo );
465
466 if (!NT_SUCCESS(status)) {
467 ERR("getIPAddrEntryForIf returning %lx\n", status);
468 }
469
470 return status;
471 }
472
473 DWORD getAddrByIndexOrName( char *name, DWORD index, IPHLPAddrType addrType ) {
474 IFInfo ifInfo;
475 HANDLE tcpFile;
476 NTSTATUS status = STATUS_SUCCESS;
477 DWORD addrOut = INADDR_ANY;
478
479 status = openTcpFile( &tcpFile );
480
481 if( NT_SUCCESS(status) ) {
482 status = getIPAddrEntryForIf( tcpFile, name, index, &ifInfo );
483 if( NT_SUCCESS(status) ) {
484 switch( addrType ) {
485 case IPAAddr: addrOut = ifInfo.ip_addr.iae_addr; break;
486 case IPABcast: addrOut = ifInfo.ip_addr.iae_bcastaddr; break;
487 case IPAMask: addrOut = ifInfo.ip_addr.iae_mask; break;
488 case IFMtu: addrOut = ifInfo.if_info.ent.if_mtu; break;
489 case IFStatus: addrOut = ifInfo.if_info.ent.if_operstatus; break;
490 }
491 }
492 closeTcpFile( tcpFile );
493 }
494
495 return addrOut;
496 }
497
498 DWORD getInterfaceIPAddrByIndex(DWORD index) {
499 return getAddrByIndexOrName( 0, index, IPAAddr );
500 }
501
502 DWORD getInterfaceBCastAddrByName(const char *name) {
503 return getAddrByIndexOrName( (char *)name, 0, IPABcast );
504 }
505
506 DWORD getInterfaceBCastAddrByIndex(DWORD index) {
507 return getAddrByIndexOrName( 0, index, IPABcast );
508 }
509
510 DWORD getInterfaceMaskByName(const char *name) {
511 return getAddrByIndexOrName( (char *)name, 0, IPAMask );
512 }
513
514 DWORD getInterfaceMaskByIndex(DWORD index) {
515 return getAddrByIndexOrName( 0, index, IPAMask );
516 }
517
518 void getInterfacePhysicalFromInfo( IFInfo *info,
519 PDWORD len, PBYTE addr, PDWORD type ) {
520 *len = info->if_info.ent.if_physaddrlen;
521 memcpy( addr, info->if_info.ent.if_physaddr, *len );
522 *type = info->if_info.ent.if_type;
523 }
524
525 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
526 PDWORD type)
527 {
528 HANDLE tcpFile;
529 IFInfo info;
530 NTSTATUS status = openTcpFile( &tcpFile );
531
532 if( NT_SUCCESS(status) ) {
533 status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
534 if( NT_SUCCESS(status) )
535 getInterfacePhysicalFromInfo( &info, len, addr, type );
536 closeTcpFile( tcpFile );
537 }
538
539 return status;
540 }
541
542 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
543 PDWORD type)
544 {
545 HANDLE tcpFile;
546 IFInfo info;
547 NTSTATUS status = openTcpFile( &tcpFile );
548
549 if( NT_SUCCESS(status) ) {
550 status = getInterfaceInfoByIndex( tcpFile, index, &info );
551 if( NT_SUCCESS(status) )
552 getInterfacePhysicalFromInfo( &info, len, addr, type );
553 closeTcpFile( tcpFile );
554 }
555
556 return status;
557 }
558
559 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) {
560 *mtu = getAddrByIndexOrName( (char *)name, 0, IFMtu );
561 return STATUS_SUCCESS;
562 }
563
564 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu) {
565 *mtu = getAddrByIndexOrName( 0, index, IFMtu );
566 return STATUS_SUCCESS;
567 }
568
569 DWORD getInterfaceStatusByName(const char *name, PDWORD status) {
570 *status = getAddrByIndexOrName( (char *)name, 0, IFStatus );
571 return STATUS_SUCCESS;
572 }
573
574 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
575 {
576 *status = getAddrByIndexOrName( 0, index, IFStatus );
577 return STATUS_SUCCESS;
578 }
579
580 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
581 {
582 HANDLE tcpFile;
583 IFInfo info;
584 NTSTATUS status = openTcpFile( &tcpFile );
585
586 TRACE("Called.\n");
587
588 if( NT_SUCCESS(status) ) {
589 status = getInterfaceInfoByName( tcpFile, (char *)name, &info );
590
591 if( NT_SUCCESS(status) ) {
592 memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
593 &info.if_info,
594 sizeof(info.if_info) );
595 }
596
597 TRACE("entry->bDescr = %s\n", entry->bDescr);
598
599 closeTcpFile( tcpFile );
600 }
601
602 return status;
603 }
604
605 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
606 {
607 HANDLE tcpFile;
608 IFInfo info;
609 NTSTATUS status = openTcpFile( &tcpFile );
610
611 TRACE("Called.\n");
612
613 if( NT_SUCCESS(status) ) {
614 status = getInterfaceInfoByIndex( tcpFile, index, &info );
615
616 if( NT_SUCCESS(status) ) {
617 memcpy( &entry->wszName[MAX_INTERFACE_NAME_LEN],
618 &info.if_info,
619 sizeof(info.if_info) );
620 }
621
622 closeTcpFile( tcpFile );
623 }
624
625 return status;
626 }
627
628 char *toIPAddressString(unsigned int addr, char string[16])
629 {
630 struct in_addr iAddr;
631
632 iAddr.s_addr = addr;
633
634 if (string)
635 strncpy(string, inet_ntoa(iAddr), 16);
636
637 return inet_ntoa(iAddr);
638 }
639
640 NTSTATUS addIPAddress( IPAddr Address, IPMask Mask, DWORD IfIndex,
641 PULONG NteContext, PULONG NteInstance )
642 {
643 HANDLE tcpFile;
644 NTSTATUS status = openTcpFile( &tcpFile );
645 IP_SET_DATA Data;
646 IO_STATUS_BLOCK Iosb;
647
648 TRACE("Called.\n");
649
650 if( !NT_SUCCESS(status) ) return status;
651
652 Data.NteContext = IfIndex;
653 Data.NewAddress = Address;
654 Data.NewNetmask = Mask;
655
656 status = NtDeviceIoControlFile( tcpFile,
657 NULL,
658 NULL,
659 NULL,
660 &Iosb,
661 IOCTL_SET_IP_ADDRESS,
662 &Data,
663 sizeof(Data),
664 &Data,
665 sizeof(Data) );
666
667 closeTcpFile( tcpFile );
668
669 if( NT_SUCCESS(status) ) {
670 *NteContext = Iosb.Information;
671 *NteInstance = Data.NewAddress;
672 }
673
674 if (!NT_SUCCESS(status)) {
675 ERR("addIPAddress for if %d returning 0x%lx\n", IfIndex, status);
676 }
677
678 return status;
679
680 }
681
682 NTSTATUS deleteIpAddress( ULONG NteContext )
683 {
684 HANDLE tcpFile;
685 NTSTATUS status = openTcpFile( &tcpFile );
686 IO_STATUS_BLOCK Iosb;
687
688 TRACE("Called.\n");
689
690 if( !NT_SUCCESS(status) ) return status;
691
692 status = NtDeviceIoControlFile( tcpFile,
693 NULL,
694 NULL,
695 NULL,
696 &Iosb,
697 IOCTL_DELETE_IP_ADDRESS,
698 &NteContext,
699 sizeof(USHORT),
700 NULL,
701 0 );
702
703 closeTcpFile( tcpFile );
704
705 if (!NT_SUCCESS(status)) {
706 ERR("deleteIpAddress(%lu) returning 0x%lx\n", NteContext, status);
707 }
708
709 return status;
710 }