Source code of Windows XP (NT5)
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.

1944 lines
50 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ndisbind.c
  5. Abstract:
  6. NDIS protocol entry points and utility routines to handle binding
  7. and unbinding from adapters.
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. arvindm 4/5/2000 Created
  12. --*/
  13. #include "precomp.h"
  14. #define __FILENUMBER 'DNIB'
  15. NDIS_OID ndisuioSupportedSetOids[] =
  16. {
  17. OID_802_11_INFRASTRUCTURE_MODE,
  18. OID_802_11_AUTHENTICATION_MODE,
  19. OID_802_11_RELOAD_DEFAULTS,
  20. OID_802_11_REMOVE_WEP,
  21. OID_802_11_WEP_STATUS,
  22. OID_802_11_BSSID_LIST_SCAN,
  23. OID_802_11_ADD_WEP,
  24. OID_802_11_SSID,
  25. OID_802_11_BSSID,
  26. OID_802_11_BSSID_LIST,
  27. OID_802_11_DISASSOCIATE,
  28. OID_802_11_STATISTICS, // Later used by power management
  29. OID_802_11_POWER_MODE, // Later used by power management
  30. OID_802_11_NETWORK_TYPE_IN_USE,
  31. OID_802_11_RSSI,
  32. OID_802_11_SUPPORTED_RATES,
  33. OID_802_11_CONFIGURATION,
  34. OID_802_3_MULTICAST_LIST
  35. };
  36. VOID
  37. NdisuioBindAdapter(
  38. OUT PNDIS_STATUS pStatus,
  39. IN NDIS_HANDLE BindContext,
  40. IN PNDIS_STRING pDeviceName,
  41. IN PVOID SystemSpecific1,
  42. IN PVOID SystemSpecific2
  43. )
  44. /*++
  45. Routine Description:
  46. Protocol Bind Handler entry point called when NDIS wants us
  47. to bind to an adapter. We go ahead and set up a binding.
  48. An OPEN_CONTEXT structure is allocated to keep state about
  49. this binding.
  50. Arguments:
  51. pStatus - place to return bind status
  52. BindContext - handle to use with NdisCompleteBindAdapter
  53. DeviceName - adapter to bind to
  54. SystemSpecific1 - used to access protocol-specific registry
  55. key for this binding
  56. SystemSpecific2 - unused
  57. Return Value:
  58. None
  59. --*/
  60. {
  61. PNDISUIO_OPEN_CONTEXT pOpenContext;
  62. NDIS_STATUS Status, ConfigStatus;
  63. NDIS_HANDLE ConfigHandle;
  64. do
  65. {
  66. //
  67. // Allocate our context for this open.
  68. //
  69. NUIO_ALLOC_MEM(pOpenContext, sizeof(NDISUIO_OPEN_CONTEXT));
  70. if (pOpenContext == NULL)
  71. {
  72. Status = NDIS_STATUS_RESOURCES;
  73. break;
  74. }
  75. //
  76. // Initialize it.
  77. //
  78. NUIO_ZERO_MEM(pOpenContext, sizeof(NDISUIO_OPEN_CONTEXT));
  79. NUIO_SET_SIGNATURE(pOpenContext, oc);
  80. NUIO_INIT_LOCK(&pOpenContext->Lock);
  81. NUIO_INIT_LIST_HEAD(&pOpenContext->PendedReads);
  82. NUIO_INIT_LIST_HEAD(&pOpenContext->PendedWrites);
  83. NUIO_INIT_LIST_HEAD(&pOpenContext->RecvPktQueue);
  84. NUIO_INIT_EVENT(&pOpenContext->PoweredUpEvent);
  85. //
  86. // Start off by assuming that the device below is powered up.
  87. //
  88. NUIO_SIGNAL_EVENT(&pOpenContext->PoweredUpEvent);
  89. //
  90. // Determine the platform we are running on.
  91. //
  92. pOpenContext->bRunningOnWin9x = TRUE;
  93. NdisOpenProtocolConfiguration(
  94. &ConfigStatus,
  95. &ConfigHandle,
  96. (PNDIS_STRING)SystemSpecific1);
  97. if (ConfigStatus == NDIS_STATUS_SUCCESS)
  98. {
  99. PNDIS_CONFIGURATION_PARAMETER pParameter;
  100. NDIS_STRING VersionKey = NDIS_STRING_CONST("Environment");
  101. NdisReadConfiguration(
  102. &ConfigStatus,
  103. &pParameter,
  104. ConfigHandle,
  105. &VersionKey,
  106. NdisParameterInteger);
  107. if ((ConfigStatus == NDIS_STATUS_SUCCESS) &&
  108. ((pParameter->ParameterType == NdisParameterInteger) ||
  109. (pParameter->ParameterType == NdisParameterHexInteger)))
  110. {
  111. pOpenContext->bRunningOnWin9x =
  112. (pParameter->ParameterData.IntegerData == NdisEnvironmentWindows);
  113. }
  114. NdisCloseConfiguration(ConfigHandle);
  115. }
  116. NUIO_REF_OPEN(pOpenContext); // Bind
  117. //
  118. // Add it to the global list.
  119. //
  120. NUIO_ACQUIRE_LOCK(&Globals.GlobalLock);
  121. NUIO_INSERT_TAIL_LIST(&Globals.OpenList,
  122. &pOpenContext->Link);
  123. NUIO_RELEASE_LOCK(&Globals.GlobalLock);
  124. //
  125. // Set up the NDIS binding.
  126. //
  127. Status = ndisuioCreateBinding(
  128. pOpenContext,
  129. (PUCHAR)pDeviceName->Buffer,
  130. pDeviceName->Length);
  131. if (Status != NDIS_STATUS_SUCCESS)
  132. {
  133. break;
  134. }
  135. }
  136. while (FALSE);
  137. *pStatus = Status;
  138. return;
  139. }
  140. VOID
  141. NdisuioOpenAdapterComplete(
  142. IN NDIS_HANDLE ProtocolBindingContext,
  143. IN NDIS_STATUS Status,
  144. IN NDIS_STATUS OpenErrorCode
  145. )
  146. /*++
  147. Routine Description:
  148. Completion routine called by NDIS if our call to NdisOpenAdapter
  149. pends. Wake up the thread that called NdisOpenAdapter.
  150. Arguments:
  151. ProtocolBindingContext - pointer to open context structure
  152. Status - status of the open
  153. OpenErrorCode - if unsuccessful, additional information
  154. Return Value:
  155. None
  156. --*/
  157. {
  158. PNDISUIO_OPEN_CONTEXT pOpenContext;
  159. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  160. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  161. pOpenContext->BindStatus = Status;
  162. NUIO_SIGNAL_EVENT(&pOpenContext->BindEvent);
  163. }
  164. VOID
  165. NdisuioUnbindAdapter(
  166. OUT PNDIS_STATUS pStatus,
  167. IN NDIS_HANDLE ProtocolBindingContext,
  168. IN NDIS_HANDLE UnbindContext
  169. )
  170. /*++
  171. Routine Description:
  172. NDIS calls this when it wants us to close the binding to an adapter.
  173. Arguments:
  174. pStatus - place to return status of Unbind
  175. ProtocolBindingContext - pointer to open context structure
  176. UnbindContext - to use in NdisCompleteUnbindAdapter if we return pending
  177. Return Value:
  178. None
  179. --*/
  180. {
  181. PNDISUIO_OPEN_CONTEXT pOpenContext;
  182. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  183. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  184. //
  185. // Mark this open as having seen an Unbind.
  186. //
  187. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  188. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_UNBIND_FLAGS, NUIOO_UNBIND_RECEIVED);
  189. //
  190. // In case we had threads blocked for the device below to be powered
  191. // up, wake them up.
  192. //
  193. NUIO_SIGNAL_EVENT(&pOpenContext->PoweredUpEvent);
  194. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  195. ndisuioShutdownBinding(pOpenContext);
  196. *pStatus = NDIS_STATUS_SUCCESS;
  197. return;
  198. }
  199. VOID
  200. NdisuioCloseAdapterComplete(
  201. IN NDIS_HANDLE ProtocolBindingContext,
  202. IN NDIS_STATUS Status
  203. )
  204. /*++
  205. Routine Description:
  206. Called by NDIS to complete a pended call to NdisCloseAdapter.
  207. We wake up the thread waiting for this completion.
  208. Arguments:
  209. ProtocolBindingContext - pointer to open context structure
  210. Status - Completion status of NdisCloseAdapter
  211. Return Value:
  212. None
  213. --*/
  214. {
  215. PNDISUIO_OPEN_CONTEXT pOpenContext;
  216. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  217. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  218. pOpenContext->BindStatus = Status;
  219. NUIO_SIGNAL_EVENT(&pOpenContext->BindEvent);
  220. }
  221. NDIS_STATUS
  222. NdisuioPnPEventHandler(
  223. IN NDIS_HANDLE ProtocolBindingContext,
  224. IN PNET_PNP_EVENT pNetPnPEvent
  225. )
  226. /*++
  227. Routine Description:
  228. Called by NDIS to notify us of a PNP event. The most significant
  229. one for us is power state change.
  230. Arguments:
  231. ProtocolBindingContext - pointer to open context structure
  232. this is NULL for global reconfig events.
  233. pNetPnPEvent - pointer to the PNP event
  234. Return Value:
  235. Our processing status for the PNP event.
  236. --*/
  237. {
  238. PNDISUIO_OPEN_CONTEXT pOpenContext;
  239. NDIS_STATUS Status;
  240. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  241. switch (pNetPnPEvent->NetEvent)
  242. {
  243. case NetEventSetPower:
  244. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  245. pOpenContext->PowerState = *(PNET_DEVICE_POWER_STATE)pNetPnPEvent->Buffer;
  246. if (pOpenContext->PowerState > NetDeviceStateD0)
  247. {
  248. //
  249. // The device below is transitioning to a low power state.
  250. // Block any threads attempting to query the device while
  251. // in this state.
  252. //
  253. NUIO_INIT_EVENT(&pOpenContext->PoweredUpEvent);
  254. //
  255. // Wait for any I/O in progress to complete.
  256. //
  257. ndisuioWaitForPendingIO(pOpenContext, FALSE);
  258. //
  259. // Return any receives that we had queued up.
  260. //
  261. ndisuioFlushReceiveQueue(pOpenContext);
  262. DEBUGP(DL_INFO, ("PnPEvent: Open %p, SetPower to %d\n",
  263. pOpenContext, pOpenContext->PowerState));
  264. }
  265. else
  266. {
  267. //
  268. // The device below is powered up.
  269. //
  270. DEBUGP(DL_INFO, ("PnPEvent: Open %p, SetPower ON: %d\n",
  271. pOpenContext, pOpenContext->PowerState));
  272. NUIO_SIGNAL_EVENT(&pOpenContext->PoweredUpEvent);
  273. }
  274. Status = NDIS_STATUS_SUCCESS;
  275. break;
  276. case NetEventQueryPower:
  277. Status = NDIS_STATUS_SUCCESS;
  278. break;
  279. case NetEventBindsComplete:
  280. NUIO_SIGNAL_EVENT(&Globals.BindsComplete);
  281. Status = NDIS_STATUS_SUCCESS;
  282. break;
  283. case NetEventQueryRemoveDevice:
  284. case NetEventCancelRemoveDevice:
  285. case NetEventReconfigure:
  286. case NetEventBindList:
  287. case NetEventPnPCapabilities:
  288. Status = NDIS_STATUS_SUCCESS;
  289. break;
  290. default:
  291. Status = NDIS_STATUS_NOT_SUPPORTED;
  292. break;
  293. }
  294. DEBUGP(DL_INFO, ("PnPEvent: Open %p, Event %d, Status %x\n",
  295. pOpenContext, pNetPnPEvent->NetEvent, Status));
  296. return (Status);
  297. }
  298. VOID
  299. NdisuioProtocolUnloadHandler(
  300. VOID
  301. )
  302. /*++
  303. Routine Description:
  304. NDIS calls this on a usermode request to uninstall us.
  305. Arguments:
  306. None
  307. Return Value:
  308. None
  309. --*/
  310. {
  311. ndisuioDoProtocolUnload();
  312. }
  313. NDIS_STATUS
  314. ndisuioCreateBinding(
  315. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  316. IN PUCHAR pBindingInfo,
  317. IN ULONG BindingInfoLength
  318. )
  319. /*++
  320. Routine Description:
  321. Utility function to create an NDIS binding to the indicated device,
  322. if no such binding exists.
  323. Here is where we also allocate additional resources (e.g. packet pool)
  324. for the binding.
  325. Things to take care of:
  326. 1. Is another thread doing this (or has finished binding) already?
  327. 2. Is the binding being closed at this time?
  328. 3. NDIS calls our Unbind handler while we are doing this.
  329. These precautions are not needed if this routine is only called from
  330. the context of our BindAdapter handler, but they are here in case
  331. we initiate binding from elsewhere (e.g. on processing a user command).
  332. NOTE: this function blocks and finishes synchronously.
  333. Arguments:
  334. pOpenContext - pointer to open context block
  335. pBindingInfo - pointer to unicode device name string
  336. BindingInfoLength - length in bytes of the above.
  337. Return Value:
  338. NDIS_STATUS_SUCCESS if a binding was successfully set up.
  339. NDIS_STATUS_XXX error code on any failure.
  340. --*/
  341. {
  342. NDIS_STATUS Status;
  343. NDIS_STATUS OpenErrorCode;
  344. UNICODE_STRING DeviceName;
  345. PLIST_ENTRY pEnt;
  346. NDIS_MEDIUM MediumArray[1] = {NdisMedium802_3};
  347. UINT SelectedMediumIndex;
  348. PNDISUIO_OPEN_CONTEXT pTmpOpenContext;
  349. BOOLEAN fDoNotDisturb = FALSE;
  350. BOOLEAN fOpenComplete = FALSE;
  351. ULONG BytesProcessed;
  352. ULONG GenericUlong = 0;
  353. DEBUGP(DL_LOUD, ("CreateBinding: open %p/%x, device [%ws]\n",
  354. pOpenContext, pOpenContext->Flags, pBindingInfo));
  355. Status = NDIS_STATUS_SUCCESS;
  356. do
  357. {
  358. //
  359. // Check if we already have a binding to this device.
  360. //
  361. pTmpOpenContext = ndisuioLookupDevice(pBindingInfo, BindingInfoLength);
  362. if (pTmpOpenContext != NULL)
  363. {
  364. DEBUGP(DL_WARN,
  365. ("CreateBinding: Binding to device %ws already exists on open %p\n",
  366. pTmpOpenContext->DeviceName.Buffer, pTmpOpenContext));
  367. NUIO_DEREF_OPEN(pTmpOpenContext); // temp ref added by Lookup
  368. Status = NDIS_STATUS_FAILURE;
  369. break;
  370. }
  371. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  372. //
  373. // Check if this open context is already bound/binding/closing.
  374. //
  375. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_IDLE) ||
  376. NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_UNBIND_FLAGS, NUIOO_UNBIND_RECEIVED))
  377. {
  378. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  379. Status = NDIS_STATUS_NOT_ACCEPTED;
  380. //
  381. // Make sure we don't abort this binding on failure cleanup.
  382. //
  383. fDoNotDisturb = TRUE;
  384. break;
  385. }
  386. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_OPENING);
  387. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  388. //
  389. // Copy in the device name. Add room for a NULL terminator.
  390. //
  391. NUIO_ALLOC_MEM(pOpenContext->DeviceName.Buffer, BindingInfoLength + sizeof(WCHAR));
  392. if (pOpenContext->DeviceName.Buffer == NULL)
  393. {
  394. DEBUGP(DL_WARN, ("CreateBinding: failed to alloc device name buf (%d bytes)\n",
  395. BindingInfoLength + sizeof(WCHAR)));
  396. Status = NDIS_STATUS_RESOURCES;
  397. break;
  398. }
  399. NUIO_COPY_MEM(pOpenContext->DeviceName.Buffer, pBindingInfo, BindingInfoLength);
  400. *(PWCHAR)((PUCHAR)pOpenContext->DeviceName.Buffer + BindingInfoLength) = L'\0';
  401. NdisInitUnicodeString(&pOpenContext->DeviceName, pOpenContext->DeviceName.Buffer);
  402. //
  403. // Allocate packet pools.
  404. //
  405. NdisAllocatePacketPoolEx(
  406. &Status,
  407. &pOpenContext->SendPacketPool,
  408. MIN_SEND_PACKET_POOL_SIZE,
  409. MAX_SEND_PACKET_POOL_SIZE - MIN_SEND_PACKET_POOL_SIZE,
  410. sizeof(NUIO_SEND_PACKET_RSVD));
  411. if (Status != NDIS_STATUS_SUCCESS)
  412. {
  413. DEBUGP(DL_WARN, ("CreateBinding: failed to alloc"
  414. " send packet pool: %x\n", Status));
  415. break;
  416. }
  417. NdisSetPacketPoolProtocolId(pOpenContext->SendPacketPool, 0x4);
  418. NdisAllocatePacketPoolEx(
  419. &Status,
  420. &pOpenContext->RecvPacketPool,
  421. MIN_RECV_PACKET_POOL_SIZE,
  422. MAX_RECV_PACKET_POOL_SIZE - MIN_RECV_PACKET_POOL_SIZE,
  423. sizeof(NUIO_RECV_PACKET_RSVD));
  424. if (Status != NDIS_STATUS_SUCCESS)
  425. {
  426. DEBUGP(DL_WARN, ("CreateBinding: failed to alloc"
  427. " recv packet pool: %x\n", Status));
  428. break;
  429. }
  430. //
  431. // Buffer pool for receives.
  432. //
  433. NdisAllocateBufferPool(
  434. &Status,
  435. &pOpenContext->RecvBufferPool,
  436. MAX_RECV_PACKET_POOL_SIZE);
  437. if (Status != NDIS_STATUS_SUCCESS)
  438. {
  439. DEBUGP(DL_WARN, ("CreateBinding: failed to alloc"
  440. " recv buffer pool: %x\n", Status));
  441. break;
  442. }
  443. //
  444. // If we are running on Win9X, allocate a buffer pool for sends
  445. // as well, since we can't simply cast MDLs to NDIS_BUFFERs.
  446. //
  447. if (pOpenContext->bRunningOnWin9x)
  448. {
  449. NdisAllocateBufferPool(
  450. &Status,
  451. &pOpenContext->SendBufferPool,
  452. MAX_SEND_PACKET_POOL_SIZE);
  453. if (Status != NDIS_STATUS_SUCCESS)
  454. {
  455. DEBUGP(DL_WARN, ("CreateBinding: failed to alloc"
  456. " send buffer pool: %x\n", Status));
  457. break;
  458. }
  459. }
  460. //
  461. // Open the adapter.
  462. //
  463. NUIO_INIT_EVENT(&pOpenContext->BindEvent);
  464. NdisOpenAdapter(
  465. &Status,
  466. &OpenErrorCode,
  467. &pOpenContext->BindingHandle,
  468. &SelectedMediumIndex,
  469. &MediumArray[0],
  470. sizeof(MediumArray) / sizeof(NDIS_MEDIUM),
  471. Globals.NdisProtocolHandle,
  472. (NDIS_HANDLE)pOpenContext,
  473. &pOpenContext->DeviceName,
  474. 0,
  475. NULL);
  476. if (Status == NDIS_STATUS_PENDING)
  477. {
  478. NUIO_WAIT_EVENT(&pOpenContext->BindEvent, 0);
  479. Status = pOpenContext->BindStatus;
  480. }
  481. if (Status != NDIS_STATUS_SUCCESS)
  482. {
  483. DEBUGP(DL_WARN, ("CreateBinding: NdisOpenAdapter (%ws) failed: %x\n",
  484. pOpenContext->DeviceName.Buffer, Status));
  485. break;
  486. }
  487. //
  488. // Note down the fact that we have successfully bound.
  489. // We don't update the state on the open just yet - this
  490. // is to prevent other threads from shutting down the binding.
  491. //
  492. fOpenComplete = TRUE;
  493. //
  494. // Get the friendly name for the adapter. It is not fatal for this
  495. // to fail.
  496. //
  497. (VOID)NdisQueryAdapterInstanceName(
  498. &pOpenContext->DeviceDescr,
  499. pOpenContext->BindingHandle
  500. );
  501. //
  502. // Get Current address
  503. //
  504. Status = ndisuioDoRequest(
  505. pOpenContext,
  506. NdisRequestQueryInformation,
  507. OID_802_3_CURRENT_ADDRESS,
  508. &pOpenContext->CurrentAddress[0],
  509. NUIO_MAC_ADDR_LEN,
  510. &BytesProcessed
  511. );
  512. if (Status != NDIS_STATUS_SUCCESS)
  513. {
  514. DEBUGP(DL_WARN, ("CreateBinding: qry current address failed: %x\n",
  515. Status));
  516. break;
  517. }
  518. //
  519. // Get MAC options.
  520. //
  521. Status = ndisuioDoRequest(
  522. pOpenContext,
  523. NdisRequestQueryInformation,
  524. OID_GEN_MAC_OPTIONS,
  525. &pOpenContext->MacOptions,
  526. sizeof(pOpenContext->MacOptions),
  527. &BytesProcessed
  528. );
  529. if (Status != NDIS_STATUS_SUCCESS)
  530. {
  531. DEBUGP(DL_WARN, ("CreateBinding: qry MAC options failed: %x\n",
  532. Status));
  533. break;
  534. }
  535. //
  536. // Get the max frame size.
  537. //
  538. Status = ndisuioDoRequest(
  539. pOpenContext,
  540. NdisRequestQueryInformation,
  541. OID_GEN_MAXIMUM_FRAME_SIZE,
  542. &pOpenContext->MaxFrameSize,
  543. sizeof(pOpenContext->MaxFrameSize),
  544. &BytesProcessed
  545. );
  546. if (Status != NDIS_STATUS_SUCCESS)
  547. {
  548. DEBUGP(DL_WARN, ("CreateBinding: qry max frame failed: %x\n",
  549. Status));
  550. break;
  551. }
  552. //
  553. // Get the media connect status.
  554. //
  555. Status = ndisuioDoRequest(
  556. pOpenContext,
  557. NdisRequestQueryInformation,
  558. OID_GEN_MEDIA_CONNECT_STATUS,
  559. &GenericUlong,
  560. sizeof(GenericUlong),
  561. &BytesProcessed
  562. );
  563. if (Status != NDIS_STATUS_SUCCESS)
  564. {
  565. DEBUGP(DL_WARN, ("CreateBinding: qry media connect status failed: %x\n",
  566. Status));
  567. break;
  568. }
  569. if (GenericUlong == NdisMediaStateConnected)
  570. {
  571. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_MEDIA_FLAGS, NUIOO_MEDIA_CONNECTED);
  572. }
  573. else
  574. {
  575. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_MEDIA_FLAGS, NUIOO_MEDIA_DISCONNECTED);
  576. }
  577. //
  578. // Assume that the device is powered up.
  579. //
  580. pOpenContext->PowerState = NetDeviceStateD0;
  581. //
  582. // Mark this open. Also check if we received an Unbind while
  583. // we were setting this up.
  584. //
  585. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  586. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE);
  587. //
  588. // Did an unbind happen in the meantime?
  589. //
  590. if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_UNBIND_FLAGS, NUIOO_UNBIND_RECEIVED))
  591. {
  592. Status = NDIS_STATUS_FAILURE;
  593. }
  594. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  595. break;
  596. }
  597. while (FALSE);
  598. if ((Status != NDIS_STATUS_SUCCESS) && !fDoNotDisturb)
  599. {
  600. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  601. //
  602. // Check if we had actually finished opening the adapter.
  603. //
  604. if (fOpenComplete)
  605. {
  606. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE);
  607. }
  608. else if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_OPENING))
  609. {
  610. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_FAILED);
  611. }
  612. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  613. ndisuioShutdownBinding(pOpenContext);
  614. }
  615. DEBUGP(DL_INFO, ("CreateBinding: OpenContext %p, Status %x\n",
  616. pOpenContext, Status));
  617. return (Status);
  618. }
  619. VOID
  620. ndisuioShutdownBinding(
  621. IN PNDISUIO_OPEN_CONTEXT pOpenContext
  622. )
  623. /*++
  624. Routine Description:
  625. Utility function to shut down the NDIS binding, if one exists, on
  626. the specified open. This is written to be called from:
  627. ndisuioCreateBinding - on failure
  628. NdisuioUnbindAdapter
  629. We handle the case where a binding is in the process of being set up.
  630. This precaution is not needed if this routine is only called from
  631. the context of our UnbindAdapter handler, but they are here in case
  632. we initiate unbinding from elsewhere (e.g. on processing a user command).
  633. NOTE: this blocks and finishes synchronously.
  634. Arguments:
  635. pOpenContext - pointer to open context block
  636. Return Value:
  637. None
  638. --*/
  639. {
  640. NDIS_STATUS Status;
  641. BOOLEAN DoCloseBinding = FALSE;
  642. do
  643. {
  644. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  645. if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_OPENING))
  646. {
  647. //
  648. // We are still in the process of setting up this binding.
  649. //
  650. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  651. break;
  652. }
  653. if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  654. {
  655. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_CLOSING);
  656. DoCloseBinding = TRUE;
  657. }
  658. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  659. if (DoCloseBinding)
  660. {
  661. //
  662. // Wait for any pending sends or requests on
  663. // the binding to complete.
  664. //
  665. ndisuioWaitForPendingIO(pOpenContext, TRUE);
  666. //
  667. // Discard any queued receives.
  668. //
  669. ndisuioFlushReceiveQueue(pOpenContext);
  670. //
  671. // Close the binding now.
  672. //
  673. NUIO_INIT_EVENT(&pOpenContext->BindEvent);
  674. DEBUGP(DL_INFO, ("ShutdownBinding: Closing OpenContext %p,"
  675. " BindingHandle %p\n",
  676. pOpenContext, pOpenContext->BindingHandle));
  677. NdisCloseAdapter(&Status, pOpenContext->BindingHandle);
  678. if (Status == NDIS_STATUS_PENDING)
  679. {
  680. NUIO_WAIT_EVENT(&pOpenContext->BindEvent, 0);
  681. Status = pOpenContext->BindStatus;
  682. }
  683. NUIO_ASSERT(Status == NDIS_STATUS_SUCCESS);
  684. pOpenContext->BindingHandle = NULL;
  685. }
  686. if (DoCloseBinding)
  687. {
  688. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  689. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_IDLE);
  690. NUIO_SET_FLAGS(pOpenContext->Flags, NUIOO_UNBIND_FLAGS, 0);
  691. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  692. }
  693. //
  694. // Remove it from the global list.
  695. //
  696. NUIO_ACQUIRE_LOCK(&Globals.GlobalLock);
  697. NUIO_REMOVE_ENTRY_LIST(&pOpenContext->Link);
  698. NUIO_RELEASE_LOCK(&Globals.GlobalLock);
  699. //
  700. // Free any other resources allocated for this bind.
  701. //
  702. ndisuioFreeBindResources(pOpenContext);
  703. NUIO_DEREF_OPEN(pOpenContext); // Shutdown binding
  704. break;
  705. }
  706. while (FALSE);
  707. }
  708. VOID
  709. ndisuioFreeBindResources(
  710. IN PNDISUIO_OPEN_CONTEXT pOpenContext
  711. )
  712. /*++
  713. Routine Description:
  714. Free any resources set up for an NDIS binding.
  715. Arguments:
  716. pOpenContext - pointer to open context block
  717. Return Value:
  718. None
  719. --*/
  720. {
  721. if (pOpenContext->SendPacketPool != NULL)
  722. {
  723. NdisFreePacketPool(pOpenContext->SendPacketPool);
  724. pOpenContext->SendPacketPool = NULL;
  725. }
  726. if (pOpenContext->RecvPacketPool != NULL)
  727. {
  728. NdisFreePacketPool(pOpenContext->RecvPacketPool);
  729. pOpenContext->RecvPacketPool = NULL;
  730. }
  731. if (pOpenContext->RecvBufferPool != NULL)
  732. {
  733. NdisFreeBufferPool(pOpenContext->RecvBufferPool);
  734. pOpenContext->RecvBufferPool = NULL;
  735. }
  736. if (pOpenContext->SendBufferPool != NULL)
  737. {
  738. NdisFreeBufferPool(pOpenContext->SendBufferPool);
  739. pOpenContext->SendBufferPool = NULL;
  740. }
  741. if (pOpenContext->DeviceName.Buffer != NULL)
  742. {
  743. NUIO_FREE_MEM(pOpenContext->DeviceName.Buffer);
  744. pOpenContext->DeviceName.Buffer = NULL;
  745. pOpenContext->DeviceName.Length =
  746. pOpenContext->DeviceName.MaximumLength = 0;
  747. }
  748. if (pOpenContext->DeviceDescr.Buffer != NULL)
  749. {
  750. //
  751. // this would have been allocated by NdisQueryAdpaterInstanceName.
  752. //
  753. NdisFreeMemory(pOpenContext->DeviceDescr.Buffer, 0, 0);
  754. pOpenContext->DeviceDescr.Buffer = NULL;
  755. }
  756. }
  757. VOID
  758. ndisuioWaitForPendingIO(
  759. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  760. IN BOOLEAN DoCancelReads
  761. )
  762. /*++
  763. Routine Description:
  764. Utility function to wait for all outstanding I/O to complete
  765. on an open context. It is assumed that the open context
  766. won't go away while we are in this routine.
  767. Arguments:
  768. pOpenContext - pointer to open context structure
  769. DoCancelReads - do we wait for pending reads to go away (and cancel them)?
  770. Return Value:
  771. None
  772. --*/
  773. {
  774. NDIS_STATUS Status;
  775. ULONG LoopCount;
  776. ULONG PendingCount;
  777. #ifdef NDIS51
  778. //
  779. // Wait for any pending sends or requests on the binding to complete.
  780. //
  781. for (LoopCount = 0; LoopCount < 60; LoopCount++)
  782. {
  783. Status = NdisQueryPendingIOCount(
  784. pOpenContext->BindingHandle,
  785. &PendingCount);
  786. if ((Status != NDIS_STATUS_SUCCESS) ||
  787. (PendingCount == 0))
  788. {
  789. break;
  790. }
  791. DEBUGP(DL_INFO, ("WaitForPendingIO: Open %p, %d pending I/O at NDIS\n",
  792. pOpenContext, PendingCount));
  793. NUIO_SLEEP(2);
  794. }
  795. NUIO_ASSERT(LoopCount < 60);
  796. #endif // NDIS51
  797. //
  798. // Make sure any threads trying to send have finished.
  799. //
  800. for (LoopCount = 0; LoopCount < 60; LoopCount++)
  801. {
  802. if (pOpenContext->PendedSendCount == 0)
  803. {
  804. break;
  805. }
  806. DEBUGP(DL_WARN, ("WaitForPendingIO: Open %p, %d pended sends\n",
  807. pOpenContext, pOpenContext->PendedSendCount));
  808. NUIO_SLEEP(1);
  809. }
  810. NUIO_ASSERT(LoopCount < 60);
  811. if (DoCancelReads)
  812. {
  813. //
  814. // Wait for any pended reads to complete/cancel.
  815. //
  816. while (pOpenContext->PendedReadCount != 0)
  817. {
  818. DEBUGP(DL_INFO, ("WaitForPendingIO: Open %p, %d pended reads\n",
  819. pOpenContext, pOpenContext->PendedReadCount));
  820. //
  821. // Cancel any pending reads.
  822. //
  823. ndisuioCancelPendingReads(pOpenContext);
  824. NUIO_SLEEP(1);
  825. }
  826. }
  827. }
  828. VOID
  829. ndisuioDoProtocolUnload(
  830. VOID
  831. )
  832. /*++
  833. Routine Description:
  834. Utility routine to handle unload from the NDIS protocol side.
  835. Arguments:
  836. None
  837. Return Value:
  838. None
  839. --*/
  840. {
  841. NDIS_HANDLE ProtocolHandle;
  842. NDIS_STATUS Status;
  843. DEBUGP(DL_INFO, ("ProtocolUnload: ProtocolHandle %lx\n",
  844. Globals.NdisProtocolHandle));
  845. if (Globals.NdisProtocolHandle != NULL)
  846. {
  847. ProtocolHandle = Globals.NdisProtocolHandle;
  848. Globals.NdisProtocolHandle = NULL;
  849. NdisDeregisterProtocol(
  850. &Status,
  851. ProtocolHandle
  852. );
  853. }
  854. }
  855. NDIS_STATUS
  856. ndisuioDoRequest(
  857. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  858. IN NDIS_REQUEST_TYPE RequestType,
  859. IN NDIS_OID Oid,
  860. IN PVOID InformationBuffer,
  861. IN UINT InformationBufferLength,
  862. OUT PUINT pBytesProcessed
  863. )
  864. /*++
  865. Routine Description:
  866. Utility routine that forms and sends an NDIS_REQUEST to the
  867. miniport, waits for it to complete, and returns status
  868. to the caller.
  869. NOTE: this assumes that the calling routine ensures validity
  870. of the binding handle until this returns.
  871. Arguments:
  872. pOpenContext - pointer to our open context
  873. RequestType - NdisRequest[Set|Query]Information
  874. Oid - the object being set/queried
  875. InformationBuffer - data for the request
  876. InformationBufferLength - length of the above
  877. pBytesProcessed - place to return bytes read/written
  878. Return Value:
  879. Status of the set/query request
  880. --*/
  881. {
  882. NDISUIO_REQUEST ReqContext;
  883. PNDIS_REQUEST pNdisRequest = &ReqContext.Request;
  884. NDIS_STATUS Status;
  885. NUIO_INIT_EVENT(&ReqContext.ReqEvent);
  886. pNdisRequest->RequestType = RequestType;
  887. switch (RequestType)
  888. {
  889. case NdisRequestQueryInformation:
  890. pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
  891. pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
  892. InformationBuffer;
  893. pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
  894. InformationBufferLength;
  895. break;
  896. case NdisRequestSetInformation:
  897. pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
  898. pNdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  899. InformationBuffer;
  900. pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  901. InformationBufferLength;
  902. break;
  903. default:
  904. NUIO_ASSERT(FALSE);
  905. break;
  906. }
  907. NdisRequest(&Status,
  908. pOpenContext->BindingHandle,
  909. pNdisRequest);
  910. if (Status == NDIS_STATUS_PENDING)
  911. {
  912. NUIO_WAIT_EVENT(&ReqContext.ReqEvent, 0);
  913. Status = ReqContext.Status;
  914. }
  915. if (Status == NDIS_STATUS_SUCCESS)
  916. {
  917. *pBytesProcessed = (RequestType == NdisRequestQueryInformation)?
  918. pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten:
  919. pNdisRequest->DATA.SET_INFORMATION.BytesRead;
  920. //
  921. // The driver below should set the correct value to BytesWritten
  922. // or BytesRead. But now, we just truncate the value to InformationBufferLength if
  923. // BytesWritten or BytesRead is greater than InformationBufferLength
  924. //
  925. if (*pBytesProcessed > InformationBufferLength)
  926. {
  927. *pBytesProcessed = InformationBufferLength;
  928. }
  929. }
  930. return (Status);
  931. }
  932. NDIS_STATUS
  933. ndisuioValidateOpenAndDoRequest(
  934. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  935. IN NDIS_REQUEST_TYPE RequestType,
  936. IN NDIS_OID Oid,
  937. IN PVOID InformationBuffer,
  938. IN UINT InformationBufferLength,
  939. OUT PUINT pBytesProcessed,
  940. IN BOOLEAN bWaitForPowerOn
  941. )
  942. /*++
  943. Routine Description:
  944. Utility routine to prevalidate and reference an open context
  945. before calling ndisuioDoRequest. This routine makes sure
  946. we have a valid binding.
  947. Arguments:
  948. pOpenContext - pointer to our open context
  949. RequestType - NdisRequest[Set|Query]Information
  950. Oid - the object being set/queried
  951. InformationBuffer - data for the request
  952. InformationBufferLength - length of the above
  953. pBytesProcessed - place to return bytes read/written
  954. bWaitForPowerOn - Wait for the device to be powered on if it isn't already.
  955. Return Value:
  956. Status of the set/query request
  957. --*/
  958. {
  959. NDIS_STATUS Status;
  960. do
  961. {
  962. if (pOpenContext == NULL)
  963. {
  964. DEBUGP(DL_WARN, ("ValidateOpenAndDoRequest: request on unassociated file object!\n"));
  965. Status = NDIS_STATUS_INVALID_DATA;
  966. break;
  967. }
  968. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  969. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  970. //
  971. // Proceed only if we have a binding.
  972. //
  973. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  974. {
  975. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  976. Status = NDIS_STATUS_INVALID_DATA;
  977. break;
  978. }
  979. NUIO_ASSERT(pOpenContext->BindingHandle != NULL);
  980. //
  981. // Make sure that the binding does not go away until we
  982. // are finished with the request.
  983. //
  984. NdisInterlockedIncrement(&pOpenContext->PendedSendCount);
  985. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  986. if (bWaitForPowerOn)
  987. {
  988. //
  989. // Wait for the device below to be powered up.
  990. // We don't wait indefinitely here - this is to avoid
  991. // a PROCESS_HAS_LOCKED_PAGES bugcheck that could happen
  992. // if the calling process terminates, and this IRP doesn't
  993. // complete within a reasonable time. An alternative would
  994. // be to explicitly handle cancellation of this IRP.
  995. //
  996. NUIO_WAIT_EVENT(&pOpenContext->PoweredUpEvent, 4500);
  997. }
  998. Status = ndisuioDoRequest(
  999. pOpenContext,
  1000. RequestType,
  1001. Oid,
  1002. InformationBuffer,
  1003. InformationBufferLength,
  1004. pBytesProcessed);
  1005. //
  1006. // Let go of the binding.
  1007. //
  1008. NdisInterlockedDecrement(&pOpenContext->PendedSendCount);
  1009. break;
  1010. }
  1011. while (FALSE);
  1012. DEBUGP(DL_LOUD, ("ValidateOpenAndDoReq: Open %p/%x, OID %x, Status %x\n",
  1013. pOpenContext, pOpenContext->Flags, Oid, Status));
  1014. return (Status);
  1015. }
  1016. VOID
  1017. NdisuioResetComplete(
  1018. IN NDIS_HANDLE ProtocolBindingContext,
  1019. IN NDIS_STATUS Status
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. NDIS entry point indicating that a protocol initiated reset
  1024. has completed. Since we never call NdisReset(), this should
  1025. never be called.
  1026. Arguments:
  1027. ProtocolBindingContext - pointer to open context
  1028. Status - status of reset completion
  1029. Return Value:
  1030. None
  1031. --*/
  1032. {
  1033. ASSERT(FALSE);
  1034. return;
  1035. }
  1036. VOID
  1037. NdisuioRequestComplete(
  1038. IN NDIS_HANDLE ProtocolBindingContext,
  1039. IN PNDIS_REQUEST pNdisRequest,
  1040. IN NDIS_STATUS Status
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. NDIS entry point indicating completion of a pended NDIS_REQUEST.
  1045. Arguments:
  1046. ProtocolBindingContext - pointer to open context
  1047. pNdisRequest - pointer to NDIS request
  1048. Status - status of reset completion
  1049. Return Value:
  1050. None
  1051. --*/
  1052. {
  1053. PNDISUIO_OPEN_CONTEXT pOpenContext;
  1054. PNDISUIO_REQUEST pReqContext;
  1055. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  1056. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  1057. //
  1058. // Get at the request context.
  1059. //
  1060. pReqContext = CONTAINING_RECORD(pNdisRequest, NDISUIO_REQUEST, Request);
  1061. //
  1062. // Save away the completion status.
  1063. //
  1064. pReqContext->Status = Status;
  1065. //
  1066. // Wake up the thread blocked for this request to complete.
  1067. //
  1068. NUIO_SIGNAL_EVENT(&pReqContext->ReqEvent);
  1069. }
  1070. VOID
  1071. NdisuioStatus(
  1072. IN NDIS_HANDLE ProtocolBindingContext,
  1073. IN NDIS_STATUS GeneralStatus,
  1074. IN PVOID StatusBuffer,
  1075. IN UINT StatusBufferSize
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. Protocol entry point called by NDIS to indicate a change
  1080. in status at the miniport.
  1081. We make note of reset and media connect status indications.
  1082. Arguments:
  1083. ProtocolBindingContext - pointer to open context
  1084. GeneralStatus - status code
  1085. StatusBuffer - status-specific additional information
  1086. StatusBufferSize - size of the above
  1087. Return Value:
  1088. None
  1089. --*/
  1090. {
  1091. PNDISUIO_OPEN_CONTEXT pOpenContext;
  1092. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  1093. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  1094. DEBUGP(DL_INFO, ("Status: Open %p, Status %x\n",
  1095. pOpenContext, GeneralStatus));
  1096. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  1097. do
  1098. {
  1099. if (pOpenContext->PowerState != NetDeviceStateD0)
  1100. {
  1101. //
  1102. // Ignore status indications if the device is in
  1103. // a low power state.
  1104. //
  1105. DEBUGP(DL_INFO, ("Status: Open %p in power state %d,"
  1106. " Status %x ignored\n", pOpenContext,
  1107. pOpenContext->PowerState, GeneralStatus));
  1108. break;
  1109. }
  1110. switch(GeneralStatus)
  1111. {
  1112. case NDIS_STATUS_RESET_START:
  1113. NUIO_ASSERT(!NUIO_TEST_FLAGS(pOpenContext->Flags,
  1114. NUIOO_RESET_FLAGS,
  1115. NUIOO_RESET_IN_PROGRESS));
  1116. NUIO_SET_FLAGS(pOpenContext->Flags,
  1117. NUIOO_RESET_FLAGS,
  1118. NUIOO_RESET_IN_PROGRESS);
  1119. break;
  1120. case NDIS_STATUS_RESET_END:
  1121. NUIO_ASSERT(NUIO_TEST_FLAGS(pOpenContext->Flags,
  1122. NUIOO_RESET_FLAGS,
  1123. NUIOO_RESET_IN_PROGRESS));
  1124. NUIO_SET_FLAGS(pOpenContext->Flags,
  1125. NUIOO_RESET_FLAGS,
  1126. NUIOO_NOT_RESETTING);
  1127. break;
  1128. case NDIS_STATUS_MEDIA_CONNECT:
  1129. NUIO_SET_FLAGS(pOpenContext->Flags,
  1130. NUIOO_MEDIA_FLAGS,
  1131. NUIOO_MEDIA_CONNECTED);
  1132. break;
  1133. case NDIS_STATUS_MEDIA_DISCONNECT:
  1134. NUIO_SET_FLAGS(pOpenContext->Flags,
  1135. NUIOO_MEDIA_FLAGS,
  1136. NUIOO_MEDIA_DISCONNECTED);
  1137. break;
  1138. default:
  1139. break;
  1140. }
  1141. }
  1142. while (FALSE);
  1143. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1144. }
  1145. VOID
  1146. NdisuioStatusComplete(
  1147. IN NDIS_HANDLE ProtocolBindingContext
  1148. )
  1149. /*++
  1150. Routine Description:
  1151. Protocol entry point called by NDIS. We ignore this.
  1152. Arguments:
  1153. ProtocolBindingContext - pointer to open context
  1154. Return Value:
  1155. None
  1156. --*/
  1157. {
  1158. PNDISUIO_OPEN_CONTEXT pOpenContext;
  1159. pOpenContext = (PNDISUIO_OPEN_CONTEXT)ProtocolBindingContext;
  1160. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  1161. return;
  1162. }
  1163. NDIS_STATUS
  1164. ndisuioQueryBinding(
  1165. IN PUCHAR pBuffer,
  1166. IN ULONG InputLength,
  1167. IN ULONG OutputLength,
  1168. OUT PULONG pBytesReturned
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. Return information about the specified binding.
  1173. Arguments:
  1174. pBuffer - pointer to NDISUIO_QUERY_BINDING
  1175. InputLength - input buffer size
  1176. OutputLength - output buffer size
  1177. pBytesReturned - place to return copied byte count.
  1178. Return Value:
  1179. NDIS_STATUS_SUCCESS if successful, failure code otherwise.
  1180. --*/
  1181. {
  1182. PNDISUIO_QUERY_BINDING pQueryBinding;
  1183. PNDISUIO_OPEN_CONTEXT pOpenContext;
  1184. PLIST_ENTRY pEnt;
  1185. ULONG Remaining;
  1186. ULONG BindingIndex;
  1187. NDIS_STATUS Status;
  1188. do
  1189. {
  1190. if (InputLength < sizeof(NDISUIO_QUERY_BINDING))
  1191. {
  1192. Status = NDIS_STATUS_RESOURCES;
  1193. break;
  1194. }
  1195. if (OutputLength < sizeof(NDISUIO_QUERY_BINDING))
  1196. {
  1197. Status = NDIS_STATUS_BUFFER_OVERFLOW;
  1198. break;
  1199. }
  1200. Remaining = OutputLength - sizeof(NDISUIO_QUERY_BINDING);
  1201. pQueryBinding = (PNDISUIO_QUERY_BINDING)pBuffer;
  1202. BindingIndex = pQueryBinding->BindingIndex;
  1203. Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
  1204. pOpenContext = NULL;
  1205. NUIO_ACQUIRE_LOCK(&Globals.GlobalLock);
  1206. for (pEnt = Globals.OpenList.Flink;
  1207. pEnt != &Globals.OpenList;
  1208. pEnt = pEnt->Flink)
  1209. {
  1210. pOpenContext = CONTAINING_RECORD(pEnt, NDISUIO_OPEN_CONTEXT, Link);
  1211. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  1212. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  1213. //
  1214. // Skip if not bound.
  1215. //
  1216. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  1217. {
  1218. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1219. continue;
  1220. }
  1221. if (BindingIndex == 0)
  1222. {
  1223. //
  1224. // Got the binding we are looking for. Copy the device
  1225. // name and description strings to the output buffer.
  1226. //
  1227. DEBUGP(DL_INFO,
  1228. ("QueryBinding: found open %p\n", pOpenContext));
  1229. pQueryBinding->DeviceNameLength = pOpenContext->DeviceName.Length + sizeof(WCHAR);
  1230. pQueryBinding->DeviceDescrLength = pOpenContext->DeviceDescr.Length + sizeof(WCHAR);
  1231. if (Remaining < pQueryBinding->DeviceNameLength +
  1232. pQueryBinding->DeviceDescrLength)
  1233. {
  1234. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1235. Status = NDIS_STATUS_BUFFER_OVERFLOW;
  1236. break;
  1237. }
  1238. NUIO_ZERO_MEM((PUCHAR)pBuffer + sizeof(NDISUIO_QUERY_BINDING),
  1239. pQueryBinding->DeviceNameLength +
  1240. pQueryBinding->DeviceDescrLength);
  1241. pQueryBinding->DeviceNameOffset = sizeof(NDISUIO_QUERY_BINDING);
  1242. NUIO_COPY_MEM((PUCHAR)pBuffer + pQueryBinding->DeviceNameOffset,
  1243. pOpenContext->DeviceName.Buffer,
  1244. pOpenContext->DeviceName.Length);
  1245. pQueryBinding->DeviceDescrOffset = pQueryBinding->DeviceNameOffset +
  1246. pQueryBinding->DeviceNameLength;
  1247. NUIO_COPY_MEM((PUCHAR)pBuffer + pQueryBinding->DeviceDescrOffset,
  1248. pOpenContext->DeviceDescr.Buffer,
  1249. pOpenContext->DeviceDescr.Length);
  1250. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1251. *pBytesReturned = pQueryBinding->DeviceDescrOffset + pQueryBinding->DeviceDescrLength;
  1252. Status = NDIS_STATUS_SUCCESS;
  1253. break;
  1254. }
  1255. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1256. BindingIndex--;
  1257. }
  1258. NUIO_RELEASE_LOCK(&Globals.GlobalLock);
  1259. }
  1260. while (FALSE);
  1261. return (Status);
  1262. }
  1263. PNDISUIO_OPEN_CONTEXT
  1264. ndisuioLookupDevice(
  1265. IN PUCHAR pBindingInfo,
  1266. IN ULONG BindingInfoLength
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. Search our global list for an open context structure that
  1271. has a binding to the specified device, and return a pointer
  1272. to it.
  1273. NOTE: we reference the open that we return.
  1274. Arguments:
  1275. pBindingInfo - pointer to unicode device name string
  1276. BindingInfoLength - length in bytes of the above.
  1277. Return Value:
  1278. Pointer to the matching open context if found, else NULL
  1279. --*/
  1280. {
  1281. PNDISUIO_OPEN_CONTEXT pOpenContext;
  1282. PLIST_ENTRY pEnt;
  1283. pOpenContext = NULL;
  1284. NUIO_ACQUIRE_LOCK(&Globals.GlobalLock);
  1285. for (pEnt = Globals.OpenList.Flink;
  1286. pEnt != &Globals.OpenList;
  1287. pEnt = pEnt->Flink)
  1288. {
  1289. pOpenContext = CONTAINING_RECORD(pEnt, NDISUIO_OPEN_CONTEXT, Link);
  1290. NUIO_STRUCT_ASSERT(pOpenContext, oc);
  1291. //
  1292. // Check if this has the name we are looking for.
  1293. //
  1294. if ((pOpenContext->DeviceName.Length == BindingInfoLength) &&
  1295. NUIO_MEM_CMP(pOpenContext->DeviceName.Buffer, pBindingInfo, BindingInfoLength))
  1296. {
  1297. NUIO_REF_OPEN(pOpenContext); // ref added by LookupDevice
  1298. break;
  1299. }
  1300. pOpenContext = NULL;
  1301. }
  1302. NUIO_RELEASE_LOCK(&Globals.GlobalLock);
  1303. return (pOpenContext);
  1304. }
  1305. NDIS_STATUS
  1306. ndisuioQueryOidValue(
  1307. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  1308. OUT PVOID pDataBuffer,
  1309. IN ULONG BufferLength,
  1310. OUT PULONG pBytesWritten
  1311. )
  1312. /*++
  1313. Routine Description:
  1314. Query an arbitrary OID value from the miniport.
  1315. Arguments:
  1316. pOpenContext - pointer to open context representing our binding to the miniport
  1317. pDataBuffer - place to store the returned value
  1318. BufferLength - length of the above
  1319. pBytesWritten - place to return length returned
  1320. Return Value:
  1321. NDIS_STATUS_SUCCESS if we successfully queried the OID.
  1322. NDIS_STATUS_XXX error code otherwise.
  1323. --*/
  1324. {
  1325. NDIS_STATUS Status;
  1326. PNDISUIO_QUERY_OID pQuery;
  1327. NDIS_OID Oid;
  1328. Oid = 0;
  1329. do
  1330. {
  1331. if (BufferLength < sizeof(NDISUIO_QUERY_OID))
  1332. {
  1333. Status = NDIS_STATUS_BUFFER_TOO_SHORT;
  1334. break;
  1335. }
  1336. pQuery = (PNDISUIO_QUERY_OID)pDataBuffer;
  1337. Oid = pQuery->Oid;
  1338. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  1339. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  1340. {
  1341. DEBUGP(DL_WARN,
  1342. ("QueryOid: Open %p/%x is in invalid state\n",
  1343. pOpenContext, pOpenContext->Flags));
  1344. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1345. Status = NDIS_STATUS_FAILURE;
  1346. break;
  1347. }
  1348. //
  1349. // Make sure the binding doesn't go away.
  1350. //
  1351. NdisInterlockedIncrement(&pOpenContext->PendedSendCount);
  1352. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1353. Status = ndisuioDoRequest(
  1354. pOpenContext,
  1355. NdisRequestQueryInformation,
  1356. Oid,
  1357. &pQuery->Data[0],
  1358. BufferLength - FIELD_OFFSET(NDISUIO_QUERY_OID, Data),
  1359. pBytesWritten);
  1360. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  1361. NdisInterlockedDecrement(&pOpenContext->PendedSendCount);
  1362. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1363. if (Status == NDIS_STATUS_SUCCESS)
  1364. {
  1365. *pBytesWritten += FIELD_OFFSET(NDISUIO_QUERY_OID, Data);
  1366. }
  1367. }
  1368. while (FALSE);
  1369. DEBUGP(DL_LOUD, ("QueryOid: Open %p/%x, OID %x, Status %x\n",
  1370. pOpenContext, pOpenContext->Flags, Oid, Status));
  1371. return (Status);
  1372. }
  1373. NDIS_STATUS
  1374. ndisuioSetOidValue(
  1375. IN PNDISUIO_OPEN_CONTEXT pOpenContext,
  1376. OUT PVOID pDataBuffer,
  1377. IN ULONG BufferLength
  1378. )
  1379. /*++
  1380. Routine Description:
  1381. Set an arbitrary OID value to the miniport.
  1382. Arguments:
  1383. pOpenContext - pointer to open context representing our binding to the miniport
  1384. pDataBuffer - buffer that contains the value to be set
  1385. BufferLength - length of the above
  1386. Return Value:
  1387. NDIS_STATUS_SUCCESS if we successfully set the OID
  1388. NDIS_STATUS_XXX error code otherwise.
  1389. --*/
  1390. {
  1391. NDIS_STATUS Status;
  1392. PNDISUIO_SET_OID pSet;
  1393. NDIS_OID Oid;
  1394. ULONG BytesWritten;
  1395. Oid = 0;
  1396. do
  1397. {
  1398. if (BufferLength < sizeof(NDISUIO_SET_OID))
  1399. {
  1400. Status = NDIS_STATUS_BUFFER_TOO_SHORT;
  1401. break;
  1402. }
  1403. pSet = (PNDISUIO_SET_OID)pDataBuffer;
  1404. Oid = pSet->Oid;
  1405. //
  1406. // We should check the OID is settable by the user mode apps
  1407. //
  1408. if (!ndisuioValidOid(Oid))
  1409. {
  1410. DEBUGP(DL_WARN, ("SetOid: Oid %x cannot be set\n", Oid));
  1411. Status = NDIS_STATUS_INVALID_DATA;
  1412. break;
  1413. }
  1414. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  1415. if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
  1416. {
  1417. DEBUGP(DL_WARN,
  1418. ("SetOid: Open %p/%x is in invalid state\n",
  1419. pOpenContext, pOpenContext->Flags));
  1420. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1421. Status = NDIS_STATUS_FAILURE;
  1422. break;
  1423. }
  1424. //
  1425. // Make sure the binding doesn't go away.
  1426. //
  1427. NdisInterlockedIncrement(&pOpenContext->PendedSendCount);
  1428. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1429. Status = ndisuioDoRequest(
  1430. pOpenContext,
  1431. NdisRequestSetInformation,
  1432. Oid,
  1433. &pSet->Data[0],
  1434. BufferLength - FIELD_OFFSET(NDISUIO_SET_OID, Data),
  1435. &BytesWritten);
  1436. NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
  1437. NdisInterlockedDecrement(&pOpenContext->PendedSendCount);
  1438. NUIO_RELEASE_LOCK(&pOpenContext->Lock);
  1439. }
  1440. while (FALSE);
  1441. DEBUGP(DL_LOUD, ("SetOid: Open %p/%x, OID %x, Status %x\n",
  1442. pOpenContext, pOpenContext->Flags, Oid, Status));
  1443. return (Status);
  1444. }
  1445. BOOLEAN
  1446. ndisuioValidOid(
  1447. IN NDIS_OID Oid
  1448. )
  1449. /*++
  1450. Routine Description:
  1451. Validate whether the given set OID is settable or not.
  1452. Arguments:
  1453. Oid - The OID which the user tries to set.
  1454. Return Value:
  1455. TRUE if the OID is allowed to set
  1456. FALSE otherwise.
  1457. --*/
  1458. {
  1459. UINT i;
  1460. UINT NumOids;
  1461. NumOids = sizeof(ndisuioSupportedSetOids) / sizeof(NDIS_OID);
  1462. for (i = 0; i < NumOids; i++)
  1463. {
  1464. if (ndisuioSupportedSetOids[i] == Oid)
  1465. {
  1466. break;
  1467. }
  1468. }
  1469. return (i < NumOids);
  1470. }