Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

907 lines
23 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. nteapi.c
  5. Abstract:
  6. Routines for manipulating dynamic IP Network Table Entries (NTEs)
  7. and NBT devices (interfaces).
  8. Author:
  9. Mike Massa (mikemas) 18-Mar-1996
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. --*/
  14. #include "clusres.h"
  15. #include <winsock2.h>
  16. #include <ipexport.h>
  17. #include <ntddip.h>
  18. #include <nteapi.h>
  19. #include <nbtioctl.h>
  20. #include <clusdef.h>
  21. #include <ntddcnet.h>
  22. #include <clusrtl.h>
  23. //
  24. // Public Routines
  25. //
  26. DWORD
  27. TcpipAddNTE(
  28. IN LPWSTR AdapterId,
  29. IN IPAddr Address,
  30. IN IPMask SubnetMask,
  31. OUT PULONG NTEContext,
  32. OUT PULONG NTEInstance
  33. )
  34. /*++
  35. Routine Description:
  36. Adds a new NTE to a specified IP interface. The target IP interface is
  37. identified by the name of the adapter associated with it.
  38. Arguments:
  39. AdapterId - A unicode string identifying the adapter/interface to which
  40. to add the new NTE.
  41. Address - The IP address to assign to the new NTE.
  42. SubnetMask - The IP subnet mask to assign to the new NTE.
  43. NTEContext - On output, contains the context value identifying the new NTE.
  44. NTEInstance - On output, contains the instance ID of the new NTE.
  45. Return Value:
  46. ERROR_SUCCESS if the operation was successful.
  47. A Windows error code otherwise.
  48. --*/
  49. {
  50. NTSTATUS status;
  51. PCLRTL_NET_ADAPTER_INFO adapterInfo;
  52. PCLRTL_NET_ADAPTER_ENUM adapterEnum;
  53. HANDLE handle;
  54. IP_ADD_NTE_REQUEST requestBuffer;
  55. PIP_ADD_NTE_RESPONSE responseBuffer =
  56. (PIP_ADD_NTE_RESPONSE) &requestBuffer;
  57. DWORD requestBufferSize = sizeof(requestBuffer);
  58. DWORD responseBufferSize = sizeof(*responseBuffer);
  59. adapterEnum = ClRtlEnumNetAdapters();
  60. if (adapterEnum != NULL) {
  61. adapterInfo = ClRtlFindNetAdapterById(adapterEnum, AdapterId);
  62. if (adapterInfo != NULL) {
  63. status = ClusResOpenDriver(&handle, DD_CLUSNET_DEVICE_NAME);
  64. if ( status == ERROR_SUCCESS ) {
  65. requestBuffer.InterfaceContext = adapterInfo->Index;
  66. requestBuffer.Address = Address;
  67. requestBuffer.SubnetMask = SubnetMask;
  68. requestBuffer.InterfaceName.Length = 0;
  69. requestBuffer.InterfaceName.MaximumLength = 0;
  70. requestBuffer.InterfaceName.Buffer = NULL;
  71. status = ClusResDoIoctl(
  72. handle,
  73. IOCTL_CLUSNET_ADD_NTE,
  74. &requestBuffer,
  75. requestBufferSize,
  76. responseBuffer,
  77. &responseBufferSize
  78. );
  79. if (NT_SUCCESS(status)) {
  80. *NTEContext = (ULONG) responseBuffer->Context;
  81. *NTEInstance = responseBuffer->Instance;
  82. status = ERROR_SUCCESS;
  83. }
  84. CloseHandle(handle);
  85. }
  86. }
  87. else {
  88. status = ERROR_INVALID_PARAMETER;
  89. }
  90. ClRtlFreeNetAdapterEnum(adapterEnum);
  91. }
  92. else {
  93. status = GetLastError();
  94. }
  95. return(status);
  96. }
  97. DWORD
  98. TcpipDeleteNTE(
  99. IN ULONG NTEContext
  100. )
  101. /*++
  102. Routine Description:
  103. Deletes a specified NTE. The target NTE must have been added using
  104. TcpipAddNTE.
  105. Arguments:
  106. NTEContext - The context value identifying the NTE to delete.
  107. Return Value:
  108. ERROR_SUCCESS if the operation was successful.
  109. A Windows error code otherwise.
  110. --*/
  111. {
  112. NTSTATUS status;
  113. HANDLE handle;
  114. IP_DELETE_NTE_REQUEST requestBuffer;
  115. DWORD requestBufferSize = sizeof(requestBuffer);
  116. DWORD responseBufferSize = 0;
  117. status = ClusResOpenDriver(&handle, DD_CLUSNET_DEVICE_NAME);
  118. if ( status != ERROR_SUCCESS ) {
  119. return status;
  120. }
  121. requestBuffer.Context = (unsigned short) NTEContext;
  122. status = ClusResDoIoctl(
  123. handle,
  124. IOCTL_CLUSNET_DELETE_NTE,
  125. &requestBuffer,
  126. requestBufferSize,
  127. NULL,
  128. &responseBufferSize
  129. );
  130. CloseHandle(handle);
  131. if (NT_SUCCESS(status)) {
  132. return(ERROR_SUCCESS);
  133. }
  134. return(RtlNtStatusToDosError(status));
  135. }
  136. DWORD
  137. TcpipSetNTEAddress(
  138. DWORD NTEContext,
  139. IPAddr Address,
  140. IPMask SubnetMask
  141. )
  142. /*++
  143. Routine Description:
  144. Sets the address of a specified NTE.
  145. Arguments:
  146. NTEContext - The context value identifying the target NTE.
  147. Address - The IP address to assign to the NTE. Assigning 0.0.0.0
  148. invalidates the NTE.
  149. SubnetMask - The IP subnet mask to assign to the NTE.
  150. Return Value:
  151. ERROR_SUCCESS if the operation was successful.
  152. A Windows error code otherwise.
  153. --*/
  154. {
  155. NTSTATUS status;
  156. HANDLE handle;
  157. IP_SET_ADDRESS_REQUEST_EX requestBuffer;
  158. DWORD requestBufferSize = sizeof(requestBuffer);
  159. DWORD responseBufferSize = 0;
  160. status = ClusResOpenDriver(&handle, DD_CLUSNET_DEVICE_NAME);
  161. if ( status != ERROR_SUCCESS ) {
  162. return status;
  163. }
  164. requestBuffer.Context = (unsigned short) NTEContext;
  165. requestBuffer.Address = Address;
  166. requestBuffer.SubnetMask = SubnetMask;
  167. requestBuffer.Type = IP_ADDRTYPE_TRANSIENT;
  168. status = ClusResDoIoctl(
  169. handle,
  170. IOCTL_CLUSNET_SET_NTE_ADDRESS,
  171. &requestBuffer,
  172. requestBufferSize,
  173. NULL,
  174. &responseBufferSize
  175. );
  176. CloseHandle(handle);
  177. if (NT_SUCCESS(status)) {
  178. return(ERROR_SUCCESS);
  179. }
  180. return(RtlNtStatusToDosError(status));
  181. }
  182. DWORD
  183. TcpipGetNTEInfo(
  184. IN ULONG NTEContext,
  185. OUT PTCPIP_NTE_INFO NTEInfo
  186. )
  187. /*++
  188. Routine Description:
  189. Gathers information about a specified NTE.
  190. Arguments:
  191. NTEContext - The context value identifying the NTE to query.
  192. Return Value:
  193. ERROR_SUCCESS if the operation was successful.
  194. A Windows error code otherwise.
  195. --*/
  196. {
  197. NTSTATUS status;
  198. HANDLE handle;
  199. IP_GET_NTE_INFO_REQUEST requestBuffer;
  200. DWORD requestBufferSize = sizeof(requestBuffer);
  201. IP_GET_NTE_INFO_RESPONSE responseBuffer;
  202. DWORD responseBufferSize = sizeof(responseBuffer);
  203. status = ClusResOpenDriver(&handle, L"\\Device\\Ip");
  204. if ( status != ERROR_SUCCESS ) {
  205. return status;
  206. }
  207. requestBuffer.Context = (unsigned short) NTEContext;
  208. status = ClusResDoIoctl(
  209. handle,
  210. IOCTL_IP_GET_NTE_INFO,
  211. &requestBuffer,
  212. requestBufferSize,
  213. &responseBuffer,
  214. &responseBufferSize
  215. );
  216. CloseHandle(handle);
  217. if (NT_SUCCESS(status)) {
  218. NTEInfo->Instance = responseBuffer.Instance;
  219. NTEInfo->Address = responseBuffer.Address;
  220. NTEInfo->SubnetMask = responseBuffer.SubnetMask;
  221. NTEInfo->Flags = responseBuffer.Flags;
  222. return(ERROR_SUCCESS);
  223. }
  224. return(RtlNtStatusToDosError(status));
  225. }
  226. DWORD
  227. NbtAddInterface(
  228. OUT LPWSTR DeviceName,
  229. IN OUT LPDWORD DeviceNameSize,
  230. OUT PULONG DeviceInstance
  231. )
  232. /*++
  233. Routine Description:
  234. Adds a new NBT interface.
  235. Arguments:
  236. DeviceName - A unicode string identifying the new NBT interface.
  237. DeviceNameSize - On input, the size of theh device name buffer.
  238. On output, the size of the device name string, or
  239. the size needed to accomodate the string.
  240. DeviceInstance - A pointer to a variable into which to place the
  241. instance ID associated with the new interface.
  242. Return Value:
  243. ERROR_SUCCESS if the operation was successful.
  244. A Windows error code otherwise.
  245. --*/
  246. {
  247. NTSTATUS status;
  248. HANDLE nbthandle = (HANDLE) NULL;
  249. HANDLE cnhandle = (HANDLE) NULL;
  250. PNETBT_ADD_DEL_IF requestBuffer = NULL;
  251. DWORD requestBufferSize = 0;
  252. PNETBT_ADD_DEL_IF responseBuffer = NULL;
  253. DWORD responseBufferSize = 0;
  254. HKEY key = NULL;
  255. LPWSTR NBTDeviceName;
  256. LPWSTR exportString = NULL;
  257. DWORD exportStringSize = 0;
  258. LONG valueType;
  259. //
  260. // get a handle to NetBT's Linkage key, query the size of the
  261. // export value, allocate a buffer large enough to hold it and
  262. // read it in
  263. //
  264. status = RegOpenKeyExW(
  265. HKEY_LOCAL_MACHINE,
  266. L"SYSTEM\\CurrentControlSet\\Services\\NetBT\\Linkage",
  267. 0,
  268. KEY_READ,
  269. &key);
  270. if (status != ERROR_SUCCESS) {
  271. goto error_exit;
  272. }
  273. status = RegQueryValueExW(
  274. key,
  275. L"Export",
  276. NULL,
  277. &valueType,
  278. NULL,
  279. &exportStringSize
  280. );
  281. if (status != ERROR_SUCCESS) {
  282. goto error_exit;
  283. }
  284. exportString = LocalAlloc( LMEM_FIXED, exportStringSize );
  285. if ( exportString == NULL ) {
  286. status = ERROR_NOT_ENOUGH_MEMORY;
  287. goto error_exit;
  288. }
  289. status = RegQueryValueExW(
  290. key,
  291. L"Export",
  292. NULL,
  293. &valueType,
  294. (LPBYTE)exportString,
  295. &exportStringSize
  296. );
  297. if (status != ERROR_SUCCESS) {
  298. goto error_exit;
  299. }
  300. //
  301. // Export is a multi-sz; loop through all the interfaces
  302. // until we find one that we can open successfully.
  303. //
  304. // Hold the handle until we are done with the ioctl so
  305. // that the NBT device doesn't go away.
  306. //
  307. NBTDeviceName = exportString;
  308. do {
  309. status = ClusResOpenDriver(&nbthandle, NBTDeviceName);
  310. if ( status == ERROR_FILE_NOT_FOUND ) {
  311. //
  312. // get the next device name from the export string
  313. //
  314. NBTDeviceName += ( lstrlenW( NBTDeviceName ) + 1 );
  315. if ( *NBTDeviceName == 0 ) {
  316. status = ERROR_FILE_NOT_FOUND;
  317. break;
  318. }
  319. }
  320. } while ( status == ERROR_FILE_NOT_FOUND );
  321. if ( status != ERROR_SUCCESS ) {
  322. goto error_exit;
  323. }
  324. requestBufferSize = FIELD_OFFSET(NETBT_ADD_DEL_IF, IfName[0])
  325. + lstrlenW( NBTDeviceName ) * sizeof(WCHAR)
  326. + sizeof(UNICODE_NULL);
  327. if (requestBufferSize < sizeof(NETBT_ADD_DEL_IF)) {
  328. requestBufferSize = sizeof(NETBT_ADD_DEL_IF);
  329. }
  330. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  331. if (requestBuffer == NULL) {
  332. status = ERROR_NOT_ENOUGH_MEMORY;
  333. goto error_exit;
  334. }
  335. RtlZeroMemory( requestBuffer, requestBufferSize );
  336. requestBuffer->Length = lstrlenW( NBTDeviceName ) * sizeof(WCHAR)
  337. + sizeof(UNICODE_NULL);
  338. RtlCopyMemory(
  339. &requestBuffer->IfName[0],
  340. NBTDeviceName,
  341. requestBuffer->Length
  342. );
  343. responseBufferSize = FIELD_OFFSET(NETBT_ADD_DEL_IF, IfName[0]) +
  344. *DeviceNameSize;
  345. if (responseBufferSize < sizeof(NETBT_ADD_DEL_IF)) {
  346. responseBufferSize = sizeof(NETBT_ADD_DEL_IF);
  347. }
  348. responseBuffer = LocalAlloc(LMEM_FIXED, responseBufferSize);
  349. if (responseBuffer == NULL) {
  350. status = ERROR_NOT_ENOUGH_MEMORY;
  351. goto error_exit;
  352. }
  353. status = ClusResOpenDriver(&cnhandle, DD_CLUSNET_DEVICE_NAME);
  354. if ( status == ERROR_SUCCESS ) {
  355. status = ClusResDoIoctl(
  356. cnhandle,
  357. IOCTL_CLUSNET_ADD_NBT_INTERFACE,
  358. requestBuffer,
  359. requestBufferSize,
  360. responseBuffer,
  361. &responseBufferSize
  362. );
  363. if (NT_SUCCESS(status)) {
  364. *DeviceNameSize = responseBuffer->Length;
  365. if (NT_SUCCESS(responseBuffer->Status)) {
  366. wcscpy(DeviceName, &(responseBuffer->IfName[0]));
  367. *DeviceInstance = responseBuffer->InstanceNumber;
  368. status = ERROR_SUCCESS;
  369. }
  370. else {
  371. status = responseBuffer->Status;
  372. }
  373. }
  374. else {
  375. status = RtlNtStatusToDosError(status);
  376. }
  377. }
  378. error_exit:
  379. if ( key ) {
  380. RegCloseKey( key );
  381. }
  382. if ( exportString ) {
  383. LocalFree( exportString );
  384. }
  385. if ( requestBuffer ) {
  386. LocalFree( requestBuffer );
  387. }
  388. if ( responseBuffer ) {
  389. LocalFree( responseBuffer );
  390. }
  391. if ( nbthandle ) {
  392. CloseHandle( nbthandle );
  393. }
  394. if ( cnhandle ) {
  395. CloseHandle( cnhandle );
  396. }
  397. return(status);
  398. }
  399. DWORD
  400. NbtDeleteInterface(
  401. IN LPWSTR DeviceName
  402. )
  403. /*++
  404. Routine Description:
  405. Deletes an NBT interface.
  406. Arguments:
  407. DeviceName - A unicode string identifying the target NBT interface.
  408. Return Value:
  409. ERROR_SUCCESS if the operation was successful.
  410. A Windows error code otherwise.
  411. --*/
  412. {
  413. NTSTATUS status;
  414. HANDLE handle = (HANDLE) NULL;
  415. DWORD responseBufferSize = 0;
  416. PNETBT_ADD_DEL_IF requestBuffer = NULL;
  417. DWORD requestBufferSize = 0;
  418. requestBufferSize = FIELD_OFFSET(NETBT_ADD_DEL_IF, IfName[0])
  419. + lstrlenW( DeviceName ) * sizeof(WCHAR)
  420. + sizeof(UNICODE_NULL);
  421. if (requestBufferSize < sizeof(NETBT_ADD_DEL_IF)) {
  422. requestBufferSize = sizeof(NETBT_ADD_DEL_IF);
  423. }
  424. requestBuffer = LocalAlloc(LMEM_FIXED, requestBufferSize);
  425. if (requestBuffer == NULL) {
  426. status = ERROR_NOT_ENOUGH_MEMORY;
  427. goto error_exit;
  428. }
  429. RtlZeroMemory( requestBuffer, requestBufferSize );
  430. requestBuffer->Length = lstrlenW( DeviceName ) * sizeof(WCHAR)
  431. + sizeof(UNICODE_NULL);
  432. RtlCopyMemory(
  433. &requestBuffer->IfName[0],
  434. DeviceName,
  435. requestBuffer->Length
  436. );
  437. status = ClusResOpenDriver(&handle, DD_CLUSNET_DEVICE_NAME);
  438. if ( status != ERROR_SUCCESS ) {
  439. goto error_exit;
  440. }
  441. status = ClusResDoIoctl(
  442. handle,
  443. IOCTL_CLUSNET_DEL_NBT_INTERFACE,
  444. requestBuffer,
  445. requestBufferSize,
  446. NULL,
  447. &responseBufferSize
  448. );
  449. if (NT_SUCCESS(status)) {
  450. status = ERROR_SUCCESS;
  451. }
  452. else {
  453. status = RtlNtStatusToDosError(status);
  454. }
  455. error_exit:
  456. if (requestBuffer) {
  457. LocalFree(requestBuffer);
  458. }
  459. if (handle) {
  460. CloseHandle(handle);
  461. }
  462. return(status);
  463. }
  464. DWORD
  465. NbtBindInterface(
  466. IN LPWSTR DeviceName,
  467. IN IPAddr Address,
  468. IN IPMask SubnetMask
  469. )
  470. /*++
  471. Routine Description:
  472. Binds a specified NBT interface to a specified IP address.
  473. Arguments:
  474. DeviceName - A unicode string identifying the target NBT interface.
  475. Address - The IP address to which bind the interface. Assigning 0.0.0.0
  476. invalidates the interface.
  477. SubnetMask - The subnet mask of the IP interface.
  478. Return Value:
  479. ERROR_SUCCESS if the operation was successful.
  480. A Windows error code otherwise.
  481. --*/
  482. {
  483. NTSTATUS status;
  484. HANDLE handle;
  485. tNEW_IP_ADDRESS requestBuffer;
  486. DWORD requestBufferSize = sizeof(requestBuffer);
  487. DWORD responseBufferSize = 0;
  488. status = ClusResOpenDriver(&handle, DeviceName);
  489. if ( status != ERROR_SUCCESS ) {
  490. return status;
  491. }
  492. requestBuffer.IpAddress = Address;
  493. requestBuffer.SubnetMask = SubnetMask;
  494. status = ClusResDoIoctl(
  495. handle,
  496. IOCTL_NETBT_NEW_IPADDRESS,
  497. &requestBuffer,
  498. requestBufferSize,
  499. NULL,
  500. &responseBufferSize
  501. );
  502. CloseHandle(handle);
  503. if (NT_SUCCESS(status)) {
  504. return(ERROR_SUCCESS);
  505. }
  506. return(RtlNtStatusToDosError(status));
  507. }
  508. DWORD
  509. NbtSetWinsAddrInterface(
  510. IN LPWSTR DeviceName,
  511. IN IPAddr PrWinsAddress,
  512. IN IPAddr SecWinsAddress
  513. )
  514. /*++
  515. Routine Description:
  516. Sets the WINS addrs for a given Nbt Interface.
  517. Arguments:
  518. DeviceName - A unicode string identifying the target NBT interface.
  519. PrWinsAddress - Primary WINS addr
  520. SecWinsAddress - Secondary WINS addr
  521. Return Value:
  522. ERROR_SUCCESS if the operation was successful.
  523. A Windows error code otherwise.
  524. --*/
  525. {
  526. NTSTATUS status;
  527. HANDLE handle;
  528. NETBT_SET_WINS_ADDR requestBuffer;
  529. DWORD requestBufferSize = sizeof(requestBuffer);
  530. DWORD responseBufferSize = 0;
  531. status = ClusResOpenDriver(&handle, DeviceName);
  532. if ( status != ERROR_SUCCESS ) {
  533. return status;
  534. }
  535. requestBuffer.PrimaryWinsAddr = ntohl(PrWinsAddress);
  536. requestBuffer.SecondaryWinsAddr = ntohl(SecWinsAddress);
  537. status = ClusResDoIoctl(
  538. handle,
  539. IOCTL_NETBT_SET_WINS_ADDRESS,
  540. &requestBuffer,
  541. requestBufferSize,
  542. NULL,
  543. &responseBufferSize
  544. );
  545. CloseHandle(handle);
  546. if (NT_SUCCESS(status)) {
  547. return(ERROR_SUCCESS);
  548. }
  549. return(RtlNtStatusToDosError(status));
  550. }
  551. DWORD
  552. NbtGetWinsAddresses(
  553. IN LPWSTR DeviceName,
  554. OUT IPAddr * PrimaryWinsServer,
  555. OUT IPAddr * SecondaryWinsServer
  556. )
  557. /*++
  558. Routine Description:
  559. Returns the addresses of the WINS servers for which the specified device
  560. is configured.
  561. Arguments:
  562. DeviceName - A unicode string identifying the target NBT interface.
  563. PrimaryWinsServer - A pointer to a variable into which to place the address
  564. of the primary WINS server.
  565. SecondaryWinsServer - A pointer to a variable into which to place the address
  566. of the primary WINS server.
  567. Return Value:
  568. ERROR_SUCCESS if the operation was successful.
  569. A Windows error code otherwise.
  570. --*/
  571. {
  572. NTSTATUS status;
  573. HANDLE handle;
  574. tWINS_ADDRESSES responseBuffer;
  575. DWORD responseBufferSize = sizeof(responseBuffer);
  576. status = ClusResOpenDriver(&handle, DeviceName);
  577. if ( status != ERROR_SUCCESS ) {
  578. return status;
  579. }
  580. status = ClusResDoIoctl(
  581. handle,
  582. IOCTL_NETBT_GET_WINS_ADDR,
  583. NULL,
  584. 0,
  585. &responseBuffer,
  586. &responseBufferSize
  587. );
  588. CloseHandle(handle);
  589. if (NT_SUCCESS(status)) {
  590. *PrimaryWinsServer = htonl(responseBuffer.PrimaryWinsServer);
  591. *SecondaryWinsServer = htonl(responseBuffer.BackupWinsServer);
  592. return(ERROR_SUCCESS);
  593. }
  594. return(RtlNtStatusToDosError(status));
  595. }
  596. DWORD
  597. NbtGetInterfaceInfo(
  598. IN LPWSTR DeviceName,
  599. OUT IPAddr * Address,
  600. OUT PULONG DeviceInstance
  601. )
  602. /*++
  603. Routine Description:
  604. Returns the IP address to which an NBT interface is bound and the interface
  605. instance ID.
  606. Arguments:
  607. DeviceName - A unicode string identifying the target NBT interface.
  608. Address - A pointer to the location in which to store the address of the
  609. interface.
  610. DeviceInstance - A pointer to the location in which to store the instance ID
  611. associated with the interface.
  612. Return Value:
  613. ERROR_SUCCESS if the operation was successful.
  614. A Windows error code otherwise.
  615. --*/
  616. {
  617. NTSTATUS status;
  618. HANDLE handle;
  619. IPAddr address;
  620. NETBT_ADD_DEL_IF responseBuffer;
  621. DWORD responseBufferSize;
  622. status = ClusResOpenDriver(&handle, DeviceName);
  623. if ( status != ERROR_SUCCESS ) {
  624. return status;
  625. }
  626. responseBufferSize = sizeof(address);
  627. status = ClusResDoIoctl(
  628. handle,
  629. IOCTL_NETBT_GET_IP_ADDRS,
  630. NULL,
  631. 0,
  632. &address,
  633. &responseBufferSize
  634. );
  635. if (!((status == STATUS_SUCCESS) || (status == STATUS_BUFFER_OVERFLOW))) {
  636. CloseHandle(handle);
  637. return(RtlNtStatusToDosError(status));
  638. }
  639. *Address = htonl(address);
  640. responseBufferSize = sizeof(responseBuffer);
  641. status = ClusResDoIoctl(
  642. handle,
  643. IOCTL_NETBT_QUERY_INTERFACE_INSTANCE,
  644. NULL,
  645. 0,
  646. &responseBuffer,
  647. &responseBufferSize
  648. );
  649. CloseHandle(handle);
  650. if (status == STATUS_SUCCESS) {
  651. if (responseBuffer.Status == STATUS_SUCCESS) {
  652. *DeviceInstance = responseBuffer.InstanceNumber;
  653. }
  654. else {
  655. status = RtlNtStatusToDosError(responseBuffer.Status);
  656. }
  657. }
  658. else {
  659. status = RtlNtStatusToDosError(status);
  660. }
  661. return(status);
  662. }