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

3366 lines
84 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. atkndis.c
  5. Abstract:
  6. This module contains the support code for the stack dealing with
  7. the NDIS 3.0 interface. The NDIS Init/Deinit and the ndis-protocol
  8. interface code.
  9. Author:
  10. Jameel Hyder (jameelh@microsoft.com)
  11. Nikhil Kamkolkar (nikhilk@microsoft.com)
  12. Revision History:
  13. 19 Jun 1992 Initial Version
  14. Notes: Tab stop: 4
  15. --*/
  16. #include <atalk.h>
  17. #pragma hdrstop
  18. #define FILENUM ATKNDIS
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(INIT, AtalkNdisInitRegisterProtocol)
  21. #pragma alloc_text(INIT, atalkNdisInitInitializeResources)
  22. #pragma alloc_text(PAGEINIT, AtalkNdisInitBind)
  23. #pragma alloc_text(PAGEINIT, AtalkInitNdisQueryAddrInfo)
  24. #pragma alloc_text(PAGEINIT, AtalkInitNdisSetLookaheadSize)
  25. #pragma alloc_text(PAGEINIT, AtalkInitNdisStartPacketReception)
  26. #pragma alloc_text(PAGEINIT, AtalkBindAdapter)
  27. #pragma alloc_text(PAGEINIT, AtalkUnbindAdapter)
  28. #endif
  29. ATALK_ERROR
  30. AtalkNdisInitRegisterProtocol(
  31. VOID
  32. )
  33. /*++
  34. Routine Description:
  35. This routine is called during initialization time to register the protocol
  36. with NDIS.
  37. Arguments:
  38. NameString- The name to be registered for this protocol- human-readable form
  39. Return Value:
  40. Status - TRUE if register went ok, FALSE otherwise.
  41. --*/
  42. {
  43. NDIS_STATUS ndisStatus;
  44. UNICODE_STRING RegName;
  45. NDIS_PROTOCOL_CHARACTERISTICS protocolInfo;
  46. RtlZeroMemory(&protocolInfo, sizeof(protocolInfo));
  47. RtlInitUnicodeString(&RegName, PROTOCOL_REGISTER_NAME);
  48. // Set up the characteristics for the protocol for registering with NDIS
  49. protocolInfo.MajorNdisVersion = PROTOCOL_MAJORNDIS_VERSION;
  50. protocolInfo.MinorNdisVersion = PROTOCOL_MINORNDIS_VERSION;
  51. protocolInfo.Name.Length = RegName.Length;
  52. protocolInfo.Name.Buffer = (PVOID)RegName.Buffer;
  53. protocolInfo.OpenAdapterCompleteHandler = AtalkOpenAdapterComplete;
  54. protocolInfo.CloseAdapterCompleteHandler = AtalkCloseAdapterComplete;
  55. protocolInfo.ResetCompleteHandler = AtalkResetComplete;
  56. protocolInfo.RequestCompleteHandler = AtalkRequestComplete;
  57. protocolInfo.SendCompleteHandler = AtalkSendComplete;
  58. protocolInfo.TransferDataCompleteHandler = AtalkTransferDataComplete;
  59. protocolInfo.ReceiveHandler = AtalkReceiveIndication;
  60. protocolInfo.ReceiveCompleteHandler = AtalkReceiveComplete;
  61. protocolInfo.StatusHandler = AtalkStatusIndication;
  62. protocolInfo.StatusCompleteHandler = AtalkStatusComplete;
  63. protocolInfo.BindAdapterHandler = AtalkBindAdapter;
  64. protocolInfo.UnbindAdapterHandler = AtalkUnbindAdapter;
  65. protocolInfo.PnPEventHandler = AtalkPnPHandler;
  66. ndisStatus = atalkNdisInitInitializeResources();
  67. if (ndisStatus == NDIS_STATUS_SUCCESS)
  68. {
  69. NdisRegisterProtocol(&ndisStatus,
  70. &AtalkNdisProtocolHandle,
  71. &protocolInfo,
  72. (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS)+RegName.Length);
  73. if (ndisStatus != NDIS_STATUS_SUCCESS)
  74. {
  75. LOG_ERROR(EVENT_ATALK_REGISTERPROTOCOL, ndisStatus, NULL, 0);
  76. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  77. ("AtalkNdisRegister: failed %ul\n", ndisStatus));
  78. }
  79. }
  80. return AtalkNdisToAtalkError(ndisStatus);
  81. }
  82. VOID
  83. AtalkNdisDeregisterProtocol(
  84. VOID
  85. )
  86. /*++
  87. Routine Description:
  88. This routine is called to deregister the protocol
  89. Arguments:
  90. NONE
  91. Return Value:
  92. NONE
  93. --*/
  94. {
  95. NDIS_STATUS ndisStatus;
  96. if (AtalkNdisProtocolHandle != (NDIS_HANDLE)NULL)
  97. {
  98. NdisDeregisterProtocol(&ndisStatus, AtalkNdisProtocolHandle);
  99. AtalkNdisProtocolHandle = (NDIS_HANDLE)NULL;
  100. if (ndisStatus != NDIS_STATUS_SUCCESS)
  101. {
  102. LOG_ERROR(EVENT_ATALK_DEREGISTERPROTOCOL, ndisStatus, NULL, 0);
  103. }
  104. }
  105. else
  106. {
  107. ASSERTMSG("AtalkNdisDeregisterProtocol: NULL ProtocolHandle\n", FALSE);
  108. }
  109. }
  110. LOCAL NDIS_STATUS
  111. atalkNdisInitInitializeResources(
  112. VOID
  113. )
  114. /*++
  115. Routine Description:
  116. Arguments:
  117. Return Value:
  118. Status - STATUS_SUCCESS if all resources were allocated
  119. STATUS_INSUFFICIENT_RESOURCES otherwise.
  120. --*/
  121. {
  122. NDIS_STATUS ndisStatus;
  123. LONG numPktDescs, numBufDescs;
  124. numPktDescs = NUM_PACKET_DESCRIPTORS;
  125. if (AtalkRouter)
  126. {
  127. numPktDescs *= ROUTING_FACTOR;
  128. }
  129. numBufDescs = NUM_BUFFER_DESCRIPTORS;
  130. if (AtalkRouter)
  131. {
  132. numBufDescs *= ROUTING_FACTOR;
  133. }
  134. do
  135. {
  136. // Setup the ndis packet descriptor pools in the Port descriptor
  137. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  138. ("atalkNdisInitInitializeResources: Allocating %ld Packets\n",
  139. numPktDescs));
  140. AtalkNdisPacketPoolHandle = (PVOID)NDIS_PACKET_POOL_TAG_FOR_APPLETALK;
  141. NdisAllocatePacketPoolEx(&ndisStatus,
  142. &AtalkNdisPacketPoolHandle,
  143. numPktDescs,
  144. numPktDescs*200, // Overflow descriptors
  145. sizeof(PROTOCOL_RESD));
  146. if ((ndisStatus != NDIS_STATUS_SUCCESS) && (ndisStatus != NDIS_STATUS_PENDING))
  147. {
  148. break;
  149. }
  150. // Setup the ndis buffer descriptor pool
  151. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  152. ("atalkNdisInitInitializeResources: Allocating %ld buffers\n",
  153. numBufDescs));
  154. NdisAllocateBufferPool(&ndisStatus,
  155. &AtalkNdisBufferPoolHandle,
  156. numBufDescs);
  157. if ((ndisStatus != NDIS_STATUS_SUCCESS) && (ndisStatus != NDIS_STATUS_PENDING))
  158. {
  159. NdisFreePacketPool(AtalkNdisPacketPoolHandle);
  160. AtalkNdisPacketPoolHandle = NULL;
  161. }
  162. } while (FALSE);
  163. if (ndisStatus != NDIS_STATUS_SUCCESS)
  164. {
  165. LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
  166. }
  167. return ndisStatus;
  168. }
  169. NDIS_STATUS
  170. AtalkNdisInitBind(
  171. IN OUT PPORT_DESCRIPTOR pPortDesc
  172. )
  173. /*++
  174. Routine Description:
  175. Arguments:
  176. Return Value:
  177. --*/
  178. {
  179. NDIS_STATUS ndisStatus, openStatus, queryStatus;
  180. ATALK_ERROR error;
  181. UINT selectedMediumIndex;
  182. NDIS_STRING FriendlyName;
  183. // reference the port for bind
  184. AtalkPortReferenceByPtr(pPortDesc, &error);
  185. if (error != ATALK_NO_ERROR)
  186. {
  187. return(STATUS_UNSUCCESSFUL);
  188. }
  189. // Reset event before possible wait
  190. KeClearEvent(&pPortDesc->pd_RequestEvent);
  191. NdisOpenAdapter(&ndisStatus, // open status
  192. &openStatus, // more info not used
  193. &pPortDesc->pd_NdisBindingHandle,
  194. &selectedMediumIndex,
  195. AtalkSupportedMedia,
  196. AtalkSupportedMediaSize,
  197. AtalkNdisProtocolHandle,
  198. (NDIS_HANDLE)pPortDesc,
  199. (PNDIS_STRING)&pPortDesc->pd_AdapterName,
  200. 0, // Open options
  201. NULL); // Addressing information
  202. if (ndisStatus == NDIS_STATUS_PENDING)
  203. {
  204. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_WARN,
  205. ("AtalkNdisInitBind: OpenAdapter is pending for %Z\n",
  206. &pPortDesc->pd_AdapterKey));
  207. // Make sure we are not at or above dispatch level
  208. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  209. // Wait on event, completion routine will set NdisRequestEvent
  210. // Use wrappers
  211. KeWaitForSingleObject(&pPortDesc->pd_RequestEvent,
  212. Executive,
  213. KernelMode,
  214. FALSE,
  215. NULL);
  216. ndisStatus = pPortDesc->pd_RequestStatus;
  217. }
  218. if (ndisStatus == NDIS_STATUS_SUCCESS)
  219. {
  220. PPORT_HANDLERS pPortHandler;
  221. pPortDesc->pd_Flags |= PD_BOUND;
  222. pPortDesc->pd_NdisPortType = AtalkSupportedMedia[selectedMediumIndex];
  223. pPortDesc->pd_PortType = GET_PORT_TYPE(pPortDesc->pd_NdisPortType);
  224. if (pPortDesc->pd_PortType != ALAP_PORT)
  225. {
  226. pPortDesc->pd_Flags |= PD_EXT_NET;
  227. }
  228. else if (pPortDesc->pd_Flags & PD_SEED_ROUTER)
  229. {
  230. pPortDesc->pd_InitialNetworkRange.anr_LastNetwork =
  231. pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork;
  232. }
  233. // is this a RAS port?
  234. if (pPortDesc->pd_NdisPortType == NdisMediumWan)
  235. {
  236. pPortDesc->pd_Flags |= PD_RAS_PORT;
  237. RasPortDesc = pPortDesc;
  238. }
  239. // Set stuff from the PortHandler structure to the port descriptor
  240. pPortHandler = &AtalkPortHandlers[pPortDesc->pd_PortType];
  241. pPortDesc->pd_AddMulticastAddr = pPortHandler->ph_AddMulticastAddr;
  242. pPortDesc->pd_RemoveMulticastAddr = pPortHandler->ph_RemoveMulticastAddr;
  243. pPortDesc->pd_AarpProtocolType = pPortHandler->ph_AarpProtocolType;
  244. pPortDesc->pd_AarpHardwareType = pPortHandler->ph_AarpHardwareType;
  245. pPortDesc->pd_BroadcastAddrLen = pPortHandler->ph_BroadcastAddrLen;
  246. RtlCopyMemory(pPortDesc->pd_BroadcastAddr,
  247. pPortHandler->ph_BroadcastAddr,
  248. pPortHandler->ph_BroadcastAddrLen);
  249. FriendlyName.MaximumLength = FriendlyName.Length = 0;
  250. FriendlyName.Buffer = NULL;
  251. queryStatus = NdisQueryAdapterInstanceName(&FriendlyName,
  252. pPortDesc->pd_NdisBindingHandle);
  253. if (queryStatus == NDIS_STATUS_SUCCESS)
  254. {
  255. ASSERT((FriendlyName.Buffer != NULL) && (FriendlyName.Length > 0));
  256. pPortDesc->pd_FriendlyAdapterName.Buffer =
  257. AtalkAllocZeroedMemory(FriendlyName.Length + sizeof(WCHAR));
  258. if (pPortDesc->pd_FriendlyAdapterName.Buffer != NULL)
  259. {
  260. pPortDesc->pd_FriendlyAdapterName.MaximumLength =
  261. FriendlyName.MaximumLength;
  262. pPortDesc->pd_FriendlyAdapterName.Length = FriendlyName.Length;
  263. RtlCopyMemory(pPortDesc->pd_FriendlyAdapterName.Buffer,
  264. FriendlyName.Buffer,
  265. FriendlyName.Length);
  266. }
  267. NdisFreeString(FriendlyName);
  268. }
  269. }
  270. else
  271. {
  272. LOG_ERRORONPORT(pPortDesc,
  273. EVENT_ATALK_OPENADAPTER,
  274. ndisStatus,
  275. NULL,
  276. 0);
  277. AtalkPortDereference(pPortDesc);
  278. }
  279. return ndisStatus;
  280. }
  281. VOID
  282. AtalkNdisUnbind(
  283. IN PPORT_DESCRIPTOR pPortDesc
  284. )
  285. /*++
  286. Routine Description:
  287. Arguments:
  288. Return Value:
  289. --*/
  290. {
  291. NDIS_STATUS ndisStatus;
  292. KIRQL OldIrql;
  293. // Reset event before possible wait
  294. KeClearEvent(&pPortDesc->pd_RequestEvent);
  295. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  296. NdisCloseAdapter(&ndisStatus, pPortDesc->pd_NdisBindingHandle);
  297. if (ndisStatus == NDIS_STATUS_PENDING)
  298. {
  299. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_WARN,
  300. ("AtalkNdisUnbind: pending for close!\n"));
  301. // Make sure we are not at or above dispatch level
  302. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  303. // Wait on event, completion routine will set NdisRequestEvent
  304. KeWaitForSingleObject(&pPortDesc->pd_RequestEvent,
  305. Executive,
  306. KernelMode,
  307. FALSE,
  308. NULL);
  309. ndisStatus = pPortDesc->pd_RequestStatus;
  310. }
  311. if (ndisStatus == NDIS_STATUS_SUCCESS)
  312. {
  313. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  314. ("AtalkNdisUnbind: CloseAdapter on %Z completed successfully\n",
  315. ((pPortDesc->pd_FriendlyAdapterName.Buffer) ?
  316. (&pPortDesc->pd_FriendlyAdapterName) : (&pPortDesc->pd_AdapterName))
  317. ));
  318. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  319. pPortDesc->pd_Flags &= ~PD_BOUND;
  320. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  321. // Remove the reference added at bind time
  322. AtalkPortDereference(pPortDesc);
  323. }
  324. else
  325. {
  326. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  327. ("AtalkNdisUnbind: CloseAdapter on %Z failed %lx\n",
  328. ((pPortDesc->pd_FriendlyAdapterName.Buffer) ?
  329. (&pPortDesc->pd_FriendlyAdapterName) : (&pPortDesc->pd_AdapterName)),
  330. ndisStatus
  331. ));
  332. LOG_ERRORONPORT(pPortDesc,
  333. EVENT_ATALK_CLOSEADAPTER,
  334. ndisStatus,
  335. NULL,
  336. 0);
  337. }
  338. }
  339. VOID
  340. AtalkNdisReleaseResources(
  341. VOID
  342. )
  343. /*++
  344. Routine Description:
  345. Arguments:
  346. Return Value:
  347. None
  348. --*/
  349. {
  350. if (AtalkNdisPacketPoolHandle != NULL)
  351. {
  352. NdisFreePacketPool(AtalkNdisPacketPoolHandle);
  353. AtalkNdisPacketPoolHandle = NULL;
  354. }
  355. if (AtalkNdisBufferPoolHandle)
  356. {
  357. NdisFreeBufferPool(AtalkNdisBufferPoolHandle);
  358. AtalkNdisBufferPoolHandle = NULL;
  359. }
  360. }
  361. ATALK_ERROR
  362. AtalkInitNdisQueryAddrInfo(
  363. IN PPORT_DESCRIPTOR pPortDesc
  364. )
  365. /*++
  366. Routine Description:
  367. Arguments:
  368. Return Value:
  369. --*/
  370. {
  371. NDIS_OID ndisOid;
  372. ULONG macOptions;
  373. PBYTE address;
  374. UINT addressLength;
  375. // We assume a single thread/init time behavior
  376. NDIS_REQUEST request;
  377. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  378. do
  379. {
  380. // Check to see it we bound successfully to this adapter
  381. if (!PORT_BOUND(pPortDesc))
  382. {
  383. LOG_ERRORONPORT(pPortDesc,
  384. EVENT_ATALK_NOTBOUNDTOMAC,
  385. STATUS_INSUFFICIENT_RESOURCES,
  386. NULL,
  387. 0);
  388. ndisStatus = NDIS_STATUS_RESOURCES;
  389. break;
  390. }
  391. switch (pPortDesc->pd_NdisPortType)
  392. {
  393. case NdisMedium802_3 :
  394. ndisOid = OID_802_3_CURRENT_ADDRESS;
  395. address = &pPortDesc->pd_PortAddr[0];
  396. addressLength = MAX_HW_ADDR_LEN;
  397. break;
  398. case NdisMediumFddi :
  399. ndisOid = OID_FDDI_LONG_CURRENT_ADDR;
  400. address = &pPortDesc->pd_PortAddr[0];
  401. addressLength = MAX_HW_ADDR_LEN;
  402. break;
  403. case NdisMedium802_5:
  404. ndisOid = OID_802_5_CURRENT_ADDRESS;
  405. address = &pPortDesc->pd_PortAddr[0];
  406. addressLength = MAX_HW_ADDR_LEN;
  407. break;
  408. case NdisMediumLocalTalk :
  409. ndisOid = OID_LTALK_CURRENT_NODE_ID;
  410. address = (PBYTE)&pPortDesc->pd_AlapNode;
  411. addressLength = sizeof(pPortDesc->pd_AlapNode);
  412. break;
  413. case NdisMediumWan:
  414. ndisOid = OID_WAN_CURRENT_ADDRESS;
  415. // NOTE: the following two fields not relevant for RAS
  416. address = &pPortDesc->pd_PortAddr[0];
  417. addressLength = MAX_HW_ADDR_LEN;
  418. break;
  419. default:
  420. KeBugCheck(0);
  421. break;
  422. }
  423. // Setup request
  424. request.RequestType = NdisRequestQueryInformation;
  425. request.DATA.QUERY_INFORMATION.Oid = ndisOid;
  426. request.DATA.QUERY_INFORMATION.InformationBuffer = address;
  427. request.DATA.QUERY_INFORMATION.InformationBufferLength = addressLength;
  428. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  429. &request,
  430. TRUE,
  431. NULL,
  432. NULL);
  433. if (ndisStatus != NDIS_STATUS_SUCCESS)
  434. {
  435. LOG_ERRORONPORT(pPortDesc,
  436. EVENT_ATALK_STATIONADDRESS,
  437. ndisStatus,
  438. NULL,
  439. 0);
  440. }
  441. // Setup request to get the mac options information
  442. request.RequestType = NdisRequestQueryInformation;
  443. request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
  444. request.DATA.QUERY_INFORMATION.InformationBuffer = &macOptions;
  445. request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG);
  446. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  447. &request,
  448. TRUE,
  449. NULL,
  450. NULL);
  451. if (ndisStatus != NDIS_STATUS_SUCCESS)
  452. {
  453. // No mac options.
  454. ndisStatus = NDIS_STATUS_SUCCESS;
  455. macOptions = 0;
  456. }
  457. pPortDesc->pd_MacOptions = macOptions;
  458. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  459. ("AtalkNdisQueryAddrInfo: MacOptions %lx\n", macOptions));
  460. } while (FALSE);
  461. return AtalkNdisToAtalkError(ndisStatus);
  462. }
  463. ATALK_ERROR
  464. AtalkInitNdisSetLookaheadSize(
  465. IN PPORT_DESCRIPTOR pPortDesc,
  466. IN INT LookaheadSize // Has to be INT
  467. )
  468. /*++
  469. Routine Description:
  470. Arguments:
  471. Return Value:
  472. --*/
  473. {
  474. NDIS_REQUEST request;
  475. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  476. do
  477. {
  478. // Check to see it we bound successfully to this adapter
  479. if (!PORT_BOUND(pPortDesc))
  480. {
  481. LOG_ERRORONPORT(pPortDesc,
  482. EVENT_ATALK_NOTBOUNDTOMAC,
  483. STATUS_INSUFFICIENT_RESOURCES,
  484. NULL,
  485. 0);
  486. ndisStatus = NDIS_STATUS_RESOURCES;
  487. break;
  488. }
  489. // Setup request
  490. request.RequestType = NdisRequestSetInformation;
  491. request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
  492. request.DATA.SET_INFORMATION.InformationBuffer = (PBYTE)&LookaheadSize;
  493. request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(LookaheadSize);
  494. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  495. &request,
  496. TRUE,
  497. NULL,
  498. NULL);
  499. if (ndisStatus != NDIS_STATUS_SUCCESS)
  500. {
  501. LOG_ERRORONPORT(pPortDesc,
  502. EVENT_ATALK_LOOKAHEADSIZE,
  503. STATUS_INSUFFICIENT_RESOURCES,
  504. NULL,
  505. 0);
  506. }
  507. } while (FALSE);
  508. return AtalkNdisToAtalkError(ndisStatus);
  509. }
  510. ATALK_ERROR
  511. AtalkInitNdisStartPacketReception(
  512. IN PPORT_DESCRIPTOR pPortDesc
  513. )
  514. /*++
  515. Routine Description:
  516. Arguments:
  517. Return Value:
  518. --*/
  519. {
  520. NDIS_REQUEST request;
  521. ULONG packetFilter;
  522. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  523. KIRQL OldIrql;
  524. do
  525. {
  526. // Check to see it we bound successfully to this adapter
  527. if (!PORT_BOUND(pPortDesc))
  528. {
  529. LOG_ERRORONPORT(pPortDesc,
  530. EVENT_ATALK_NOTBOUNDTOMAC,
  531. STATUS_INSUFFICIENT_RESOURCES,
  532. NULL,
  533. 0);
  534. ndisStatus = NDIS_STATUS_RESOURCES;
  535. break;
  536. }
  537. switch (pPortDesc->pd_NdisPortType)
  538. {
  539. case NdisMedium802_3 :
  540. case NdisMediumFddi :
  541. packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
  542. break;
  543. case NdisMedium802_5:
  544. packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL;
  545. break;
  546. case NdisMediumLocalTalk :
  547. packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST;
  548. break;
  549. case NdisMediumWan:
  550. packetFilter = NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST;
  551. break;
  552. default:
  553. KeBugCheck(0);
  554. break;
  555. }
  556. // Setup request
  557. request.RequestType = NdisRequestSetInformation;
  558. request.DATA.SET_INFORMATION.Oid =OID_GEN_CURRENT_PACKET_FILTER;
  559. request.DATA.SET_INFORMATION.InformationBuffer = (PBYTE)&packetFilter;
  560. request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(packetFilter);
  561. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  562. &request,
  563. TRUE,
  564. NULL,
  565. NULL);
  566. if (ndisStatus != NDIS_STATUS_SUCCESS)
  567. {
  568. LOG_ERRORONPORT(pPortDesc,
  569. EVENT_ATALK_PACKETFILTER,
  570. STATUS_INSUFFICIENT_RESOURCES,
  571. NULL,
  572. 0);
  573. }
  574. } while (FALSE);
  575. return AtalkNdisToAtalkError(ndisStatus);
  576. }
  577. NDIS_STATUS
  578. AtalkNdisSubmitRequest(
  579. PPORT_DESCRIPTOR pPortDesc,
  580. PNDIS_REQUEST Request,
  581. BOOLEAN ExecuteSync,
  582. REQ_COMPLETION CompletionRoutine,
  583. PVOID Ctx
  584. )
  585. /*++
  586. Routine Description:
  587. Arguments:
  588. Return Value:
  589. None
  590. --*/
  591. {
  592. NDIS_STATUS ndisStatus;
  593. PATALK_NDIS_REQ atalkNdisRequest;
  594. // Allocate an atalk request packet
  595. if ((atalkNdisRequest = AtalkAllocMemory(sizeof(ATALK_NDIS_REQ))) == NULL)
  596. {
  597. return NDIS_STATUS_RESOURCES;
  598. }
  599. atalkNdisRequest->nr_Request = *Request;
  600. atalkNdisRequest->nr_Sync = ExecuteSync;
  601. atalkNdisRequest->nr_RequestCompletion = CompletionRoutine;
  602. atalkNdisRequest->nr_Ctx = Ctx;
  603. if (ExecuteSync)
  604. {
  605. // Make sure we are not at or above dispatch level
  606. // Also assert that the completion routine is NULL
  607. ASSERT(KeGetCurrentIrql() == LOW_LEVEL);
  608. ASSERT(CompletionRoutine == NULL);
  609. // Initialize event to not signalled before possible wait.
  610. KeInitializeEvent(&atalkNdisRequest->nr_Event,
  611. NotificationEvent,
  612. FALSE);
  613. }
  614. NdisRequest(&ndisStatus,
  615. pPortDesc->pd_NdisBindingHandle,
  616. &atalkNdisRequest->nr_Request);
  617. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  618. ("atalkNdisSubmitRequest: status NdisRequest %lx\n", ndisStatus));
  619. if (ndisStatus == NDIS_STATUS_PENDING)
  620. {
  621. if (ExecuteSync)
  622. {
  623. KeWaitForSingleObject(&atalkNdisRequest->nr_Event,
  624. Executive,
  625. KernelMode,
  626. FALSE,
  627. NULL);
  628. ndisStatus = atalkNdisRequest->nr_RequestStatus;
  629. AtalkFreeMemory((PVOID)atalkNdisRequest);
  630. }
  631. }
  632. else if (ndisStatus == NDIS_STATUS_SUCCESS)
  633. {
  634. // Ndis will not call the completion routine.
  635. if (!ExecuteSync)
  636. {
  637. // Call the users completion routine if specified.
  638. if (CompletionRoutine != NULL)
  639. {
  640. (*CompletionRoutine)(NDIS_STATUS_SUCCESS, Ctx);
  641. }
  642. }
  643. AtalkFreeMemory((PVOID)atalkNdisRequest);
  644. }
  645. else
  646. {
  647. // There was an error. Just free up the atalk ndis request.
  648. AtalkFreeMemory((PVOID)atalkNdisRequest);
  649. }
  650. return ndisStatus;
  651. }
  652. // Protocol/NDIS interaction code
  653. VOID
  654. AtalkOpenAdapterComplete(
  655. IN NDIS_HANDLE NdisBindCtx,
  656. IN NDIS_STATUS Status,
  657. IN NDIS_STATUS OpenErrorStatus
  658. )
  659. /*++
  660. Routine Description:
  661. This routine is called during by NDIS to indicate that an open adapter
  662. is complete. This happens only during initialization and single-file. Clear
  663. the event, so the blocked init thread can go on to the next adapter. Set the
  664. status in the ndis port descriptor for this adapter.
  665. Arguments:
  666. NdisBindCtx- Pointer to a port descriptor for this port
  667. Status- completion status of open adapter
  668. OpenErrorStatus- Extra status information
  669. Return Value:
  670. None
  671. --*/
  672. {
  673. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)NdisBindCtx;
  674. pPortDesc->pd_RequestStatus = Status;
  675. KeSetEvent(&pPortDesc->pd_RequestEvent, IO_NETWORK_INCREMENT, FALSE);
  676. }
  677. VOID
  678. AtalkCloseAdapterComplete(
  679. IN NDIS_HANDLE NdisBindCtx,
  680. IN NDIS_STATUS Status
  681. )
  682. /*++
  683. Routine Description:
  684. This routine is called by NDIS to indicate that a close adapter is complete.
  685. Arguments:
  686. NdisBindCtx- Pointer to a port descriptor for this port
  687. Status- completion status of close adapter
  688. Return Value:
  689. None
  690. --*/
  691. {
  692. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)NdisBindCtx;
  693. pPortDesc->pd_RequestStatus = Status;
  694. KeSetEvent(&pPortDesc->pd_RequestEvent, IO_NETWORK_INCREMENT, FALSE);
  695. }
  696. VOID
  697. AtalkResetComplete(
  698. IN NDIS_HANDLE NdisBindCtx,
  699. IN NDIS_STATUS Status
  700. )
  701. /*++
  702. Routine Description:
  703. This routine is called by NDIS to indicate that a reset is complete.
  704. Arguments:
  705. NdisBindCtx- Pointer to a port descriptor for this port
  706. Status- completion status of close adapter
  707. Return Value:
  708. None
  709. --*/
  710. {
  711. UNREFERENCED_PARAMETER(NdisBindCtx);
  712. }
  713. VOID
  714. AtalkRequestComplete(
  715. IN NDIS_HANDLE NdisBindCtx,
  716. IN PNDIS_REQUEST NdisRequest,
  717. IN NDIS_STATUS Status
  718. )
  719. /*++
  720. Routine Description:
  721. This routine is called by NDIS to indicate that a NdisRequest is complete.
  722. Arguments:
  723. NdisBindCtx- Pointer to a port descriptor for this port
  724. NdisRequest- Block identifying the request
  725. Status- completion status of close adapter
  726. Return Value:
  727. None
  728. --*/
  729. {
  730. PATALK_NDIS_REQ atalkRequest;
  731. // Get the AtalkRequest block
  732. atalkRequest = CONTAINING_RECORD(NdisRequest, ATALK_NDIS_REQ, nr_Request);
  733. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  734. ("AtalkRequestComplete: %lx status %lx\n", atalkRequest, Status));
  735. if (atalkRequest->nr_Sync)
  736. {
  737. // This was a sync request
  738. // Set status and clear event
  739. ASSERT(atalkRequest->nr_RequestCompletion == NULL);
  740. atalkRequest->nr_RequestStatus = Status;
  741. KeSetEvent(&atalkRequest->nr_Event, IO_NETWORK_INCREMENT, FALSE);
  742. }
  743. // Call the completion routine if specified
  744. if (atalkRequest->nr_RequestCompletion != NULL)
  745. {
  746. (*atalkRequest->nr_RequestCompletion)(Status, atalkRequest->nr_Ctx);
  747. }
  748. if (!atalkRequest->nr_Sync)
  749. AtalkFreeMemory(atalkRequest);
  750. }
  751. VOID
  752. AtalkStatusIndication(
  753. IN NDIS_HANDLE NdisBindCtx,
  754. IN NDIS_STATUS GeneralStatus,
  755. IN PVOID StatusBuf,
  756. IN UINT StatusBufLen
  757. )
  758. /*++
  759. Routine Description:
  760. This routine is called by NDIS to indicate a status change.
  761. Arguments:
  762. NdisBindCtx- Pointer to a port descriptor for this port
  763. GeneralStatus- A general status value
  764. StatusBuffer - A more specific status value
  765. Return Value:
  766. None
  767. --*/
  768. {
  769. PPORT_DESCRIPTOR pPortDesc;
  770. pPortDesc = (PPORT_DESCRIPTOR)NdisBindCtx;
  771. // line-up, line-down or stat request from ndiswan? deal with it!
  772. if (pPortDesc == RasPortDesc)
  773. {
  774. RasStatusIndication(GeneralStatus, StatusBuf, StatusBufLen);
  775. }
  776. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_ERR,
  777. ("AtalkStatusIndication: Status indication called %lx\n", GeneralStatus));
  778. }
  779. VOID
  780. AtalkStatusComplete (
  781. IN NDIS_HANDLE ProtoBindCtx
  782. )
  783. /*++
  784. Routine Description:
  785. This routine is called by NDIS to allow postprocessing after a status event.
  786. Arguments:
  787. ProtoBindCtx- Value associated with the binding with the adapter
  788. Return Value:
  789. None
  790. --*/
  791. {
  792. UNREFERENCED_PARAMETER(ProtoBindCtx);
  793. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_WARN,
  794. ("AtalkStatusComplete: Status complete called\n"));
  795. }
  796. typedef struct
  797. {
  798. REQ_COMPLETION AddCompletion;
  799. PVOID AddContext;
  800. PBYTE Buffer;
  801. } ADDMC, *PADDMC;
  802. LOCAL VOID
  803. atalkNdisAddMulticastCompletion(
  804. IN NDIS_STATUS Status,
  805. IN PADDMC pAmc
  806. )
  807. {
  808. if (pAmc->Buffer != NULL)
  809. AtalkFreeMemory(pAmc->Buffer);
  810. if (pAmc->AddCompletion != NULL)
  811. (*pAmc->AddCompletion)(Status, pAmc->AddContext);
  812. AtalkFreeMemory(pAmc);
  813. }
  814. ATALK_ERROR
  815. AtalkNdisReplaceMulticast(
  816. IN PPORT_DESCRIPTOR pPortDesc,
  817. IN PBYTE OldAddress,
  818. IN PBYTE NewAddress
  819. )
  820. {
  821. INT sizeOfList, i, numberInList;
  822. PBYTE addressData, currentList, tempList;
  823. KIRQL OldIrql;
  824. NDIS_REQUEST request;
  825. NDIS_OID ndisOid;
  826. NDIS_STATUS ndisStatus;
  827. PADDMC pAmc;
  828. // Check to see it we bound successfully to this adapter
  829. if (!PORT_BOUND(pPortDesc))
  830. {
  831. LOG_ERRORONPORT(pPortDesc,
  832. EVENT_ATALK_NOTBOUNDTOMAC,
  833. STATUS_INSUFFICIENT_RESOURCES,
  834. NULL,
  835. 0);
  836. ndisStatus = NDIS_STATUS_RESOURCES;
  837. goto errorExit;
  838. }
  839. // Grab the perport spinlock. Again, a very infrequent operation.
  840. // Probably just twice in the lifetime of the stack.
  841. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  842. if (pPortDesc->pd_MulticastList != NULL)
  843. {
  844. numberInList = pPortDesc->pd_MulticastListSize/ELAP_ADDR_LEN;
  845. currentList = pPortDesc->pd_MulticastList;
  846. for (i = 0; i < numberInList; i++, currentList += ELAP_ADDR_LEN)
  847. {
  848. // Search for the address and remember the index if found
  849. if (RtlCompareMemory(currentList,
  850. OldAddress,
  851. ELAP_ADDR_LEN) == ELAP_ADDR_LEN)
  852. {
  853. // Move all address following this overwriting this address
  854. // we ignore wasted space that will never be touched anymore.
  855. // This could turn out to be a NOP if we are removing the last
  856. // address in the list.
  857. RtlMoveMemory(currentList,
  858. currentList + ELAP_ADDR_LEN,
  859. pPortDesc->pd_MulticastListSize-((i+1)*ELAP_ADDR_LEN));
  860. pPortDesc->pd_MulticastListSize -= ELAP_ADDR_LEN;
  861. // Have we removed the last address. If so, reset values.
  862. if (pPortDesc->pd_MulticastListSize == 0)
  863. {
  864. AtalkFreeMemory(pPortDesc->pd_MulticastList);
  865. pPortDesc->pd_MulticastList = NULL;
  866. }
  867. break;
  868. }
  869. }
  870. }
  871. else
  872. {
  873. // Nothing to remove
  874. pPortDesc->pd_MulticastListSize = 0;
  875. }
  876. sizeOfList = pPortDesc->pd_MulticastListSize + ELAP_ADDR_LEN;
  877. ASSERTMSG("AtalkNdisAddMulticast: Size is not > 0\n", (sizeOfList > 0));
  878. // Allocate/reallocate the list for the port descriptor, and also
  879. // for a copy to be used in the NDIS request function.
  880. tempList = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
  881. addressData = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
  882. pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
  883. if ((tempList == NULL) || (addressData == NULL) || (pAmc == NULL))
  884. {
  885. // Release the spinlock
  886. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  887. if (pAmc != NULL)
  888. AtalkFreeMemory(pAmc);
  889. if (tempList != NULL)
  890. AtalkFreeMemory(tempList);
  891. if (addressData != NULL)
  892. AtalkFreeMemory(addressData);
  893. return ATALK_RESR_MEM;
  894. }
  895. if (pPortDesc->pd_MulticastList != NULL)
  896. {
  897. // Copy the old list over to the new space
  898. RtlCopyMemory(tempList,
  899. pPortDesc->pd_MulticastList,
  900. pPortDesc->pd_MulticastListSize);
  901. // Set the proper values back into PortDesc after freeing the old list
  902. AtalkFreeMemory(pPortDesc->pd_MulticastList);
  903. }
  904. // Guaranteed space is available to copy the new address
  905. // Ready to copy our new address here and then do the set!
  906. RtlCopyMemory(tempList + pPortDesc->pd_MulticastListSize,
  907. NewAddress,
  908. ELAP_ADDR_LEN);
  909. pPortDesc->pd_MulticastList = tempList;
  910. pPortDesc->pd_MulticastListSize = sizeOfList;
  911. switch (pPortDesc->pd_NdisPortType)
  912. {
  913. case NdisMedium802_3 :
  914. ndisOid = OID_802_3_MULTICAST_LIST;
  915. break;
  916. case NdisMediumFddi:
  917. // FDDI supports 2byte and 6byte multicast addresses. We use the
  918. // 6byte multicast addresses for appletalk.
  919. ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
  920. break;
  921. default:
  922. KeBugCheck(0);
  923. break;
  924. }
  925. // Setup request
  926. // Move the list to our buffer
  927. ASSERTMSG("AtalkNdisAddMulticast: Size incorrect!\n",
  928. ((ULONG)sizeOfList == pPortDesc->pd_MulticastListSize));
  929. RtlCopyMemory(addressData,
  930. pPortDesc->pd_MulticastList,
  931. pPortDesc->pd_MulticastListSize);
  932. // Release the spinlock
  933. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  934. request.RequestType = NdisRequestSetInformation;
  935. request.DATA.SET_INFORMATION.Oid = ndisOid;
  936. request.DATA.SET_INFORMATION.InformationBuffer = addressData;
  937. request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
  938. pAmc->AddCompletion = NULL;
  939. pAmc->AddContext = NULL;
  940. pAmc->Buffer = addressData;
  941. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  942. &request,
  943. FALSE,
  944. atalkNdisAddMulticastCompletion,
  945. pAmc);
  946. // NOTE: Sumbit calls completion if success is being returned.
  947. if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
  948. (ndisStatus != NDIS_STATUS_PENDING))
  949. {
  950. LOG_ERRORONPORT(pPortDesc,
  951. EVENT_ATALK_NDISREQUEST,
  952. ndisStatus,
  953. NULL,
  954. 0);
  955. }
  956. errorExit:
  957. return AtalkNdisToAtalkError(ndisStatus);
  958. }
  959. ATALK_ERROR
  960. AtalkNdisAddMulticast(
  961. IN PPORT_DESCRIPTOR pPortDesc,
  962. IN PBYTE Address,
  963. IN BOOLEAN ExecuteSynchronously,
  964. IN REQ_COMPLETION AddCompletion,
  965. IN PVOID AddContext
  966. )
  967. /*++
  968. Routine Description:
  969. Arguments:
  970. Return Value:
  971. --*/
  972. {
  973. INT sizeOfList;
  974. PBYTE addressData, tempList;
  975. KIRQL OldIrql;
  976. NDIS_OID ndisOid;
  977. NDIS_REQUEST request;
  978. NDIS_STATUS ndisStatus;
  979. PADDMC pAmc;
  980. // Check to see it we bound successfully to this adapter
  981. if (!PORT_BOUND(pPortDesc))
  982. {
  983. LOG_ERRORONPORT(pPortDesc,
  984. EVENT_ATALK_NOTBOUNDTOMAC,
  985. STATUS_INSUFFICIENT_RESOURCES,
  986. NULL,
  987. 0);
  988. return ATALK_FAILURE;
  989. }
  990. // Grab the perport spinlock. We need to allocate within a
  991. // critical section as the size might change. This routine
  992. // is called very infrequently, during init and when we
  993. // receive our default zone from zip.
  994. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  995. sizeOfList = pPortDesc->pd_MulticastListSize + ELAP_ADDR_LEN;
  996. ASSERTMSG("AtalkNdisAddMulticast: Size is not > 0\n", (sizeOfList > 0));
  997. // Allocate/reallocate the list for the port descriptor, and also
  998. // for a copy to be used in the NDIS request function.
  999. tempList = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
  1000. addressData = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
  1001. pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
  1002. if ((tempList == NULL) || (addressData == NULL) || (pAmc == NULL))
  1003. {
  1004. // Release the spinlock
  1005. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1006. if (pAmc != NULL)
  1007. AtalkFreeMemory(pAmc);
  1008. if (tempList != NULL)
  1009. AtalkFreeMemory(tempList);
  1010. if (addressData != NULL)
  1011. AtalkFreeMemory(addressData);
  1012. return ATALK_RESR_MEM;
  1013. }
  1014. if (pPortDesc->pd_MulticastList == NULL)
  1015. {
  1016. // No old addresses to work with.
  1017. pPortDesc->pd_MulticastListSize = 0;
  1018. }
  1019. else
  1020. {
  1021. // Copy the old list over to the new space
  1022. RtlCopyMemory(tempList,
  1023. pPortDesc->pd_MulticastList,
  1024. pPortDesc->pd_MulticastListSize);
  1025. // Set the proper values back into PortDesc after freeing the old list
  1026. AtalkFreeMemory(pPortDesc->pd_MulticastList);
  1027. }
  1028. // Guaranteed space is available to copy the new address
  1029. // Ready to copy our new address here and then do the set!
  1030. RtlCopyMemory(tempList + pPortDesc->pd_MulticastListSize,
  1031. Address,
  1032. ELAP_ADDR_LEN);
  1033. pPortDesc->pd_MulticastList = tempList;
  1034. pPortDesc->pd_MulticastListSize = sizeOfList;
  1035. switch (pPortDesc->pd_NdisPortType)
  1036. {
  1037. case NdisMedium802_3 :
  1038. ndisOid = OID_802_3_MULTICAST_LIST;
  1039. break;
  1040. case NdisMediumFddi:
  1041. // FDDI supports 2byte and 6byte multicast addresses. We use the
  1042. // 6byte multicast addresses for appletalk.
  1043. ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
  1044. break;
  1045. default:
  1046. KeBugCheck(0);
  1047. break;
  1048. }
  1049. // Setup request
  1050. // Move the list to our buffer
  1051. ASSERTMSG("AtalkNdisAddMulticast: Size incorrect!\n",
  1052. ((ULONG)sizeOfList == pPortDesc->pd_MulticastListSize));
  1053. RtlCopyMemory(addressData,
  1054. pPortDesc->pd_MulticastList,
  1055. pPortDesc->pd_MulticastListSize);
  1056. // Release the spinlock
  1057. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1058. request.RequestType = NdisRequestSetInformation;
  1059. request.DATA.SET_INFORMATION.Oid = ndisOid;
  1060. request.DATA.SET_INFORMATION.InformationBuffer = addressData;
  1061. request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
  1062. pAmc->AddCompletion = AddCompletion;
  1063. pAmc->AddContext = AddContext;
  1064. pAmc->Buffer = addressData;
  1065. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1066. &request,
  1067. FALSE,
  1068. atalkNdisAddMulticastCompletion,
  1069. pAmc);
  1070. // NOTE: Sumbit calls completion if success is being returned.
  1071. if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
  1072. (ndisStatus != NDIS_STATUS_PENDING))
  1073. {
  1074. LOG_ERRORONPORT(pPortDesc,
  1075. EVENT_ATALK_NDISREQUEST,
  1076. ndisStatus,
  1077. NULL,
  1078. 0);
  1079. }
  1080. return AtalkNdisToAtalkError(ndisStatus);
  1081. }
  1082. ATALK_ERROR
  1083. AtalkNdisRemoveMulticast(
  1084. IN PPORT_DESCRIPTOR pPortDesc,
  1085. IN PBYTE Address,
  1086. IN BOOLEAN ExecuteSynchronously,
  1087. IN REQ_COMPLETION RemoveCompletion,
  1088. IN PVOID RemoveContext
  1089. )
  1090. {
  1091. INT sizeOfList, i, numberInList;
  1092. PBYTE addressData, currentList;
  1093. KIRQL OldIrql;
  1094. NDIS_REQUEST request;
  1095. NDIS_OID ndisOid;
  1096. NDIS_STATUS ndisStatus;
  1097. PADDMC pAmc;
  1098. do
  1099. {
  1100. // Check to see it we bound successfully to this adapter
  1101. if (!PORT_BOUND(pPortDesc))
  1102. {
  1103. LOG_ERRORONPORT(pPortDesc,
  1104. EVENT_ATALK_NOTBOUNDTOMAC,
  1105. STATUS_INSUFFICIENT_RESOURCES,
  1106. NULL,
  1107. 0);
  1108. ndisStatus = NDIS_STATUS_RESOURCES;
  1109. break;
  1110. }
  1111. // Grab the perport spinlock. Again, a very infrequent operation.
  1112. // Probably just twice in the lifetime of the stack.
  1113. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  1114. ASSERT(pPortDesc->pd_MulticastList != NULL);
  1115. if (pPortDesc->pd_MulticastList == NULL)
  1116. {
  1117. // Nothing to remove!
  1118. ndisStatus = NDIS_STATUS_SUCCESS;
  1119. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1120. break;
  1121. }
  1122. numberInList = pPortDesc->pd_MulticastListSize/ELAP_ADDR_LEN;
  1123. currentList = pPortDesc->pd_MulticastList;
  1124. for (i = 0; i < numberInList; i++, currentList += ELAP_ADDR_LEN)
  1125. {
  1126. // Search for the address and remember the index if found
  1127. if (RtlCompareMemory(currentList,
  1128. Address,
  1129. ELAP_ADDR_LEN) == ELAP_ADDR_LEN)
  1130. {
  1131. // Move all address following this overwriting this address
  1132. // we ignore wasted space that will never be touched anymore.
  1133. // This could turn out to be a NOP if we are removing the last
  1134. // address in the list.
  1135. RtlMoveMemory(currentList,
  1136. currentList + ELAP_ADDR_LEN,
  1137. pPortDesc->pd_MulticastListSize-((i+1)*ELAP_ADDR_LEN));
  1138. pPortDesc->pd_MulticastListSize -= ELAP_ADDR_LEN;
  1139. // Have we removed the last address. If so, reset values.
  1140. if (pPortDesc->pd_MulticastListSize == 0)
  1141. {
  1142. AtalkFreeMemory(pPortDesc->pd_MulticastList);
  1143. pPortDesc->pd_MulticastList = NULL;
  1144. }
  1145. break;
  1146. }
  1147. }
  1148. // We assume address was found and the list is changed as expected
  1149. // Set this new list
  1150. switch (pPortDesc->pd_NdisPortType)
  1151. {
  1152. case NdisMedium802_3 :
  1153. ndisOid = OID_802_3_MULTICAST_LIST;
  1154. break;
  1155. case NdisMediumFddi:
  1156. // FDDI supports 2byte and 6byte multicast addresses. We use the
  1157. // 6byte multicast addresses for appletalk.
  1158. ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
  1159. break;
  1160. default:
  1161. KeBugCheck(0);
  1162. break;
  1163. }
  1164. addressData = NULL;
  1165. sizeOfList = pPortDesc->pd_MulticastListSize;
  1166. pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
  1167. if (pAmc == NULL)
  1168. {
  1169. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1170. ndisStatus = NDIS_STATUS_RESOURCES;
  1171. break;
  1172. }
  1173. if (sizeOfList > 0)
  1174. {
  1175. // Allocate addressData and copy list to it
  1176. addressData = (PBYTE)AtalkAllocMemory(sizeOfList);
  1177. if (addressData == NULL)
  1178. {
  1179. // Release the spinlock
  1180. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1181. AtalkFreeMemory(pAmc);
  1182. ndisStatus = NDIS_STATUS_RESOURCES;
  1183. break;
  1184. }
  1185. // Move the list to our buffer
  1186. RtlCopyMemory(addressData,
  1187. pPortDesc->pd_MulticastList,
  1188. pPortDesc->pd_MulticastListSize);
  1189. }
  1190. // Release the spinlock
  1191. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1192. request.RequestType = NdisRequestSetInformation;
  1193. request.DATA.SET_INFORMATION.Oid = ndisOid;
  1194. request.DATA.SET_INFORMATION.InformationBuffer = addressData;
  1195. request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
  1196. pAmc->AddCompletion = RemoveCompletion;
  1197. pAmc->AddContext = RemoveContext;
  1198. pAmc->Buffer = addressData;
  1199. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1200. &request,
  1201. FALSE,
  1202. atalkNdisAddMulticastCompletion,
  1203. pAmc);
  1204. if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
  1205. (ndisStatus != NDIS_STATUS_PENDING))
  1206. {
  1207. LOG_ERRORONPORT(pPortDesc,
  1208. EVENT_ATALK_NDISREQUEST,
  1209. ndisStatus,
  1210. NULL,
  1211. 0);
  1212. }
  1213. } while (FALSE);
  1214. return AtalkNdisToAtalkError(ndisStatus);
  1215. }
  1216. ATALK_ERROR
  1217. AtalkNdisSendPacket(
  1218. IN PPORT_DESCRIPTOR pPortDesc,
  1219. IN PBUFFER_DESC BufferChain,
  1220. IN SEND_COMPLETION SendCompletion OPTIONAL,
  1221. IN PSEND_COMPL_INFO pSendInfo OPTIONAL
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. This routine is called by the portable code to send a packet out on
  1226. ethernet. It will build the NDIS packet descriptor for the passed in
  1227. chain and then send the packet on the specified port.
  1228. Arguments:
  1229. Return Value:
  1230. TRUE- If sent/pending, FALSE otherwise
  1231. TransmitComplete is called if this call pended by completion code
  1232. --*/
  1233. {
  1234. PNDIS_PACKET ndisPacket;
  1235. PNDIS_BUFFER ndisBuffer;
  1236. PPROTOCOL_RESD protocolResd;
  1237. ATALK_ERROR error;
  1238. PSENDBUF pSendBuf;
  1239. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  1240. PMDL pMdl;
  1241. PMDL pFirstMdl=NULL;
  1242. if (PORT_CLOSING(pPortDesc))
  1243. {
  1244. // If we are not active, return!
  1245. return ATALK_PORT_CLOSING;
  1246. }
  1247. do
  1248. {
  1249. pSendBuf = (PSENDBUF)((PBYTE)BufferChain - sizeof(BUFFER_HDR));
  1250. ndisPacket = pSendBuf->sb_BuffHdr.bh_NdisPkt;
  1251. // Store the information needed in the packet descriptor
  1252. protocolResd = (PPROTOCOL_RESD)&ndisPacket->ProtocolReserved;
  1253. protocolResd->Send.pr_Port = pPortDesc;
  1254. protocolResd->Send.pr_BufferDesc = BufferChain;
  1255. protocolResd->Send.pr_SendCompletion = SendCompletion;
  1256. if (pSendInfo != NULL)
  1257. protocolResd->Send.pr_SendInfo = *pSendInfo;
  1258. else RtlZeroMemory(&protocolResd->Send.pr_SendInfo, sizeof(SEND_COMPL_INFO));
  1259. // For the first buffer, set up the length of the NDIS buffer to be
  1260. // the same as in indicated in the descriptor.
  1261. NdisAdjustBufferLength(pSendBuf->sb_BuffHdr.bh_NdisBuffer,
  1262. BufferChain->bd_Length);
  1263. // NOTE: There is either a PBYTE being pointed to, or a PAMDL
  1264. // being pointed to by the buffer descriptor. Also, the
  1265. // size of the data will be the size that is to be
  1266. // used. At the end, just assert that the total length
  1267. // equals length passed in.
  1268. if (BufferChain->bd_Next != NULL)
  1269. {
  1270. if (BufferChain->bd_Next->bd_Flags & BD_CHAR_BUFFER)
  1271. {
  1272. NdisAllocateBuffer(&ndisStatus,
  1273. &ndisBuffer,
  1274. AtalkNdisBufferPoolHandle,
  1275. (PVOID)BufferChain->bd_Next->bd_CharBuffer,
  1276. (UINT)BufferChain->bd_Next->bd_Length);
  1277. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1278. {
  1279. DBGPRINT(DBG_COMP_NDISSEND, DBG_LEVEL_ERR,
  1280. ("AtalkNdisSendPacket: NdisAllocateBuffer %lx\n", ndisStatus));
  1281. // LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
  1282. break;
  1283. }
  1284. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  1285. NdisChainBufferAtBack(ndisPacket, ndisBuffer);
  1286. }
  1287. else
  1288. {
  1289. // It is an MDL
  1290. pMdl = (PMDL)BufferChain->bd_Next->bd_OpaqueBuffer;
  1291. ASSERT(AtalkSizeMdlChain(pMdl) == BufferChain->bd_Next->bd_Length);
  1292. while (pMdl)
  1293. {
  1294. NdisCopyBuffer(&ndisStatus,
  1295. &ndisBuffer,
  1296. AtalkNdisBufferPoolHandle,
  1297. (PVOID)pMdl,
  1298. 0, //Offset
  1299. (UINT)MmGetMdlByteCount(pMdl));
  1300. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1301. {
  1302. if (pFirstMdl)
  1303. {
  1304. AtalkNdisFreeBuffer(pFirstMdl);
  1305. }
  1306. break;
  1307. }
  1308. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  1309. if (!pFirstMdl)
  1310. {
  1311. pFirstMdl = pMdl;
  1312. }
  1313. NdisChainBufferAtBack(ndisPacket, ndisBuffer);
  1314. pMdl = pMdl->Next;
  1315. }
  1316. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1317. {
  1318. DBGPRINT(DBG_COMP_NDISSEND, DBG_LEVEL_ERR,
  1319. ("AtalkNdisSendPacket: NdisCopyBuffer %lx\n", ndisStatus));
  1320. break;
  1321. }
  1322. }
  1323. }
  1324. #ifdef PROFILING
  1325. INTERLOCKED_INCREMENT_LONG_DPC(
  1326. &pPortDesc->pd_PortStats.prtst_CurSendsOutstanding,
  1327. &AtalkStatsLock.SpinLock);
  1328. #endif
  1329. INTERLOCKED_INCREMENT_LONG_DPC(
  1330. &pPortDesc->pd_PortStats.prtst_NumPacketsOut,
  1331. &AtalkStatsLock.SpinLock);
  1332. // Now send the built packet descriptor
  1333. NdisSend(&ndisStatus,
  1334. pPortDesc->pd_NdisBindingHandle,
  1335. ndisPacket);
  1336. // Completion will dereference the port!
  1337. if (ndisStatus != NDIS_STATUS_PENDING)
  1338. {
  1339. // Call the completion handler
  1340. AtalkSendComplete(pPortDesc->pd_NdisBindingHandle,
  1341. ndisPacket,
  1342. ndisStatus);
  1343. ndisStatus = NDIS_STATUS_PENDING;
  1344. }
  1345. } while (FALSE);
  1346. return AtalkNdisToAtalkError(ndisStatus);
  1347. }
  1348. ATALK_ERROR
  1349. AtalkNdisAddFunctional(
  1350. IN PPORT_DESCRIPTOR pPortDesc,
  1351. IN PBYTE Address,
  1352. IN BOOLEAN ExecuteSynchronously,
  1353. IN REQ_COMPLETION AddCompletion,
  1354. IN PVOID AddContext
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. Arguments:
  1359. Return Value:
  1360. --*/
  1361. {
  1362. ULONG i;
  1363. NDIS_REQUEST request;
  1364. NDIS_STATUS ndisStatus;
  1365. KIRQL OldIrql;
  1366. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1367. ("Current %02x%02x%02x%02x, Adding %02x%02x%02x%02x\n",
  1368. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1369. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3],
  1370. Address[2], Address[3], Address[4], Address[5]));
  1371. // Grab the perport spinlock
  1372. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  1373. // We only need the last four bytes of the address assuming that the
  1374. // first two bytes always remain the same (C000) and that the MAC assumes
  1375. // the same- NDIS 3.0 OID length = 4
  1376. for (i = 0;
  1377. i < sizeof(ULONG);
  1378. i++)
  1379. pPortDesc->pd_FunctionalAddr[i] |= Address[2+i];
  1380. // Release the spinlock
  1381. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1382. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1383. ("After Add %02x%02x%02x%02x\n",
  1384. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1385. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3]));
  1386. request.RequestType = NdisRequestSetInformation;
  1387. request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
  1388. request.DATA.SET_INFORMATION.InformationBuffer = pPortDesc->pd_FunctionalAddr;
  1389. request.DATA.SET_INFORMATION.InformationBufferLength = TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN;
  1390. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1391. &request,
  1392. ExecuteSynchronously,
  1393. AddCompletion,
  1394. AddContext);
  1395. if (ndisStatus == NDIS_STATUS_PENDING)
  1396. {
  1397. ASSERT(ExecuteSynchronously != TRUE);
  1398. }
  1399. else if (ndisStatus != NDIS_STATUS_SUCCESS)
  1400. {
  1401. LOG_ERRORONPORT(pPortDesc,
  1402. EVENT_ATALK_NDISREQUEST,
  1403. ndisStatus,
  1404. NULL,
  1405. 0);
  1406. }
  1407. return AtalkNdisToAtalkError(ndisStatus);
  1408. }
  1409. ATALK_ERROR
  1410. AtalkNdisRemoveFunctional(
  1411. IN PPORT_DESCRIPTOR pPortDesc,
  1412. IN PBYTE Address,
  1413. IN BOOLEAN ExecuteSynchronously,
  1414. IN REQ_COMPLETION RemoveCompletion,
  1415. IN PVOID RemoveContext
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. Arguments:
  1420. Return Value:
  1421. --*/
  1422. {
  1423. ULONG i;
  1424. KIRQL OldIrql;
  1425. NDIS_REQUEST request;
  1426. NDIS_STATUS ndisStatus;
  1427. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1428. ("Current %02x%02x%02x%02x, Removing %02x%02x%02x%02x\n",
  1429. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1430. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3],
  1431. Address[2], Address[3], Address[4], Address[5]));
  1432. // Grab the perport spinlock
  1433. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  1434. // We only need the last four bytes of the address assuming that the
  1435. // first two bytes always remain the same (C000) and that the MAC assumes
  1436. // the same- NDIS 3.0 OID length = 4
  1437. for (i = 0; i < sizeof(ULONG); i++)
  1438. pPortDesc->pd_FunctionalAddr[i] &= ~Address[2+i];
  1439. // Release the spinlock
  1440. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1441. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1442. ("After Remove %02x%02x%02x%02x\n",
  1443. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1444. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3]));
  1445. request.RequestType = NdisRequestSetInformation;
  1446. request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
  1447. request.DATA.SET_INFORMATION.InformationBuffer = pPortDesc->pd_FunctionalAddr;
  1448. request.DATA.SET_INFORMATION.InformationBufferLength = TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN;
  1449. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1450. &request,
  1451. ExecuteSynchronously,
  1452. RemoveCompletion,
  1453. RemoveContext);
  1454. if (ndisStatus == NDIS_STATUS_PENDING)
  1455. {
  1456. ASSERT(ExecuteSynchronously != TRUE);
  1457. }
  1458. else if (ndisStatus != NDIS_STATUS_SUCCESS)
  1459. {
  1460. LOG_ERRORONPORT(pPortDesc,
  1461. EVENT_ATALK_NDISREQUEST,
  1462. ndisStatus,
  1463. NULL,
  1464. 0);
  1465. }
  1466. return AtalkNdisToAtalkError(ndisStatus);
  1467. }
  1468. USHORT
  1469. AtalkNdisBuildEthHdr(
  1470. IN PUCHAR PortAddr, // 802 address of port
  1471. IN PBYTE pLinkHdr, // Start of link header
  1472. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1473. IN LOGICAL_PROTOCOL Protocol, // Logical protocol
  1474. IN USHORT ActualDataLen // Length for ethernet packets
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. Arguments:
  1479. Return Value:
  1480. --*/
  1481. {
  1482. USHORT len;
  1483. // Set destination address.
  1484. if (pDestHwOrMcastAddr == NULL)
  1485. pDestHwOrMcastAddr = AtalkElapBroadcastAddr;
  1486. RtlCopyMemory(pLinkHdr,
  1487. pDestHwOrMcastAddr,
  1488. ELAP_ADDR_LEN);
  1489. // Set source address.
  1490. RtlCopyMemory(pLinkHdr += ELAP_ADDR_LEN,
  1491. PortAddr,
  1492. ELAP_ADDR_LEN);
  1493. // Set length, excluding Ethernet hardware header.
  1494. len = ActualDataLen + IEEE8022_HDR_LEN;
  1495. pLinkHdr += ELAP_ADDR_LEN;
  1496. PUTSHORT2SHORT(pLinkHdr, len);
  1497. pLinkHdr += sizeof(USHORT);
  1498. ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
  1499. // Return the link header length.
  1500. return (ELAP_LINKHDR_LEN + IEEE8022_HDR_LEN);
  1501. }
  1502. USHORT
  1503. AtalkNdisBuildTRHdr(
  1504. IN PUCHAR PortAddr, // 802 address of port
  1505. IN PBYTE pLinkHdr, // Start of link header
  1506. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1507. IN LOGICAL_PROTOCOL Protocol, // Logical protocol
  1508. IN PBYTE pRouteInfo, // Routing info for tokenring
  1509. IN USHORT RouteInfoLen // Length of above
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Arguments:
  1514. Return Value:
  1515. --*/
  1516. {
  1517. USHORT linkLen;
  1518. // Here we need to worry about the routing info.
  1519. // If we currently do not have any, set the values
  1520. if (pDestHwOrMcastAddr == NULL)
  1521. {
  1522. // Broadcast?
  1523. pRouteInfo = AtalkBroadcastRouteInfo;
  1524. RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
  1525. }
  1526. else if (RouteInfoLen != 0)
  1527. {
  1528. // We are all set
  1529. }
  1530. else if (AtalkFixedCompareCaseSensitive(pDestHwOrMcastAddr,
  1531. TLAP_BROADCAST_DEST_LEN,
  1532. AtalkBroadcastDestHdr,
  1533. TLAP_BROADCAST_DEST_LEN))
  1534. {
  1535. // Multicast?
  1536. pRouteInfo = AtalkBroadcastRouteInfo;
  1537. RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
  1538. }
  1539. else
  1540. {
  1541. // No routing know; use simple non-broadcast
  1542. pRouteInfo = AtalkSimpleRouteInfo;
  1543. RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
  1544. }
  1545. linkLen = TLAP_MIN_LINKHDR_LEN + RouteInfoLen + IEEE8022_HDR_LEN;
  1546. // Set the first two bytes in the header
  1547. *pLinkHdr++ = TLAP_ACCESS_CTRL_VALUE;
  1548. *pLinkHdr++ = TLAP_FRAME_CTRL_VALUE ;
  1549. // Set detination address.
  1550. if (pDestHwOrMcastAddr == NULL)
  1551. pDestHwOrMcastAddr = AtalkTlapBroadcastAddr;
  1552. RtlCopyMemory(pLinkHdr,
  1553. pDestHwOrMcastAddr ,
  1554. TLAP_ADDR_LEN);
  1555. // Set source address.
  1556. RtlCopyMemory(pLinkHdr += TLAP_ADDR_LEN,
  1557. PortAddr,
  1558. TLAP_ADDR_LEN);
  1559. ASSERTMSG("AtalkNdisBuildTRHdr: Routing Info is 0!\n", (RouteInfoLen > 0));
  1560. *pLinkHdr |= TLAP_SRC_ROUTING_MASK;
  1561. // Move in routing info.
  1562. RtlCopyMemory(pLinkHdr += TLAP_ADDR_LEN,
  1563. pRouteInfo,
  1564. RouteInfoLen);
  1565. pLinkHdr += RouteInfoLen;
  1566. ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
  1567. // Return the link header length.
  1568. return linkLen;
  1569. }
  1570. USHORT
  1571. AtalkNdisBuildFDDIHdr(
  1572. IN PUCHAR PortAddr, // 802 address of port
  1573. IN PBYTE pLinkHdr, // Start of link header
  1574. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1575. IN LOGICAL_PROTOCOL Protocol // Logical protocol
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. Arguments:
  1580. Return Value:
  1581. --*/
  1582. {
  1583. *pLinkHdr++ = FDDI_HEADER_BYTE;
  1584. // Set destination address.
  1585. if (pDestHwOrMcastAddr == NULL)
  1586. pDestHwOrMcastAddr = AtalkElapBroadcastAddr;
  1587. // Set destination address.
  1588. RtlCopyMemory(pLinkHdr,
  1589. pDestHwOrMcastAddr,
  1590. FDDI_ADDR_LEN);
  1591. // Set source address.
  1592. RtlCopyMemory(pLinkHdr += FDDI_ADDR_LEN,
  1593. PortAddr,
  1594. FDDI_ADDR_LEN);
  1595. pLinkHdr += FDDI_ADDR_LEN;
  1596. // NOTE: No Length field for FDDI, unlike Ethernet.
  1597. ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
  1598. // Return the link header length.
  1599. return (FDDI_LINKHDR_LEN + IEEE8022_HDR_LEN);
  1600. }
  1601. USHORT
  1602. AtalkNdisBuildLTHdr(
  1603. IN PBYTE pLinkHdr, // Start of link header
  1604. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1605. IN BYTE AlapSrc, // Localtalk source node
  1606. IN BYTE AlapType // Localtalk ddp header type
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. Arguments:
  1611. Return Value:
  1612. --*/
  1613. {
  1614. // Fill in LAP header.
  1615. if (pDestHwOrMcastAddr == NULL)
  1616. pLinkHdr = AtalkAlapBroadcastAddr;
  1617. *pLinkHdr++ = *pDestHwOrMcastAddr;
  1618. *pLinkHdr++ = AlapSrc;
  1619. *pLinkHdr = AlapType;
  1620. // Return the link header length.
  1621. return ALAP_LINKHDR_LEN;
  1622. }
  1623. VOID
  1624. AtalkNdisSendTokRingTestResp(
  1625. IN PPORT_DESCRIPTOR pPortDesc,
  1626. IN PBYTE HdrBuf,
  1627. IN UINT HdrBufSize,
  1628. IN PBYTE LkBuf,
  1629. IN UINT LkBufSize,
  1630. IN UINT PktSize
  1631. )
  1632. {
  1633. PBUFFER_DESC pBufDesc, pHdrDesc;
  1634. PBYTE pResp;
  1635. UINT routeInfoLen = 0;
  1636. // Allocate a buffer to hold the response and call NdisSend
  1637. // providing a completion routine which will free up the buffer.
  1638. ASSERT(PktSize == LkBufSize);
  1639. // make sure there are at least 14 bytes!
  1640. if (HdrBufSize < TLAP_ROUTE_INFO_OFFSET)
  1641. {
  1642. ASSERT(0);
  1643. return;
  1644. }
  1645. // First allocate a buffer to hold the link header.
  1646. AtalkNdisAllocBuf(&pHdrDesc);
  1647. if (pHdrDesc == NULL)
  1648. {
  1649. return;
  1650. }
  1651. if ((pBufDesc = AtalkAllocBuffDesc(NULL,
  1652. (USHORT)LkBufSize,
  1653. BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
  1654. {
  1655. AtalkNdisFreeBuf(pHdrDesc);
  1656. RES_LOG_ERROR();
  1657. return;
  1658. }
  1659. pResp = pHdrDesc->bd_CharBuffer;
  1660. *pResp++ = TLAP_ACCESS_CTRL_VALUE;
  1661. *pResp++ = TLAP_FRAME_CTRL_VALUE;
  1662. // Set destination address to be the incoming src addr.
  1663. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1664. pResp,
  1665. HdrBuf+TLAP_SRC_OFFSET,
  1666. TLAP_ADDR_LEN);
  1667. // Make sure we do not have the routing bit set.
  1668. *pResp &= ~TLAP_SRC_ROUTING_MASK;
  1669. pResp += TLAP_ADDR_LEN;
  1670. // Set source address to be the incoming destination address.
  1671. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1672. pResp,
  1673. HdrBuf+TLAP_DEST_OFFSET,
  1674. TLAP_ADDR_LEN);
  1675. // Is there routing info present?
  1676. if (HdrBuf[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
  1677. {
  1678. routeInfoLen = (HdrBuf[TLAP_ROUTE_INFO_OFFSET] & TLAP_ROUTE_INFO_SIZE_MASK);
  1679. ASSERT(routeInfoLen != 0);
  1680. ASSERTMSG("RouteInfo incorrect!\n",
  1681. (routeInfoLen <= TLAP_MAX_ROUTING_BYTES));
  1682. if (HdrBufSize < (TLAP_ROUTE_INFO_OFFSET+routeInfoLen))
  1683. {
  1684. ASSERT(0);
  1685. AtalkNdisFreeBuf(pHdrDesc);
  1686. AtalkFreeBuffDesc(pBufDesc);
  1687. return;
  1688. }
  1689. // Copy it in the response packet and then tune it.
  1690. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1691. pResp + TLAP_ADDR_LEN,
  1692. HdrBuf+TLAP_ROUTE_INFO_OFFSET,
  1693. routeInfoLen);
  1694. // Set to "non-broadcast" and invert "direction".
  1695. *(pResp+TLAP_ADDR_LEN) &= TLAP_NON_BROADCAST_MASK;
  1696. *(pResp+TLAP_ADDR_LEN+1) ^= TLAP_DIRECTION_MASK;
  1697. // Set the routing info bit in the source address
  1698. *pResp |= TLAP_SRC_ROUTING_MASK;
  1699. }
  1700. // Set the length for this buffer descriptor.
  1701. AtalkSetSizeOfBuffDescData(pHdrDesc, TLAP_ROUTE_INFO_OFFSET + routeInfoLen);
  1702. // Copy the remaining data
  1703. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1704. pBufDesc->bd_CharBuffer,
  1705. LkBuf,
  1706. LkBufSize);
  1707. // Set the source SAP to indicate FINAL (0xAB instead of 0xAA)
  1708. pBufDesc->bd_CharBuffer[IEEE8022_SSAP_OFFSET] = SNAP_SAP_FINAL;
  1709. // Chain the passed in buffer desc onto the tail of the one
  1710. // returned above.
  1711. AtalkPrependBuffDesc(pHdrDesc, pBufDesc);
  1712. // Call send at this point
  1713. if (!ATALK_SUCCESS(AtalkNdisSendPacket(pPortDesc,
  1714. pHdrDesc,
  1715. AtalkNdisSendTokRingTestRespComplete,
  1716. NULL)))
  1717. {
  1718. AtalkNdisSendTokRingTestRespComplete(NDIS_STATUS_RESOURCES,
  1719. pHdrDesc,
  1720. NULL);
  1721. }
  1722. }
  1723. VOID
  1724. AtalkNdisSendTokRingTestRespComplete(
  1725. IN NDIS_STATUS Status,
  1726. IN PBUFFER_DESC pBufDesc,
  1727. IN PSEND_COMPL_INFO pInfo
  1728. )
  1729. /*++
  1730. Routine Description:
  1731. Arguments:
  1732. Return Value:
  1733. --*/
  1734. {
  1735. // Free up the buffer descriptor
  1736. ASSERT((pBufDesc != NULL) && (pBufDesc->bd_Next != NULL));
  1737. ASSERT(pBufDesc->bd_Flags & BD_CHAR_BUFFER);
  1738. AtalkFreeBuffDesc(pBufDesc->bd_Next);
  1739. AtalkNdisFreeBuf(pBufDesc);
  1740. }
  1741. NDIS_STATUS
  1742. AtalkReceiveIndication(
  1743. IN NDIS_HANDLE BindingCtx,
  1744. IN NDIS_HANDLE ReceiveCtx,
  1745. IN PVOID HdrBuf,
  1746. IN UINT HdrBufSize,
  1747. IN PVOID LkBuf,
  1748. IN UINT LkBufSize,
  1749. IN UINT PktSize
  1750. )
  1751. /*++
  1752. Routine Description:
  1753. This routine is called by NDIS to indicate a receive
  1754. Arguments:
  1755. BindingCtx- Pointer to a port descriptor for this port
  1756. ReceiveCtx- To be used in a transfer data if necessary
  1757. LkBuf- buffer with lookahead data
  1758. LkBufSize- Size of the above buffer
  1759. PktSize- Size of whole packet
  1760. Return Value:
  1761. STATUS_SUCCESS- Packet accepted
  1762. STATUS_NOT_RECOGNIZED- Not our packet
  1763. Other
  1764. --*/
  1765. {
  1766. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)BindingCtx;
  1767. PNDIS_PACKET ndisPkt;
  1768. PBUFFER_HDR pBufferHdr = NULL;
  1769. PPROTOCOL_RESD protocolResd; // Protocolresd field in ndisPkt
  1770. UINT actualPktSize; // Size of data to copy
  1771. UINT bytesTransferred; // Number of bytes transferred in XferData
  1772. BOOLEAN result;
  1773. UINT xferOffset;
  1774. PBYTE lkBufOrig = (PBYTE)LkBuf;
  1775. ATALK_ERROR error = ATALK_NO_ERROR;
  1776. BOOLEAN shortDdpHdr = FALSE;
  1777. BYTE indicate = 0,
  1778. subType = 0;
  1779. NDIS_MEDIUM Media;
  1780. PBYTE packet = NULL; // Where we will copy the packet
  1781. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  1782. LOGICAL_PROTOCOL protocol = UNKNOWN_PROTOCOL;
  1783. PARAPCONN pArapConn;
  1784. PATCPCONN pAtcpConn;
  1785. ATALK_NODEADDR ClientNode;
  1786. #ifdef PROFILING
  1787. TIME TimeS, TimeE, TimeD;
  1788. TimeS = KeQueryPerformanceCounter(NULL);
  1789. #endif
  1790. do
  1791. {
  1792. if ((pPortDesc->pd_Flags & (PD_ACTIVE | PD_CLOSING)) != PD_ACTIVE)
  1793. {
  1794. // If we are not active, return!
  1795. ndisStatus = ATALK_PORT_CLOSING;
  1796. break;
  1797. }
  1798. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1799. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1800. Media = pPortDesc->pd_NdisPortType;
  1801. // Reduce 802.2 code, avoid making it a routine. First 802.2.
  1802. switch (Media)
  1803. {
  1804. case NdisMedium802_3:
  1805. case NdisMediumFddi:
  1806. case NdisMedium802_5:
  1807. ATALK_VERIFY8022_HDR((PBYTE)LkBuf, LkBufSize, protocol, result);
  1808. if (!result)
  1809. {
  1810. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1811. if (LkBufSize < IEEE8022_CONTROL_OFFSET+1)
  1812. {
  1813. ASSERT(0);
  1814. break;
  1815. }
  1816. if (Media == NdisMedium802_5)
  1817. {
  1818. // BUG #16002
  1819. // On tokenring the macs also send out a Unnumbered format
  1820. // TEST frame to which we need to respond. Check for that
  1821. // here.
  1822. if ((((PBYTE)LkBuf)[IEEE8022_DSAP_OFFSET] == SNAP_SAP) &&
  1823. (((PBYTE)LkBuf)[IEEE8022_SSAP_OFFSET] == SNAP_SAP) &&
  1824. (((PBYTE)LkBuf)[IEEE8022_CONTROL_OFFSET] == UNNUMBERED_FORMAT))
  1825. {
  1826. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
  1827. ("atalkNdisAcceptTlapPacket: LLC TEST FRAME RECD!\n"));
  1828. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1829. // Due to the aarp lookahead size setting, we are guaranteed
  1830. // the entire frame is contained in the lookahead data.
  1831. AtalkNdisSendTokRingTestResp(pPortDesc,
  1832. (PBYTE)HdrBuf,
  1833. HdrBufSize,
  1834. (PBYTE)LkBuf,
  1835. LkBufSize,
  1836. PktSize);
  1837. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1838. }
  1839. }
  1840. break;
  1841. }
  1842. if (protocol == APPLETALK_PROTOCOL)
  1843. {
  1844. // Do we at least have a 802.2 and DDP header in the indicated packet?
  1845. if ((PktSize < (IEEE8022_HDR_LEN + LDDP_HDR_LEN)) ||
  1846. (PktSize > (IEEE8022_HDR_LEN + MAX_LDDP_PKT_SIZE)))
  1847. {
  1848. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1849. break;
  1850. }
  1851. }
  1852. else // AARP
  1853. {
  1854. UINT routeInfoLen = 0; // length of routing info if present (802.5)
  1855. switch (Media)
  1856. {
  1857. case NdisMediumFddi:
  1858. // For fddi, there could be padding included in the packet. Shrink
  1859. // the length if so. Note header length is not included in packetlength.
  1860. //
  1861. if (PktSize >= (MIN_FDDI_PKT_LEN - FDDI_LINKHDR_LEN))
  1862. {
  1863. PktSize = (IEEE8022_HDR_LEN + AARP_MIN_DATA_SIZE);
  1864. }
  1865. break;
  1866. case NdisMedium802_5:
  1867. // Remember- routing info is in the header buffer
  1868. if (((PBYTE)HdrBuf)[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
  1869. {
  1870. routeInfoLen = (((PBYTE)HdrBuf)[TLAP_ROUTE_INFO_OFFSET] &
  1871. TLAP_ROUTE_INFO_SIZE_MASK);
  1872. ASSERTMSG("RouteInfo incorrect!\n",
  1873. ((routeInfoLen > 0) && (routeInfoLen <= TLAP_MAX_ROUTING_BYTES)));
  1874. // Routing info must be of reasonable size, and not odd.
  1875. if ((routeInfoLen & 1) ||
  1876. (routeInfoLen > TLAP_MAX_ROUTING_BYTES))
  1877. {
  1878. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1879. break;
  1880. }
  1881. }
  1882. // Fall through to 802.3 case
  1883. case NdisMedium802_3:
  1884. if (PktSize >= (ELAP_MIN_PKT_LEN - ELAP_LINKHDR_LEN))
  1885. {
  1886. PktSize = (IEEE8022_HDR_LEN + AARP_MIN_DATA_SIZE);
  1887. }
  1888. }
  1889. if (((PktSize - IEEE8022_HDR_LEN) > AARP_MAX_DATA_SIZE) ||
  1890. ((PktSize - IEEE8022_HDR_LEN) < AARP_MIN_DATA_SIZE))
  1891. {
  1892. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1893. break;
  1894. }
  1895. }
  1896. actualPktSize = (PktSize + HdrBufSize - IEEE8022_HDR_LEN);
  1897. (PBYTE)LkBuf += IEEE8022_HDR_LEN;
  1898. xferOffset = IEEE8022_HDR_LEN;
  1899. break;
  1900. case NdisMediumLocalTalk:
  1901. // No AARP/802.2 header on localtalk
  1902. protocol = APPLETALK_PROTOCOL;
  1903. // we should have enough bytes to have at least the short-header
  1904. if (LkBufSize < SDDP_PROTO_TYPE_OFFSET+1)
  1905. {
  1906. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1907. ASSERT(0);
  1908. break;
  1909. }
  1910. if (((PBYTE)HdrBuf)[ALAP_TYPE_OFFSET] == ALAP_SDDP_HDR_TYPE)
  1911. {
  1912. shortDdpHdr = TRUE;
  1913. }
  1914. else if (((PBYTE)HdrBuf)[ALAP_TYPE_OFFSET] != ALAP_LDDP_HDR_TYPE)
  1915. {
  1916. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1917. break;
  1918. }
  1919. actualPktSize = PktSize + HdrBufSize;
  1920. xferOffset = 0;
  1921. break;
  1922. case NdisMediumWan:
  1923. if (pPortDesc->pd_Flags & PD_RAS_PORT)
  1924. {
  1925. //
  1926. // 1st byte 0x01 tells us it's a PPP connection
  1927. //
  1928. if ((((PBYTE)HdrBuf)[0] == PPP_ID_BYTE1) &&
  1929. (((PBYTE)HdrBuf)[1] == PPP_ID_BYTE2))
  1930. {
  1931. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1932. DBGDUMPBYTES("Packet from PPP client:", (PBYTE)LkBuf,LkBufSize,4);
  1933. if (AtalkReferenceDefaultPort())
  1934. {
  1935. AtalkDdpPacketIn(AtalkDefaultPort, // came on which port
  1936. NULL, // Link Hdr
  1937. (PBYTE)LkBuf, // packet
  1938. (USHORT)LkBufSize, // how big is the pkt
  1939. TRUE); // did this come on WAN?
  1940. AtalkPortDereference(AtalkDefaultPort);
  1941. }
  1942. }
  1943. //
  1944. // this is ARAP connection: lot of stuff to be done before pkt
  1945. // can be given to the right destination...
  1946. //
  1947. else
  1948. {
  1949. ASSERT ((((PBYTE)HdrBuf)[0] == ARAP_ID_BYTE1) &&
  1950. (((PBYTE)HdrBuf)[1] == ARAP_ID_BYTE2));
  1951. *((ULONG UNALIGNED *)(&pArapConn)) =
  1952. *((ULONG UNALIGNED *)(&((PBYTE)HdrBuf)[2]));
  1953. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1954. ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
  1955. //
  1956. // NDISWAN guarantees that all the data is in the LookAhead buffer
  1957. //
  1958. ArapRcvIndication( pArapConn,
  1959. LkBuf,
  1960. LkBufSize );
  1961. }
  1962. }
  1963. break;
  1964. default:
  1965. // Should never happen!
  1966. DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_FATAL,
  1967. ("AtalkReceiveIndication: Unknown media\n"));
  1968. ASSERT(0);
  1969. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1970. break;
  1971. }
  1972. // we have already taken care of the Wan case: quit here
  1973. if (Media == NdisMediumWan)
  1974. {
  1975. break;
  1976. }
  1977. //
  1978. // if pkt not interesting, quit., if this is ras adapter, quit
  1979. //
  1980. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1981. {
  1982. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1983. break;
  1984. }
  1985. INTERLOCKED_INCREMENT_LONG_DPC(
  1986. &pPortDesc->pd_PortStats.prtst_NumPacketsIn,
  1987. &AtalkStatsLock.SpinLock);
  1988. INTERLOCKED_ADD_STATISTICS(&pPortDesc->pd_PortStats.prtst_DataIn,
  1989. (LONG)actualPktSize,
  1990. &AtalkStatsLock.SpinLock);
  1991. ASSERT ((protocol == APPLETALK_PROTOCOL) || (protocol == AARP_PROTOCOL));
  1992. // At this point, the IEEE802.2 header has been skipped in the lookahead
  1993. // buffer.
  1994. // Packet is to be accepted! Get an appropriate buffer and set the
  1995. // fields.
  1996. switch (protocol)
  1997. {
  1998. case APPLETALK_PROTOCOL:
  1999. // We either need to receive this packet on the default port, or
  2000. // we must be a router.
  2001. if ((pPortDesc == AtalkDefaultPort) || AtalkRouter)
  2002. {
  2003. if (shortDdpHdr)
  2004. {
  2005. // Check to see if we can indicate this to ATP/ADSP.
  2006. if ((((PBYTE)LkBuf)[SDDP_PROTO_TYPE_OFFSET] == DDPPROTO_ATP) &&
  2007. ((USHORT)(LkBufSize - xferOffset) >= (SDDP_HDR_LEN + ATP_HEADER_SIZE)))
  2008. {
  2009. indicate = INDICATE_ATP;
  2010. }
  2011. }
  2012. else
  2013. {
  2014. // Check to see if we can indicate this to ATP/ADSP.
  2015. if ((((PBYTE)LkBuf)[LDDP_PROTO_TYPE_OFFSET] == DDPPROTO_ATP) &&
  2016. ((USHORT)(LkBufSize - xferOffset) >= (LDDP_HDR_LEN + ATP_HEADER_SIZE)))
  2017. {
  2018. indicate = INDICATE_ATP;
  2019. }
  2020. }
  2021. }
  2022. // First check for optimizing ATP/ADSP packets.
  2023. if (indicate == INDICATE_ATP)
  2024. {
  2025. error = AtalkIndAtpPkt(pPortDesc,
  2026. (PBYTE)LkBuf,
  2027. (USHORT)(PktSize - xferOffset),
  2028. &xferOffset, // IN/OUT parameter
  2029. HdrBuf,
  2030. shortDdpHdr,
  2031. &subType,
  2032. &packet,
  2033. &ndisPkt);
  2034. if (ATALK_SUCCESS(error))
  2035. {
  2036. break;
  2037. }
  2038. else if (error == ATALK_INVALID_PKT)
  2039. {
  2040. // This indicates that the indication code has figured out that
  2041. // the packet is bad.
  2042. break;
  2043. }
  2044. else
  2045. {
  2046. // This is the case where the indication code cannot figure out
  2047. // if this packet qualifies.
  2048. indicate = 0;
  2049. error = ATALK_NO_ERROR;
  2050. }
  2051. }
  2052. if (actualPktSize > (sizeof(DDP_SMBUFFER) - sizeof(BUFFER_HDR)))
  2053. {
  2054. pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_DDPLG);
  2055. }
  2056. else
  2057. {
  2058. pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_DDPSM);
  2059. }
  2060. break;
  2061. case AARP_PROTOCOL:
  2062. pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_AARP);
  2063. break;
  2064. default:
  2065. KeBugCheck(0);
  2066. break;
  2067. }
  2068. if (!ATALK_SUCCESS(error) || ((pBufferHdr == NULL) && (indicate == 0)))
  2069. {
  2070. #if DBG
  2071. UINT i;
  2072. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2073. ("AtalkReceiveIndication: Dropping packet (2) %ld\n", error));
  2074. for (i = 0; i < HdrBufSize; i++)
  2075. DBGPRINTSKIPHDR(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2076. ("%02x ", ((PUCHAR)HdrBuf)[i]));
  2077. for (i = 0; i < LkBufSize; i++)
  2078. DBGPRINTSKIPHDR(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2079. ("%02x ", ((PUCHAR)LkBuf)[i]));
  2080. #endif
  2081. // No logging in this critical path.
  2082. // LOG_ERRORONPORT(pPortDesc,
  2083. // EVENT_ATALK_AARPPACKET,
  2084. // actualPktSize,
  2085. // HdrBuf,
  2086. // HdrBufSize);
  2087. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2088. if (error != ATALK_DUP_PKT)
  2089. {
  2090. INTERLOCKED_INCREMENT_LONG_DPC(
  2091. &pPortDesc->pd_PortStats.prtst_NumPktDropped,
  2092. &AtalkStatsLock.SpinLock);
  2093. }
  2094. ndisStatus = NDIS_STATUS_RESOURCES;
  2095. break;
  2096. }
  2097. if (indicate == 0)
  2098. {
  2099. packet = (PBYTE)pBufferHdr + sizeof(BUFFER_HDR);
  2100. // Get a pointer to the NDIS packet descriptor from the buffer header.
  2101. ndisPkt = pBufferHdr->bh_NdisPkt;
  2102. }
  2103. protocolResd = (PPROTOCOL_RESD)(ndisPkt->ProtocolReserved);
  2104. // Store the information needed in the packet descriptor
  2105. protocolResd->Receive.pr_Port = pPortDesc;
  2106. protocolResd->Receive.pr_Protocol = protocol;
  2107. protocolResd->Receive.pr_Processed = FALSE;
  2108. // Queue up the packet in the receive queue on this port
  2109. // Then, go ahead with the transfer data etc. For Atp response
  2110. // case when SubType == ATP_USER_BUFX, we do not want any
  2111. // Recv. completion processing, do not queue. In this case
  2112. // TransferData completion frees up the Ndis resources.
  2113. if ((indicate != INDICATE_ATP) ||
  2114. (protocolResd->Receive.pr_OptimizeSubType != ATP_USER_BUFX))
  2115. {
  2116. ATALK_RECV_INDICATION_COPY(pPortDesc,
  2117. protocolResd->Receive.pr_LinkHdr,
  2118. (PBYTE)HdrBuf,
  2119. HdrBufSize);
  2120. InsertTailList(&pPortDesc->pd_ReceiveQueue,
  2121. &protocolResd->Receive.pr_Linkage);
  2122. }
  2123. else
  2124. {
  2125. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2126. ("AtalkReceiveIndication: Skipping link hdr !!!\n"));
  2127. }
  2128. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2129. #ifdef PROFILING
  2130. INTERLOCKED_INCREMENT_LONG_DPC(
  2131. &pPortDesc->pd_PortStats.prtst_CurReceiveQueue,
  2132. &AtalkStatsLock.SpinLock);
  2133. #endif
  2134. // Adjust for the link header size. Set size in protocol reserved. We want
  2135. // to avoid changing the size described by the NDIS buffer descriptor.
  2136. if (indicate == 0)
  2137. {
  2138. actualPktSize -= HdrBufSize;
  2139. protocolResd->Receive.pr_DataLength = (USHORT)actualPktSize;
  2140. }
  2141. else
  2142. {
  2143. actualPktSize = protocolResd->Receive.pr_DataLength;
  2144. }
  2145. ASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
  2146. if ((PktSize <= LkBufSize) &&
  2147. ((indicate != INDICATE_ATP) || (subType != ATP_RESPONSE)))
  2148. {
  2149. // LkBuf has already been advanced to skip the ieee 802.2 header.
  2150. // We may need to skip more. Use the original lkbuf and xfer offset.
  2151. ATALK_RECV_INDICATION_COPY(pPortDesc,
  2152. packet,
  2153. (PBYTE)lkBufOrig + xferOffset,
  2154. actualPktSize);
  2155. bytesTransferred = actualPktSize;
  2156. }
  2157. else
  2158. {
  2159. // Skip 802.2 header (both AARP and Appletalk), localtalk doesnt have one!
  2160. if (actualPktSize > 0)
  2161. {
  2162. NdisTransferData(&ndisStatus,
  2163. pPortDesc->pd_NdisBindingHandle,
  2164. ReceiveCtx,
  2165. xferOffset,
  2166. actualPktSize,
  2167. ndisPkt,
  2168. &bytesTransferred);
  2169. ASSERT(bytesTransferred == actualPktSize);
  2170. }
  2171. }
  2172. if (ndisStatus == NDIS_STATUS_PENDING)
  2173. {
  2174. ndisStatus = NDIS_STATUS_SUCCESS;
  2175. }
  2176. else
  2177. {
  2178. // Transfer data completed, call the transfer data completion
  2179. // routine to do rest of the work. If an error happened, ReceiveCompletion
  2180. // will drop the packet.
  2181. protocolResd->Receive.pr_ReceiveStatus = ndisStatus;
  2182. protocolResd->Receive.pr_Processed = TRUE;
  2183. // In case of intermediate Atp response, the packet is not actually linked
  2184. // into the receive queue, just free it.
  2185. if ((protocolResd->Receive.pr_OptimizeType == INDICATE_ATP) &&
  2186. (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUFX))
  2187. {
  2188. PNDIS_BUFFER ndisBuffer;
  2189. // Free NDIS buffers if any are present.
  2190. NdisUnchainBufferAtFront(ndisPkt, &ndisBuffer);
  2191. if (ndisBuffer != NULL)
  2192. {
  2193. AtalkNdisFreeBuffer(ndisBuffer);
  2194. }
  2195. NdisDprFreePacket(ndisPkt);
  2196. }
  2197. }
  2198. } while (FALSE);
  2199. #ifdef PROFILING
  2200. TimeE = KeQueryPerformanceCounter(NULL);
  2201. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  2202. INTERLOCKED_ADD_LARGE_INTGR_DPC(&pPortDesc->pd_PortStats.prtst_RcvIndProcessTime,
  2203. TimeD,
  2204. &AtalkStatsLock.SpinLock);
  2205. INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_RcvIndCount,
  2206. &AtalkStatsLock.SpinLock);
  2207. #endif
  2208. return ndisStatus;
  2209. }
  2210. VOID
  2211. AtalkTransferDataComplete(
  2212. IN NDIS_HANDLE BindingCtx,
  2213. IN PNDIS_PACKET NdisPkt,
  2214. IN NDIS_STATUS Status,
  2215. IN UINT BytesTransferred
  2216. )
  2217. /*++
  2218. Routine Description:
  2219. This routine is called by NDIS to indicate completion of a TransferData
  2220. Arguments:
  2221. BindingCtx- Pointer to a port descriptor for this port
  2222. NdisPkt- Ndis packet into which data was transferred
  2223. Status- Status of request
  2224. bytesTransferred- Actual number of bytes transferred
  2225. Return Value:
  2226. None
  2227. --*/
  2228. {
  2229. PPROTOCOL_RESD protocolResd;
  2230. PNDIS_BUFFER ndisBuffer;
  2231. protocolResd = (PPROTOCOL_RESD)(NdisPkt->ProtocolReserved);
  2232. protocolResd->Receive.pr_ReceiveStatus = Status;
  2233. protocolResd->Receive.pr_Processed = TRUE;
  2234. // In case of intermediate Atp response, the packet is not actually linked
  2235. // into the receive queue, just free it.
  2236. if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUFX)
  2237. {
  2238. // Free NDIS buffers if any are present.
  2239. NdisUnchainBufferAtFront(NdisPkt, &ndisBuffer);
  2240. if (ndisBuffer != NULL)
  2241. {
  2242. AtalkNdisFreeBuffer(ndisBuffer);
  2243. }
  2244. NdisDprFreePacket(NdisPkt);
  2245. }
  2246. }
  2247. VOID
  2248. AtalkReceiveComplete(
  2249. IN NDIS_HANDLE BindingCtx
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. We experimented with queueing up a work item for receive completion. It really
  2254. KILLED performance with multiple clients as apparently the receive completion
  2255. kept getting interrupted with receive indications. AS the optimization was
  2256. put in for slow cards like the ELNKII which do not have adequate buffering,
  2257. we decided to take it out. The retry values (or timeout trimming) should be
  2258. enough for the slow cards. They will inevitably drop packets.
  2259. Arguments:
  2260. Return Value:
  2261. --*/
  2262. {
  2263. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)BindingCtx;
  2264. PPROTOCOL_RESD protocolResd;
  2265. PNDIS_PACKET ndisPkt;
  2266. PNDIS_BUFFER ndisBuffer;
  2267. PBUFFER_HDR pBufHdr;
  2268. NDIS_MEDIUM Media;
  2269. PLIST_ENTRY p;
  2270. PBYTE packet;
  2271. LOGICAL_PROTOCOL protocol;
  2272. UINT packetLength;
  2273. BOOLEAN fDerefDefPort=FALSE;
  2274. #ifdef PROFILING
  2275. TIME TimeS, TimeE, TimeD;
  2276. #endif
  2277. if (pPortDesc->pd_Flags & PD_RAS_PORT)
  2278. {
  2279. // give ARAP guys a chance
  2280. ArapRcvComplete();
  2281. if (!AtalkReferenceDefaultPort())
  2282. {
  2283. return;
  2284. }
  2285. fDerefDefPort = TRUE;
  2286. // give PPP guys a chance
  2287. pPortDesc = AtalkDefaultPort;
  2288. }
  2289. // Get the stuff off the receive queue for the port and send it up. Do not
  2290. // enter if the queue is initially empty.
  2291. if (IsListEmpty(&pPortDesc->pd_ReceiveQueue))
  2292. {
  2293. if (fDerefDefPort)
  2294. {
  2295. AtalkPortDereference(AtalkDefaultPort);
  2296. }
  2297. return;
  2298. }
  2299. #ifdef PROFILING
  2300. TimeS = KeQueryPerformanceCounter(NULL);
  2301. #endif
  2302. while (TRUE)
  2303. {
  2304. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2305. p = pPortDesc->pd_ReceiveQueue.Flink;
  2306. if (p == &pPortDesc->pd_ReceiveQueue)
  2307. {
  2308. // Queue is empty
  2309. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2310. break;
  2311. }
  2312. ndisPkt = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved[0]);
  2313. protocolResd = (PPROTOCOL_RESD)(ndisPkt->ProtocolReserved);
  2314. // Check if the queued receive is done processing. Since we are looping
  2315. // through the queue and since receive complete only checks if the first
  2316. // is done, we need this check here for subsequent queued up receives.
  2317. if (!protocolResd->Receive.pr_Processed)
  2318. {
  2319. // Queue is empty
  2320. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2321. break;
  2322. }
  2323. // Dequeue and indicate this packet to the ddp/atp layer
  2324. p = RemoveHeadList(&pPortDesc->pd_ReceiveQueue);
  2325. pBufHdr = protocolResd->Receive.pr_BufHdr;
  2326. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2327. #ifdef PROFILING
  2328. INTERLOCKED_DECREMENT_LONG_DPC(
  2329. &pPortDesc->pd_PortStats.prtst_CurReceiveQueue,
  2330. &AtalkStatsLock.SpinLock);
  2331. #endif
  2332. Media = pPortDesc->pd_NdisPortType;
  2333. protocol = protocolResd->Receive.pr_Protocol;
  2334. if ((protocol == APPLETALK_PROTOCOL) &&
  2335. (protocolResd->Receive.pr_OptimizeType == INDICATE_ATP))
  2336. {
  2337. protocolResd->Receive.pr_OptimizeType = 0;
  2338. ASSERT(protocolResd->Receive.pr_OptimizeSubType != ATP_USER_BUFX);
  2339. // Check the receive status- accept only if ok
  2340. if (protocolResd->Receive.pr_ReceiveStatus == NDIS_STATUS_SUCCESS)
  2341. {
  2342. // Glean information. Check for route info if tokenring network.
  2343. if (Media != NdisMediumLocalTalk)
  2344. {
  2345. AtalkAarpOptGleanInfo(pPortDesc,
  2346. protocolResd->Receive.pr_LinkHdr,
  2347. &protocolResd->Receive.pr_SrcAddr,
  2348. &protocolResd->Receive.pr_DestAddr,
  2349. protocolResd->Receive.pr_OffCablePkt);
  2350. }
  2351. // Different calls for response & non-response packets.
  2352. if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUF)
  2353. {
  2354. AtalkAtpPacketIn(AtalkDefaultPort,
  2355. protocolResd->Receive.pr_AtpAddrObj->atpao_DdpAddr,
  2356. protocolResd->Receive.pr_AtpHdr,
  2357. (USHORT)(protocolResd->Receive.pr_DataLength + 8),
  2358. &protocolResd->Receive.pr_SrcAddr,
  2359. &protocolResd->Receive.pr_DestAddr,
  2360. ATALK_NO_ERROR,
  2361. DDPPROTO_ATP,
  2362. protocolResd->Receive.pr_AtpAddrObj,
  2363. TRUE,
  2364. protocolResd->Receive.pr_OptimizeCtx);
  2365. }
  2366. else
  2367. {
  2368. ASSERT (protocolResd->Receive.pr_OptimizeSubType == ATP_ALLOC_BUF);
  2369. packet = (PBYTE)pBufHdr + sizeof(BUFFER_HDR);
  2370. ASSERT(packet != NULL);
  2371. AtalkAtpPacketIn(AtalkDefaultPort,
  2372. protocolResd->Receive.pr_AtpAddrObj->atpao_DdpAddr,
  2373. packet,
  2374. (USHORT)protocolResd->Receive.pr_DataLength,
  2375. &protocolResd->Receive.pr_SrcAddr,
  2376. &protocolResd->Receive.pr_DestAddr,
  2377. ATALK_NO_ERROR,
  2378. DDPPROTO_ATP,
  2379. protocolResd->Receive.pr_AtpAddrObj,
  2380. TRUE,
  2381. protocolResd->Receive.pr_OptimizeCtx);
  2382. }
  2383. }
  2384. // Different calls for user buffer/allocated packets
  2385. if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUF)
  2386. {
  2387. // Free NDIS buffers if any are present.
  2388. NdisUnchainBufferAtFront(ndisPkt, &ndisBuffer);
  2389. if (ndisBuffer != NULL)
  2390. {
  2391. AtalkNdisFreeBuffer(ndisBuffer);
  2392. }
  2393. NdisDprFreePacket(ndisPkt);
  2394. }
  2395. else
  2396. {
  2397. AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
  2398. }
  2399. continue;
  2400. }
  2401. // IMPORTANT:
  2402. // We know that the buffer is virtually contiguous since we allocated
  2403. // it. And we also know that only one buffer is allocated. So we use
  2404. // that knowledge to get the actual address and pass that onto the
  2405. // higher level routines.
  2406. // !!!!
  2407. // Although, the allocated buffer contains the link header tagged on at
  2408. // the end, we do not have the packet descriptor describing that. As
  2409. // far as we are concerned here, that tagged entity does not exist and
  2410. // is independently pointed to by protocolResd->pr_LinkHdr.
  2411. // !!!!
  2412. packet = (PBYTE)pBufHdr + sizeof(BUFFER_HDR);
  2413. ASSERT(packet != NULL);
  2414. packetLength = protocolResd->Receive.pr_DataLength;
  2415. // Check the receive status- accept only if ok
  2416. if (protocolResd->Receive.pr_ReceiveStatus != NDIS_STATUS_SUCCESS)
  2417. {
  2418. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2419. ("AtalkReceiveComplete: ReceiveStatus FAILURE %lx!\n",
  2420. protocolResd->Receive.pr_ReceiveStatus));
  2421. AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
  2422. continue;
  2423. }
  2424. // The packet descriptor is now associate with the buffer, and we cant
  2425. // release the buffer (and hence the descriptor) until after we indicate to
  2426. // the higher levels
  2427. switch (Media)
  2428. {
  2429. case NdisMedium802_3 :
  2430. case NdisMediumFddi :
  2431. case NdisMedium802_5 :
  2432. case NdisMediumLocalTalk :
  2433. if (protocol == APPLETALK_PROTOCOL)
  2434. {
  2435. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
  2436. ("AtalkReceiveComplete: Indicating DDP Ethernet\n"));
  2437. AtalkDdpPacketIn(pPortDesc,
  2438. protocolResd->Receive.pr_LinkHdr,
  2439. packet,
  2440. (USHORT)packetLength,
  2441. FALSE);
  2442. }
  2443. else
  2444. {
  2445. // AARP Packet
  2446. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
  2447. ("AtalkReceiveComplete: Indicating AARP Ethernet\n"));
  2448. ASSERT(Media != NdisMediumLocalTalk);
  2449. AtalkAarpPacketIn(pPortDesc,
  2450. protocolResd->Receive.pr_LinkHdr,
  2451. packet,
  2452. (USHORT)packetLength);
  2453. }
  2454. break;
  2455. default:
  2456. KeBugCheck(0);
  2457. break;
  2458. }
  2459. // !!!!
  2460. // We dont have to free the link header. This follows the packet
  2461. // buffer (and was allocated along with it) and will be freed when
  2462. // the packet is freed.
  2463. AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
  2464. }
  2465. if (fDerefDefPort)
  2466. {
  2467. AtalkPortDereference(AtalkDefaultPort);
  2468. }
  2469. #ifdef PROFILING
  2470. TimeE = KeQueryPerformanceCounter(NULL);
  2471. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  2472. INTERLOCKED_ADD_LARGE_INTGR_DPC(
  2473. &pPortDesc->pd_PortStats.prtst_RcvCompProcessTime,
  2474. TimeD,
  2475. &AtalkStatsLock.SpinLock);
  2476. INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_RcvCompCount,
  2477. &AtalkStatsLock.SpinLock);
  2478. #endif
  2479. }
  2480. VOID
  2481. AtalkSendComplete(
  2482. IN NDIS_HANDLE ProtoBindCtx,
  2483. IN PNDIS_PACKET NdisPkt,
  2484. IN NDIS_STATUS NdisStatus
  2485. )
  2486. /*++
  2487. Routine Description:
  2488. Arguments:
  2489. ProtoBindCtx- Binding associated with mac
  2490. NdisPkt- Packet which was sent
  2491. NdisStatus- Final status of send
  2492. Return Value:
  2493. None
  2494. --*/
  2495. {
  2496. PPROTOCOL_RESD pProtocolResd;
  2497. PNDIS_BUFFER pNdisBuffer=NULL, pNdisFirstBuffer=NULL;
  2498. PPORT_DESCRIPTOR pPortDesc;
  2499. PBUFFER_DESC pBufferDesc;
  2500. SEND_COMPLETION pSendComp;
  2501. SEND_COMPL_INFO sendInfo;
  2502. // Call the completion routine, we don't care about status now
  2503. pProtocolResd = (PPROTOCOL_RESD)(NdisPkt->ProtocolReserved);
  2504. ASSERT(pProtocolResd != NULL);
  2505. pPortDesc = pProtocolResd->Send.pr_Port;
  2506. sendInfo = pProtocolResd->Send.pr_SendInfo;
  2507. pBufferDesc = pProtocolResd->Send.pr_BufferDesc;
  2508. pSendComp = pProtocolResd->Send.pr_SendCompletion;
  2509. // We free up all the ndis buffer descriptors except the first one.
  2510. // NOTE: The presence of a second buffer descriptor indicates that more
  2511. // than one NdisBuffer is present. But not necessarily just two. If
  2512. // the client had passed in a MDL chain, we would create a corresponding
  2513. // NDIS buffer descriptor chain. Therefore, remove the first, free up
  2514. // all remaining ones, then queue back the first.
  2515. NdisUnchainBufferAtFront(NdisPkt, &pNdisFirstBuffer);
  2516. if (pProtocolResd->Send.pr_BufferDesc->bd_Next != NULL)
  2517. {
  2518. while (TRUE)
  2519. {
  2520. NdisUnchainBufferAtBack(NdisPkt,
  2521. &pNdisBuffer);
  2522. if (pNdisBuffer == NULL)
  2523. {
  2524. break;
  2525. }
  2526. // Free up the ndis buffer descriptor.
  2527. AtalkNdisFreeBuffer(pNdisBuffer);
  2528. }
  2529. }
  2530. // Reintialize the packet descriptor.
  2531. NdisReinitializePacket(NdisPkt);
  2532. // Put first buffer back in.
  2533. if (pNdisFirstBuffer != NULL)
  2534. {
  2535. NdisChainBufferAtFront(NdisPkt, pNdisFirstBuffer);
  2536. }
  2537. // Call the completion routine for the transmit. This invalidates NdisPkt.
  2538. if (pSendComp)
  2539. {
  2540. (*pSendComp)(NdisStatus, pBufferDesc, &sendInfo);
  2541. }
  2542. // Dereference the port
  2543. ASSERT(pPortDesc != NULL);
  2544. #ifdef PROFILING
  2545. INTERLOCKED_DECREMENT_LONG(
  2546. &pPortDesc->pd_PortStats.prtst_CurSendsOutstanding,
  2547. &AtalkStatsLock.SpinLock);
  2548. #endif
  2549. }
  2550. VOID
  2551. AtalkBindAdapter(
  2552. OUT PNDIS_STATUS Status,
  2553. IN NDIS_HANDLE BindContext,
  2554. IN PNDIS_STRING DeviceName,
  2555. IN PVOID SystemSpecific1,
  2556. IN PVOID SystemSpecific2
  2557. )
  2558. {
  2559. // are we unloading? if so, just return
  2560. if (AtalkBindnUnloadStates & ATALK_UNLOADING)
  2561. {
  2562. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2563. ("AtalkBindAdapter: nothing to do: driver unloading\n"));
  2564. return;
  2565. }
  2566. AtalkBindnUnloadStates |= ATALK_BINDING;
  2567. AtalkLockInitIfNecessary();
  2568. *Status = AtalkInitAdapter(DeviceName, NULL);
  2569. ASSERT(*Status != NDIS_STATUS_PENDING);
  2570. AtalkUnlockInitIfNecessary();
  2571. AtalkBindnUnloadStates &= ~ATALK_BINDING;
  2572. }
  2573. VOID
  2574. AtalkUnbindAdapter(
  2575. OUT PNDIS_STATUS Status,
  2576. IN NDIS_HANDLE ProtocolBindingContext,
  2577. IN NDIS_HANDLE UnbindContext
  2578. )
  2579. {
  2580. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)ProtocolBindingContext;
  2581. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
  2582. ("AtalkUnbindAdapter on %lx\n",ProtocolBindingContext));
  2583. ASSERT( VALID_PORT(pPortDesc) );
  2584. AtalkLockInitIfNecessary();
  2585. // First and foremost: tell guys above so they can cleanup
  2586. if ((pPortDesc->pd_Flags & PD_DEF_PORT) ||
  2587. (pPortDesc->pd_Flags & PD_RAS_PORT))
  2588. {
  2589. if (pPortDesc->pd_Flags & PD_DEF_PORT)
  2590. {
  2591. ASSERT(pPortDesc == AtalkDefaultPort);
  2592. if (TdiAddressChangeRegHandle)
  2593. {
  2594. TdiDeregisterNetAddress(TdiAddressChangeRegHandle);
  2595. TdiAddressChangeRegHandle = NULL;
  2596. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  2597. ("AtalkUnbindAdapter: TdiDeregisterNetAddress on %Z done\n",
  2598. &pPortDesc->pd_AdapterName));
  2599. }
  2600. // this will tell AFP
  2601. if (TdiRegistrationHandle)
  2602. {
  2603. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  2604. ("AtalkUnbindAdapter: default adapter unbound, telling AFP, RAS\n"));
  2605. TdiDeregisterDeviceObject(TdiRegistrationHandle);
  2606. TdiRegistrationHandle = NULL;
  2607. }
  2608. }
  2609. else
  2610. {
  2611. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  2612. ("AtalkUnbindAdapter: RAS adapter unbound! telling AFP, RAS\n"));
  2613. }
  2614. // this will take care of informing ARAP and PPP engine above
  2615. AtalkPnPInformRas(FALSE);
  2616. }
  2617. *Status = AtalkDeinitAdapter(pPortDesc);
  2618. ASSERT(*Status != NDIS_STATUS_PENDING);
  2619. AtalkUnlockInitIfNecessary();
  2620. }
  2621.