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.

3313 lines
89 KiB

  1. /*++
  2. Copyright(c) 1992-2000 Microsoft Corporation
  3. Module Name:
  4. protocol.c
  5. Abstract:
  6. NDIS Protocol Entry points and utility functions for the NDIS
  7. MUX Intermediate Miniport sample.
  8. The protocol edge binds to Ethernet (NdisMedium802_3) adapters,
  9. and initiates creation of zero or more Virtual Ethernet LAN (VELAN)
  10. miniport instances by calling NdisIMInitializeDeviceInstanceEx once
  11. for each VELAN configured over a lower binding.
  12. Environment:
  13. Kernel mode.
  14. Revision History:
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #define MODULE_NUMBER MODULE_PROT
  19. VOID
  20. PtBindAdapter(
  21. OUT PNDIS_STATUS Status,
  22. IN NDIS_HANDLE BindContext,
  23. IN PNDIS_STRING DeviceName,
  24. IN PVOID SystemSpecific1,
  25. IN PVOID SystemSpecific2
  26. )
  27. /*++
  28. Routine Description:
  29. Called by NDIS to bind to a miniport below. This routine
  30. creates a binding by calling NdisOpenAdapter, and then
  31. initiates creation of all configured VELANs on this binding.
  32. Arguments:
  33. Status - Return status of bind here.
  34. BindContext - Can be passed to NdisCompleteBindAdapter if this
  35. call is pended.
  36. DeviceName - Device name to bind to. This is passed to
  37. NdisOpenAdapter.
  38. SystemSpecific1 - Can be passed to NdisOpenProtocolConfiguration to
  39. read per-binding information
  40. SystemSpecific2 - Unused
  41. Return Value:
  42. *Status is set to NDIS_STATUS_SUCCESS if no failure occurred
  43. while handling this call, otherwise an error code.
  44. --*/
  45. {
  46. PADAPT pAdapt = NULL;
  47. NDIS_STATUS OpenErrorStatus;
  48. UINT MediumIndex;
  49. PNDIS_STRING pConfigString;
  50. ULONG Length;
  51. pConfigString = (PNDIS_STRING)SystemSpecific1;
  52. DBGPRINT(MUX_LOUD, ("==> Protocol BindAdapter: %ws\n", pConfigString->Buffer));
  53. do
  54. {
  55. //
  56. // Allocate memory for Adapter struct plus the config
  57. // string with two extra WCHARs for NULL termination.
  58. //
  59. Length = sizeof(ADAPT) +
  60. pConfigString->MaximumLength + sizeof(WCHAR);
  61. NdisAllocateMemoryWithTag(&pAdapt, Length , TAG);
  62. if (pAdapt == NULL)
  63. {
  64. *Status = NDIS_STATUS_RESOURCES;
  65. break;
  66. }
  67. //
  68. // Initialize the adapter structure
  69. //
  70. NdisZeroMemory(pAdapt, sizeof(ADAPT));
  71. (VOID)PtReferenceAdapter(pAdapt, "openadapter");
  72. //
  73. // Copy in the Config string - we will use this to open the
  74. // registry section for this adapter at a later point.
  75. //
  76. pAdapt->ConfigString.MaximumLength = pConfigString->MaximumLength;
  77. pAdapt->ConfigString.Length = pConfigString->Length;
  78. pAdapt->ConfigString.Buffer = (PWCHAR)((PUCHAR)pAdapt +
  79. sizeof(ADAPT));
  80. NdisMoveMemory(pAdapt->ConfigString.Buffer,
  81. pConfigString->Buffer,
  82. pConfigString->Length);
  83. pAdapt->ConfigString.Buffer[pConfigString->Length/sizeof(WCHAR)] =
  84. ((WCHAR)0);
  85. NdisInitializeEvent(&pAdapt->Event);
  86. NdisInitializeListHead(&pAdapt->VElanList);
  87. pAdapt->PtDevicePowerState = NdisDeviceStateD0;
  88. MUX_INIT_ADAPT_RW_LOCK(pAdapt);
  89. //
  90. // TODO: Allocate a packet pool and buffers for send & receive.
  91. //
  92. // Now open the adapter below and complete the initialization
  93. //
  94. NdisOpenAdapter(Status,
  95. &OpenErrorStatus,
  96. &pAdapt->BindingHandle,
  97. &MediumIndex,
  98. MediumArray,
  99. sizeof(MediumArray)/sizeof(NDIS_MEDIUM),
  100. ProtHandle,
  101. pAdapt,
  102. DeviceName,
  103. 0,
  104. NULL);
  105. if (*Status == NDIS_STATUS_PENDING)
  106. {
  107. NdisWaitEvent(&pAdapt->Event, 0);
  108. *Status = pAdapt->Status;
  109. }
  110. if (*Status != NDIS_STATUS_SUCCESS)
  111. {
  112. break;
  113. }
  114. pAdapt->Medium = MediumArray[MediumIndex];
  115. //
  116. // Add this adapter to the global AdapterList
  117. //
  118. MUX_ACQUIRE_MUTEX(&GlobalMutex);
  119. InsertTailList(&AdapterList, &pAdapt->Link);
  120. MUX_RELEASE_MUTEX(&GlobalMutex);
  121. //
  122. // Get some information from the adapter below.
  123. //
  124. PtQueryAdapterInfo(pAdapt);
  125. //
  126. // Start all VELANS configured on this adapter.
  127. //
  128. PtBootStrapVElans(pAdapt);
  129. } while(FALSE);
  130. if (*Status != NDIS_STATUS_SUCCESS)
  131. {
  132. if (pAdapt != NULL)
  133. {
  134. PtDereferenceAdapter(pAdapt, "openadapter");
  135. pAdapt = NULL;
  136. }
  137. }
  138. DBGPRINT(MUX_INFO, ("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *Status));
  139. }
  140. VOID
  141. PtOpenAdapterComplete(
  142. IN NDIS_HANDLE ProtocolBindingContext,
  143. IN NDIS_STATUS Status,
  144. IN NDIS_STATUS OpenErrorStatus
  145. )
  146. /*++
  147. Routine Description:
  148. Completion routine for NdisOpenAdapter issued from within the
  149. PtBindAdapter. Simply unblock the caller.
  150. Arguments:
  151. ProtocolBindingContext Pointer to the adapter
  152. Status Status of the NdisOpenAdapter call
  153. OpenErrorStatus Secondary status(ignored by us).
  154. Return Value:
  155. None
  156. --*/
  157. {
  158. PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
  159. DBGPRINT(MUX_LOUD, ("==> PtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
  160. pAdapt->Status = Status;
  161. NdisSetEvent(&pAdapt->Event);
  162. }
  163. VOID
  164. PtQueryAdapterInfo(
  165. IN PADAPT pAdapt
  166. )
  167. /*++
  168. Routine Description:
  169. Query the adapter we are bound to for some standard OID values
  170. which we cache.
  171. Arguments:
  172. pAdapt Pointer to the adapter
  173. Return Value:
  174. None
  175. --*/
  176. {
  177. //
  178. // Get the link speed.
  179. //
  180. pAdapt->LinkSpeed = MUX_DEFAULT_LINK_SPEED;
  181. PtQueryAdapterSync(pAdapt,
  182. OID_GEN_LINK_SPEED,
  183. &pAdapt->LinkSpeed,
  184. sizeof(pAdapt->LinkSpeed));
  185. //
  186. // Get the max lookahead size.
  187. //
  188. pAdapt->MaxLookAhead = MUX_DEFAULT_LOOKAHEAD_SIZE;
  189. PtQueryAdapterSync(pAdapt,
  190. OID_GEN_MAXIMUM_LOOKAHEAD,
  191. &pAdapt->MaxLookAhead,
  192. sizeof(pAdapt->MaxLookAhead));
  193. //
  194. // Get the Ethernet MAC address.
  195. //
  196. PtQueryAdapterSync(pAdapt,
  197. OID_802_3_CURRENT_ADDRESS,
  198. &pAdapt->CurrentAddress,
  199. sizeof(pAdapt->CurrentAddress));
  200. }
  201. VOID
  202. PtQueryAdapterSync(
  203. IN PADAPT pAdapt,
  204. IN NDIS_OID Oid,
  205. IN PVOID InformationBuffer,
  206. IN ULONG InformationBufferLength
  207. )
  208. /*++
  209. Routine Description:
  210. Utility routine to query the adapter for a single OID value. This
  211. blocks for the query to complete.
  212. Arguments:
  213. pAdapt Pointer to the adapter
  214. Oid OID to query for
  215. InformationBuffer Place for the result
  216. InformationBufferLength Length of the above
  217. Return Value:
  218. None.
  219. --*/
  220. {
  221. PMUX_NDIS_REQUEST pMuxNdisRequest = NULL;
  222. NDIS_STATUS Status;
  223. do
  224. {
  225. NdisAllocateMemoryWithTag(&pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), TAG);
  226. if (pMuxNdisRequest == NULL)
  227. {
  228. break;
  229. }
  230. pMuxNdisRequest->pVElan = NULL; // internal request
  231. //
  232. // Set up completion routine.
  233. //
  234. pMuxNdisRequest->pCallback = PtCompleteBlockingRequest;
  235. NdisInitializeEvent(&pMuxNdisRequest->Event);
  236. pMuxNdisRequest->Request.RequestType = NdisRequestQueryInformation;
  237. pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid = Oid;
  238. pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
  239. InformationBuffer;
  240. pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
  241. InformationBufferLength;
  242. NdisRequest(&Status,
  243. pAdapt->BindingHandle,
  244. &pMuxNdisRequest->Request);
  245. if (Status == NDIS_STATUS_PENDING)
  246. {
  247. NdisWaitEvent(&pMuxNdisRequest->Event, 0);
  248. Status = pMuxNdisRequest->Status;
  249. }
  250. }
  251. while (FALSE);
  252. if (NULL != pMuxNdisRequest)
  253. {
  254. NdisFreeMemory(pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), 0);
  255. }
  256. }
  257. VOID
  258. PtRequestAdapterAsync(
  259. IN PADAPT pAdapt,
  260. IN NDIS_REQUEST_TYPE RequestType,
  261. IN NDIS_OID Oid,
  262. IN PVOID InformationBuffer,
  263. IN ULONG InformationBufferLength,
  264. IN PMUX_REQ_COMPLETE_HANDLER pCallback
  265. )
  266. /*++
  267. Routine Description:
  268. Utility routine to query the adapter for a single OID value.
  269. This completes asynchronously, i.e. the calling thread is
  270. not blocked until the request completes.
  271. Arguments:
  272. pAdapt Pointer to the adapter
  273. RequestType NDIS request type
  274. Oid OID to set/query
  275. InformationBuffer Input/output buffer
  276. InformationBufferLength Length of the above
  277. pCallback Function to call on request completion
  278. Return Value:
  279. None.
  280. --*/
  281. {
  282. PMUX_NDIS_REQUEST pMuxNdisRequest = NULL;
  283. PNDIS_REQUEST pNdisRequest;
  284. NDIS_STATUS Status;
  285. do
  286. {
  287. NdisAllocateMemoryWithTag(&pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), TAG);
  288. if (pMuxNdisRequest == NULL)
  289. {
  290. break;
  291. }
  292. pMuxNdisRequest->pVElan = NULL; // internal request
  293. //
  294. // Set up completion routine.
  295. //
  296. pMuxNdisRequest->pCallback = pCallback;
  297. pNdisRequest = &pMuxNdisRequest->Request;
  298. pNdisRequest->RequestType = RequestType;
  299. switch (RequestType)
  300. {
  301. case NdisRequestQueryInformation:
  302. pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
  303. pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer =
  304. InformationBuffer;
  305. pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength =
  306. InformationBufferLength;
  307. break;
  308. case NdisRequestSetInformation:
  309. pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
  310. pNdisRequest->DATA.SET_INFORMATION.InformationBuffer =
  311. InformationBuffer;
  312. pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
  313. InformationBufferLength;
  314. break;
  315. default:
  316. ASSERT(FALSE);
  317. break;
  318. }
  319. NdisRequest(&Status,
  320. pAdapt->BindingHandle,
  321. pNdisRequest);
  322. if (Status != NDIS_STATUS_PENDING)
  323. {
  324. PtRequestComplete(
  325. (NDIS_HANDLE)pAdapt,
  326. pNdisRequest,
  327. Status);
  328. }
  329. }
  330. while (FALSE);
  331. }
  332. VOID
  333. PtUnbindAdapter(
  334. OUT PNDIS_STATUS Status,
  335. IN NDIS_HANDLE ProtocolBindingContext,
  336. IN NDIS_HANDLE UnbindContext
  337. )
  338. /*++
  339. Routine Description:
  340. Called by NDIS when we are required to unbind to the adapter below.
  341. Go through all VELANs on the adapter and shut them down.
  342. Arguments:
  343. Status Placeholder for return status
  344. ProtocolBindingContext Pointer to the adapter structure
  345. UnbindContext Context for NdisUnbindComplete() if this pends
  346. Return Value:
  347. Status from closing the binding.
  348. --*/
  349. {
  350. PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
  351. PLIST_ENTRY p;
  352. PVELAN pVElan = NULL;
  353. LOCK_STATE LockState;
  354. DBGPRINT(MUX_LOUD, ("==> PtUnbindAdapter: Adapt %p\n", pAdapt));
  355. //
  356. // Stop all VELANs associated with the adapter.
  357. // Repeatedly find the first unprocessed VELAN on
  358. // the adapter, mark it, and stop it.
  359. //
  360. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  361. do
  362. {
  363. for (p = pAdapt->VElanList.Flink;
  364. p != &pAdapt->VElanList;
  365. p = p->Flink)
  366. {
  367. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  368. if (!pVElan->DeInitializing)
  369. {
  370. pVElan->DeInitializing = TRUE;
  371. break;
  372. }
  373. }
  374. if (p != &pAdapt->VElanList)
  375. {
  376. ASSERT(pVElan == CONTAINING_RECORD(p, VELAN, Link));
  377. //
  378. // Got a VELAN to stop. Add a temp ref
  379. // so that the VELAN won't go away when
  380. // we release the ADAPT lock below.
  381. //
  382. PtReferenceVElan(pVElan, "UnbindTemp");
  383. //
  384. // Release the read lock because we want to
  385. // run StopVElan at passive IRQL.
  386. //
  387. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  388. PtStopVElan(pVElan);
  389. PtDereferenceVElan(pVElan, "UnbindTemp");
  390. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  391. }
  392. else
  393. {
  394. //
  395. // No unmarked VELAN, so exit.
  396. //
  397. break;
  398. }
  399. }
  400. while (TRUE);
  401. //
  402. // Wait until all VELANs are unlinked from the adapter.
  403. // This is so that we don't attempt to forward down packets
  404. // and/or requests from VELANs after calling NdisCloseAdapter.
  405. //
  406. while (!IsListEmpty(&pAdapt->VElanList))
  407. {
  408. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  409. DBGPRINT(MUX_INFO, ("PtUnbindAdapter: pAdapt %p, VELANlist not yet empty\n",
  410. pAdapt));
  411. NdisMSleep(2000);
  412. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  413. }
  414. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  415. //
  416. // Close the binding to the lower adapter.
  417. //
  418. if (pAdapt->BindingHandle != NULL)
  419. {
  420. NdisResetEvent(&pAdapt->Event);
  421. NdisCloseAdapter(Status, pAdapt->BindingHandle);
  422. //
  423. // Wait for it to complete.
  424. //
  425. if (*Status == NDIS_STATUS_PENDING)
  426. {
  427. NdisWaitEvent(&pAdapt->Event, 0);
  428. *Status = pAdapt->Status;
  429. }
  430. }
  431. else
  432. {
  433. //
  434. // Binding Handle should not be NULL.
  435. //
  436. *Status = NDIS_STATUS_FAILURE;
  437. ASSERT(0);
  438. }
  439. //
  440. // Remove the adapter from the global AdapterList
  441. //
  442. MUX_ACQUIRE_MUTEX(&GlobalMutex);
  443. RemoveEntryList(&pAdapt->Link);
  444. MUX_RELEASE_MUTEX(&GlobalMutex);
  445. //
  446. // Free all the resources associated with this Adapter except the
  447. // ADAPT struct itself, because that will be freed by
  448. // PtDereferenceAdapter call when the reference drops to zero.
  449. // Note: Every VELAN associated with this Adapter takes a ref count
  450. // on it. So the adapter memory wouldn't be freed until all the VELANs
  451. // are shutdown.
  452. //
  453. PtDereferenceAdapter(pAdapt, "Unbind");
  454. DBGPRINT(MUX_INFO, ("<== PtUnbindAdapter: Adapt %p\n", pAdapt));
  455. }
  456. VOID
  457. PtCloseAdapterComplete(
  458. IN NDIS_HANDLE ProtocolBindingContext,
  459. IN NDIS_STATUS Status
  460. )
  461. /*++
  462. Routine Description:
  463. Completion for the CloseAdapter call.
  464. Arguments:
  465. ProtocolBindingContext Pointer to the adapter structure
  466. Status Completion status
  467. Return Value:
  468. None.
  469. --*/
  470. {
  471. PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
  472. DBGPRINT(MUX_INFO, ("==> PtCloseAdapterComplete: Adapt %p, Status %x\n",
  473. pAdapt, Status));
  474. pAdapt->Status = Status;
  475. NdisSetEvent(&pAdapt->Event);
  476. }
  477. VOID
  478. PtResetComplete(
  479. IN NDIS_HANDLE ProtocolBindingContext,
  480. IN NDIS_STATUS Status
  481. )
  482. /*++
  483. Routine Description:
  484. Completion for the reset.
  485. Arguments:
  486. ProtocolBindingContext Pointer to the adapter structure
  487. Status Completion status
  488. Return Value:
  489. None.
  490. --*/
  491. {
  492. PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
  493. DBGPRINT(MUX_ERROR, ("==> PtResetComplete: Adapt %p, Status %x\n",
  494. pAdapt, Status));
  495. //
  496. // We never issue a reset, so we should not be here.
  497. //
  498. ASSERT(0);
  499. }
  500. VOID
  501. PtRequestComplete(
  502. IN NDIS_HANDLE ProtocolBindingContext,
  503. IN PNDIS_REQUEST NdisRequest,
  504. IN NDIS_STATUS Status
  505. )
  506. /*++
  507. Routine Description:
  508. Completion handler for an NDIS request sent to a lower
  509. miniport.
  510. Arguments:
  511. ProtocolBindingContext Pointer to the adapter structure
  512. NdisRequest The completed request
  513. Status Completion status
  514. Return Value:
  515. None
  516. --*/
  517. {
  518. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  519. PMUX_NDIS_REQUEST pMuxNdisRequest;
  520. pMuxNdisRequest = CONTAINING_RECORD(NdisRequest, MUX_NDIS_REQUEST, Request);
  521. ASSERT(pMuxNdisRequest->pCallback != NULL);
  522. //
  523. // Completion is handled by the callback routine:
  524. //
  525. (*pMuxNdisRequest->pCallback)(pAdapt,
  526. pMuxNdisRequest,
  527. Status);
  528. }
  529. VOID
  530. PtCompleteForwardedRequest(
  531. IN PADAPT pAdapt,
  532. IN PMUX_NDIS_REQUEST pMuxNdisRequest,
  533. IN NDIS_STATUS Status
  534. )
  535. /*++
  536. Routine Description:
  537. Handle completion of an NDIS request that was originally
  538. submitted to our VELAN miniport and was forwarded down
  539. to the lower binding.
  540. We do some postprocessing, to cache the results of
  541. certain queries.
  542. Arguments:
  543. pAdapt - Adapter on which the request was forwarded
  544. pMuxNdisRequest - super-struct for request
  545. Status - request completion status
  546. Return Value:
  547. None
  548. --*/
  549. {
  550. PVELAN pVElan = NULL;
  551. PNDIS_REQUEST pNdisRequest = &pMuxNdisRequest->Request;
  552. NDIS_OID Oid = pNdisRequest->DATA.SET_INFORMATION.Oid;
  553. //
  554. // Get the originating VELAN. The VELAN will not be dereferenced
  555. // away until the pended request is completed.
  556. //
  557. pVElan = pMuxNdisRequest->pVElan;
  558. ASSERT(pVElan != NULL);
  559. ASSERT(pMuxNdisRequest == &pVElan->Request);
  560. if (Status != NDIS_STATUS_SUCCESS)
  561. {
  562. DBGPRINT(MUX_WARN, ("PtCompleteForwardedReq: pVElan %p, OID %x, Status %x\n",
  563. pVElan,
  564. pMuxNdisRequest->Request.DATA.QUERY_INFORMATION.Oid,
  565. Status));
  566. }
  567. //
  568. // Complete the original request.
  569. //
  570. switch (pNdisRequest->RequestType)
  571. {
  572. case NdisRequestQueryInformation:
  573. *pVElan->BytesReadOrWritten =
  574. pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
  575. *pVElan->BytesNeeded =
  576. pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
  577. //
  578. // Before completing the request, do any necessary
  579. // post-processing.
  580. //
  581. Oid = pNdisRequest->DATA.QUERY_INFORMATION.Oid;
  582. if (Status == NDIS_STATUS_SUCCESS)
  583. {
  584. if (Oid == OID_GEN_LINK_SPEED)
  585. {
  586. pVElan->LinkSpeed = *(PULONG)
  587. pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
  588. }
  589. else if (Oid == OID_PNP_CAPABILITIES)
  590. {
  591. PtPostProcessPnPCapabilities(pVElan,
  592. pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
  593. pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength);
  594. }
  595. }
  596. NdisMQueryInformationComplete(pVElan->MiniportAdapterHandle, Status);
  597. break;
  598. case NdisRequestSetInformation:
  599. *pVElan->BytesReadOrWritten =
  600. pNdisRequest->DATA.SET_INFORMATION.BytesRead;
  601. *pVElan->BytesNeeded =
  602. pNdisRequest->DATA.SET_INFORMATION.BytesNeeded;
  603. //
  604. // Before completing the request, cache relevant information
  605. // in our structure.
  606. //
  607. if (Status == NDIS_STATUS_SUCCESS)
  608. {
  609. Oid = pNdisRequest->DATA.SET_INFORMATION.Oid;
  610. switch (Oid)
  611. {
  612. case OID_GEN_CURRENT_LOOKAHEAD:
  613. pVElan->LookAhead = *(PULONG)
  614. pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
  615. break;
  616. default:
  617. break;
  618. }
  619. }
  620. NdisMSetInformationComplete(pVElan->MiniportAdapterHandle, Status);
  621. break;
  622. default:
  623. ASSERT(FALSE);
  624. break;
  625. }
  626. MUX_DECR_PENDING_SENDS(pVElan);
  627. }
  628. VOID
  629. PtPostProcessPnPCapabilities(
  630. IN PVELAN pVElan,
  631. IN PVOID InformationBuffer,
  632. IN ULONG InformationBufferLength
  633. )
  634. /*++
  635. Routine Description:
  636. Postprocess a successfully completed query for OID_PNP_CAPABILITIES.
  637. We modify the returned information slightly before completing
  638. it to the VELAN above.
  639. Arguments:
  640. pVElan - Pointer to VELAN
  641. InformationBuffer - points to buffer for the OID
  642. InformationBufferLength - byte length of the above.
  643. Return Value:
  644. None
  645. --*/
  646. {
  647. PNDIS_PNP_CAPABILITIES pPNPCapabilities;
  648. PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
  649. if (InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
  650. {
  651. pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)InformationBuffer;
  652. //
  653. // The following fields must be overwritten by an IM driver.
  654. //
  655. pPMstruct= &pPNPCapabilities->WakeUpCapabilities;
  656. pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
  657. pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
  658. pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
  659. }
  660. }
  661. VOID
  662. PtCompleteBlockingRequest(
  663. IN PADAPT pAdapt,
  664. IN PMUX_NDIS_REQUEST pMuxNdisRequest,
  665. IN NDIS_STATUS Status
  666. )
  667. /*++
  668. Routine Description:
  669. Handle completion of an NDIS request that was originated
  670. by this driver and the calling thread is blocked waiting
  671. for completion.
  672. Arguments:
  673. pAdapt - Adapter on which the request was forwarded
  674. pMuxNdisRequest - super-struct for request
  675. Status - request completion status
  676. Return Value:
  677. None
  678. --*/
  679. {
  680. pMuxNdisRequest->Status = Status;
  681. //
  682. // The request was originated from this driver. Wake up the
  683. // thread blocked for its completion.
  684. //
  685. pMuxNdisRequest->Status = Status;
  686. NdisSetEvent(&pMuxNdisRequest->Event);
  687. }
  688. VOID
  689. PtDiscardCompletedRequest(
  690. IN PADAPT pAdapt,
  691. IN PMUX_NDIS_REQUEST pMuxNdisRequest,
  692. IN NDIS_STATUS Status
  693. )
  694. /*++
  695. Routine Description:
  696. Handle completion of an NDIS request that was originated
  697. by this driver - the request is to be discarded.
  698. Arguments:
  699. pAdapt - Adapter on which the request was forwarded
  700. pMuxNdisRequest - super-struct for request
  701. Status - request completion status
  702. Return Value:
  703. None
  704. --*/
  705. {
  706. UNREFERENCED_PARAMETER(pAdapt);
  707. UNREFERENCED_PARAMETER(Status);
  708. NdisFreeMemory(pMuxNdisRequest, sizeof(MUX_NDIS_REQUEST), 0);
  709. }
  710. VOID
  711. PtStatus(
  712. IN NDIS_HANDLE ProtocolBindingContext,
  713. IN NDIS_STATUS GeneralStatus,
  714. IN PVOID StatusBuffer,
  715. IN UINT StatusBufferSize
  716. )
  717. /*++
  718. Routine Description:
  719. Handle a status indication on the lower binding (ADAPT).
  720. If this is a media status indication, we also pass this
  721. on to all associated VELANs.
  722. Arguments:
  723. ProtocolBindingContext Pointer to the adapter structure
  724. GeneralStatus Status code
  725. StatusBuffer Status buffer
  726. StatusBufferSize Size of the status buffer
  727. Return Value:
  728. None
  729. --*/
  730. {
  731. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  732. PLIST_ENTRY p;
  733. PVELAN pVElan;
  734. LOCK_STATE LockState;
  735. DBGPRINT(MUX_LOUD, ("PtStatus: Adapt %p, Status %x\n", pAdapt, GeneralStatus));
  736. do
  737. {
  738. //
  739. // Ignore status indications that we aren't going
  740. // to pass up.
  741. //
  742. if ((GeneralStatus != NDIS_STATUS_MEDIA_CONNECT) &&
  743. (GeneralStatus != NDIS_STATUS_MEDIA_DISCONNECT))
  744. {
  745. break;
  746. }
  747. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  748. for (p = pAdapt->VElanList.Flink;
  749. p != &pAdapt->VElanList;
  750. p = p->Flink)
  751. {
  752. BOOLEAN bIndicateReceive;
  753. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  754. MUX_INCR_PENDING_RECEIVES(pVElan);
  755. //
  756. // Should the indication be sent on this VELAN?
  757. //
  758. if ((pVElan->MiniportHalting) ||
  759. (pVElan->MiniportAdapterHandle == NULL) ||
  760. MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
  761. {
  762. MUX_DECR_PENDING_RECEIVES(pVElan);
  763. if (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState))
  764. {
  765. //
  766. // Keep track of the lastest status to indicated when VELAN power is on
  767. //
  768. ASSERT((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) || (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT));
  769. pVElan->LatestUnIndicateStatus = GeneralStatus;
  770. }
  771. continue;
  772. }
  773. //
  774. // Save the last indicated status when
  775. pVElan->LastIndicatedStatus = GeneralStatus;
  776. NdisMIndicateStatus(pVElan->MiniportAdapterHandle,
  777. GeneralStatus,
  778. StatusBuffer,
  779. StatusBufferSize);
  780. //
  781. // Mark this so that we forward a status complete
  782. // indication as well.
  783. //
  784. pVElan->IndicateStatusComplete = TRUE;
  785. MUX_DECR_PENDING_RECEIVES(pVElan);
  786. }
  787. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  788. }
  789. while (FALSE);
  790. }
  791. VOID
  792. PtStatusComplete(
  793. IN NDIS_HANDLE ProtocolBindingContext
  794. )
  795. /*++
  796. Routine Description:
  797. Marks the end of a status indication. Pass it on to
  798. associated VELANs if necessary.
  799. Arguments:
  800. ProtocolBindingContext - pointer to ADAPT
  801. Return Value:
  802. None.
  803. --*/
  804. {
  805. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  806. PLIST_ENTRY p;
  807. PVELAN pVElan;
  808. LOCK_STATE LockState;
  809. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  810. for (p = pAdapt->VElanList.Flink;
  811. p != &pAdapt->VElanList;
  812. p = p->Flink)
  813. {
  814. BOOLEAN bIndicateReceive;
  815. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  816. MUX_INCR_PENDING_RECEIVES(pVElan);
  817. //
  818. // Should this indication be sent on this VELAN?
  819. //
  820. if ((pVElan->MiniportHalting) ||
  821. (pVElan->MiniportAdapterHandle == NULL) ||
  822. (!pVElan->IndicateStatusComplete) ||
  823. (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
  824. {
  825. MUX_DECR_PENDING_RECEIVES(pVElan);
  826. continue;
  827. }
  828. pVElan->IndicateStatusComplete = FALSE;
  829. NdisMIndicateStatusComplete(pVElan->MiniportAdapterHandle);
  830. MUX_DECR_PENDING_RECEIVES(pVElan);
  831. }
  832. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  833. }
  834. VOID
  835. PtSendComplete(
  836. IN NDIS_HANDLE ProtocolBindingContext,
  837. IN PNDIS_PACKET Packet,
  838. IN NDIS_STATUS Status
  839. )
  840. /*++
  841. Routine Description:
  842. Called by NDIS when the miniport below had completed a send.
  843. We complete the corresponding upper-edge send this represents.
  844. The packet being completed belongs to our send packet pool,
  845. however we store a pointer to the original packet this represents,
  846. in the packet's reserved field.
  847. Arguments:
  848. ProtocolBindingContext - Points to ADAPT structure
  849. Packet - Packet being completed by the lower miniport
  850. Status - status of send
  851. Return Value:
  852. None
  853. --*/
  854. {
  855. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  856. PVELAN pVElan;
  857. PMUX_SEND_RSVD pSendReserved;
  858. PNDIS_PACKET OriginalPacket;
  859. #if IEEE_VLAN_SUPPORT
  860. NDIS_PACKET_8021Q_INFO NdisPacket8021qInfo;
  861. BOOLEAN IsTagInsert;
  862. PNDIS_BUFFER pNdisBuffer;
  863. PVOID pVa;
  864. ULONG BufferLength;
  865. #endif
  866. pSendReserved = MUX_RSVD_FROM_SEND_PACKET(Packet);
  867. OriginalPacket = pSendReserved->pOriginalPacket;
  868. pVElan = pSendReserved->pVElan;
  869. #if IEEE_VLAN_SUPPORT
  870. //
  871. // Check if we had inserted a tag header
  872. //
  873. IsTagInsert = FALSE;
  874. NdisPacket8021qInfo.Value = NDIS_PER_PACKET_INFO_FROM_PACKET(
  875. OriginalPacket,
  876. Ieee8021QInfo);
  877. if ((pVElan->VlanId != 0) || (NdisPacket8021qInfo.Value != NULL))
  878. {
  879. IsTagInsert = TRUE;
  880. }
  881. #endif
  882. #ifndef WIN9X
  883. NdisIMCopySendCompletePerPacketInfo(OriginalPacket, Packet);
  884. #endif
  885. //
  886. // Update statistics.
  887. //
  888. if (Status == NDIS_STATUS_SUCCESS)
  889. {
  890. MUX_INCR_STATISTICS64(&pVElan->GoodTransmits);
  891. }
  892. else
  893. {
  894. MUX_INCR_STATISTICS(&pVElan->TransmitFailuresOther);
  895. }
  896. //
  897. // Complete the original send.
  898. //
  899. NdisMSendComplete(pVElan->MiniportAdapterHandle,
  900. OriginalPacket,
  901. Status);
  902. #if IEEE_VLAN_SUPPORT
  903. //
  904. // If we had inserted a tag header, then remove the header
  905. // buffer and free it. We would also have created a new
  906. // NDIS buffer to map part of the original packet's header;
  907. // free that, too.
  908. //
  909. if (IsTagInsert)
  910. {
  911. pNdisBuffer = Packet->Private.Head;
  912. #ifdef NDIS51_MINIPORT
  913. NdisQueryBufferSafe(pNdisBuffer, &pVa, &BufferLength, NormalPagePriority);
  914. #else
  915. NdisQueryBuffer(pNdisBuffer, &pVa, &BufferLength);
  916. #endif
  917. if (pVa != NULL)
  918. {
  919. NdisFreeToNPagedLookasideList(&pVElan->TagLookaside, pVa);
  920. }
  921. NdisFreeBuffer(NDIS_BUFFER_LINKAGE(pNdisBuffer));
  922. NdisFreeBuffer (pNdisBuffer);
  923. }
  924. #endif
  925. //
  926. // Free our packet.
  927. //
  928. NdisFreePacket(Packet);
  929. //
  930. // Note down send-completion.
  931. //
  932. MUX_DECR_PENDING_SENDS(pVElan);
  933. }
  934. VOID
  935. PtTransferDataComplete(
  936. IN NDIS_HANDLE ProtocolBindingContext,
  937. IN PNDIS_PACKET Packet,
  938. IN NDIS_STATUS Status,
  939. IN UINT BytesTransferred
  940. )
  941. /*++
  942. Routine Description:
  943. Entry point called by NDIS to indicate completion of a call by us
  944. to NdisTransferData. We locate the original packet and VELAN on
  945. which our TransferData function (see MPTransferData) was called,
  946. and complete the original request.
  947. Arguments:
  948. ProtocolBindingContext - lower binding context, pointer to ADAPT
  949. Packet - Packet allocated by us
  950. Status - Completion status
  951. BytesTransferred - Number of bytes copied in
  952. Return Value:
  953. None
  954. --*/
  955. {
  956. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  957. PVELAN pVElan;
  958. PNDIS_PACKET pOriginalPacket;
  959. PMUX_TD_RSVD pTDReserved;
  960. pTDReserved = MUX_RSVD_FROM_TD_PACKET(Packet);
  961. pOriginalPacket = pTDReserved->pOriginalPacket;
  962. pVElan = pTDReserved->pVElan;
  963. //
  964. // Complete the original TransferData request.
  965. //
  966. NdisMTransferDataComplete(pVElan->MiniportAdapterHandle,
  967. pOriginalPacket,
  968. Status,
  969. BytesTransferred);
  970. //
  971. // Free our packet.
  972. //
  973. NdisFreePacket(Packet);
  974. }
  975. BOOLEAN
  976. PtMulticastMatch(
  977. IN PVELAN pVElan,
  978. IN PUCHAR pDstMac
  979. )
  980. /*++
  981. Routine Description:
  982. Check if the given multicast destination MAC address matches
  983. any of the multicast address entries set on the VELAN.
  984. NOTE: the caller is assumed to hold a READ/WRITE lock
  985. to the parent ADAPT structure. This is so that the multicast
  986. list on the VELAN is invariant for the duration of this call.
  987. Arguments:
  988. pVElan - VELAN to look in
  989. pDstMac - Destination MAC address to compare
  990. Return Value:
  991. TRUE iff the address matches an entry in the VELAN
  992. --*/
  993. {
  994. ULONG i;
  995. UINT AddrCompareResult;
  996. for (i = 0; i < pVElan->McastAddrCount; i++)
  997. {
  998. ETH_COMPARE_NETWORK_ADDRESSES_EQ(pVElan->McastAddrs[i],
  999. pDstMac,
  1000. &AddrCompareResult);
  1001. if (AddrCompareResult == 0)
  1002. {
  1003. break;
  1004. }
  1005. }
  1006. return (i != pVElan->McastAddrCount);
  1007. }
  1008. BOOLEAN
  1009. PtMatchPacketToVElan(
  1010. IN PVELAN pVElan,
  1011. IN PUCHAR pDstMac,
  1012. IN BOOLEAN bIsMulticast,
  1013. IN BOOLEAN bIsBroadcast
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Check if the destination address of a received packet
  1018. matches the receive criteria on the specified VELAN.
  1019. NOTE: the caller is assumed to hold a READ/WRITE lock
  1020. to the parent ADAPT structure.
  1021. Arguments:
  1022. pVElan - VELAN to check on
  1023. pDstMac - Destination MAC address in received packet
  1024. bIsMulticast - is this a multicast address
  1025. bIsBroadcast - is this a broadcast address
  1026. Return Value:
  1027. TRUE iff this packet should be received on the VELAN
  1028. --*/
  1029. {
  1030. UINT AddrCompareResult;
  1031. ULONG PacketFilter;
  1032. BOOLEAN bPacketMatch;
  1033. PacketFilter = pVElan->PacketFilter;
  1034. //
  1035. // Handle the directed packet case first.
  1036. //
  1037. if (!bIsMulticast)
  1038. {
  1039. //
  1040. // If the VELAN is not in promisc. mode, check if
  1041. // the destination MAC address matches the local
  1042. // address.
  1043. //
  1044. if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == 0)
  1045. {
  1046. ETH_COMPARE_NETWORK_ADDRESSES_EQ(pVElan->CurrentAddress,
  1047. pDstMac,
  1048. &AddrCompareResult);
  1049. bPacketMatch = ((AddrCompareResult == 0) &&
  1050. ((PacketFilter & NDIS_PACKET_TYPE_DIRECTED) != 0));
  1051. }
  1052. else
  1053. {
  1054. bPacketMatch = TRUE;
  1055. }
  1056. }
  1057. else
  1058. {
  1059. //
  1060. // Multicast or broadcast packet.
  1061. //
  1062. //
  1063. // Indicate if the filter is set to promisc mode ...
  1064. //
  1065. if ((PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
  1066. ||
  1067. //
  1068. // or if this is a broadcast packet and the filter
  1069. // is set to receive all broadcast packets...
  1070. //
  1071. (bIsBroadcast &&
  1072. (PacketFilter & NDIS_PACKET_TYPE_BROADCAST))
  1073. ||
  1074. //
  1075. // or if this is a multicast packet, and the filter is
  1076. // either set to receive all multicast packets, or
  1077. // set to receive specific multicast packets. In the
  1078. // latter case, indicate receive only if the destn
  1079. // MAC address is present in the list of multicast
  1080. // addresses set on the VELAN.
  1081. //
  1082. (!bIsBroadcast &&
  1083. ((PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
  1084. ((PacketFilter & NDIS_PACKET_TYPE_MULTICAST) &&
  1085. PtMulticastMatch(pVElan, pDstMac))))
  1086. )
  1087. {
  1088. bPacketMatch = TRUE;
  1089. }
  1090. else
  1091. {
  1092. //
  1093. // No protocols above are interested in this
  1094. // multicast/broadcast packet.
  1095. //
  1096. bPacketMatch = FALSE;
  1097. }
  1098. }
  1099. return (bPacketMatch);
  1100. }
  1101. NDIS_STATUS
  1102. PtReceive(
  1103. IN NDIS_HANDLE ProtocolBindingContext,
  1104. IN NDIS_HANDLE MacReceiveContext,
  1105. IN PVOID HeaderBuffer,
  1106. IN UINT HeaderBufferSize,
  1107. IN PVOID LookAheadBuffer,
  1108. IN UINT LookAheadBufferSize,
  1109. IN UINT PacketSize
  1110. )
  1111. /*++
  1112. Routine Description:
  1113. Handle receive data indicated up by the miniport below.
  1114. We forward this up to all VELANs that are eligible to
  1115. receive this packet:
  1116. - If this is directed to a broadcast/multicast address,
  1117. indicate up on all VELANs that have multicast or broadcast
  1118. or promisc. bits set in their packet filters.
  1119. - If this is a directed packet, indicate it up on all VELANs
  1120. that have the a matching MAC address or have the promisc.
  1121. bit set in their packet filters.
  1122. We acquire a read lock on the ADAPT structure to ensure
  1123. that the VELAN list on the adapter is undisturbed.
  1124. If the miniport below indicates packets, NDIS would more
  1125. likely call us at our ReceivePacket handler. However we
  1126. might be called here in certain situations even though
  1127. the miniport below has indicated a receive packet, e.g.
  1128. if the miniport had set packet status to NDIS_STATUS_RESOURCES.
  1129. Arguments:
  1130. <see DDK ref page for ProtocolReceive>
  1131. Return Value:
  1132. NDIS_STATUS_SUCCESS if we processed the receive successfully,
  1133. NDIS_STATUS_XXX error code if we discarded it.
  1134. --*/
  1135. {
  1136. PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
  1137. PLIST_ENTRY p;
  1138. PVELAN pVElan, pNextVElan;
  1139. PNDIS_PACKET MyPacket, Packet;
  1140. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1141. PUCHAR pData;
  1142. PUCHAR pDstMac;
  1143. BOOLEAN bIsMulticast, bIsBroadcast;
  1144. PMUX_RECV_RSVD pRecvReserved;
  1145. LOCK_STATE LockState;
  1146. #if IEEE_VLAN_SUPPORT
  1147. VLAN_TAG_HEADER UNALIGNED * pTagHeader;
  1148. USHORT UNALIGNED * pTpid;
  1149. MUX_RCV_CONTEXT MuxRcvContext;
  1150. #endif
  1151. do
  1152. {
  1153. if (HeaderBufferSize != ETH_HEADER_SIZE)
  1154. {
  1155. Status = NDIS_STATUS_NOT_ACCEPTED;
  1156. break;
  1157. }
  1158. if (pAdapt->PacketFilter == 0)
  1159. {
  1160. //
  1161. // We could get receives in the interval between
  1162. // initiating a request to set the packet filter on
  1163. // the binding to 0 and completion of that request.
  1164. // Drop such packets.
  1165. //
  1166. Status = NDIS_STATUS_NOT_ACCEPTED;
  1167. break;
  1168. }
  1169. //
  1170. // Collect some information from the packet.
  1171. //
  1172. pData = (PUCHAR)HeaderBuffer;
  1173. pDstMac = pData;
  1174. bIsMulticast = ETH_IS_MULTICAST(pDstMac);
  1175. bIsBroadcast = ETH_IS_BROADCAST(pDstMac);
  1176. //
  1177. // Get at the packet, if any, indicated up by the miniport below.
  1178. //
  1179. Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
  1180. //
  1181. // Lock down the VELAN list on the adapter so that
  1182. // no insertions/deletions to this list happen while
  1183. // we loop through it. The packet filter will also not
  1184. // change during the time we hold the read lock.
  1185. //
  1186. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1187. for (p = pAdapt->VElanList.Flink;
  1188. p != &pAdapt->VElanList;
  1189. p = p->Flink)
  1190. {
  1191. BOOLEAN bIndicateReceive;
  1192. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1193. //
  1194. // Should the packet be indicated up on this VELAN?
  1195. //
  1196. bIndicateReceive = PtMatchPacketToVElan(pVElan,
  1197. pDstMac,
  1198. bIsMulticast,
  1199. bIsBroadcast);
  1200. if (!bIndicateReceive)
  1201. {
  1202. continue;
  1203. }
  1204. //
  1205. // Make sure we don't Halt the VELAN miniport while
  1206. // we are accessing it here. See MPHalt.
  1207. //
  1208. // Also don't indicate receives if the virtual miniport
  1209. // has been set to a low power state. A specific case
  1210. // is when the system is resuming from "Stand-by", if
  1211. // the lower adapter is restored to D0 before the upper
  1212. // miniports are.
  1213. //
  1214. //
  1215. MUX_INCR_PENDING_RECEIVES(pVElan);
  1216. if ((pVElan->MiniportHalting) ||
  1217. (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
  1218. {
  1219. MUX_DECR_PENDING_RECEIVES(pVElan);
  1220. continue;
  1221. }
  1222. if (Packet != NULL)
  1223. {
  1224. //
  1225. // The miniport below did indicate up a packet. Use information
  1226. // from that packet to construct a new packet to indicate up.
  1227. //
  1228. //
  1229. // Get a packet off our receive pool and indicate that up.
  1230. //
  1231. NdisDprAllocatePacket(&Status,
  1232. &MyPacket,
  1233. pVElan->RecvPacketPoolHandle);
  1234. if (Status == NDIS_STATUS_SUCCESS)
  1235. {
  1236. //
  1237. // Make our packet point to data from the original
  1238. // packet. NOTE: this works only because we are
  1239. // indicating a receive directly from the context of
  1240. // our receive indication. If we need to queue this
  1241. // packet and indicate it from another thread context,
  1242. // we will also have to allocate a new buffer and copy
  1243. // over the packet contents, OOB data and per-packet
  1244. // information. This is because the packet data
  1245. // is available only for the duration of this
  1246. // receive indication call.
  1247. //
  1248. MyPacket->Private.Head = Packet->Private.Head;
  1249. MyPacket->Private.Tail = Packet->Private.Tail;
  1250. #if IEEE_VLAN_SUPPORT
  1251. Status = PtHandleRcvTagging(pVElan, Packet, MyPacket);
  1252. if (Status != NDIS_STATUS_SUCCESS)
  1253. {
  1254. NdisFreePacket(MyPacket);
  1255. MUX_DECR_PENDING_RECEIVES(pVElan);
  1256. continue;
  1257. }
  1258. #endif
  1259. //
  1260. // Get the original packet (it could be the same packet
  1261. // as the one received or a different one based on the
  1262. // number of layered miniports below) and set it on the
  1263. // indicated packet so the OOB data is visible correctly
  1264. // at protocols above.
  1265. //
  1266. NDIS_SET_ORIGINAL_PACKET(MyPacket,
  1267. NDIS_GET_ORIGINAL_PACKET(Packet));
  1268. NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
  1269. //
  1270. // Copy packet flags.
  1271. //
  1272. NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
  1273. //
  1274. // Force protocols above to make a copy if they want to hang
  1275. // on to data in this packet. This is because we are in our
  1276. // Receive handler (not ReceivePacket), and the original
  1277. // packet can't be accessed after we return from here.
  1278. //
  1279. NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
  1280. //
  1281. // Set our context information in the packet. Since
  1282. // the original packet from the miniport below is not being
  1283. // queued up, set this to NULL:
  1284. //
  1285. pRecvReserved = MUX_RSVD_FROM_RECV_PACKET(MyPacket);
  1286. pRecvReserved->pOriginalPacket = NULL;
  1287. MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
  1288. //
  1289. // By setting NDIS_STATUS_RESOURCES, we also know that
  1290. // we can reclaim this packet as soon as the call to
  1291. // NdisMIndicateReceivePacket returns.
  1292. //
  1293. NdisMIndicateReceivePacket(pVElan->MiniportAdapterHandle,
  1294. &MyPacket,
  1295. 1);
  1296. //
  1297. // Reclaim the indicated packet. Since we had set its status
  1298. // to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
  1299. // above are done with it. Our ReturnPacket handler will
  1300. // not be called for this packet, so call it ourselves.
  1301. //
  1302. MPReturnPacket((NDIS_HANDLE)pVElan, MyPacket);
  1303. //
  1304. // Done with this VELAN.
  1305. //
  1306. continue;
  1307. }
  1308. //
  1309. // else...
  1310. //
  1311. // Failed to allocate a packet to indicate up - fall through.
  1312. // We will still indicate up using the non-packet API, but
  1313. // other per-packet/OOB information won't be available
  1314. // to protocols above.
  1315. //
  1316. }
  1317. else
  1318. {
  1319. //
  1320. // The miniport below us uses the old-style (not packet)
  1321. // receive indication. Fall through.
  1322. //
  1323. }
  1324. //
  1325. // Fall through to here if the miniport below us has
  1326. // either not indicated an NDIS_PACKET or we could not
  1327. // allocate one.
  1328. //
  1329. //
  1330. // Mark the VELAN so that we will forward up a receive
  1331. // complete indication.
  1332. //
  1333. pVElan->IndicateRcvComplete = TRUE;
  1334. #if IEEE_VLAN_SUPPORT
  1335. //
  1336. // Get at the EtherType field.
  1337. //
  1338. pTpid = (PUSHORT)((PUCHAR)HeaderBuffer + 2 * ETH_LENGTH_OF_ADDRESS);
  1339. //
  1340. // Check if the EtherType indicates presence of a tag header.
  1341. //
  1342. if (*pTpid == TPID)
  1343. {
  1344. pTagHeader = (VLAN_TAG_HEADER UNALIGNED *)LookAheadBuffer;
  1345. //
  1346. // Drop this frame if it contains Routing information;
  1347. // we don't support this.
  1348. //
  1349. if (GET_CANONICAL_FORMAT_ID_FROM_TAG(pTagHeader) != 0)
  1350. {
  1351. Status = NDIS_STATUS_INVALID_PACKET;
  1352. MUX_DECR_PENDING_RECEIVES(pVElan);
  1353. MUX_INCR_STATISTICS(&pVElan->RcvFormatErrors);
  1354. continue;
  1355. }
  1356. //
  1357. // If there is a VLAN ID in this frame, and we have
  1358. // a configured VLAN ID for this VELAN, check if they
  1359. // are the same - drop if not.
  1360. //
  1361. if ((GET_VLAN_ID_FROM_TAG(pTagHeader) != 0) &&
  1362. (pVElan->VlanId != 0) &&
  1363. (GET_VLAN_ID_FROM_TAG(pTagHeader) != pVElan->VlanId))
  1364. {
  1365. Status = NDIS_STATUS_NOT_ACCEPTED;
  1366. MUX_DECR_PENDING_RECEIVES(pVElan);
  1367. MUX_INCR_STATISTICS(&pVElan->RcvVlanIdErrors);
  1368. continue;
  1369. }
  1370. //
  1371. // Copy information from the tag header to per-packet
  1372. // info fields.
  1373. //
  1374. MuxRcvContext.NdisPacket8021QInfo.Value = NULL;
  1375. COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(
  1376. MuxRcvContext.NdisPacket8021QInfo,
  1377. pTagHeader);
  1378. //
  1379. // Prepare for indicating up this frame (the tag
  1380. // header must be removed). First, copy in the real
  1381. // EtherType value from the tag header.
  1382. //
  1383. *pTpid = *((PUSHORT)((PUCHAR)LookAheadBuffer + sizeof(pTagHeader->TagInfo)));
  1384. //
  1385. // Account for removing the tag header.
  1386. //
  1387. LookAheadBuffer = (PVOID)((PUCHAR)LookAheadBuffer + VLAN_TAG_HEADER_SIZE);
  1388. LookAheadBufferSize -= VLAN_TAG_HEADER_SIZE;
  1389. PacketSize -= VLAN_TAG_HEADER_SIZE;
  1390. //
  1391. // Use MuxRcvContext to store context for the receive,
  1392. // to be used in MpTransferData, if called.
  1393. //
  1394. MuxRcvContext.TagHeaderLen = VLAN_TAG_HEADER_SIZE;
  1395. }
  1396. else
  1397. {
  1398. MuxRcvContext.TagHeaderLen = 0;
  1399. }
  1400. MuxRcvContext.MacRcvContext = MacReceiveContext;
  1401. //
  1402. // In order not to change the code a lot
  1403. //
  1404. MacReceiveContext = &MuxRcvContext;
  1405. #endif
  1406. MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
  1407. //
  1408. // Indicate receive using the non-packet API.
  1409. //
  1410. NdisMEthIndicateReceive(pVElan->MiniportAdapterHandle,
  1411. MacReceiveContext,
  1412. HeaderBuffer,
  1413. HeaderBufferSize,
  1414. LookAheadBuffer,
  1415. LookAheadBufferSize,
  1416. PacketSize);
  1417. MUX_DECR_PENDING_RECEIVES(pVElan);
  1418. } // for (each VELAN)
  1419. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1420. break;
  1421. }
  1422. while(FALSE);
  1423. return Status;
  1424. }
  1425. VOID
  1426. PtReceiveComplete(
  1427. IN NDIS_HANDLE ProtocolBindingContext
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. Called by the adapter below us when it is done indicating a batch of
  1432. received packets. We forward this up on all VELANs that need
  1433. this indication.
  1434. Arguments:
  1435. ProtocolBindingContext Pointer to our adapter structure.
  1436. Return Value:
  1437. None
  1438. --*/
  1439. {
  1440. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  1441. PLIST_ENTRY p;
  1442. PVELAN pVElan;
  1443. LOCK_STATE LockState;
  1444. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1445. for (p = pAdapt->VElanList.Flink;
  1446. p != &pAdapt->VElanList;
  1447. p = p->Flink)
  1448. {
  1449. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1450. if (pVElan->IndicateRcvComplete)
  1451. {
  1452. pVElan->IndicateRcvComplete = FALSE;
  1453. NdisMEthIndicateReceiveComplete(pVElan->MiniportAdapterHandle);
  1454. }
  1455. }
  1456. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1457. }
  1458. INT
  1459. PtReceivePacket(
  1460. IN NDIS_HANDLE ProtocolBindingContext,
  1461. IN PNDIS_PACKET Packet
  1462. )
  1463. /*++
  1464. Routine Description:
  1465. ReceivePacket handler. Called by NDIS if the miniport below supports
  1466. NDIS 4.0 style receives. Re-package the buffer chain in a new packet
  1467. and indicate the new packet to interested protocols above us.
  1468. Arguments:
  1469. ProtocolBindingContext - Pointer to our adapter structure.
  1470. Packet - Pointer to the packet
  1471. Return Value:
  1472. == 0 -> We are done with the packet
  1473. != 0 -> We will keep the packet and call NdisReturnPackets() this
  1474. many times when done.
  1475. --*/
  1476. {
  1477. PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
  1478. PVELAN pVElan;
  1479. PLIST_ENTRY p;
  1480. NDIS_STATUS Status;
  1481. PNDIS_PACKET MyPacket;
  1482. PUCHAR pData;
  1483. PNDIS_BUFFER pNdisBuffer;
  1484. UINT FirstBufferLength;
  1485. UINT TotalLength;
  1486. PUCHAR pDstMac;
  1487. BOOLEAN bIsMulticast, bIsBroadcast;
  1488. PMUX_RECV_RSVD pRecvReserved;
  1489. ULONG ReturnCount;
  1490. LOCK_STATE LockState;
  1491. ReturnCount = 0;
  1492. do
  1493. {
  1494. if (pAdapt->PacketFilter == 0)
  1495. {
  1496. //
  1497. // We could get receives in the interval between
  1498. // initiating a request to set the packet filter on
  1499. // the binding to 0 and completion of that request.
  1500. // Drop such packets.
  1501. //
  1502. break;
  1503. }
  1504. #ifdef NDIS51
  1505. //
  1506. // Collect some information from the packet.
  1507. //
  1508. NdisGetFirstBufferFromPacketSafe(Packet,
  1509. &pNdisBuffer,
  1510. &pData,
  1511. &FirstBufferLength,
  1512. &TotalLength,
  1513. NormalPagePriority);
  1514. if (pNdisBuffer == NULL)
  1515. {
  1516. //
  1517. // Out of system resources. Drop this packet.
  1518. //
  1519. break;
  1520. }
  1521. #else
  1522. NdisGetFirstBufferFromPacket(Packet,
  1523. &pNdisBuffer,
  1524. &pData,
  1525. &FirstBufferLength,
  1526. &TotalLength);
  1527. #endif
  1528. pDstMac = pData;
  1529. bIsMulticast = ETH_IS_MULTICAST(pDstMac);
  1530. bIsBroadcast = ETH_IS_BROADCAST(pDstMac);
  1531. //
  1532. // Lock down the VELAN list on the adapter so that
  1533. // no insertions/deletions to this list happen while
  1534. // we loop through it. The packet filter will also not
  1535. // change during the time we hold the read lock.
  1536. //
  1537. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1538. for (p = pAdapt->VElanList.Flink;
  1539. p != &pAdapt->VElanList;
  1540. p = p->Flink)
  1541. {
  1542. BOOLEAN bIndicateReceive;
  1543. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1544. //
  1545. // Should the packet be indicated up on this VELAN?
  1546. //
  1547. bIndicateReceive = PtMatchPacketToVElan(pVElan,
  1548. pDstMac,
  1549. bIsMulticast,
  1550. bIsBroadcast);
  1551. if (!bIndicateReceive)
  1552. {
  1553. continue;
  1554. }
  1555. //
  1556. // Make sure we don't Halt the VELAN miniport while
  1557. // we are accessing it here. See MPHalt.
  1558. //
  1559. // Also don't indicate receives if the virtual miniport
  1560. // has been set to a low power state. A specific case
  1561. // is when the system is resuming from "Stand-by", if
  1562. // the lower adapter is restored to D0 before the upper
  1563. // miniports are.
  1564. //
  1565. MUX_INCR_PENDING_RECEIVES(pVElan);
  1566. if ((pVElan->MiniportHalting) ||
  1567. (MUX_IS_LOW_POWER_STATE(pVElan->MPDevicePowerState)))
  1568. {
  1569. MUX_DECR_PENDING_RECEIVES(pVElan);
  1570. continue;
  1571. }
  1572. //
  1573. // Get a packet off the pool and indicate that up
  1574. //
  1575. NdisDprAllocatePacket(&Status,
  1576. &MyPacket,
  1577. pVElan->RecvPacketPoolHandle);
  1578. if (Status == NDIS_STATUS_SUCCESS)
  1579. {
  1580. pRecvReserved = MUX_RSVD_FROM_RECV_PACKET(MyPacket);
  1581. pRecvReserved->pOriginalPacket = Packet;
  1582. MyPacket->Private.Head = Packet->Private.Head;
  1583. MyPacket->Private.Tail = Packet->Private.Tail;
  1584. //
  1585. // Get the original packet (it could be the same
  1586. // packet as the one received or a different one
  1587. // based on the number of layered miniports below)
  1588. // and set it on the indicated packet so the OOB
  1589. // data is visible correctly to protocols above us.
  1590. //
  1591. NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
  1592. //
  1593. // Copy Packet Flags
  1594. //
  1595. NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
  1596. Status = NDIS_GET_PACKET_STATUS(Packet);
  1597. NDIS_SET_PACKET_STATUS(MyPacket, Status);
  1598. NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
  1599. #if IEEE_VLAN_SUPPORT
  1600. Status = PtHandleRcvTagging(pVElan, Packet, MyPacket);
  1601. if (Status != NDIS_STATUS_SUCCESS)
  1602. {
  1603. NdisFreePacket(MyPacket);
  1604. MUX_DECR_PENDING_RECEIVES(pVElan);
  1605. continue;
  1606. }
  1607. #endif
  1608. MUX_INCR_STATISTICS64(&pVElan->GoodReceives);
  1609. //
  1610. // Indicate it up.
  1611. //
  1612. ReturnCount++;
  1613. NdisMIndicateReceivePacket(pVElan->MiniportAdapterHandle,
  1614. &MyPacket,
  1615. 1);
  1616. //
  1617. // Check if we had indicated up the packet with
  1618. // status set to NDIS_STATUS_RESOURCES.
  1619. //
  1620. // NOTE -- do not use NDIS_GET_PACKET_STATUS(MyPacket)
  1621. // for this since it might have changed! Use the value
  1622. // saved in the local variable.
  1623. //
  1624. if (Status == NDIS_STATUS_RESOURCES)
  1625. {
  1626. //
  1627. // Our ReturnPackets handler will not be called
  1628. // for this packet. We should reclaim it right here.
  1629. //
  1630. MPReturnPacket((NDIS_HANDLE)pVElan, MyPacket);
  1631. }
  1632. }
  1633. else
  1634. {
  1635. //
  1636. // Failed to allocate a packet.
  1637. //
  1638. MUX_INCR_STATISTICS(&pVElan->RcvResourceErrors);
  1639. MUX_DECR_PENDING_RECEIVES(pVElan);
  1640. }
  1641. } // for (loop thru all VELANs)
  1642. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1643. break;
  1644. }
  1645. while (FALSE);
  1646. //
  1647. // Return the # of receive indications made for this packet.
  1648. // We will call NdisReturnPackets for this packet as many
  1649. // times (see MPReturnPackets).
  1650. //
  1651. return (ReturnCount);
  1652. }
  1653. NDIS_STATUS
  1654. PtPnPNetEventSetPower(
  1655. IN PADAPT pAdapt,
  1656. IN PNET_PNP_EVENT pNetPnPEvent
  1657. )
  1658. /*++
  1659. Routine Description:
  1660. This is a notification to our protocol edge of the power state
  1661. of the lower miniport. If it is going to a low-power state, we must
  1662. wait here for all outstanding sends and requests to complete.
  1663. Arguments:
  1664. pAdapt - Pointer to the adpater structure
  1665. pNetPnPEvent - The Net Pnp Event. this contains the new device state
  1666. Return Value:
  1667. NDIS_STATUS_SUCCESS
  1668. --*/
  1669. {
  1670. PLIST_ENTRY p;
  1671. PVELAN pVElan;
  1672. LOCK_STATE LockState;
  1673. NDIS_STATUS Status;
  1674. //
  1675. // Store the new power state.
  1676. //
  1677. pAdapt->PtDevicePowerState = *(PNDIS_DEVICE_POWER_STATE)pNetPnPEvent->Buffer;
  1678. DBGPRINT(MUX_LOUD, ("PnPNetEventSetPower: Adapt %p, SetPower to %d\n",
  1679. pAdapt, pAdapt->PtDevicePowerState));
  1680. //
  1681. // Check if the miniport below is going to a low power state.
  1682. //
  1683. if (MUX_IS_LOW_POWER_STATE(pAdapt->PtDevicePowerState))
  1684. {
  1685. ULONG i;
  1686. //
  1687. // It is going to a low power state. Wait for outstanding
  1688. // I/O to complete on the adapter.
  1689. //
  1690. for (i = 0; i < 10000; i++)
  1691. {
  1692. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1693. for (p = pAdapt->VElanList.Flink;
  1694. p != &pAdapt->VElanList;
  1695. p = p->Flink)
  1696. {
  1697. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1698. if ((pVElan->OutstandingSends != 0) ||
  1699. (pVElan->OutstandingReceives != 0))
  1700. {
  1701. break;
  1702. }
  1703. }
  1704. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1705. if (p == &pAdapt->VElanList)
  1706. {
  1707. //
  1708. // There are no VELANs with pending I/O.
  1709. //
  1710. break;
  1711. }
  1712. DBGPRINT(MUX_INFO, ("SetPower: Adapt %p, waiting for pending IO to complete\n",
  1713. pAdapt));
  1714. NdisMSleep(1000);
  1715. }
  1716. }
  1717. else
  1718. {
  1719. //
  1720. // The device below is powered on. If we had requests
  1721. // pending on any VELANs, send them down now.
  1722. //
  1723. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1724. for (p = pAdapt->VElanList.Flink;
  1725. p != &pAdapt->VElanList;
  1726. p = p->Flink)
  1727. {
  1728. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  1729. if (pVElan->QueuedRequest)
  1730. {
  1731. pVElan->QueuedRequest = FALSE;
  1732. NdisRequest(&Status,
  1733. pAdapt->BindingHandle,
  1734. &pVElan->Request.Request);
  1735. if (Status != NDIS_STATUS_PENDING)
  1736. {
  1737. PtRequestComplete(pAdapt,
  1738. &pVElan->Request.Request,
  1739. Status);
  1740. }
  1741. }
  1742. }
  1743. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  1744. }
  1745. return (NDIS_STATUS_SUCCESS);
  1746. }
  1747. NDIS_STATUS
  1748. PtPNPHandler(
  1749. IN NDIS_HANDLE ProtocolBindingContext,
  1750. IN PNET_PNP_EVENT pNetPnPEvent
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. This is called by NDIS to notify us of a PNP event related to a lower
  1755. binding. Based on the event, this dispatches to other helper routines.
  1756. Arguments:
  1757. ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
  1758. for "global" notifications
  1759. pNetPnPEvent - Pointer to the PNP event to be processed.
  1760. Return Value:
  1761. NDIS_STATUS code indicating status of event processing.
  1762. --*/
  1763. {
  1764. PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
  1765. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  1766. PNOTIFY_CUSTOM_EVENT event = NULL;
  1767. PVELAN pVElan = NULL;
  1768. NDIS_STRING deviceName;
  1769. PLIST_ENTRY p;
  1770. DBGPRINT(MUX_LOUD, ("PtPnPHandler: Adapt %p, NetPnPEvent %d\n", pAdapt,
  1771. pNetPnPEvent->NetEvent));
  1772. switch (pNetPnPEvent->NetEvent)
  1773. {
  1774. case NetEventSetPower:
  1775. Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
  1776. break;
  1777. case NetEventReconfigure:
  1778. //
  1779. // Rescan configuration and bring up any VELANs that
  1780. // have been newly added. Make sure that the global
  1781. // adapter list is undisturbed while we traverse it.
  1782. //
  1783. MUX_ACQUIRE_MUTEX(&GlobalMutex);
  1784. for (p = AdapterList.Flink;
  1785. p != &AdapterList;
  1786. p = p->Flink)
  1787. {
  1788. pAdapt = CONTAINING_RECORD(p, ADAPT, Link);
  1789. PtBootStrapVElans(pAdapt);
  1790. }
  1791. MUX_RELEASE_MUTEX(&GlobalMutex);
  1792. Status = NDIS_STATUS_SUCCESS;
  1793. break;
  1794. default:
  1795. Status = NDIS_STATUS_SUCCESS;
  1796. break;
  1797. }
  1798. return Status;
  1799. }
  1800. NDIS_STATUS
  1801. PtCreateAndStartVElan(
  1802. IN PADAPT pAdapt,
  1803. IN PNDIS_STRING pVElanKey
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. Create and start a VELAN with the given key name. Check if a VELAN
  1808. with this key name already exists; if so do nothing.
  1809. ASSUMPTION: this is called from either the BindAdapter handler for
  1810. the underlying adapter, or from the PNP reconfig handler. Both these
  1811. routines are protected by NDIS against pre-emption by UnbindAdapter.
  1812. If this routine will be called from any other context, it should
  1813. be protected against a simultaneous call to our UnbindAdapter handler.
  1814. Arguments:
  1815. pAdapt - Pointer to Adapter structure
  1816. pVElanKey - Points to a Unicode string naming the VELAN to create.
  1817. Return Value:
  1818. NDIS_STATUS_SUCCESS if we either found a duplicate VELAN or
  1819. successfully initiated a new ELAN with the given key.
  1820. NDIS_STATUS_XXX error code otherwise (failure initiating a new VELAN).
  1821. --*/
  1822. {
  1823. NDIS_STATUS Status;
  1824. PVELAN pVElan;
  1825. Status = NDIS_STATUS_SUCCESS;
  1826. pVElan = NULL;
  1827. DBGPRINT(MUX_LOUD, ("=> Create VElan: Adapter %p, ElanKey %ws\n",
  1828. pAdapt, pVElanKey->Buffer));
  1829. do
  1830. {
  1831. //
  1832. // Weed out duplicates.
  1833. //
  1834. if (pVElanKey != NULL)
  1835. {
  1836. pVElan = PtFindVElan(pAdapt, pVElanKey);
  1837. if (NULL != pVElan)
  1838. {
  1839. //
  1840. // Duplicate - bail out silently.
  1841. //
  1842. DBGPRINT(MUX_WARN, ("CreateElan: found duplicate pVElan %x\n", pVElan));
  1843. Status = NDIS_STATUS_SUCCESS;
  1844. pVElan = NULL;
  1845. break;
  1846. }
  1847. }
  1848. pVElan = PtAllocateAndInitializeVElan(pAdapt, pVElanKey);
  1849. if (pVElan == NULL)
  1850. {
  1851. Status = NDIS_STATUS_RESOURCES;
  1852. break;
  1853. }
  1854. //
  1855. // Request NDIS to initialize the virtual miniport. Set
  1856. // the flag below just in case an unbind occurs before
  1857. // MiniportInitialize is called.
  1858. //
  1859. pVElan->MiniportInitPending = TRUE;
  1860. NdisInitializeEvent(&pVElan->MiniportInitEvent);
  1861. Status = NdisIMInitializeDeviceInstanceEx(DriverHandle,
  1862. &pVElan->CfgDeviceName,
  1863. pVElan);
  1864. if (Status != NDIS_STATUS_SUCCESS)
  1865. {
  1866. PtUnlinkVElanFromAdapter(pVElan); // IMInit failed
  1867. pVElan = NULL;
  1868. break;
  1869. }
  1870. }
  1871. while (FALSE);
  1872. DBGPRINT(MUX_INFO, ("<= Create VElan: Adapter %p, VELAN %p\n", pAdapt, pVElan));
  1873. return Status;
  1874. }
  1875. PVELAN
  1876. PtAllocateAndInitializeVElan(
  1877. IN PADAPT pAdapt,
  1878. IN PNDIS_STRING pVElanKey
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Allocates and initializes a VELAN structure. Also links it to
  1883. the specified ADAPT.
  1884. Arguments:
  1885. pAdapt - Adapter to link VELAN to
  1886. pVElanKey - Key to the VELAN
  1887. Return Value:
  1888. Pointer to VELAN structure if successful, NULL otherwise.
  1889. --*/
  1890. {
  1891. PVELAN pVElan;
  1892. ULONG Length;
  1893. NDIS_STATUS Status;
  1894. LOCK_STATE LockState;
  1895. pVElan = NULL;
  1896. Status = NDIS_STATUS_SUCCESS;
  1897. do
  1898. {
  1899. Length = sizeof(VELAN) + pVElanKey->Length + sizeof(WCHAR);
  1900. //
  1901. // Allocate a VELAN data structure.
  1902. //
  1903. NdisAllocateMemoryWithTag(&pVElan, Length, TAG);
  1904. if (pVElan == NULL)
  1905. {
  1906. DBGPRINT(MUX_FATAL, ("AllocateVElan: Failed to allocate %d bytes for VELAN\n",
  1907. Length));
  1908. Status = NDIS_STATUS_RESOURCES;
  1909. break;
  1910. }
  1911. //
  1912. // Initialize it.
  1913. //
  1914. NdisZeroMemory(pVElan, Length);
  1915. NdisInitializeListHead(&pVElan->Link);
  1916. //
  1917. // Initialize the built-in request structure to signify
  1918. // that it is used to forward NDIS requests.
  1919. //
  1920. pVElan->Request.pVElan = pVElan;
  1921. NdisInitializeEvent(&pVElan->Request.Event);
  1922. //
  1923. // Store in the key name.
  1924. //
  1925. pVElan->CfgDeviceName.Length = 0;
  1926. pVElan->CfgDeviceName.Buffer = (PWCHAR)((PUCHAR)pVElan +
  1927. sizeof(VELAN));
  1928. pVElan->CfgDeviceName.MaximumLength =
  1929. pVElanKey->MaximumLength + sizeof(WCHAR);
  1930. (VOID)NdisUpcaseUnicodeString(&pVElan->CfgDeviceName, pVElanKey);
  1931. pVElan->CfgDeviceName.Buffer[pVElanKey->Length/sizeof(WCHAR)] =
  1932. ((WCHAR)0);
  1933. //
  1934. // Initialize LastIndicatedStatus to media connect
  1935. //
  1936. pVElan->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
  1937. //
  1938. // Set power state of virtual miniport to D0.
  1939. //
  1940. pVElan->MPDevicePowerState = NdisDeviceStateD0;
  1941. //
  1942. // Cache the binding handle for quick reference.
  1943. //
  1944. pVElan->BindingHandle = pAdapt->BindingHandle;
  1945. pVElan->pAdapt = pAdapt;
  1946. //
  1947. // Copy in some adapter parameters.
  1948. //
  1949. pVElan->LookAhead = pAdapt->MaxLookAhead;
  1950. pVElan->LinkSpeed = pAdapt->LinkSpeed;
  1951. NdisMoveMemory(pVElan->PermanentAddress,
  1952. pAdapt->CurrentAddress,
  1953. sizeof(pVElan->PermanentAddress));
  1954. NdisMoveMemory(pVElan->CurrentAddress,
  1955. pAdapt->CurrentAddress,
  1956. sizeof(pVElan->CurrentAddress));
  1957. DBGPRINT(MUX_LOUD, ("Alloced VELAN %p, MAC addr %s\n",
  1958. pVElan, MacAddrToString(pVElan->CurrentAddress)));
  1959. #if IEEE_VLAN_SUPPORT
  1960. //
  1961. // Allocate lookaside list for tag headers.
  1962. //
  1963. NdisInitializeNPagedLookasideList (
  1964. &pVElan->TagLookaside,
  1965. NULL,
  1966. NULL,
  1967. 0,
  1968. ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE,
  1969. 'TxuM',
  1970. 0);
  1971. #endif
  1972. //
  1973. // Allocate a packet pool for sends.
  1974. //
  1975. NdisAllocatePacketPoolEx(&Status,
  1976. &pVElan->SendPacketPoolHandle,
  1977. MIN_PACKET_POOL_SIZE,
  1978. MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
  1979. sizeof(MUX_SEND_RSVD));
  1980. if (Status != NDIS_STATUS_SUCCESS)
  1981. {
  1982. DBGPRINT(MUX_FATAL, ("PtAllocateVElan: failed to allocate send packet pool\n"));
  1983. break;
  1984. }
  1985. //
  1986. // NOTE: this sample driver does not -originate- packets in the
  1987. // send or receive directions. If the driver must originate packets,
  1988. // here is a good place to allocate NDIS buffer pool(s) for
  1989. // this purpose.
  1990. //
  1991. #if IEEE_VLAN_SUPPORT
  1992. //
  1993. // Allocate a buffer pool for tag headers.
  1994. //
  1995. NdisAllocateBufferPool (&Status,
  1996. &pVElan->BufferPoolHandle,
  1997. MIN_PACKET_POOL_SIZE);
  1998. ASSERT(Status == NDIS_STATUS_SUCCESS);
  1999. #endif
  2000. //
  2001. // Allocate a packet pool for receives.
  2002. //
  2003. NdisAllocatePacketPoolEx(&Status,
  2004. &pVElan->RecvPacketPoolHandle,
  2005. MIN_PACKET_POOL_SIZE,
  2006. MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
  2007. PROTOCOL_RESERVED_SIZE_IN_PACKET);
  2008. if (Status != NDIS_STATUS_SUCCESS)
  2009. {
  2010. DBGPRINT(MUX_FATAL, ("PtAllocateVElan: failed to allocate receive packet pool\n"));
  2011. break;
  2012. }
  2013. //
  2014. // Finally link this VELAN to the Adapter's VELAN list.
  2015. //
  2016. PtReferenceVElan(pVElan, "adapter");
  2017. MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2018. PtReferenceAdapter(pAdapt, "VElan");
  2019. InsertTailList(&pAdapt->VElanList, &pVElan->Link);
  2020. pAdapt->VElanCount++;
  2021. pVElan->VElanNumber = NdisInterlockedIncrement(&NextVElanNumber);
  2022. MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2023. }
  2024. while (FALSE);
  2025. if (Status != NDIS_STATUS_SUCCESS)
  2026. {
  2027. if (pVElan)
  2028. {
  2029. PtDeallocateVElan(pVElan);
  2030. pVElan = NULL;
  2031. }
  2032. }
  2033. return (pVElan);
  2034. }
  2035. VOID
  2036. PtDeallocateVElan(
  2037. IN PVELAN pVElan
  2038. )
  2039. /*++
  2040. Routine Description:
  2041. Free up all resources allocated to a VELAN, and then the VELAN
  2042. structure itself.
  2043. Arguments:
  2044. pVElan - Pointer to VELAN to be deallocated.
  2045. Return Value:
  2046. None
  2047. --*/
  2048. {
  2049. if (pVElan->SendPacketPoolHandle != NULL)
  2050. {
  2051. NdisFreePacketPool(pVElan->SendPacketPoolHandle);
  2052. }
  2053. if (pVElan->RecvPacketPoolHandle != NULL)
  2054. {
  2055. NdisFreePacketPool(pVElan->RecvPacketPoolHandle);
  2056. }
  2057. #if IEEE_VLAN_SUPPORT
  2058. NdisFreeBufferPool(pVElan->BufferPoolHandle);
  2059. NdisDeleteNPagedLookasideList(&pVElan->TagLookaside);
  2060. #endif
  2061. NdisFreeMemory(pVElan, 0, 0);
  2062. }
  2063. VOID
  2064. PtStopVElan(
  2065. IN PVELAN pVElan
  2066. )
  2067. /*++
  2068. Routine Description:
  2069. Stop a VELAN by requesting NDIS to halt the virtual miniport.
  2070. The caller has a reference on the VELAN, so it won't go away
  2071. while we are executing in this routine.
  2072. ASSUMPTION: this is only called in the context of unbinding
  2073. from the underlying miniport. If it may be called from elsewhere,
  2074. this should protect itself from re-entrancy.
  2075. Arguments:
  2076. pVElan - Pointer to VELAN to be stopped.
  2077. Return Value:
  2078. None
  2079. --*/
  2080. {
  2081. NDIS_STATUS Status;
  2082. NDIS_HANDLE MiniportAdapterHandle;
  2083. BOOLEAN bMiniportInitCancelled = FALSE;
  2084. DBGPRINT(MUX_LOUD, ("=> StopVElan: VELAN %p, Adapt %p\n", pVElan, pVElan->pAdapt));
  2085. //
  2086. // We make blocking calls below.
  2087. //
  2088. ASSERT_AT_PASSIVE();
  2089. //
  2090. // If there was a queued request on this VELAN, fail it now.
  2091. //
  2092. if (pVElan->QueuedRequest)
  2093. {
  2094. pVElan->QueuedRequest = FALSE;
  2095. PtRequestComplete(pVElan->pAdapt,
  2096. &pVElan->Request.Request,
  2097. NDIS_STATUS_FAILURE);
  2098. }
  2099. //
  2100. // Check if we had called NdisIMInitializeDeviceInstanceEx and
  2101. // we are awaiting a call to MiniportInitialize.
  2102. //
  2103. if (pVElan->MiniportInitPending)
  2104. {
  2105. //
  2106. // Attempt to cancel miniport init.
  2107. //
  2108. Status = NdisIMCancelInitializeDeviceInstance(
  2109. DriverHandle,
  2110. &pVElan->CfgDeviceName);
  2111. if (Status == NDIS_STATUS_SUCCESS)
  2112. {
  2113. //
  2114. // Successfully cancelled IM initialization; our
  2115. // Miniport Init routine will not be called for this
  2116. // VELAN miniport.
  2117. //
  2118. pVElan->MiniportInitPending = FALSE;
  2119. ASSERT(pVElan->MiniportAdapterHandle == NULL);
  2120. bMiniportInitCancelled = TRUE;
  2121. }
  2122. else
  2123. {
  2124. //
  2125. // Our Miniport Initialize routine will be called
  2126. // (may be running on another thread at this time).
  2127. // Wait for it to finish.
  2128. //
  2129. NdisWaitEvent(&pVElan->MiniportInitEvent, 0);
  2130. ASSERT(pVElan->MiniportInitPending == FALSE);
  2131. }
  2132. }
  2133. //
  2134. // Check if Miniport Init has run. If so, deinitialize the virtual
  2135. // miniport. This will result in a call to our Miniport Halt routine,
  2136. // where the VELAN will be cleaned up.
  2137. //
  2138. MiniportAdapterHandle = pVElan->MiniportAdapterHandle;
  2139. if ((NULL != MiniportAdapterHandle) &&
  2140. (!pVElan->MiniportHalting))
  2141. {
  2142. //
  2143. // The miniport was initialized, and has not yet halted.
  2144. //
  2145. ASSERT(bMiniportInitCancelled == FALSE);
  2146. (VOID)NdisIMDeInitializeDeviceInstance(MiniportAdapterHandle);
  2147. }
  2148. else
  2149. {
  2150. if (bMiniportInitCancelled)
  2151. {
  2152. //
  2153. // No NDIS events can come to this VELAN since it
  2154. // was never initialized as a miniport. We need to unlink
  2155. // it explicitly here.
  2156. //
  2157. PtUnlinkVElanFromAdapter(pVElan);
  2158. }
  2159. }
  2160. }
  2161. VOID
  2162. PtUnlinkVElanFromAdapter(
  2163. IN PVELAN pVElan
  2164. )
  2165. /*++
  2166. Routine Description:
  2167. Utility routine to unlink a VELAN from its parent ADAPT structure.
  2168. Arguments:
  2169. pVElan - Pointer to VELAN to be unlinked.
  2170. Return Value:
  2171. None
  2172. --*/
  2173. {
  2174. PADAPT pAdapt = pVElan->pAdapt;
  2175. LOCK_STATE LockState;
  2176. ASSERT(pAdapt != NULL);
  2177. //
  2178. // Remove this VELAN from the Adapter list
  2179. //
  2180. MUX_ACQUIRE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2181. RemoveEntryList(&pVElan->Link);
  2182. pAdapt->VElanCount--;
  2183. MUX_RELEASE_ADAPT_WRITE_LOCK(pAdapt, &LockState);
  2184. pVElan->pAdapt = NULL;
  2185. PtDereferenceVElan(pVElan, "adapter");
  2186. PtDereferenceAdapter(pAdapt, "VElan");
  2187. }
  2188. PVELAN
  2189. PtFindVElan(
  2190. IN PADAPT pAdapt,
  2191. IN PNDIS_STRING pVElanKey
  2192. )
  2193. /*++
  2194. Routine Description:
  2195. Find an ELAN by bind name/key
  2196. Arguments:
  2197. pAdapt - Pointer to an adapter struct.
  2198. pVElanKey - The VELAN's device name
  2199. Return Value:
  2200. Pointer to matching VELAN or NULL if not found.
  2201. --*/
  2202. {
  2203. PLIST_ENTRY p;
  2204. PVELAN pVElan;
  2205. BOOLEAN Found;
  2206. NDIS_STRING VElanKeyName;
  2207. LOCK_STATE LockState;
  2208. ASSERT_AT_PASSIVE();
  2209. DBGPRINT(MUX_LOUD, ("FindElan: Adapter %p, ElanKey %ws\n", pAdapt,
  2210. pVElanKey->Buffer));
  2211. pVElan = NULL;
  2212. Found = FALSE;
  2213. VElanKeyName.Buffer = NULL;
  2214. do
  2215. {
  2216. //
  2217. // Make an up-cased copy of the given string.
  2218. //
  2219. NdisAllocateMemoryWithTag(&VElanKeyName.Buffer,
  2220. pVElanKey->MaximumLength, TAG);
  2221. if (VElanKeyName.Buffer == NULL)
  2222. {
  2223. break;
  2224. }
  2225. VElanKeyName.Length = pVElanKey->Length;
  2226. VElanKeyName.MaximumLength = pVElanKey->MaximumLength;
  2227. (VOID)NdisUpcaseUnicodeString(&VElanKeyName, pVElanKey);
  2228. //
  2229. // Go through all VELANs on the ADAPT structure, looking
  2230. // for a VELAN that has a matching device name.
  2231. //
  2232. MUX_ACQUIRE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2233. p = pAdapt->VElanList.Flink;
  2234. while (p != &pAdapt->VElanList)
  2235. {
  2236. pVElan = CONTAINING_RECORD(p, VELAN, Link);
  2237. if ((VElanKeyName.Length == pVElan->CfgDeviceName.Length) &&
  2238. (memcmp(VElanKeyName.Buffer, pVElan->CfgDeviceName.Buffer,
  2239. VElanKeyName.Length) == 0))
  2240. {
  2241. Found = TRUE;
  2242. break;
  2243. }
  2244. p = p->Flink;
  2245. }
  2246. MUX_RELEASE_ADAPT_READ_LOCK(pAdapt, &LockState);
  2247. }
  2248. while (FALSE);
  2249. if (!Found)
  2250. {
  2251. DBGPRINT(MUX_INFO, ( "FindElan: No match found!\n"));
  2252. pVElan = NULL;
  2253. }
  2254. if (VElanKeyName.Buffer)
  2255. {
  2256. NdisFreeMemory(VElanKeyName.Buffer, VElanKeyName.Length, 0);
  2257. }
  2258. return pVElan;
  2259. }
  2260. VOID
  2261. PtBootStrapVElans(
  2262. IN PADAPT pAdapt
  2263. )
  2264. /*++
  2265. Routine Description:
  2266. Start up the VELANs configured for an adapter.
  2267. Arguments:
  2268. pAdapt - Pointer to ATMLANE Adapter structure
  2269. Return Value:
  2270. None
  2271. --*/
  2272. {
  2273. NDIS_STATUS Status;
  2274. NDIS_HANDLE AdapterConfigHandle;
  2275. PVELAN pVElan;
  2276. PNDIS_CONFIGURATION_PARAMETER Param;
  2277. NDIS_STRING DeviceStr = NDIS_STRING_CONST("UpperBindings");
  2278. PWSTR buffer;
  2279. //
  2280. // Initialize.
  2281. //
  2282. Status = NDIS_STATUS_SUCCESS;
  2283. AdapterConfigHandle = NULL;
  2284. do
  2285. {
  2286. DBGPRINT(MUX_LOUD, ("BootStrapElans: Starting ELANs on adapter %x\n", pAdapt));
  2287. //
  2288. // Open the protocol configuration section for this adapter.
  2289. //
  2290. NdisOpenProtocolConfiguration(&Status,
  2291. &AdapterConfigHandle,
  2292. &pAdapt->ConfigString);
  2293. if (NDIS_STATUS_SUCCESS != Status)
  2294. {
  2295. AdapterConfigHandle = NULL;
  2296. DBGPRINT(MUX_ERROR, ("BootStrapElans: OpenProtocolConfiguration failed\n"));
  2297. Status = NDIS_STATUS_OPEN_FAILED;
  2298. break;
  2299. }
  2300. //
  2301. // Read the "UpperBindings" reserved key that contains a list
  2302. // of device names representing our miniport instances corresponding
  2303. // to this lower binding. The UpperBindings is a
  2304. // MULTI_SZ containing a list of device names. We will loop through
  2305. // this list and initialize the virtual miniports.
  2306. //
  2307. NdisReadConfiguration(&Status,
  2308. &Param,
  2309. AdapterConfigHandle,
  2310. &DeviceStr,
  2311. NdisParameterMultiString);
  2312. if (NDIS_STATUS_SUCCESS != Status)
  2313. {
  2314. DBGPRINT(MUX_ERROR, ("BootStrapElans: NdisReadConfiguration failed\n"));
  2315. break;
  2316. }
  2317. //
  2318. // Parse the Multi_sz string to extract the device name of each VELAN.
  2319. // This is used as the key name for the VELAN.
  2320. //
  2321. buffer = (PWSTR)Param->ParameterData.StringData.Buffer;
  2322. while(*buffer != L'\0')
  2323. {
  2324. NDIS_STRING DeviceName;
  2325. NdisInitUnicodeString(&DeviceName, buffer);
  2326. Status = PtCreateAndStartVElan(pAdapt, &DeviceName);
  2327. if (NDIS_STATUS_SUCCESS != Status)
  2328. {
  2329. DBGPRINT(MUX_ERROR, ("BootStrapElans: CreateVElan failed\n"));
  2330. break;
  2331. }
  2332. buffer = (PWSTR)((PUCHAR)buffer + DeviceName.Length + sizeof(WCHAR));
  2333. };
  2334. } while (FALSE);
  2335. //
  2336. // Close config handles
  2337. //
  2338. if (NULL != AdapterConfigHandle)
  2339. {
  2340. NdisCloseConfiguration(AdapterConfigHandle);
  2341. }
  2342. return;
  2343. }
  2344. VOID
  2345. PtReferenceVElan(
  2346. IN PVELAN pVElan,
  2347. IN PUCHAR String
  2348. )
  2349. /*++
  2350. Routine Description:
  2351. Add a references to an Elan structure.
  2352. Arguments:
  2353. pElan - Pointer to the Elan structure.
  2354. Return Value:
  2355. None.
  2356. --*/
  2357. {
  2358. NdisInterlockedIncrement(&pVElan->RefCount);
  2359. DBGPRINT(MUX_LOUD, ("ReferenceElan: Elan %p (%s) new count %d\n",
  2360. pVElan, String, pVElan->RefCount));
  2361. return;
  2362. }
  2363. ULONG
  2364. PtDereferenceVElan(
  2365. IN PVELAN pVElan,
  2366. IN PUCHAR String
  2367. )
  2368. /*++
  2369. Routine Description:
  2370. Subtract a reference from an VElan structure.
  2371. If the reference count becomes zero, deallocate it.
  2372. Arguments:
  2373. pElan - Pointer to an VElan structure.
  2374. Return Value:
  2375. None.
  2376. --*/
  2377. {
  2378. ULONG rc;
  2379. ASSERT(pVElan->RefCount > 0);
  2380. rc = NdisInterlockedDecrement(&pVElan->RefCount);
  2381. if (rc == 0)
  2382. {
  2383. //
  2384. // Free memory if there is no outstanding reference.
  2385. // Note: Length field is not required if the memory
  2386. // is allocated with NdisAllocateMemoryWithTag.
  2387. //
  2388. PtDeallocateVElan(pVElan);
  2389. }
  2390. DBGPRINT(MUX_LOUD, ("DereferenceElan: VElan %p (%s) new count %d\n",
  2391. pVElan, String, rc));
  2392. return (rc);
  2393. }
  2394. BOOLEAN
  2395. PtReferenceAdapter(
  2396. IN PADAPT pAdapt,
  2397. IN PUCHAR String
  2398. )
  2399. /*++
  2400. Routine Description:
  2401. Add a references to an Adapter structure.
  2402. Arguments:
  2403. pAdapt - Pointer to the Adapter structure.
  2404. Return Value:
  2405. None.
  2406. --*/
  2407. {
  2408. NdisInterlockedIncrement(&pAdapt->RefCount);
  2409. DBGPRINT(MUX_LOUD, ("ReferenceAdapter: Adapter %x (%s) new count %d\n",
  2410. pAdapt, String, pAdapt->RefCount));
  2411. return TRUE;
  2412. }
  2413. ULONG
  2414. PtDereferenceAdapter(
  2415. IN PADAPT pAdapt,
  2416. IN PUCHAR String
  2417. )
  2418. /*++
  2419. Routine Description:
  2420. Subtract a reference from an Adapter structure.
  2421. If the reference count becomes zero, deallocate it.
  2422. Arguments:
  2423. pAdapt - Pointer to an adapter structure.
  2424. Return Value:
  2425. None.
  2426. --*/
  2427. {
  2428. ULONG rc;
  2429. ASSERT(pAdapt->RefCount > 0);
  2430. rc = NdisInterlockedDecrement (&pAdapt->RefCount);
  2431. if (rc == 0)
  2432. {
  2433. //
  2434. // Free memory if there is no outstanding reference.
  2435. // Note: Length field is not required if the memory
  2436. // is allocated with NdisAllocateMemoryWithTag.
  2437. //
  2438. NdisFreeMemory(pAdapt, 0, 0);
  2439. }
  2440. DBGPRINT(MUX_LOUD, ("DereferenceAdapter: Adapter %x (%s) new count %d\n",
  2441. pAdapt, String, rc));
  2442. return (rc);
  2443. }
  2444. #if IEEE_VLAN_SUPPORT
  2445. NDIS_STATUS
  2446. PtHandleRcvTagging(
  2447. IN PVELAN pVElan,
  2448. IN PNDIS_PACKET Packet,
  2449. IN OUT PNDIS_PACKET MyPacket
  2450. )
  2451. /*++
  2452. Routine Description:
  2453. Parse a received Ethernet frame for 802.1Q tag information.
  2454. If a tag header is present, copy in relevant field values to
  2455. per-packet information to the new packet (MyPacket) used to
  2456. indicate up this frame.
  2457. Arguments:
  2458. pVElan - Pointer to the VELAN structure.
  2459. Packet - Pointer to the indicated packet from the lower miniport
  2460. MyPacket - Pointer to the new allocated packet
  2461. Return Value:
  2462. NDIS_STATUS_SUCCESS if the frame was successfully parsed
  2463. and hence should be indicated up this VELAN. NDIS_STATUS_XXX
  2464. otherwise.
  2465. --*/
  2466. {
  2467. VLAN_TAG_HEADER UNALIGNED * pTagHeader;
  2468. USHORT UNALIGNED * pTpid;
  2469. PVOID pVa;
  2470. ULONG BufferLength;
  2471. PNDIS_BUFFER pNdisBuffer;
  2472. NDIS_PACKET_8021Q_INFO NdisPacket8021qInfo;
  2473. PVOID pDst;
  2474. BOOLEAN OnlyOneBuffer = FALSE;
  2475. NDIS_STATUS Status;
  2476. Status = NDIS_STATUS_SUCCESS;
  2477. do
  2478. {
  2479. pNdisBuffer = Packet->Private.Head;
  2480. #ifdef NDIS51_MINIPORT
  2481. NdisQueryBufferSafe(pNdisBuffer, &pVa, &BufferLength, NormalPagePriority );
  2482. if (pVa == NULL)
  2483. {
  2484. Status = NDIS_STATUS_RESOURCES;
  2485. MUX_INCR_STATISTICS(&pVElan->RcvResourceErrors);
  2486. break;
  2487. }
  2488. #else
  2489. NdisQueryBuffer(pNdisBuffer, &pVa, &BufferLength);
  2490. #endif
  2491. //
  2492. // The first NDIS buffer (lookahead) must be longer than
  2493. // ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE
  2494. //
  2495. ASSERT(BufferLength >= ETH_HEADER_SIZE + VLAN_TAG_HEADER_SIZE);
  2496. //
  2497. // Get at the EtherType field.
  2498. //
  2499. pTpid = (USHORT UNALIGNED *)((PUCHAR)pVa + 2 * ETH_LENGTH_OF_ADDRESS);
  2500. //
  2501. // Check if a tag header is present.
  2502. //
  2503. if (*pTpid != TPID)
  2504. {
  2505. //
  2506. // No tag header exists - nothing more to do here.
  2507. //
  2508. NDIS_PER_PACKET_INFO_FROM_PACKET(MyPacket, Ieee8021QInfo) = 0;
  2509. break;
  2510. }
  2511. //
  2512. // We do have a tag header. Parse it further.
  2513. //
  2514. //
  2515. // If E-RIF is present, discard the packet - we don't
  2516. // support this variation.
  2517. //
  2518. pTagHeader = (VLAN_TAG_HEADER UNALIGNED *)(pTpid + 1);
  2519. if (GET_CANONICAL_FORMAT_ID_FROM_TAG(pTagHeader) != 0)
  2520. {
  2521. //
  2522. // Drop the packet
  2523. //
  2524. Status = NDIS_STATUS_NOT_ACCEPTED;
  2525. MUX_INCR_STATISTICS(&pVElan->RcvFormatErrors);
  2526. break;
  2527. }
  2528. //
  2529. // If there is a VLAN ID in this frame, and we have
  2530. // a configured VLAN ID for this VELAN, check if they
  2531. // are the same - drop if not.
  2532. //
  2533. if ((GET_VLAN_ID_FROM_TAG(pTagHeader) != 0) &&
  2534. (pVElan->VlanId != 0) &&
  2535. (GET_VLAN_ID_FROM_TAG(pTagHeader) != pVElan->VlanId))
  2536. {
  2537. Status = NDIS_STATUS_NOT_ACCEPTED;
  2538. MUX_INCR_STATISTICS(&pVElan->RcvVlanIdErrors);
  2539. break;
  2540. }
  2541. //
  2542. // Parsed this frame successfully. Copy in relevant
  2543. // parts of the tag header to per-packet information.
  2544. //
  2545. NdisPacket8021qInfo.Value = NULL; // initialize
  2546. COPY_TAG_INFO_FROM_HEADER_TO_PACKET_INFO(NdisPacket8021qInfo, pTagHeader);
  2547. NDIS_PER_PACKET_INFO_FROM_PACKET(MyPacket, Ieee8021QInfo) =
  2548. NdisPacket8021qInfo.Value;
  2549. //
  2550. // Strip off the tag header "in place":
  2551. //
  2552. pDst = (PVOID)((PUCHAR)pVa + VLAN_TAG_HEADER_SIZE);
  2553. RtlMoveMemory(pDst, pVa, 2 * ETH_LENGTH_OF_ADDRESS);
  2554. //
  2555. // Allocate a new buffer to describe the new first
  2556. // buffer in the packet. This could very well be the
  2557. // only buffer in the packet.
  2558. //
  2559. NdisAllocateBuffer(&Status,
  2560. &pNdisBuffer,
  2561. pVElan->BufferPoolHandle,
  2562. pDst,
  2563. BufferLength - VLAN_TAG_HEADER_SIZE);
  2564. if (Status != NDIS_STATUS_SUCCESS)
  2565. {
  2566. //
  2567. // Drop the packet
  2568. //
  2569. Status = NDIS_STATUS_RESOURCES;
  2570. MUX_INCR_STATISTICS(&pVElan->RcvResourceErrors);
  2571. break;
  2572. }
  2573. //
  2574. // Prepare the new packet to be indicated up: this consists
  2575. // of the buffer chain starting with the second buffer,
  2576. // appended to the first buffer set up in the previous step.
  2577. //
  2578. MyPacket->Private.Head = NDIS_BUFFER_LINKAGE(Packet->Private.Head);
  2579. //
  2580. // Only one buffer in the packet
  2581. //
  2582. if (MyPacket->Private.Head == NULL)
  2583. {
  2584. OnlyOneBuffer = TRUE;
  2585. }
  2586. NdisChainBufferAtFront(MyPacket, pNdisBuffer);
  2587. if (OnlyOneBuffer)
  2588. {
  2589. MyPacket->Private.Tail = MyPacket->Private.Head;
  2590. }
  2591. else
  2592. {
  2593. MyPacket->Private.Tail = Packet->Private.Tail;
  2594. }
  2595. break;
  2596. }
  2597. while (FALSE);
  2598. return Status;
  2599. }
  2600. #endif // IEEE_VLAN_SUPPORT