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.

695 lines
22 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ndisapi.c
  5. Abstract:
  6. NDIS User-Mode apis to support PnP from the network UI
  7. Author:
  8. JameelH
  9. Environment:
  10. Kernel mode, FSD
  11. Revision History:
  12. Aug 1997 JameelH Initial version
  13. --*/
  14. #include <windows.h>
  15. #include <wtypes.h>
  16. #include <ntddndis.h>
  17. #include <ndisprv.h>
  18. #include <devioctl.h>
  19. #ifndef UNICODE_STRING
  20. typedef struct _UNICODE_STRING
  21. {
  22. USHORT Length;
  23. USHORT MaximumLength;
  24. PWSTR Buffer;
  25. } UNICODE_STRING, *PUNICODE_STRING;
  26. #endif
  27. #include <ndispnp.h>
  28. #include <ndisprv.h>
  29. #define MAC_ADDRESS_SIZE 6
  30. #define VENDOR_ID_SIZE 3
  31. extern
  32. VOID
  33. InitUnicodeString(
  34. IN PUNICODE_STRING DestinationString,
  35. IN PCWSTR SourceString
  36. );
  37. extern
  38. LONG
  39. AppendUnicodeStringToString(
  40. IN PUNICODE_STRING Destination,
  41. IN PUNICODE_STRING Source
  42. );
  43. extern
  44. HANDLE
  45. OpenDevice(
  46. IN PUNICODE_STRING DeviceName
  47. );
  48. //
  49. // UNICODE_STRING_SIZE calculates the size of the buffer needed to
  50. // store a given UNICODE_STRING including an appended null-terminator.
  51. //
  52. // ULONG
  53. // UNICODE_STRING_SIZE(
  54. // PUNICODE_STRING String
  55. // );
  56. //
  57. #define UNICODE_STRING_SIZE(x) \
  58. ((((x) == NULL) ? 0 : (x)->Length) + sizeof(WCHAR))
  59. VOID
  60. NdispUnicodeStringToVar(
  61. IN PVOID Base,
  62. IN PUNICODE_STRING String,
  63. IN OUT PNDIS_VAR_DATA_DESC NdisVar
  64. )
  65. /*++
  66. Routine Description:
  67. This function copies the contents of a UNICODE_STRING to an
  68. NDIS_VAR_DATA structure. NdisVar->Offset is treated as an input parameter
  69. and represents the offset into Base that the string characters should be
  70. copied to.
  71. Arguments:
  72. Base - Specifies the base address of the IOCTL buffer.
  73. String - Supplies a pointer to the UNICODE_STRING that should be copied.
  74. NdisVar - Supplies a pointer to the target NDIS_VAR_DATA_DESC. Its Offset
  75. field is taken as input, and its Length and MaximumLength fields
  76. are treated as output.
  77. Return Value:
  78. None.
  79. --*/
  80. {
  81. PWCHAR destination;
  82. //
  83. // NdisVar->Offset is assumed to be filled in and is treated
  84. // as an input parameter.
  85. //
  86. destination = (PWCHAR)(((PCHAR)Base) + NdisVar->Offset);
  87. //
  88. // Copy over the UNICODE_STRING, if any, and set NdisVar->Length
  89. //
  90. if ((String != NULL) && (String->Length > 0)) {
  91. NdisVar->Length = String->Length;
  92. memcpy(destination, String->Buffer, NdisVar->Length );
  93. } else {
  94. NdisVar->Length = 0;
  95. }
  96. //
  97. // Null-terminate, fill in MaxiumLength and we're done.
  98. //
  99. *(destination + NdisVar->Length / sizeof(WCHAR)) = L'\0';
  100. NdisVar->MaximumLength = NdisVar->Length + sizeof(WCHAR);
  101. }
  102. UINT
  103. NdisHandlePnPEvent(
  104. IN UINT Layer,
  105. IN UINT Operation,
  106. IN PUNICODE_STRING LowerComponent OPTIONAL,
  107. IN PUNICODE_STRING UpperComponent OPTIONAL,
  108. IN PUNICODE_STRING BindList OPTIONAL,
  109. IN PVOID ReConfigBuffer OPTIONAL,
  110. IN UINT ReConfigBufferSize OPTIONAL
  111. )
  112. {
  113. PNDIS_PNP_OPERATION Op;
  114. NDIS_PNP_OPERATION tempOp;
  115. HANDLE hDevice;
  116. BOOL fResult = FALSE;
  117. UINT cb, Size;
  118. DWORD Error;
  119. ULONG padding;
  120. do
  121. {
  122. //
  123. // Validate Layer & Operation
  124. //
  125. if (((Layer != NDIS) && (Layer != TDI)) ||
  126. ((Operation != BIND) && (Operation != UNBIND) && (Operation != RECONFIGURE) &&
  127. (Operation != UNLOAD) && (Operation != REMOVE_DEVICE) &&
  128. (Operation != ADD_IGNORE_BINDING) &&
  129. (Operation != DEL_IGNORE_BINDING) &&
  130. (Operation != BIND_LIST)))
  131. {
  132. Error = ERROR_INVALID_PARAMETER;
  133. break;
  134. }
  135. //
  136. // Allocate and initialize memory for the block to be passed down. The buffer
  137. // will look like this:
  138. //
  139. //
  140. // +=================================+
  141. // | NDIS_PNP_OPERATION |
  142. // | ReConfigBufferOff | ----+
  143. // +--- | LowerComponent.Offset | |
  144. // | | UpperComponent.Offset | --+ |
  145. // +-|--- | BindList.Offset | | |
  146. // | +--> +---------------------------------+ | |
  147. // | | LowerComponentStringBuffer | | |
  148. // | +---------------------------------+ <-+ |
  149. // | | UpperComponentStringBuffer | |
  150. // +----> +---------------------------------+ |
  151. // | BindListStringBuffer | |
  152. // +---------------------------------+ |
  153. // | Padding to ensure ULONG_PTR | |
  154. // | alignment of ReConfigBuffer | |
  155. // +---------------------------------+ <---+
  156. // | ReConfigBuffer |
  157. // +=================================+
  158. //
  159. // tempOp is a temporary structure into which we will store offsets as
  160. // they are calculated. This temporary structure will be moved to
  161. // the head of the real buffer once its size is known and it is
  162. // allocated.
  163. //
  164. Size = sizeof(NDIS_PNP_OPERATION);
  165. tempOp.LowerComponent.Offset = Size;
  166. Size += UNICODE_STRING_SIZE(LowerComponent);
  167. tempOp.UpperComponent.Offset = Size;
  168. Size += UNICODE_STRING_SIZE(UpperComponent);
  169. tempOp.BindList.Offset = Size;
  170. Size += UNICODE_STRING_SIZE(BindList);
  171. padding = (sizeof(ULONG_PTR) - (Size & (sizeof(ULONG_PTR) - 1))) &
  172. (sizeof(ULONG_PTR) - 1);
  173. Size += padding;
  174. tempOp.ReConfigBufferOff = Size;
  175. Size += ReConfigBufferSize + 1;
  176. Op = (PNDIS_PNP_OPERATION)LocalAlloc(LPTR, Size);
  177. if (Op == NULL)
  178. {
  179. Error = ERROR_NOT_ENOUGH_MEMORY;
  180. break;
  181. }
  182. //
  183. // We have a buffer of the necessary size. Copy in the partially-
  184. // filled in tempOp, then fill in the remaining fields and copy the
  185. // data into the buffer.
  186. //
  187. *Op = tempOp;
  188. Op->Layer = Layer;
  189. Op->Operation = Operation;
  190. //
  191. // Copy over the three unicode strings
  192. //
  193. NdispUnicodeStringToVar( Op, LowerComponent, &Op->LowerComponent );
  194. NdispUnicodeStringToVar( Op, UpperComponent, &Op->UpperComponent );
  195. NdispUnicodeStringToVar( Op, BindList, &Op->BindList );
  196. //
  197. // Finally, copy over the ReConfigBuffer
  198. //
  199. Op->ReConfigBufferSize = ReConfigBufferSize;
  200. if (ReConfigBufferSize > 0)
  201. {
  202. memcpy((PUCHAR)Op + Op->ReConfigBufferOff,
  203. ReConfigBuffer,
  204. ReConfigBufferSize);
  205. }
  206. *((PUCHAR)Op + Op->ReConfigBufferOff + ReConfigBufferSize) = 0;
  207. hDevice = CreateFile(L"\\\\.\\NDIS",
  208. GENERIC_READ | GENERIC_WRITE,
  209. 0, // sharing mode - not significant
  210. NULL, // security attributes
  211. OPEN_EXISTING,
  212. 0, // file attributes and flags
  213. NULL); // handle to template file
  214. if (hDevice != INVALID_HANDLE_VALUE)
  215. {
  216. fResult = DeviceIoControl(hDevice,
  217. IOCTL_NDIS_DO_PNP_OPERATION,
  218. Op, // input buffer
  219. Size, // input buffer size
  220. NULL, // output buffer
  221. 0, // output buffer size
  222. &cb, // bytes returned
  223. NULL); // OVERLAPPED structure
  224. Error = GetLastError();
  225. CloseHandle(hDevice);
  226. }
  227. else
  228. {
  229. Error = GetLastError();
  230. }
  231. LocalFree(Op);
  232. } while (FALSE);
  233. SetLastError(Error);
  234. return(fResult);
  235. }
  236. NDIS_OID StatsOidList[] =
  237. {
  238. OID_GEN_LINK_SPEED,
  239. OID_GEN_MEDIA_IN_USE | NDIS_OID_PRIVATE,
  240. OID_GEN_MEDIA_CONNECT_STATUS | NDIS_OID_PRIVATE,
  241. OID_GEN_XMIT_OK,
  242. OID_GEN_RCV_OK,
  243. OID_GEN_XMIT_ERROR,
  244. OID_GEN_RCV_ERROR,
  245. OID_GEN_DIRECTED_FRAMES_RCV | NDIS_OID_PRIVATE,
  246. OID_GEN_DIRECTED_BYTES_XMIT | NDIS_OID_PRIVATE,
  247. OID_GEN_DIRECTED_BYTES_RCV | NDIS_OID_PRIVATE,
  248. OID_GEN_ELAPSED_TIME | NDIS_OID_PRIVATE,
  249. OID_GEN_INIT_TIME_MS | NDIS_OID_PRIVATE,
  250. OID_GEN_RESET_COUNTS | NDIS_OID_PRIVATE,
  251. OID_GEN_MEDIA_SENSE_COUNTS | NDIS_OID_PRIVATE,
  252. OID_GEN_PHYSICAL_MEDIUM | NDIS_OID_PRIVATE
  253. };
  254. UINT NumOidsInList = sizeof(StatsOidList)/sizeof(NDIS_OID);
  255. UINT
  256. NdisQueryStatistics(
  257. IN PUNICODE_STRING Device,
  258. OUT PNIC_STATISTICS Statistics
  259. )
  260. {
  261. NDIS_STATISTICS_VALUE StatsBuf[4*sizeof(StatsOidList)/sizeof(NDIS_OID)];
  262. PNDIS_STATISTICS_VALUE pStatsBuf;
  263. HANDLE hDevice;
  264. BOOL fResult = FALSE;
  265. UINT cb, Size, Index;
  266. DWORD Error;
  267. if (Statistics->Size != sizeof(NIC_STATISTICS))
  268. {
  269. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  270. return(FALSE);
  271. }
  272. memset(Statistics, 0, sizeof(NIC_STATISTICS));
  273. Statistics->DeviceState = DEVICE_STATE_DISCONNECTED;
  274. Statistics->MediaState = MEDIA_STATE_UNKNOWN;
  275. hDevice = OpenDevice(Device);
  276. if (hDevice != NULL)
  277. {
  278. Statistics->MediaState = MEDIA_STATE_CONNECTED; // default, if the device does not support
  279. Statistics->DeviceState = DEVICE_STATE_CONNECTED;
  280. fResult = DeviceIoControl(hDevice,
  281. IOCTL_NDIS_QUERY_SELECTED_STATS,
  282. StatsOidList, // input buffer
  283. sizeof(StatsOidList), // input buffer size
  284. StatsBuf, // output buffer
  285. sizeof(StatsBuf), // output buffer size
  286. &cb, // bytes returned
  287. NULL); // OVERLAPPED structure
  288. Error = GetLastError();
  289. CloseHandle(hDevice);
  290. if (fResult)
  291. {
  292. Error = NO_ERROR;
  293. for (Index = Size = 0, pStatsBuf = StatsBuf; Size < cb; Index++)
  294. {
  295. LARGE_INTEGER Value;
  296. NDIS_OID Oid;
  297. Value.QuadPart = 0;
  298. if (pStatsBuf->DataLength == sizeof(LARGE_INTEGER))
  299. {
  300. // Use memcpy rather than assignment to avoid unalignment
  301. // faults on ia64.
  302. //
  303. memcpy(&Value.QuadPart, &pStatsBuf->Data[0], pStatsBuf->DataLength);
  304. }
  305. else
  306. {
  307. Value.LowPart = *(PULONG)(&pStatsBuf->Data[0]);
  308. }
  309. Size += (pStatsBuf->DataLength + FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data));
  310. Oid = pStatsBuf->Oid;
  311. pStatsBuf = (PNDIS_STATISTICS_VALUE)((PUCHAR)pStatsBuf +
  312. FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data) +
  313. pStatsBuf->DataLength);
  314. switch (Oid & ~NDIS_OID_PRIVATE)
  315. {
  316. case OID_GEN_LINK_SPEED:
  317. Statistics->LinkSpeed = Value.LowPart;
  318. break;
  319. case OID_GEN_MEDIA_CONNECT_STATUS:
  320. Statistics->MediaState = (Value.LowPart == NdisMediaStateConnected) ?
  321. MEDIA_STATE_CONNECTED : MEDIA_STATE_DISCONNECTED;
  322. break;
  323. case OID_GEN_MEDIA_IN_USE:
  324. Statistics->MediaType = Value.LowPart;
  325. break;
  326. case OID_GEN_XMIT_OK:
  327. Statistics->PacketsSent = Value.QuadPart;
  328. break;
  329. case OID_GEN_RCV_OK:
  330. Statistics->PacketsReceived = Value.QuadPart;
  331. break;
  332. case OID_GEN_XMIT_ERROR:
  333. Statistics->PacketsSendErrors = Value.LowPart;
  334. break;
  335. case OID_GEN_RCV_ERROR:
  336. Statistics->PacketsReceiveErrors = Value.LowPart;
  337. break;
  338. case OID_GEN_DIRECTED_BYTES_XMIT:
  339. Statistics->BytesSent += Value.QuadPart;
  340. break;
  341. case OID_GEN_MULTICAST_BYTES_XMIT:
  342. Statistics->BytesSent += Value.QuadPart;
  343. break;
  344. case OID_GEN_BROADCAST_BYTES_XMIT:
  345. Statistics->BytesSent += Value.QuadPart;
  346. break;
  347. case OID_GEN_DIRECTED_BYTES_RCV:
  348. Statistics->BytesReceived += Value.QuadPart;
  349. Statistics->DirectedBytesReceived = Value.QuadPart;
  350. break;
  351. case OID_GEN_DIRECTED_FRAMES_RCV:
  352. Statistics->DirectedPacketsReceived = Value.QuadPart;
  353. break;
  354. case OID_GEN_MULTICAST_BYTES_RCV:
  355. Statistics->BytesReceived += Value.QuadPart;
  356. break;
  357. case OID_GEN_BROADCAST_BYTES_RCV:
  358. Statistics->BytesReceived += Value.QuadPart;
  359. break;
  360. case OID_GEN_ELAPSED_TIME:
  361. Statistics->ConnectTime = Value.LowPart;
  362. break;
  363. case OID_GEN_INIT_TIME_MS:
  364. Statistics->InitTime = Value.LowPart;
  365. break;
  366. case OID_GEN_RESET_COUNTS:
  367. Statistics->ResetCount = Value.LowPart;
  368. break;
  369. case OID_GEN_MEDIA_SENSE_COUNTS:
  370. Statistics->MediaSenseConnectCount = Value.LowPart >> 16;
  371. Statistics->MediaSenseDisconnectCount = Value.LowPart & 0xFFFF;
  372. break;
  373. case OID_GEN_PHYSICAL_MEDIUM:
  374. Statistics->PhysicalMediaType = Value.LowPart;
  375. break;
  376. default:
  377. // ASSERT(0);
  378. break;
  379. }
  380. }
  381. }
  382. else
  383. {
  384. Error = GetLastError();
  385. }
  386. }
  387. else
  388. {
  389. Error = GetLastError();
  390. }
  391. SetLastError(Error);
  392. return(fResult);
  393. }
  394. UINT
  395. NdisEnumerateInterfaces(
  396. IN PNDIS_ENUM_INTF Interfaces,
  397. IN UINT Size
  398. )
  399. {
  400. HANDLE hDevice;
  401. BOOL fResult = FALSE;
  402. UINT cb;
  403. DWORD Error = NO_ERROR;
  404. do
  405. {
  406. hDevice = CreateFile(L"\\\\.\\NDIS",
  407. GENERIC_READ | GENERIC_WRITE,
  408. 0, // sharing mode - not significant
  409. NULL, // security attributes
  410. OPEN_EXISTING,
  411. 0, // file attributes and flags
  412. NULL); // handle to template file
  413. if (hDevice != INVALID_HANDLE_VALUE)
  414. {
  415. fResult = DeviceIoControl(hDevice,
  416. IOCTL_NDIS_ENUMERATE_INTERFACES,
  417. NULL, // input buffer
  418. 0, // input buffer size
  419. Interfaces, // output buffer
  420. Size, // output buffer size
  421. &cb, // bytes returned
  422. NULL); // OVERLAPPED structure
  423. Error = GetLastError();
  424. CloseHandle(hDevice);
  425. if (Error == NO_ERROR)
  426. {
  427. UINT i;
  428. //
  429. // Fix-up pointers
  430. //
  431. for (i = 0; i < Interfaces->TotalInterfaces; i++)
  432. {
  433. OFFSET_TO_POINTER(Interfaces->Interface[i].DeviceName.Buffer, Interfaces);
  434. OFFSET_TO_POINTER(Interfaces->Interface[i].DeviceDescription.Buffer, Interfaces);
  435. }
  436. }
  437. }
  438. else
  439. {
  440. Error = GetLastError();
  441. }
  442. } while (FALSE);
  443. SetLastError(Error);
  444. return(fResult);
  445. }
  446. #if 0
  447. UINT
  448. NdisQueryDeviceBundle(
  449. IN PUNICODE_STRING Device,
  450. OUT PDEVICE_BUNDLE BundleBuffer,
  451. IN UINT BufferSize
  452. )
  453. {
  454. HANDLE hDevice;
  455. BOOL fResult = FALSE;
  456. UINT cb;
  457. DWORD Error = NO_ERROR;
  458. do
  459. {
  460. if (BufferSize < (sizeof(DEVICE_BUNDLE) + Device->MaximumLength))
  461. {
  462. Error = ERROR_INSUFFICIENT_BUFFER;
  463. break;
  464. }
  465. hDevice = OpenDevice(Device);
  466. if (hDevice != NULL)
  467. {
  468. fResult = DeviceIoControl(hDevice,
  469. IOCTL_NDIS_GET_DEVICE_BUNDLE,
  470. NULL, // input buffer
  471. 0, // input buffer size
  472. BundleBuffer, // output buffer
  473. BufferSize, // output buffer size
  474. &cb, // bytes returned
  475. NULL); // OVERLAPPED structure
  476. Error = GetLastError();
  477. CloseHandle(hDevice);
  478. if (Error == NO_ERROR)
  479. {
  480. UINT i;
  481. //
  482. // Fix-up pointers
  483. //
  484. for (i = 0; i < BundleBuffer->TotalEntries; i++)
  485. {
  486. OFFSET_TO_POINTER(BundleBuffer->Entries[i].Name.Buffer, BundleBuffer);
  487. }
  488. }
  489. }
  490. else
  491. {
  492. Error = ERROR_FILE_NOT_FOUND;
  493. }
  494. } while (FALSE);
  495. SetLastError(Error);
  496. return(fResult);
  497. }
  498. #endif
  499. UINT
  500. NdisQueryHwAddress(
  501. IN PUNICODE_STRING Device,
  502. OUT PUCHAR CurrentAddress,
  503. OUT PUCHAR PermanentAddress,
  504. OUT PUCHAR VendorId
  505. )
  506. {
  507. UCHAR Buf[3*sizeof(NDIS_STATISTICS_VALUE) + 48];
  508. PNDIS_STATISTICS_VALUE pBuf;
  509. NDIS_OID Oids[] = { OID_802_3_CURRENT_ADDRESS, OID_802_3_PERMANENT_ADDRESS, OID_GEN_VENDOR_ID };
  510. HANDLE hDevice;
  511. BOOL fResult = FALSE;
  512. UINT cb;
  513. DWORD Error;
  514. memset(CurrentAddress, 0, MAC_ADDRESS_SIZE);
  515. memset(PermanentAddress, 0, MAC_ADDRESS_SIZE);
  516. memset(VendorId, 0, VENDOR_ID_SIZE);
  517. hDevice = OpenDevice(Device);
  518. if (hDevice != NULL)
  519. {
  520. fResult = DeviceIoControl(hDevice,
  521. IOCTL_NDIS_QUERY_SELECTED_STATS,
  522. &Oids, // input buffer
  523. sizeof(Oids), // input buffer size
  524. Buf, // output buffer
  525. sizeof(Buf), // output buffer size
  526. &cb, // bytes returned
  527. NULL); // OVERLAPPED structure
  528. Error = GetLastError();
  529. CloseHandle(hDevice);
  530. if (fResult)
  531. {
  532. UINT Size, tmp;
  533. Error = NO_ERROR;
  534. pBuf = (PNDIS_STATISTICS_VALUE)Buf;
  535. for (Size = 0; Size < cb; )
  536. {
  537. tmp = (pBuf->DataLength + FIELD_OFFSET(NDIS_STATISTICS_VALUE, Data));
  538. Size += tmp;
  539. switch (pBuf->Oid)
  540. {
  541. case OID_802_3_CURRENT_ADDRESS:
  542. memcpy(CurrentAddress, pBuf->Data, MAC_ADDRESS_SIZE);
  543. break;
  544. case OID_802_3_PERMANENT_ADDRESS:
  545. memcpy(PermanentAddress, pBuf->Data, MAC_ADDRESS_SIZE);
  546. break;
  547. case OID_GEN_VENDOR_ID:
  548. memcpy(VendorId, pBuf->Data, VENDOR_ID_SIZE);
  549. }
  550. pBuf = (PNDIS_STATISTICS_VALUE)((PUCHAR)pBuf + tmp);
  551. }
  552. }
  553. else
  554. {
  555. Error = GetLastError();
  556. }
  557. }
  558. else
  559. {
  560. Error = ERROR_FILE_NOT_FOUND;
  561. }
  562. SetLastError(Error);
  563. return(fResult);
  564. }
  565. VOID
  566. XSetLastError(
  567. IN ULONG Error
  568. )
  569. {
  570. SetLastError(Error);
  571. }