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.

3189 lines
76 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. AtalkNdisAddMulticast(
  816. IN PPORT_DESCRIPTOR pPortDesc,
  817. IN PBYTE Address,
  818. IN BOOLEAN ExecuteSynchronously,
  819. IN REQ_COMPLETION AddCompletion,
  820. IN PVOID AddContext
  821. )
  822. /*++
  823. Routine Description:
  824. Arguments:
  825. Return Value:
  826. --*/
  827. {
  828. INT sizeOfList;
  829. PBYTE addressData, tempList;
  830. KIRQL OldIrql;
  831. NDIS_OID ndisOid;
  832. NDIS_REQUEST request;
  833. NDIS_STATUS ndisStatus;
  834. PADDMC pAmc;
  835. // Check to see it we bound successfully to this adapter
  836. if (!PORT_BOUND(pPortDesc))
  837. {
  838. LOG_ERRORONPORT(pPortDesc,
  839. EVENT_ATALK_NOTBOUNDTOMAC,
  840. STATUS_INSUFFICIENT_RESOURCES,
  841. NULL,
  842. 0);
  843. return ATALK_FAILURE;
  844. }
  845. // Grab the perport spinlock. We need to allocate within a
  846. // critical section as the size might change. This routine
  847. // is called very infrequently, during init and when we
  848. // receive our default zone from zip.
  849. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  850. sizeOfList = pPortDesc->pd_MulticastListSize + ELAP_ADDR_LEN;
  851. ASSERTMSG("AtalkNdisAddMulticast: Size is not > 0\n", (sizeOfList > 0));
  852. // Allocate/reallocate the list for the port descriptor, and also
  853. // for a copy to be used in the NDIS request function.
  854. tempList = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
  855. addressData = (PBYTE)AtalkAllocZeroedMemory(sizeOfList);
  856. pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
  857. if ((tempList == NULL) || (addressData == NULL) || (pAmc == NULL))
  858. {
  859. // Release the spinlock
  860. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  861. if (pAmc != NULL)
  862. AtalkFreeMemory(pAmc);
  863. if (tempList != NULL)
  864. AtalkFreeMemory(tempList);
  865. if (addressData != NULL)
  866. AtalkFreeMemory(addressData);
  867. return ATALK_RESR_MEM;
  868. }
  869. if (pPortDesc->pd_MulticastList == NULL)
  870. {
  871. // No old addresses to work with.
  872. pPortDesc->pd_MulticastListSize = 0;
  873. }
  874. else
  875. {
  876. // Copy the old list over to the new space
  877. RtlCopyMemory(tempList,
  878. pPortDesc->pd_MulticastList,
  879. pPortDesc->pd_MulticastListSize);
  880. // Set the proper values back into PortDesc after freeing the old list
  881. AtalkFreeMemory(pPortDesc->pd_MulticastList);
  882. }
  883. // Guaranteed space is available to copy the new address
  884. // Ready to copy our new address here and then do the set!
  885. RtlCopyMemory(tempList + pPortDesc->pd_MulticastListSize,
  886. Address,
  887. ELAP_ADDR_LEN);
  888. pPortDesc->pd_MulticastList = tempList;
  889. pPortDesc->pd_MulticastListSize = sizeOfList;
  890. switch (pPortDesc->pd_NdisPortType)
  891. {
  892. case NdisMedium802_3 :
  893. ndisOid = OID_802_3_MULTICAST_LIST;
  894. break;
  895. case NdisMediumFddi:
  896. // FDDI supports 2byte and 6byte multicast addresses. We use the
  897. // 6byte multicast addresses for appletalk.
  898. ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
  899. break;
  900. default:
  901. KeBugCheck(0);
  902. break;
  903. }
  904. // Setup request
  905. // Move the list to our buffer
  906. ASSERTMSG("AtalkNdisAddMulticast: Size incorrect!\n",
  907. ((ULONG)sizeOfList == pPortDesc->pd_MulticastListSize));
  908. RtlCopyMemory(addressData,
  909. pPortDesc->pd_MulticastList,
  910. pPortDesc->pd_MulticastListSize);
  911. // Release the spinlock
  912. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  913. request.RequestType = NdisRequestSetInformation;
  914. request.DATA.SET_INFORMATION.Oid = ndisOid;
  915. request.DATA.SET_INFORMATION.InformationBuffer = addressData;
  916. request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
  917. pAmc->AddCompletion = AddCompletion;
  918. pAmc->AddContext = AddContext;
  919. pAmc->Buffer = addressData;
  920. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  921. &request,
  922. FALSE,
  923. atalkNdisAddMulticastCompletion,
  924. pAmc);
  925. // NOTE: Sumbit calls completion if success is being returned.
  926. if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
  927. (ndisStatus != NDIS_STATUS_PENDING))
  928. {
  929. LOG_ERRORONPORT(pPortDesc,
  930. EVENT_ATALK_NDISREQUEST,
  931. ndisStatus,
  932. NULL,
  933. 0);
  934. }
  935. return AtalkNdisToAtalkError(ndisStatus);
  936. }
  937. ATALK_ERROR
  938. AtalkNdisRemoveMulticast(
  939. IN PPORT_DESCRIPTOR pPortDesc,
  940. IN PBYTE Address,
  941. IN BOOLEAN ExecuteSynchronously,
  942. IN REQ_COMPLETION RemoveCompletion,
  943. IN PVOID RemoveContext
  944. )
  945. {
  946. INT sizeOfList, i, numberInList;
  947. PBYTE addressData, currentList;
  948. KIRQL OldIrql;
  949. NDIS_REQUEST request;
  950. NDIS_OID ndisOid;
  951. NDIS_STATUS ndisStatus;
  952. PADDMC pAmc;
  953. do
  954. {
  955. // Check to see it we bound successfully to this adapter
  956. if (!PORT_BOUND(pPortDesc))
  957. {
  958. LOG_ERRORONPORT(pPortDesc,
  959. EVENT_ATALK_NOTBOUNDTOMAC,
  960. STATUS_INSUFFICIENT_RESOURCES,
  961. NULL,
  962. 0);
  963. ndisStatus = NDIS_STATUS_RESOURCES;
  964. break;
  965. }
  966. // Grab the perport spinlock. Again, a very infrequent operation.
  967. // Probably just twice in the lifetime of the stack.
  968. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  969. ASSERT(pPortDesc->pd_MulticastList != NULL);
  970. if (pPortDesc->pd_MulticastList == NULL)
  971. {
  972. // Nothing to remove!
  973. ndisStatus = NDIS_STATUS_SUCCESS;
  974. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  975. break;
  976. }
  977. numberInList = pPortDesc->pd_MulticastListSize/ELAP_ADDR_LEN;
  978. currentList = pPortDesc->pd_MulticastList;
  979. for (i = 0; i < numberInList; i++, currentList += ELAP_ADDR_LEN)
  980. {
  981. // Search for the address and remember the index if found
  982. if (RtlCompareMemory(currentList,
  983. Address,
  984. ELAP_ADDR_LEN) == ELAP_ADDR_LEN)
  985. {
  986. // Move all address following this overwriting this address
  987. // we ignore wasted space that will never be touched anymore.
  988. // This could turn out to be a NOP if we are removing the last
  989. // address in the list.
  990. RtlMoveMemory(currentList,
  991. currentList + ELAP_ADDR_LEN,
  992. pPortDesc->pd_MulticastListSize-((i+1)*ELAP_ADDR_LEN));
  993. pPortDesc->pd_MulticastListSize -= ELAP_ADDR_LEN;
  994. // Have we removed the last address. If so, reset values.
  995. if (pPortDesc->pd_MulticastListSize == 0)
  996. {
  997. AtalkFreeMemory(pPortDesc->pd_MulticastList);
  998. pPortDesc->pd_MulticastList = NULL;
  999. }
  1000. break;
  1001. }
  1002. }
  1003. // We assume address was found and the list is changed as expected
  1004. // Set this new list
  1005. switch (pPortDesc->pd_NdisPortType)
  1006. {
  1007. case NdisMedium802_3 :
  1008. ndisOid = OID_802_3_MULTICAST_LIST;
  1009. break;
  1010. case NdisMediumFddi:
  1011. // FDDI supports 2byte and 6byte multicast addresses. We use the
  1012. // 6byte multicast addresses for appletalk.
  1013. ndisOid = OID_FDDI_LONG_MULTICAST_LIST;
  1014. break;
  1015. default:
  1016. KeBugCheck(0);
  1017. break;
  1018. }
  1019. addressData = NULL;
  1020. sizeOfList = pPortDesc->pd_MulticastListSize;
  1021. pAmc = (PADDMC)AtalkAllocZeroedMemory(sizeof(ADDMC));
  1022. if (pAmc == NULL)
  1023. {
  1024. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1025. ndisStatus = NDIS_STATUS_RESOURCES;
  1026. break;
  1027. }
  1028. if (sizeOfList > 0)
  1029. {
  1030. // Allocate addressData and copy list to it
  1031. addressData = (PBYTE)AtalkAllocMemory(sizeOfList);
  1032. if (addressData == NULL)
  1033. {
  1034. // Release the spinlock
  1035. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1036. AtalkFreeMemory(pAmc);
  1037. ndisStatus = NDIS_STATUS_RESOURCES;
  1038. break;
  1039. }
  1040. // Move the list to our buffer
  1041. RtlCopyMemory(addressData,
  1042. pPortDesc->pd_MulticastList,
  1043. pPortDesc->pd_MulticastListSize);
  1044. }
  1045. // Release the spinlock
  1046. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1047. request.RequestType = NdisRequestSetInformation;
  1048. request.DATA.SET_INFORMATION.Oid = ndisOid;
  1049. request.DATA.SET_INFORMATION.InformationBuffer = addressData;
  1050. request.DATA.SET_INFORMATION.InformationBufferLength = sizeOfList;
  1051. pAmc->AddCompletion = RemoveCompletion;
  1052. pAmc->AddContext = RemoveContext;
  1053. pAmc->Buffer = addressData;
  1054. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1055. &request,
  1056. FALSE,
  1057. atalkNdisAddMulticastCompletion,
  1058. pAmc);
  1059. if ((ndisStatus != NDIS_STATUS_SUCCESS) &&
  1060. (ndisStatus != NDIS_STATUS_PENDING))
  1061. {
  1062. LOG_ERRORONPORT(pPortDesc,
  1063. EVENT_ATALK_NDISREQUEST,
  1064. ndisStatus,
  1065. NULL,
  1066. 0);
  1067. }
  1068. } while (FALSE);
  1069. return AtalkNdisToAtalkError(ndisStatus);
  1070. }
  1071. ATALK_ERROR
  1072. AtalkNdisSendPacket(
  1073. IN PPORT_DESCRIPTOR pPortDesc,
  1074. IN PBUFFER_DESC BufferChain,
  1075. IN SEND_COMPLETION SendCompletion OPTIONAL,
  1076. IN PSEND_COMPL_INFO pSendInfo OPTIONAL
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. This routine is called by the portable code to send a packet out on
  1081. ethernet. It will build the NDIS packet descriptor for the passed in
  1082. chain and then send the packet on the specified port.
  1083. Arguments:
  1084. Return Value:
  1085. TRUE- If sent/pending, FALSE otherwise
  1086. TransmitComplete is called if this call pended by completion code
  1087. --*/
  1088. {
  1089. PNDIS_PACKET ndisPacket;
  1090. PNDIS_BUFFER ndisBuffer;
  1091. PPROTOCOL_RESD protocolResd;
  1092. ATALK_ERROR error;
  1093. PSENDBUF pSendBuf;
  1094. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  1095. PMDL pMdl;
  1096. PMDL pFirstMdl=NULL;
  1097. if (PORT_CLOSING(pPortDesc))
  1098. {
  1099. // If we are not active, return!
  1100. return ATALK_PORT_CLOSING;
  1101. }
  1102. do
  1103. {
  1104. pSendBuf = (PSENDBUF)((PBYTE)BufferChain - sizeof(BUFFER_HDR));
  1105. ndisPacket = pSendBuf->sb_BuffHdr.bh_NdisPkt;
  1106. // Store the information needed in the packet descriptor
  1107. protocolResd = (PPROTOCOL_RESD)&ndisPacket->ProtocolReserved;
  1108. protocolResd->Send.pr_Port = pPortDesc;
  1109. protocolResd->Send.pr_BufferDesc = BufferChain;
  1110. protocolResd->Send.pr_SendCompletion = SendCompletion;
  1111. if (pSendInfo != NULL)
  1112. protocolResd->Send.pr_SendInfo = *pSendInfo;
  1113. else RtlZeroMemory(&protocolResd->Send.pr_SendInfo, sizeof(SEND_COMPL_INFO));
  1114. // For the first buffer, set up the length of the NDIS buffer to be
  1115. // the same as in indicated in the descriptor.
  1116. NdisAdjustBufferLength(pSendBuf->sb_BuffHdr.bh_NdisBuffer,
  1117. BufferChain->bd_Length);
  1118. // NOTE: There is either a PBYTE being pointed to, or a PAMDL
  1119. // being pointed to by the buffer descriptor. Also, the
  1120. // size of the data will be the size that is to be
  1121. // used. At the end, just assert that the total length
  1122. // equals length passed in.
  1123. if (BufferChain->bd_Next != NULL)
  1124. {
  1125. if (BufferChain->bd_Next->bd_Flags & BD_CHAR_BUFFER)
  1126. {
  1127. NdisAllocateBuffer(&ndisStatus,
  1128. &ndisBuffer,
  1129. AtalkNdisBufferPoolHandle,
  1130. (PVOID)BufferChain->bd_Next->bd_CharBuffer,
  1131. (UINT)BufferChain->bd_Next->bd_Length);
  1132. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1133. {
  1134. DBGPRINT(DBG_COMP_NDISSEND, DBG_LEVEL_ERR,
  1135. ("AtalkNdisSendPacket: NdisAllocateBuffer %lx\n", ndisStatus));
  1136. // LOG_ERROR(EVENT_ATALK_NDISRESOURCES, ndisStatus, NULL, 0);
  1137. break;
  1138. }
  1139. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  1140. NdisChainBufferAtBack(ndisPacket, ndisBuffer);
  1141. }
  1142. else
  1143. {
  1144. // It is an MDL
  1145. pMdl = (PMDL)BufferChain->bd_Next->bd_OpaqueBuffer;
  1146. ASSERT(AtalkSizeMdlChain(pMdl) == BufferChain->bd_Next->bd_Length);
  1147. while (pMdl)
  1148. {
  1149. NdisCopyBuffer(&ndisStatus,
  1150. &ndisBuffer,
  1151. AtalkNdisBufferPoolHandle,
  1152. (PVOID)pMdl,
  1153. 0, //Offset
  1154. (UINT)MmGetMdlByteCount(pMdl));
  1155. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1156. {
  1157. if (pFirstMdl)
  1158. {
  1159. AtalkNdisFreeBuffer(pFirstMdl);
  1160. }
  1161. break;
  1162. }
  1163. ATALK_DBG_INC_COUNT(AtalkDbgMdlsAlloced);
  1164. if (!pFirstMdl)
  1165. {
  1166. pFirstMdl = pMdl;
  1167. }
  1168. NdisChainBufferAtBack(ndisPacket, ndisBuffer);
  1169. pMdl = pMdl->Next;
  1170. }
  1171. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1172. {
  1173. DBGPRINT(DBG_COMP_NDISSEND, DBG_LEVEL_ERR,
  1174. ("AtalkNdisSendPacket: NdisCopyBuffer %lx\n", ndisStatus));
  1175. break;
  1176. }
  1177. }
  1178. }
  1179. #ifdef PROFILING
  1180. INTERLOCKED_INCREMENT_LONG_DPC(
  1181. &pPortDesc->pd_PortStats.prtst_CurSendsOutstanding,
  1182. &AtalkStatsLock.SpinLock);
  1183. #endif
  1184. INTERLOCKED_INCREMENT_LONG_DPC(
  1185. &pPortDesc->pd_PortStats.prtst_NumPacketsOut,
  1186. &AtalkStatsLock.SpinLock);
  1187. // Now send the built packet descriptor
  1188. NdisSend(&ndisStatus,
  1189. pPortDesc->pd_NdisBindingHandle,
  1190. ndisPacket);
  1191. // Completion will dereference the port!
  1192. if (ndisStatus != NDIS_STATUS_PENDING)
  1193. {
  1194. // Call the completion handler
  1195. AtalkSendComplete(pPortDesc->pd_NdisBindingHandle,
  1196. ndisPacket,
  1197. ndisStatus);
  1198. ndisStatus = NDIS_STATUS_PENDING;
  1199. }
  1200. } while (FALSE);
  1201. return AtalkNdisToAtalkError(ndisStatus);
  1202. }
  1203. ATALK_ERROR
  1204. AtalkNdisAddFunctional(
  1205. IN PPORT_DESCRIPTOR pPortDesc,
  1206. IN PBYTE Address,
  1207. IN BOOLEAN ExecuteSynchronously,
  1208. IN REQ_COMPLETION AddCompletion,
  1209. IN PVOID AddContext
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Arguments:
  1214. Return Value:
  1215. --*/
  1216. {
  1217. ULONG i;
  1218. NDIS_REQUEST request;
  1219. NDIS_STATUS ndisStatus;
  1220. KIRQL OldIrql;
  1221. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1222. ("Current %02x%02x%02x%02x, Adding %02x%02x%02x%02x\n",
  1223. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1224. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3],
  1225. Address[2], Address[3], Address[4], Address[5]));
  1226. // Grab the perport spinlock
  1227. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  1228. // We only need the last four bytes of the address assuming that the
  1229. // first two bytes always remain the same (C000) and that the MAC assumes
  1230. // the same- NDIS 3.0 OID length = 4
  1231. for (i = 0;
  1232. i < sizeof(ULONG);
  1233. i++)
  1234. pPortDesc->pd_FunctionalAddr[i] |= Address[2+i];
  1235. // Release the spinlock
  1236. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1237. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1238. ("After Add %02x%02x%02x%02x\n",
  1239. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1240. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3]));
  1241. request.RequestType = NdisRequestSetInformation;
  1242. request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
  1243. request.DATA.SET_INFORMATION.InformationBuffer = pPortDesc->pd_FunctionalAddr;
  1244. request.DATA.SET_INFORMATION.InformationBufferLength = TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN;
  1245. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1246. &request,
  1247. ExecuteSynchronously,
  1248. AddCompletion,
  1249. AddContext);
  1250. if (ndisStatus == NDIS_STATUS_PENDING)
  1251. {
  1252. ASSERT(ExecuteSynchronously != TRUE);
  1253. }
  1254. else if (ndisStatus != NDIS_STATUS_SUCCESS)
  1255. {
  1256. LOG_ERRORONPORT(pPortDesc,
  1257. EVENT_ATALK_NDISREQUEST,
  1258. ndisStatus,
  1259. NULL,
  1260. 0);
  1261. }
  1262. return AtalkNdisToAtalkError(ndisStatus);
  1263. }
  1264. ATALK_ERROR
  1265. AtalkNdisRemoveFunctional(
  1266. IN PPORT_DESCRIPTOR pPortDesc,
  1267. IN PBYTE Address,
  1268. IN BOOLEAN ExecuteSynchronously,
  1269. IN REQ_COMPLETION RemoveCompletion,
  1270. IN PVOID RemoveContext
  1271. )
  1272. /*++
  1273. Routine Description:
  1274. Arguments:
  1275. Return Value:
  1276. --*/
  1277. {
  1278. ULONG i;
  1279. KIRQL OldIrql;
  1280. NDIS_REQUEST request;
  1281. NDIS_STATUS ndisStatus;
  1282. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1283. ("Current %02x%02x%02x%02x, Removing %02x%02x%02x%02x\n",
  1284. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1285. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3],
  1286. Address[2], Address[3], Address[4], Address[5]));
  1287. // Grab the perport spinlock
  1288. ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
  1289. // We only need the last four bytes of the address assuming that the
  1290. // first two bytes always remain the same (C000) and that the MAC assumes
  1291. // the same- NDIS 3.0 OID length = 4
  1292. for (i = 0; i < sizeof(ULONG); i++)
  1293. pPortDesc->pd_FunctionalAddr[i] &= ~Address[2+i];
  1294. // Release the spinlock
  1295. RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
  1296. DBGPRINT(DBG_COMP_NDISREQ, DBG_LEVEL_INFO,
  1297. ("After Remove %02x%02x%02x%02x\n",
  1298. pPortDesc->pd_FunctionalAddr[0], pPortDesc->pd_FunctionalAddr[1],
  1299. pPortDesc->pd_FunctionalAddr[2], pPortDesc->pd_FunctionalAddr[3]));
  1300. request.RequestType = NdisRequestSetInformation;
  1301. request.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
  1302. request.DATA.SET_INFORMATION.InformationBuffer = pPortDesc->pd_FunctionalAddr;
  1303. request.DATA.SET_INFORMATION.InformationBufferLength = TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN;
  1304. ndisStatus = AtalkNdisSubmitRequest(pPortDesc,
  1305. &request,
  1306. ExecuteSynchronously,
  1307. RemoveCompletion,
  1308. RemoveContext);
  1309. if (ndisStatus == NDIS_STATUS_PENDING)
  1310. {
  1311. ASSERT(ExecuteSynchronously != TRUE);
  1312. }
  1313. else if (ndisStatus != NDIS_STATUS_SUCCESS)
  1314. {
  1315. LOG_ERRORONPORT(pPortDesc,
  1316. EVENT_ATALK_NDISREQUEST,
  1317. ndisStatus,
  1318. NULL,
  1319. 0);
  1320. }
  1321. return AtalkNdisToAtalkError(ndisStatus);
  1322. }
  1323. USHORT
  1324. AtalkNdisBuildEthHdr(
  1325. IN PUCHAR PortAddr, // 802 address of port
  1326. IN PBYTE pLinkHdr, // Start of link header
  1327. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1328. IN LOGICAL_PROTOCOL Protocol, // Logical protocol
  1329. IN USHORT ActualDataLen // Length for ethernet packets
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. Arguments:
  1334. Return Value:
  1335. --*/
  1336. {
  1337. USHORT len;
  1338. // Set destination address.
  1339. if (pDestHwOrMcastAddr == NULL)
  1340. pDestHwOrMcastAddr = AtalkElapBroadcastAddr;
  1341. RtlCopyMemory(pLinkHdr,
  1342. pDestHwOrMcastAddr,
  1343. ELAP_ADDR_LEN);
  1344. // Set source address.
  1345. RtlCopyMemory(pLinkHdr += ELAP_ADDR_LEN,
  1346. PortAddr,
  1347. ELAP_ADDR_LEN);
  1348. // Set length, excluding Ethernet hardware header.
  1349. len = ActualDataLen + IEEE8022_HDR_LEN;
  1350. pLinkHdr += ELAP_ADDR_LEN;
  1351. PUTSHORT2SHORT(pLinkHdr, len);
  1352. pLinkHdr += sizeof(USHORT);
  1353. ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
  1354. // Return the link header length.
  1355. return (ELAP_LINKHDR_LEN + IEEE8022_HDR_LEN);
  1356. }
  1357. USHORT
  1358. AtalkNdisBuildTRHdr(
  1359. IN PUCHAR PortAddr, // 802 address of port
  1360. IN PBYTE pLinkHdr, // Start of link header
  1361. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1362. IN LOGICAL_PROTOCOL Protocol, // Logical protocol
  1363. IN PBYTE pRouteInfo, // Routing info for tokenring
  1364. IN USHORT RouteInfoLen // Length of above
  1365. )
  1366. /*++
  1367. Routine Description:
  1368. Arguments:
  1369. Return Value:
  1370. --*/
  1371. {
  1372. USHORT linkLen;
  1373. // Here we need to worry about the routing info.
  1374. // If we currently do not have any, set the values
  1375. if (pDestHwOrMcastAddr == NULL)
  1376. {
  1377. // Broadcast?
  1378. pRouteInfo = AtalkBroadcastRouteInfo;
  1379. RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
  1380. }
  1381. else if (RouteInfoLen != 0)
  1382. {
  1383. // We are all set
  1384. }
  1385. else if (AtalkFixedCompareCaseSensitive(pDestHwOrMcastAddr,
  1386. TLAP_BROADCAST_DEST_LEN,
  1387. AtalkBroadcastDestHdr,
  1388. TLAP_BROADCAST_DEST_LEN))
  1389. {
  1390. // Multicast?
  1391. pRouteInfo = AtalkBroadcastRouteInfo;
  1392. RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
  1393. }
  1394. else
  1395. {
  1396. // No routing know; use simple non-broadcast
  1397. pRouteInfo = AtalkSimpleRouteInfo;
  1398. RouteInfoLen = TLAP_MIN_ROUTING_BYTES;
  1399. }
  1400. linkLen = TLAP_MIN_LINKHDR_LEN + RouteInfoLen + IEEE8022_HDR_LEN;
  1401. // Set the first two bytes in the header
  1402. *pLinkHdr++ = TLAP_ACCESS_CTRL_VALUE;
  1403. *pLinkHdr++ = TLAP_FRAME_CTRL_VALUE ;
  1404. // Set detination address.
  1405. if (pDestHwOrMcastAddr == NULL)
  1406. pDestHwOrMcastAddr = AtalkTlapBroadcastAddr;
  1407. RtlCopyMemory(pLinkHdr,
  1408. pDestHwOrMcastAddr ,
  1409. TLAP_ADDR_LEN);
  1410. // Set source address.
  1411. RtlCopyMemory(pLinkHdr += TLAP_ADDR_LEN,
  1412. PortAddr,
  1413. TLAP_ADDR_LEN);
  1414. ASSERTMSG("AtalkNdisBuildTRHdr: Routing Info is 0!\n", (RouteInfoLen > 0));
  1415. *pLinkHdr |= TLAP_SRC_ROUTING_MASK;
  1416. // Move in routing info.
  1417. RtlCopyMemory(pLinkHdr += TLAP_ADDR_LEN,
  1418. pRouteInfo,
  1419. RouteInfoLen);
  1420. pLinkHdr += RouteInfoLen;
  1421. ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
  1422. // Return the link header length.
  1423. return linkLen;
  1424. }
  1425. USHORT
  1426. AtalkNdisBuildFDDIHdr(
  1427. IN PUCHAR PortAddr, // 802 address of port
  1428. IN PBYTE pLinkHdr, // Start of link header
  1429. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1430. IN LOGICAL_PROTOCOL Protocol // Logical protocol
  1431. )
  1432. /*++
  1433. Routine Description:
  1434. Arguments:
  1435. Return Value:
  1436. --*/
  1437. {
  1438. *pLinkHdr++ = FDDI_HEADER_BYTE;
  1439. // Set destination address.
  1440. if (pDestHwOrMcastAddr == NULL)
  1441. pDestHwOrMcastAddr = AtalkElapBroadcastAddr;
  1442. // Set destination address.
  1443. RtlCopyMemory(pLinkHdr,
  1444. pDestHwOrMcastAddr,
  1445. FDDI_ADDR_LEN);
  1446. // Set source address.
  1447. RtlCopyMemory(pLinkHdr += FDDI_ADDR_LEN,
  1448. PortAddr,
  1449. FDDI_ADDR_LEN);
  1450. pLinkHdr += FDDI_ADDR_LEN;
  1451. // NOTE: No Length field for FDDI, unlike Ethernet.
  1452. ATALK_BUILD8022_HDR(pLinkHdr, Protocol);
  1453. // Return the link header length.
  1454. return (FDDI_LINKHDR_LEN + IEEE8022_HDR_LEN);
  1455. }
  1456. USHORT
  1457. AtalkNdisBuildLTHdr(
  1458. IN PBYTE pLinkHdr, // Start of link header
  1459. IN PBYTE pDestHwOrMcastAddr, // Destination or multicast addr
  1460. IN BYTE AlapSrc, // Localtalk source node
  1461. IN BYTE AlapType // Localtalk ddp header type
  1462. )
  1463. /*++
  1464. Routine Description:
  1465. Arguments:
  1466. Return Value:
  1467. --*/
  1468. {
  1469. // Fill in LAP header.
  1470. if (pDestHwOrMcastAddr == NULL)
  1471. pLinkHdr = AtalkAlapBroadcastAddr;
  1472. *pLinkHdr++ = *pDestHwOrMcastAddr;
  1473. *pLinkHdr++ = AlapSrc;
  1474. *pLinkHdr = AlapType;
  1475. // Return the link header length.
  1476. return ALAP_LINKHDR_LEN;
  1477. }
  1478. VOID
  1479. AtalkNdisSendTokRingTestResp(
  1480. IN PPORT_DESCRIPTOR pPortDesc,
  1481. IN PBYTE HdrBuf,
  1482. IN UINT HdrBufSize,
  1483. IN PBYTE LkBuf,
  1484. IN UINT LkBufSize,
  1485. IN UINT PktSize
  1486. )
  1487. {
  1488. PBUFFER_DESC pBufDesc, pHdrDesc;
  1489. PBYTE pResp;
  1490. UINT routeInfoLen = 0;
  1491. // Allocate a buffer to hold the response and call NdisSend
  1492. // providing a completion routine which will free up the buffer.
  1493. ASSERT(PktSize == LkBufSize);
  1494. // make sure there are at least 14 bytes!
  1495. if (HdrBufSize < TLAP_ROUTE_INFO_OFFSET)
  1496. {
  1497. ASSERT(0);
  1498. return;
  1499. }
  1500. // First allocate a buffer to hold the link header.
  1501. AtalkNdisAllocBuf(&pHdrDesc);
  1502. if (pHdrDesc == NULL)
  1503. {
  1504. return;
  1505. }
  1506. if ((pBufDesc = AtalkAllocBuffDesc(NULL,
  1507. (USHORT)LkBufSize,
  1508. BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
  1509. {
  1510. AtalkNdisFreeBuf(pHdrDesc);
  1511. RES_LOG_ERROR();
  1512. return;
  1513. }
  1514. pResp = pHdrDesc->bd_CharBuffer;
  1515. *pResp++ = TLAP_ACCESS_CTRL_VALUE;
  1516. *pResp++ = TLAP_FRAME_CTRL_VALUE;
  1517. // Set destination address to be the incoming src addr.
  1518. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1519. pResp,
  1520. HdrBuf+TLAP_SRC_OFFSET,
  1521. TLAP_ADDR_LEN);
  1522. // Make sure we do not have the routing bit set.
  1523. *pResp &= ~TLAP_SRC_ROUTING_MASK;
  1524. pResp += TLAP_ADDR_LEN;
  1525. // Set source address to be the incoming destination address.
  1526. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1527. pResp,
  1528. HdrBuf+TLAP_DEST_OFFSET,
  1529. TLAP_ADDR_LEN);
  1530. // Is there routing info present?
  1531. if (HdrBuf[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
  1532. {
  1533. routeInfoLen = (HdrBuf[TLAP_ROUTE_INFO_OFFSET] & TLAP_ROUTE_INFO_SIZE_MASK);
  1534. ASSERT(routeInfoLen != 0);
  1535. ASSERTMSG("RouteInfo incorrect!\n",
  1536. (routeInfoLen <= TLAP_MAX_ROUTING_BYTES));
  1537. if (HdrBufSize < (TLAP_ROUTE_INFO_OFFSET+routeInfoLen))
  1538. {
  1539. ASSERT(0);
  1540. AtalkNdisFreeBuf(pHdrDesc);
  1541. AtalkFreeBuffDesc(pBufDesc);
  1542. return;
  1543. }
  1544. // Copy it in the response packet and then tune it.
  1545. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1546. pResp + TLAP_ADDR_LEN,
  1547. HdrBuf+TLAP_ROUTE_INFO_OFFSET,
  1548. routeInfoLen);
  1549. // Set to "non-broadcast" and invert "direction".
  1550. *(pResp+TLAP_ADDR_LEN) &= TLAP_NON_BROADCAST_MASK;
  1551. *(pResp+TLAP_ADDR_LEN+1) ^= TLAP_DIRECTION_MASK;
  1552. // Set the routing info bit in the source address
  1553. *pResp |= TLAP_SRC_ROUTING_MASK;
  1554. }
  1555. // Set the length for this buffer descriptor.
  1556. AtalkSetSizeOfBuffDescData(pHdrDesc, TLAP_ROUTE_INFO_OFFSET + routeInfoLen);
  1557. // Copy the remaining data
  1558. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1559. pBufDesc->bd_CharBuffer,
  1560. LkBuf,
  1561. LkBufSize);
  1562. // Set the source SAP to indicate FINAL (0xAB instead of 0xAA)
  1563. pBufDesc->bd_CharBuffer[IEEE8022_SSAP_OFFSET] = SNAP_SAP_FINAL;
  1564. // Chain the passed in buffer desc onto the tail of the one
  1565. // returned above.
  1566. AtalkPrependBuffDesc(pHdrDesc, pBufDesc);
  1567. // Call send at this point
  1568. if (!ATALK_SUCCESS(AtalkNdisSendPacket(pPortDesc,
  1569. pHdrDesc,
  1570. AtalkNdisSendTokRingTestRespComplete,
  1571. NULL)))
  1572. {
  1573. AtalkNdisSendTokRingTestRespComplete(NDIS_STATUS_RESOURCES,
  1574. pHdrDesc,
  1575. NULL);
  1576. }
  1577. }
  1578. VOID
  1579. AtalkNdisSendTokRingTestRespComplete(
  1580. IN NDIS_STATUS Status,
  1581. IN PBUFFER_DESC pBufDesc,
  1582. IN PSEND_COMPL_INFO pInfo
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. Arguments:
  1587. Return Value:
  1588. --*/
  1589. {
  1590. // Free up the buffer descriptor
  1591. ASSERT((pBufDesc != NULL) && (pBufDesc->bd_Next != NULL));
  1592. ASSERT(pBufDesc->bd_Flags & BD_CHAR_BUFFER);
  1593. AtalkFreeBuffDesc(pBufDesc->bd_Next);
  1594. AtalkNdisFreeBuf(pBufDesc);
  1595. }
  1596. NDIS_STATUS
  1597. AtalkReceiveIndication(
  1598. IN NDIS_HANDLE BindingCtx,
  1599. IN NDIS_HANDLE ReceiveCtx,
  1600. IN PVOID HdrBuf,
  1601. IN UINT HdrBufSize,
  1602. IN PVOID LkBuf,
  1603. IN UINT LkBufSize,
  1604. IN UINT PktSize
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. This routine is called by NDIS to indicate a receive
  1609. Arguments:
  1610. BindingCtx- Pointer to a port descriptor for this port
  1611. ReceiveCtx- To be used in a transfer data if necessary
  1612. LkBuf- buffer with lookahead data
  1613. LkBufSize- Size of the above buffer
  1614. PktSize- Size of whole packet
  1615. Return Value:
  1616. STATUS_SUCCESS- Packet accepted
  1617. STATUS_NOT_RECOGNIZED- Not our packet
  1618. Other
  1619. --*/
  1620. {
  1621. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)BindingCtx;
  1622. PNDIS_PACKET ndisPkt;
  1623. PBUFFER_HDR pBufferHdr = NULL;
  1624. PPROTOCOL_RESD protocolResd; // Protocolresd field in ndisPkt
  1625. UINT actualPktSize; // Size of data to copy
  1626. UINT bytesTransferred; // Number of bytes transferred in XferData
  1627. BOOLEAN result;
  1628. UINT xferOffset;
  1629. PBYTE lkBufOrig = (PBYTE)LkBuf;
  1630. ATALK_ERROR error = ATALK_NO_ERROR;
  1631. BOOLEAN shortDdpHdr = FALSE;
  1632. BYTE indicate = 0,
  1633. subType = 0;
  1634. NDIS_MEDIUM Media;
  1635. PBYTE packet = NULL; // Where we will copy the packet
  1636. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  1637. LOGICAL_PROTOCOL protocol = UNKNOWN_PROTOCOL;
  1638. PARAPCONN pArapConn;
  1639. PATCPCONN pAtcpConn;
  1640. ATALK_NODEADDR ClientNode;
  1641. #ifdef PROFILING
  1642. TIME TimeS, TimeE, TimeD;
  1643. TimeS = KeQueryPerformanceCounter(NULL);
  1644. #endif
  1645. do
  1646. {
  1647. if ((pPortDesc->pd_Flags & (PD_ACTIVE | PD_CLOSING)) != PD_ACTIVE)
  1648. {
  1649. // If we are not active, return!
  1650. ndisStatus = ATALK_PORT_CLOSING;
  1651. break;
  1652. }
  1653. ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
  1654. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1655. Media = pPortDesc->pd_NdisPortType;
  1656. // Reduce 802.2 code, avoid making it a routine. First 802.2.
  1657. switch (Media)
  1658. {
  1659. case NdisMedium802_3:
  1660. case NdisMediumFddi:
  1661. case NdisMedium802_5:
  1662. ATALK_VERIFY8022_HDR((PBYTE)LkBuf, LkBufSize, protocol, result);
  1663. if (!result)
  1664. {
  1665. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1666. if (LkBufSize < IEEE8022_CONTROL_OFFSET+1)
  1667. {
  1668. ASSERT(0);
  1669. break;
  1670. }
  1671. if (Media == NdisMedium802_5)
  1672. {
  1673. // BUG #16002
  1674. // On tokenring the macs also send out a Unnumbered format
  1675. // TEST frame to which we need to respond. Check for that
  1676. // here.
  1677. if ((((PBYTE)LkBuf)[IEEE8022_DSAP_OFFSET] == SNAP_SAP) &&
  1678. (((PBYTE)LkBuf)[IEEE8022_SSAP_OFFSET] == SNAP_SAP) &&
  1679. (((PBYTE)LkBuf)[IEEE8022_CONTROL_OFFSET] == UNNUMBERED_FORMAT))
  1680. {
  1681. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
  1682. ("atalkNdisAcceptTlapPacket: LLC TEST FRAME RECD!\n"));
  1683. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1684. // Due to the aarp lookahead size setting, we are guaranteed
  1685. // the entire frame is contained in the lookahead data.
  1686. AtalkNdisSendTokRingTestResp(pPortDesc,
  1687. (PBYTE)HdrBuf,
  1688. HdrBufSize,
  1689. (PBYTE)LkBuf,
  1690. LkBufSize,
  1691. PktSize);
  1692. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1693. }
  1694. }
  1695. break;
  1696. }
  1697. if (protocol == APPLETALK_PROTOCOL)
  1698. {
  1699. // Do we at least have a 802.2 and DDP header in the indicated packet?
  1700. if ((PktSize < (IEEE8022_HDR_LEN + LDDP_HDR_LEN)) ||
  1701. (PktSize > (IEEE8022_HDR_LEN + MAX_LDDP_PKT_SIZE)))
  1702. {
  1703. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1704. break;
  1705. }
  1706. }
  1707. else // AARP
  1708. {
  1709. UINT routeInfoLen = 0; // length of routing info if present (802.5)
  1710. switch (Media)
  1711. {
  1712. case NdisMediumFddi:
  1713. // For fddi, there could be padding included in the packet. Shrink
  1714. // the length if so. Note header length is not included in packetlength.
  1715. //
  1716. if (PktSize >= (MIN_FDDI_PKT_LEN - FDDI_LINKHDR_LEN))
  1717. {
  1718. PktSize = (IEEE8022_HDR_LEN + AARP_MIN_DATA_SIZE);
  1719. }
  1720. break;
  1721. case NdisMedium802_5:
  1722. // Remember- routing info is in the header buffer
  1723. if (((PBYTE)HdrBuf)[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
  1724. {
  1725. routeInfoLen = (((PBYTE)HdrBuf)[TLAP_ROUTE_INFO_OFFSET] &
  1726. TLAP_ROUTE_INFO_SIZE_MASK);
  1727. ASSERTMSG("RouteInfo incorrect!\n",
  1728. ((routeInfoLen > 0) && (routeInfoLen <= TLAP_MAX_ROUTING_BYTES)));
  1729. // Routing info must be of reasonable size, and not odd.
  1730. if ((routeInfoLen & 1) ||
  1731. (routeInfoLen > TLAP_MAX_ROUTING_BYTES))
  1732. {
  1733. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1734. break;
  1735. }
  1736. }
  1737. // Fall through to 802.3 case
  1738. case NdisMedium802_3:
  1739. if (PktSize >= (ELAP_MIN_PKT_LEN - ELAP_LINKHDR_LEN))
  1740. {
  1741. PktSize = (IEEE8022_HDR_LEN + AARP_MIN_DATA_SIZE);
  1742. }
  1743. }
  1744. if (((PktSize - IEEE8022_HDR_LEN) > AARP_MAX_DATA_SIZE) ||
  1745. ((PktSize - IEEE8022_HDR_LEN) < AARP_MIN_DATA_SIZE))
  1746. {
  1747. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1748. break;
  1749. }
  1750. }
  1751. actualPktSize = (PktSize + HdrBufSize - IEEE8022_HDR_LEN);
  1752. (PBYTE)LkBuf += IEEE8022_HDR_LEN;
  1753. xferOffset = IEEE8022_HDR_LEN;
  1754. break;
  1755. case NdisMediumLocalTalk:
  1756. // No AARP/802.2 header on localtalk
  1757. protocol = APPLETALK_PROTOCOL;
  1758. // we should have enough bytes to have at least the short-header
  1759. if (LkBufSize < SDDP_PROTO_TYPE_OFFSET+1)
  1760. {
  1761. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1762. ASSERT(0);
  1763. break;
  1764. }
  1765. if (((PBYTE)HdrBuf)[ALAP_TYPE_OFFSET] == ALAP_SDDP_HDR_TYPE)
  1766. {
  1767. shortDdpHdr = TRUE;
  1768. }
  1769. else if (((PBYTE)HdrBuf)[ALAP_TYPE_OFFSET] != ALAP_LDDP_HDR_TYPE)
  1770. {
  1771. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1772. break;
  1773. }
  1774. actualPktSize = PktSize + HdrBufSize;
  1775. xferOffset = 0;
  1776. break;
  1777. case NdisMediumWan:
  1778. if (pPortDesc->pd_Flags & PD_RAS_PORT)
  1779. {
  1780. //
  1781. // 1st byte 0x01 tells us it's a PPP connection
  1782. //
  1783. if ((((PBYTE)HdrBuf)[0] == PPP_ID_BYTE1) &&
  1784. (((PBYTE)HdrBuf)[1] == PPP_ID_BYTE2))
  1785. {
  1786. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1787. DBGDUMPBYTES("Packet from PPP client:", (PBYTE)LkBuf,LkBufSize,4);
  1788. if (AtalkReferenceDefaultPort())
  1789. {
  1790. AtalkDdpPacketIn(AtalkDefaultPort, // came on which port
  1791. NULL, // Link Hdr
  1792. (PBYTE)LkBuf, // packet
  1793. (USHORT)LkBufSize, // how big is the pkt
  1794. TRUE); // did this come on WAN?
  1795. AtalkPortDereference(AtalkDefaultPort);
  1796. }
  1797. }
  1798. //
  1799. // this is ARAP connection: lot of stuff to be done before pkt
  1800. // can be given to the right destination...
  1801. //
  1802. else
  1803. {
  1804. ASSERT ((((PBYTE)HdrBuf)[0] == ARAP_ID_BYTE1) &&
  1805. (((PBYTE)HdrBuf)[1] == ARAP_ID_BYTE2));
  1806. *((ULONG UNALIGNED *)(&pArapConn)) =
  1807. *((ULONG UNALIGNED *)(&((PBYTE)HdrBuf)[2]));
  1808. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1809. ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
  1810. //
  1811. // NDISWAN guarantees that all the data is in the LookAhead buffer
  1812. //
  1813. ArapRcvIndication( pArapConn,
  1814. LkBuf,
  1815. LkBufSize );
  1816. }
  1817. }
  1818. break;
  1819. default:
  1820. // Should never happen!
  1821. DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_FATAL,
  1822. ("AtalkReceiveIndication: Unknown media\n"));
  1823. ASSERT(0);
  1824. ndisStatus = NDIS_STATUS_NOT_RECOGNIZED;
  1825. break;
  1826. }
  1827. // we have already taken care of the Wan case: quit here
  1828. if (Media == NdisMediumWan)
  1829. {
  1830. break;
  1831. }
  1832. //
  1833. // if pkt not interesting, quit., if this is ras adapter, quit
  1834. //
  1835. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1836. {
  1837. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1838. break;
  1839. }
  1840. INTERLOCKED_INCREMENT_LONG_DPC(
  1841. &pPortDesc->pd_PortStats.prtst_NumPacketsIn,
  1842. &AtalkStatsLock.SpinLock);
  1843. INTERLOCKED_ADD_STATISTICS(&pPortDesc->pd_PortStats.prtst_DataIn,
  1844. (LONG)actualPktSize,
  1845. &AtalkStatsLock.SpinLock);
  1846. ASSERT ((protocol == APPLETALK_PROTOCOL) || (protocol == AARP_PROTOCOL));
  1847. // At this point, the IEEE802.2 header has been skipped in the lookahead
  1848. // buffer.
  1849. // Packet is to be accepted! Get an appropriate buffer and set the
  1850. // fields.
  1851. switch (protocol)
  1852. {
  1853. case APPLETALK_PROTOCOL:
  1854. // We either need to receive this packet on the default port, or
  1855. // we must be a router.
  1856. if ((pPortDesc == AtalkDefaultPort) || AtalkRouter)
  1857. {
  1858. if (shortDdpHdr)
  1859. {
  1860. // Check to see if we can indicate this to ATP/ADSP.
  1861. if ((((PBYTE)LkBuf)[SDDP_PROTO_TYPE_OFFSET] == DDPPROTO_ATP) &&
  1862. ((USHORT)(LkBufSize - xferOffset) >= (SDDP_HDR_LEN + ATP_HEADER_SIZE)))
  1863. {
  1864. indicate = INDICATE_ATP;
  1865. }
  1866. }
  1867. else
  1868. {
  1869. // Check to see if we can indicate this to ATP/ADSP.
  1870. if ((((PBYTE)LkBuf)[LDDP_PROTO_TYPE_OFFSET] == DDPPROTO_ATP) &&
  1871. ((USHORT)(LkBufSize - xferOffset) >= (LDDP_HDR_LEN + ATP_HEADER_SIZE)))
  1872. {
  1873. indicate = INDICATE_ATP;
  1874. }
  1875. }
  1876. }
  1877. // First check for optimizing ATP/ADSP packets.
  1878. if (indicate == INDICATE_ATP)
  1879. {
  1880. error = AtalkIndAtpPkt(pPortDesc,
  1881. (PBYTE)LkBuf,
  1882. (USHORT)(PktSize - xferOffset),
  1883. &xferOffset, // IN/OUT parameter
  1884. HdrBuf,
  1885. shortDdpHdr,
  1886. &subType,
  1887. &packet,
  1888. &ndisPkt);
  1889. if (ATALK_SUCCESS(error))
  1890. {
  1891. break;
  1892. }
  1893. else if (error == ATALK_INVALID_PKT)
  1894. {
  1895. // This indicates that the indication code has figured out that
  1896. // the packet is bad.
  1897. break;
  1898. }
  1899. else
  1900. {
  1901. // This is the case where the indication code cannot figure out
  1902. // if this packet qualifies.
  1903. indicate = 0;
  1904. error = ATALK_NO_ERROR;
  1905. }
  1906. }
  1907. if (actualPktSize > (sizeof(DDP_SMBUFFER) - sizeof(BUFFER_HDR)))
  1908. {
  1909. pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_DDPLG);
  1910. }
  1911. else
  1912. {
  1913. pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_DDPSM);
  1914. }
  1915. break;
  1916. case AARP_PROTOCOL:
  1917. pBufferHdr = (PBUFFER_HDR)AtalkBPAllocBlock(BLKID_AARP);
  1918. break;
  1919. default:
  1920. KeBugCheck(0);
  1921. break;
  1922. }
  1923. if (!ATALK_SUCCESS(error) || ((pBufferHdr == NULL) && (indicate == 0)))
  1924. {
  1925. #if DBG
  1926. UINT i;
  1927. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  1928. ("AtalkReceiveIndication: Dropping packet (2) %ld\n", error));
  1929. for (i = 0; i < HdrBufSize; i++)
  1930. DBGPRINTSKIPHDR(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  1931. ("%02x ", ((PUCHAR)HdrBuf)[i]));
  1932. for (i = 0; i < LkBufSize; i++)
  1933. DBGPRINTSKIPHDR(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  1934. ("%02x ", ((PUCHAR)LkBuf)[i]));
  1935. #endif
  1936. // No logging in this critical path.
  1937. // LOG_ERRORONPORT(pPortDesc,
  1938. // EVENT_ATALK_AARPPACKET,
  1939. // actualPktSize,
  1940. // HdrBuf,
  1941. // HdrBufSize);
  1942. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1943. if (error != ATALK_DUP_PKT)
  1944. {
  1945. INTERLOCKED_INCREMENT_LONG_DPC(
  1946. &pPortDesc->pd_PortStats.prtst_NumPktDropped,
  1947. &AtalkStatsLock.SpinLock);
  1948. }
  1949. ndisStatus = NDIS_STATUS_RESOURCES;
  1950. break;
  1951. }
  1952. if (indicate == 0)
  1953. {
  1954. packet = (PBYTE)pBufferHdr + sizeof(BUFFER_HDR);
  1955. // Get a pointer to the NDIS packet descriptor from the buffer header.
  1956. ndisPkt = pBufferHdr->bh_NdisPkt;
  1957. }
  1958. protocolResd = (PPROTOCOL_RESD)(ndisPkt->ProtocolReserved);
  1959. // Store the information needed in the packet descriptor
  1960. protocolResd->Receive.pr_Port = pPortDesc;
  1961. protocolResd->Receive.pr_Protocol = protocol;
  1962. protocolResd->Receive.pr_Processed = FALSE;
  1963. // Queue up the packet in the receive queue on this port
  1964. // Then, go ahead with the transfer data etc. For Atp response
  1965. // case when SubType == ATP_USER_BUFX, we do not want any
  1966. // Recv. completion processing, do not queue. In this case
  1967. // TransferData completion frees up the Ndis resources.
  1968. if ((indicate != INDICATE_ATP) ||
  1969. (protocolResd->Receive.pr_OptimizeSubType != ATP_USER_BUFX))
  1970. {
  1971. ATALK_RECV_INDICATION_COPY(pPortDesc,
  1972. protocolResd->Receive.pr_LinkHdr,
  1973. (PBYTE)HdrBuf,
  1974. HdrBufSize);
  1975. InsertTailList(&pPortDesc->pd_ReceiveQueue,
  1976. &protocolResd->Receive.pr_Linkage);
  1977. }
  1978. else
  1979. {
  1980. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  1981. ("AtalkReceiveIndication: Skipping link hdr !!!\n"));
  1982. }
  1983. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  1984. #ifdef PROFILING
  1985. INTERLOCKED_INCREMENT_LONG_DPC(
  1986. &pPortDesc->pd_PortStats.prtst_CurReceiveQueue,
  1987. &AtalkStatsLock.SpinLock);
  1988. #endif
  1989. // Adjust for the link header size. Set size in protocol reserved. We want
  1990. // to avoid changing the size described by the NDIS buffer descriptor.
  1991. if (indicate == 0)
  1992. {
  1993. actualPktSize -= HdrBufSize;
  1994. protocolResd->Receive.pr_DataLength = (USHORT)actualPktSize;
  1995. }
  1996. else
  1997. {
  1998. actualPktSize = protocolResd->Receive.pr_DataLength;
  1999. }
  2000. ASSERT(ndisStatus == NDIS_STATUS_SUCCESS);
  2001. if ((PktSize <= LkBufSize) &&
  2002. ((indicate != INDICATE_ATP) || (subType != ATP_RESPONSE)))
  2003. {
  2004. // LkBuf has already been advanced to skip the ieee 802.2 header.
  2005. // We may need to skip more. Use the original lkbuf and xfer offset.
  2006. ATALK_RECV_INDICATION_COPY(pPortDesc,
  2007. packet,
  2008. (PBYTE)lkBufOrig + xferOffset,
  2009. actualPktSize);
  2010. bytesTransferred = actualPktSize;
  2011. }
  2012. else
  2013. {
  2014. // Skip 802.2 header (both AARP and Appletalk), localtalk doesnt have one!
  2015. if (actualPktSize > 0)
  2016. {
  2017. NdisTransferData(&ndisStatus,
  2018. pPortDesc->pd_NdisBindingHandle,
  2019. ReceiveCtx,
  2020. xferOffset,
  2021. actualPktSize,
  2022. ndisPkt,
  2023. &bytesTransferred);
  2024. ASSERT(bytesTransferred == actualPktSize);
  2025. }
  2026. }
  2027. if (ndisStatus == NDIS_STATUS_PENDING)
  2028. {
  2029. ndisStatus = NDIS_STATUS_SUCCESS;
  2030. }
  2031. else
  2032. {
  2033. // Transfer data completed, call the transfer data completion
  2034. // routine to do rest of the work. If an error happened, ReceiveCompletion
  2035. // will drop the packet.
  2036. protocolResd->Receive.pr_ReceiveStatus = ndisStatus;
  2037. protocolResd->Receive.pr_Processed = TRUE;
  2038. // In case of intermediate Atp response, the packet is not actually linked
  2039. // into the receive queue, just free it.
  2040. if ((protocolResd->Receive.pr_OptimizeType == INDICATE_ATP) &&
  2041. (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUFX))
  2042. {
  2043. PNDIS_BUFFER ndisBuffer;
  2044. // Free NDIS buffers if any are present.
  2045. NdisUnchainBufferAtFront(ndisPkt, &ndisBuffer);
  2046. if (ndisBuffer != NULL)
  2047. {
  2048. AtalkNdisFreeBuffer(ndisBuffer);
  2049. }
  2050. NdisDprFreePacket(ndisPkt);
  2051. }
  2052. }
  2053. } while (FALSE);
  2054. #ifdef PROFILING
  2055. TimeE = KeQueryPerformanceCounter(NULL);
  2056. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  2057. INTERLOCKED_ADD_LARGE_INTGR_DPC(&pPortDesc->pd_PortStats.prtst_RcvIndProcessTime,
  2058. TimeD,
  2059. &AtalkStatsLock.SpinLock);
  2060. INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_RcvIndCount,
  2061. &AtalkStatsLock.SpinLock);
  2062. #endif
  2063. return ndisStatus;
  2064. }
  2065. VOID
  2066. AtalkTransferDataComplete(
  2067. IN NDIS_HANDLE BindingCtx,
  2068. IN PNDIS_PACKET NdisPkt,
  2069. IN NDIS_STATUS Status,
  2070. IN UINT BytesTransferred
  2071. )
  2072. /*++
  2073. Routine Description:
  2074. This routine is called by NDIS to indicate completion of a TransferData
  2075. Arguments:
  2076. BindingCtx- Pointer to a port descriptor for this port
  2077. NdisPkt- Ndis packet into which data was transferred
  2078. Status- Status of request
  2079. bytesTransferred- Actual number of bytes transferred
  2080. Return Value:
  2081. None
  2082. --*/
  2083. {
  2084. PPROTOCOL_RESD protocolResd;
  2085. PNDIS_BUFFER ndisBuffer;
  2086. protocolResd = (PPROTOCOL_RESD)(NdisPkt->ProtocolReserved);
  2087. protocolResd->Receive.pr_ReceiveStatus = Status;
  2088. protocolResd->Receive.pr_Processed = TRUE;
  2089. // In case of intermediate Atp response, the packet is not actually linked
  2090. // into the receive queue, just free it.
  2091. if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUFX)
  2092. {
  2093. // Free NDIS buffers if any are present.
  2094. NdisUnchainBufferAtFront(NdisPkt, &ndisBuffer);
  2095. if (ndisBuffer != NULL)
  2096. {
  2097. AtalkNdisFreeBuffer(ndisBuffer);
  2098. }
  2099. NdisDprFreePacket(NdisPkt);
  2100. }
  2101. }
  2102. VOID
  2103. AtalkReceiveComplete(
  2104. IN NDIS_HANDLE BindingCtx
  2105. )
  2106. /*++
  2107. Routine Description:
  2108. We experimented with queueing up a work item for receive completion. It really
  2109. KILLED performance with multiple clients as apparently the receive completion
  2110. kept getting interrupted with receive indications. AS the optimization was
  2111. put in for slow cards like the ELNKII which do not have adequate buffering,
  2112. we decided to take it out. The retry values (or timeout trimming) should be
  2113. enough for the slow cards. They will inevitably drop packets.
  2114. Arguments:
  2115. Return Value:
  2116. --*/
  2117. {
  2118. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)BindingCtx;
  2119. PPROTOCOL_RESD protocolResd;
  2120. PNDIS_PACKET ndisPkt;
  2121. PNDIS_BUFFER ndisBuffer;
  2122. PBUFFER_HDR pBufHdr;
  2123. NDIS_MEDIUM Media;
  2124. PLIST_ENTRY p;
  2125. PBYTE packet;
  2126. LOGICAL_PROTOCOL protocol;
  2127. UINT packetLength;
  2128. BOOLEAN fDerefDefPort=FALSE;
  2129. #ifdef PROFILING
  2130. TIME TimeS, TimeE, TimeD;
  2131. #endif
  2132. if (pPortDesc->pd_Flags & PD_RAS_PORT)
  2133. {
  2134. // give ARAP guys a chance
  2135. ArapRcvComplete();
  2136. if (!AtalkReferenceDefaultPort())
  2137. {
  2138. return;
  2139. }
  2140. fDerefDefPort = TRUE;
  2141. // give PPP guys a chance
  2142. pPortDesc = AtalkDefaultPort;
  2143. }
  2144. // Get the stuff off the receive queue for the port and send it up. Do not
  2145. // enter if the queue is initially empty.
  2146. if (IsListEmpty(&pPortDesc->pd_ReceiveQueue))
  2147. {
  2148. if (fDerefDefPort)
  2149. {
  2150. AtalkPortDereference(AtalkDefaultPort);
  2151. }
  2152. return;
  2153. }
  2154. #ifdef PROFILING
  2155. TimeS = KeQueryPerformanceCounter(NULL);
  2156. #endif
  2157. while (TRUE)
  2158. {
  2159. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2160. p = pPortDesc->pd_ReceiveQueue.Flink;
  2161. if (p == &pPortDesc->pd_ReceiveQueue)
  2162. {
  2163. // Queue is empty
  2164. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2165. break;
  2166. }
  2167. ndisPkt = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved[0]);
  2168. protocolResd = (PPROTOCOL_RESD)(ndisPkt->ProtocolReserved);
  2169. // Check if the queued receive is done processing. Since we are looping
  2170. // through the queue and since receive complete only checks if the first
  2171. // is done, we need this check here for subsequent queued up receives.
  2172. if (!protocolResd->Receive.pr_Processed)
  2173. {
  2174. // Queue is empty
  2175. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2176. break;
  2177. }
  2178. // Dequeue and indicate this packet to the ddp/atp layer
  2179. p = RemoveHeadList(&pPortDesc->pd_ReceiveQueue);
  2180. pBufHdr = protocolResd->Receive.pr_BufHdr;
  2181. RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
  2182. #ifdef PROFILING
  2183. INTERLOCKED_DECREMENT_LONG_DPC(
  2184. &pPortDesc->pd_PortStats.prtst_CurReceiveQueue,
  2185. &AtalkStatsLock.SpinLock);
  2186. #endif
  2187. Media = pPortDesc->pd_NdisPortType;
  2188. protocol = protocolResd->Receive.pr_Protocol;
  2189. if ((protocol == APPLETALK_PROTOCOL) &&
  2190. (protocolResd->Receive.pr_OptimizeType == INDICATE_ATP))
  2191. {
  2192. protocolResd->Receive.pr_OptimizeType = 0;
  2193. ASSERT(protocolResd->Receive.pr_OptimizeSubType != ATP_USER_BUFX);
  2194. // Check the receive status- accept only if ok
  2195. if (protocolResd->Receive.pr_ReceiveStatus == NDIS_STATUS_SUCCESS)
  2196. {
  2197. // Glean information. Check for route info if tokenring network.
  2198. if (Media != NdisMediumLocalTalk)
  2199. {
  2200. AtalkAarpOptGleanInfo(pPortDesc,
  2201. protocolResd->Receive.pr_LinkHdr,
  2202. &protocolResd->Receive.pr_SrcAddr,
  2203. &protocolResd->Receive.pr_DestAddr,
  2204. protocolResd->Receive.pr_OffCablePkt);
  2205. }
  2206. // Different calls for response & non-response packets.
  2207. if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUF)
  2208. {
  2209. AtalkAtpPacketIn(AtalkDefaultPort,
  2210. protocolResd->Receive.pr_AtpAddrObj->atpao_DdpAddr,
  2211. protocolResd->Receive.pr_AtpHdr,
  2212. (USHORT)(protocolResd->Receive.pr_DataLength + 8),
  2213. &protocolResd->Receive.pr_SrcAddr,
  2214. &protocolResd->Receive.pr_DestAddr,
  2215. ATALK_NO_ERROR,
  2216. DDPPROTO_ATP,
  2217. protocolResd->Receive.pr_AtpAddrObj,
  2218. TRUE,
  2219. protocolResd->Receive.pr_OptimizeCtx);
  2220. }
  2221. else
  2222. {
  2223. ASSERT (protocolResd->Receive.pr_OptimizeSubType == ATP_ALLOC_BUF);
  2224. packet = (PBYTE)pBufHdr + sizeof(BUFFER_HDR);
  2225. ASSERT(packet != NULL);
  2226. AtalkAtpPacketIn(AtalkDefaultPort,
  2227. protocolResd->Receive.pr_AtpAddrObj->atpao_DdpAddr,
  2228. packet,
  2229. (USHORT)protocolResd->Receive.pr_DataLength,
  2230. &protocolResd->Receive.pr_SrcAddr,
  2231. &protocolResd->Receive.pr_DestAddr,
  2232. ATALK_NO_ERROR,
  2233. DDPPROTO_ATP,
  2234. protocolResd->Receive.pr_AtpAddrObj,
  2235. TRUE,
  2236. protocolResd->Receive.pr_OptimizeCtx);
  2237. }
  2238. }
  2239. // Different calls for user buffer/allocated packets
  2240. if (protocolResd->Receive.pr_OptimizeSubType == ATP_USER_BUF)
  2241. {
  2242. // Free NDIS buffers if any are present.
  2243. NdisUnchainBufferAtFront(ndisPkt, &ndisBuffer);
  2244. if (ndisBuffer != NULL)
  2245. {
  2246. AtalkNdisFreeBuffer(ndisBuffer);
  2247. }
  2248. NdisDprFreePacket(ndisPkt);
  2249. }
  2250. else
  2251. {
  2252. AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
  2253. }
  2254. continue;
  2255. }
  2256. // IMPORTANT:
  2257. // We know that the buffer is virtually contiguous since we allocated
  2258. // it. And we also know that only one buffer is allocated. So we use
  2259. // that knowledge to get the actual address and pass that onto the
  2260. // higher level routines.
  2261. // !!!!
  2262. // Although, the allocated buffer contains the link header tagged on at
  2263. // the end, we do not have the packet descriptor describing that. As
  2264. // far as we are concerned here, that tagged entity does not exist and
  2265. // is independently pointed to by protocolResd->pr_LinkHdr.
  2266. // !!!!
  2267. packet = (PBYTE)pBufHdr + sizeof(BUFFER_HDR);
  2268. ASSERT(packet != NULL);
  2269. packetLength = protocolResd->Receive.pr_DataLength;
  2270. // Check the receive status- accept only if ok
  2271. if (protocolResd->Receive.pr_ReceiveStatus != NDIS_STATUS_SUCCESS)
  2272. {
  2273. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2274. ("AtalkReceiveComplete: ReceiveStatus FAILURE %lx!\n",
  2275. protocolResd->Receive.pr_ReceiveStatus));
  2276. AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
  2277. continue;
  2278. }
  2279. // The packet descriptor is now associate with the buffer, and we cant
  2280. // release the buffer (and hence the descriptor) until after we indicate to
  2281. // the higher levels
  2282. switch (Media)
  2283. {
  2284. case NdisMedium802_3 :
  2285. case NdisMediumFddi :
  2286. case NdisMedium802_5 :
  2287. case NdisMediumLocalTalk :
  2288. if (protocol == APPLETALK_PROTOCOL)
  2289. {
  2290. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
  2291. ("AtalkReceiveComplete: Indicating DDP Ethernet\n"));
  2292. AtalkDdpPacketIn(pPortDesc,
  2293. protocolResd->Receive.pr_LinkHdr,
  2294. packet,
  2295. (USHORT)packetLength,
  2296. FALSE);
  2297. }
  2298. else
  2299. {
  2300. // AARP Packet
  2301. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_INFO,
  2302. ("AtalkReceiveComplete: Indicating AARP Ethernet\n"));
  2303. ASSERT(Media != NdisMediumLocalTalk);
  2304. AtalkAarpPacketIn(pPortDesc,
  2305. protocolResd->Receive.pr_LinkHdr,
  2306. packet,
  2307. (USHORT)packetLength);
  2308. }
  2309. break;
  2310. default:
  2311. KeBugCheck(0);
  2312. break;
  2313. }
  2314. // !!!!
  2315. // We dont have to free the link header. This follows the packet
  2316. // buffer (and was allocated along with it) and will be freed when
  2317. // the packet is freed.
  2318. AtalkBPFreeBlock(packet-sizeof(BUFFER_HDR));
  2319. }
  2320. if (fDerefDefPort)
  2321. {
  2322. AtalkPortDereference(AtalkDefaultPort);
  2323. }
  2324. #ifdef PROFILING
  2325. TimeE = KeQueryPerformanceCounter(NULL);
  2326. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  2327. INTERLOCKED_ADD_LARGE_INTGR_DPC(
  2328. &pPortDesc->pd_PortStats.prtst_RcvCompProcessTime,
  2329. TimeD,
  2330. &AtalkStatsLock.SpinLock);
  2331. INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_RcvCompCount,
  2332. &AtalkStatsLock.SpinLock);
  2333. #endif
  2334. }
  2335. VOID
  2336. AtalkSendComplete(
  2337. IN NDIS_HANDLE ProtoBindCtx,
  2338. IN PNDIS_PACKET NdisPkt,
  2339. IN NDIS_STATUS NdisStatus
  2340. )
  2341. /*++
  2342. Routine Description:
  2343. Arguments:
  2344. ProtoBindCtx- Binding associated with mac
  2345. NdisPkt- Packet which was sent
  2346. NdisStatus- Final status of send
  2347. Return Value:
  2348. None
  2349. --*/
  2350. {
  2351. PPROTOCOL_RESD pProtocolResd;
  2352. PNDIS_BUFFER pNdisBuffer=NULL, pNdisFirstBuffer=NULL;
  2353. PPORT_DESCRIPTOR pPortDesc;
  2354. PBUFFER_DESC pBufferDesc;
  2355. SEND_COMPLETION pSendComp;
  2356. SEND_COMPL_INFO sendInfo;
  2357. // Call the completion routine, we don't care about status now
  2358. pProtocolResd = (PPROTOCOL_RESD)(NdisPkt->ProtocolReserved);
  2359. ASSERT(pProtocolResd != NULL);
  2360. pPortDesc = pProtocolResd->Send.pr_Port;
  2361. sendInfo = pProtocolResd->Send.pr_SendInfo;
  2362. pBufferDesc = pProtocolResd->Send.pr_BufferDesc;
  2363. pSendComp = pProtocolResd->Send.pr_SendCompletion;
  2364. // We free up all the ndis buffer descriptors except the first one.
  2365. // NOTE: The presence of a second buffer descriptor indicates that more
  2366. // than one NdisBuffer is present. But not necessarily just two. If
  2367. // the client had passed in a MDL chain, we would create a corresponding
  2368. // NDIS buffer descriptor chain. Therefore, remove the first, free up
  2369. // all remaining ones, then queue back the first.
  2370. NdisUnchainBufferAtFront(NdisPkt, &pNdisFirstBuffer);
  2371. if (pProtocolResd->Send.pr_BufferDesc->bd_Next != NULL)
  2372. {
  2373. while (TRUE)
  2374. {
  2375. NdisUnchainBufferAtBack(NdisPkt,
  2376. &pNdisBuffer);
  2377. if (pNdisBuffer == NULL)
  2378. {
  2379. break;
  2380. }
  2381. // Free up the ndis buffer descriptor.
  2382. AtalkNdisFreeBuffer(pNdisBuffer);
  2383. }
  2384. }
  2385. // Reintialize the packet descriptor.
  2386. NdisReinitializePacket(NdisPkt);
  2387. // Put first buffer back in.
  2388. if (pNdisFirstBuffer != NULL)
  2389. {
  2390. NdisChainBufferAtFront(NdisPkt, pNdisFirstBuffer);
  2391. }
  2392. // Call the completion routine for the transmit. This invalidates NdisPkt.
  2393. if (pSendComp)
  2394. {
  2395. (*pSendComp)(NdisStatus, pBufferDesc, &sendInfo);
  2396. }
  2397. // Dereference the port
  2398. ASSERT(pPortDesc != NULL);
  2399. #ifdef PROFILING
  2400. INTERLOCKED_DECREMENT_LONG(
  2401. &pPortDesc->pd_PortStats.prtst_CurSendsOutstanding,
  2402. &AtalkStatsLock.SpinLock);
  2403. #endif
  2404. }
  2405. VOID
  2406. AtalkBindAdapter(
  2407. OUT PNDIS_STATUS Status,
  2408. IN NDIS_HANDLE BindContext,
  2409. IN PNDIS_STRING DeviceName,
  2410. IN PVOID SystemSpecific1,
  2411. IN PVOID SystemSpecific2
  2412. )
  2413. {
  2414. // are we unloading? if so, just return
  2415. if (AtalkBindnUnloadStates & ATALK_UNLOADING)
  2416. {
  2417. DBGPRINT(DBG_COMP_NDISRECV, DBG_LEVEL_ERR,
  2418. ("AtalkBindAdapter: nothing to do: driver unloading\n"));
  2419. return;
  2420. }
  2421. AtalkBindnUnloadStates |= ATALK_BINDING;
  2422. AtalkLockInitIfNecessary();
  2423. *Status = AtalkInitAdapter(DeviceName, NULL);
  2424. ASSERT(*Status != NDIS_STATUS_PENDING);
  2425. AtalkUnlockInitIfNecessary();
  2426. AtalkBindnUnloadStates &= ~ATALK_BINDING;
  2427. }
  2428. VOID
  2429. AtalkUnbindAdapter(
  2430. OUT PNDIS_STATUS Status,
  2431. IN NDIS_HANDLE ProtocolBindingContext,
  2432. IN NDIS_HANDLE UnbindContext
  2433. )
  2434. {
  2435. PPORT_DESCRIPTOR pPortDesc = (PPORT_DESCRIPTOR)ProtocolBindingContext;
  2436. DBGPRINT(DBG_COMP_ACTION, DBG_LEVEL_ERR,
  2437. ("AtalkUnbindAdapter on %lx\n",ProtocolBindingContext));
  2438. ASSERT( VALID_PORT(pPortDesc) );
  2439. AtalkLockInitIfNecessary();
  2440. // First and foremost: tell guys above so they can cleanup
  2441. if ((pPortDesc->pd_Flags & PD_DEF_PORT) ||
  2442. (pPortDesc->pd_Flags & PD_RAS_PORT))
  2443. {
  2444. if (pPortDesc->pd_Flags & PD_DEF_PORT)
  2445. {
  2446. ASSERT(pPortDesc == AtalkDefaultPort);
  2447. if (TdiAddressChangeRegHandle)
  2448. {
  2449. TdiDeregisterNetAddress(TdiAddressChangeRegHandle);
  2450. TdiAddressChangeRegHandle = NULL;
  2451. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  2452. ("AtalkUnbindAdapter: TdiDeregisterNetAddress on %Z done\n",
  2453. &pPortDesc->pd_AdapterName));
  2454. }
  2455. // this will tell AFP
  2456. if (TdiRegistrationHandle)
  2457. {
  2458. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  2459. ("AtalkUnbindAdapter: default adapter unbound, telling AFP, RAS\n"));
  2460. TdiDeregisterDeviceObject(TdiRegistrationHandle);
  2461. TdiRegistrationHandle = NULL;
  2462. }
  2463. }
  2464. else
  2465. {
  2466. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  2467. ("AtalkUnbindAdapter: RAS adapter unbound! telling AFP, RAS\n"));
  2468. }
  2469. // this will take care of informing ARAP and PPP engine above
  2470. AtalkPnPInformRas(FALSE);
  2471. }
  2472. *Status = AtalkDeinitAdapter(pPortDesc);
  2473. ASSERT(*Status != NDIS_STATUS_PENDING);
  2474. AtalkUnlockInitIfNecessary();
  2475. }