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.

1091 lines
31 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems Ab
  4. Module Name:
  5. llclink.c
  6. Abstract:
  7. The module implements the open, connect and close primitives
  8. for a link station object. The link stations have also been
  9. initialized within this module.
  10. Contents:
  11. LlcOpenLinkStation
  12. LlcConnectStation
  13. InitiateAsyncLinkCommand
  14. LlcDisconnectStation
  15. LlcFlowControl
  16. LinkFlowControl
  17. SearchLinkAddress
  18. SetLinkParameters
  19. CheckLinkParameters
  20. CopyLinkParameters
  21. CopyNonZeroBytes
  22. RunInterlockedStateMachineCommand
  23. Author:
  24. Antti Saarenheimo (o-anttis) 28-MAY-1991
  25. Revision History:
  26. --*/
  27. #include <llc.h>
  28. DLC_STATUS
  29. LlcOpenLinkStation(
  30. IN PLLC_SAP pSap,
  31. IN UCHAR DestinationSap,
  32. IN PUCHAR pDestinationAddress OPTIONAL,
  33. IN PUCHAR pReceivedLanHeader OPTIONAL,
  34. IN PVOID hClientStation,
  35. OUT PVOID* phLlcHandle
  36. )
  37. /*++
  38. Routine Description:
  39. creates a DATA_LINK structure and fills it in. Called either as a result
  40. of receiving a SABME, or via DLC.OPEN.STATION
  41. This operation is the same as ACTIVATE_LS primitive in IBM TR Arch. ref.
  42. Arguments:
  43. pSap - pointer to SAP
  44. DestinationSap - remote SAP number
  45. pDestinationAddress - remote node address. If this function is being called
  46. as a result of receiving a SABME for a new link then
  47. this parameter is NULL
  48. pReceivedLanHeader - LAN header as received off the wire, containing source
  49. and destination adapter addresses, optional source
  50. routing and source and destination SAPs
  51. hClientStation - handle (address) of LLC client's link station object
  52. phLlcHandle - pointer to returned handle (address) to LLC DATA_LINK
  53. object
  54. Return Value:
  55. DLC_STATUS
  56. Success - STATUS_SUCCESS
  57. link station has been opened successfully
  58. Failure - DLC_STATUS_INVALID_SAP_VALUE
  59. the link station already exists or the SAP is really invalid.
  60. DLC_NO_MEMORY
  61. there was no free preallocated link station
  62. --*/
  63. {
  64. PDATA_LINK pLink;
  65. PDATA_LINK* ppLink;
  66. PADAPTER_CONTEXT pAdapterContext = pSap->Gen.pAdapterContext;
  67. DLC_STATUS LlcStatus = STATUS_SUCCESS;
  68. UINT AddressTranslation;
  69. //
  70. // We need a temporary buffer to build lan header for link,
  71. // because user may use different ndis medium from network.
  72. //
  73. UCHAR auchTempBuffer[32];
  74. ASSUME_IRQL(DISPATCH_LEVEL);
  75. LlcZeroMem(auchTempBuffer, sizeof(auchTempBuffer));
  76. if (pSap->Gen.ObjectType != LLC_SAP_OBJECT) {
  77. return DLC_STATUS_INVALID_SAP_VALUE;
  78. }
  79. ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
  80. ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
  81. pLink = (PDATA_LINK)ALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool);
  82. if (pLink == NULL) {
  83. LlcStatus = DLC_STATUS_NO_MEMORY;
  84. goto ErrorExit;
  85. }
  86. //
  87. // This reference keeps the object alive, until it is dereferenced
  88. // in the delete.
  89. //
  90. ReferenceObject(pLink);
  91. //
  92. // LLC driver have two different address formats:
  93. //
  94. // 1. External format of the binding (ethernet or token-ring,
  95. // DLC driver uses always token-ring format, the ethernet
  96. // support is compiled in conditionally.
  97. //
  98. // 2. Internal send format (always the actual lan type,
  99. // ethernet, dix or tokenring). The user provides link
  100. // address in its own mode and we must build the actual
  101. // lan link header from it.
  102. //
  103. if (pDestinationAddress != NULL) {
  104. //
  105. // link created by DLC.CONNECT.STATION
  106. //
  107. AddressTranslation = pSap->Gen.pLlcBinding->AddressTranslation;
  108. LlcBuildAddress(pSap->Gen.pLlcBinding->NdisMedium,
  109. pDestinationAddress,
  110. NULL,
  111. auchTempBuffer
  112. );
  113. } else {
  114. //
  115. // link created by incoming SABME
  116. //
  117. pLink->Flags |= DLC_ACTIVE_REMOTE_CONNECT_REQUEST;
  118. AddressTranslation = pAdapterContext->AddressTranslationMode;
  119. LlcBuildAddressFromLanHeader(pAdapterContext->NdisMedium,
  120. pReceivedLanHeader,
  121. auchTempBuffer
  122. );
  123. }
  124. //
  125. // We want to use always DIX lan headers in the token-ring case
  126. //
  127. if (AddressTranslation == LLC_SEND_802_5_TO_802_3) {
  128. AddressTranslation = LLC_SEND_802_5_TO_DIX;
  129. } else if (AddressTranslation == LLC_SEND_802_3_TO_802_3) {
  130. AddressTranslation = LLC_SEND_802_3_TO_DIX;
  131. }
  132. //
  133. // Now we can build the actual network header for the sending
  134. // (this same routine build lan header also for all
  135. // other packet types)
  136. //
  137. pLink->cbLanHeaderLength = CopyLanHeader(AddressTranslation,
  138. auchTempBuffer,
  139. pAdapterContext->NodeAddress,
  140. pLink->auchLanHeader,
  141. pAdapterContext->ConfigInfo.SwapAddressBits
  142. );
  143. //
  144. // We always build a DIX header but it is only used when the Ethernet type
  145. // is actually DIX
  146. //
  147. if (pAdapterContext->NdisMedium == NdisMedium802_3
  148. && pSap->Gen.pLlcBinding->EthernetType != LLC_ETHERNET_TYPE_DIX) {
  149. pLink->cbLanHeaderLength = 14;
  150. }
  151. //
  152. // Save the client handle, but reset and initailize everything else.
  153. // The link must be ready for any kind extrnal inputs when
  154. // we will connenct it to the hash table of the link stations.
  155. // (actually that's not true now, because we init the link to
  156. // LINK_CLOSED state, but we may change the state machine.
  157. // It would be a different thing with a 802.2 state machine)
  158. //
  159. pLink->Gen.ObjectType = LLC_LINK_OBJECT;
  160. //
  161. // RLF 07/22/92. The link state should be DISCONNECTED so that we can
  162. // accept incoming SABMEs for this SAP/link station. This is also
  163. // according to IBM LAN Tech. Ref. p. 2-33. It is safe to set the
  164. // DISCONNECTED state now because we have the send and object database
  165. // spin locks, so we can't get interrupted by NDIS driver
  166. //
  167. //
  168. // RLF 08/13/92. Ho Hum. This still isn't correct - we must put the link
  169. // into different states depending on how its being opened - DISCONNECTED
  170. // if the upper layers are creating the link, or LINK_CLOSED if we're
  171. // creating the link as a result of receiving a SABME. Use pReceivedLanHeader
  172. // as a flag: DLC calls this routine with this parameter set to NULL
  173. //
  174. ////pLink->State = LINK_CLOSED;
  175. //pLink->State = DISCONNECTED;
  176. pLink->State = pReceivedLanHeader ? LINK_CLOSED : DISCONNECTED;
  177. //
  178. // RLF 10/01/92. We need some way of knowing that the link station was
  179. // created by receiving a SABME. We need this to decide what to do with
  180. // the source routing info in a subsequent DLC.CONNECT.STATION command.
  181. // This field used to be Reserved
  182. //
  183. pLink->RemoteOpen = hClientStation == NULL;
  184. //
  185. // RLF 05/09/94
  186. //
  187. // We set the framing type to unspecified. This field is only used if the
  188. // adapter was opened in AUTO mode. It will be set to 802.3 or DIX by the
  189. // SABME received processing (new link created by remote station) or when
  190. // the first UA is received in response to the 2 SABMEs we send out (802.3
  191. // and DIX)
  192. //
  193. pLink->FramingType = (ULONG)LLC_SEND_UNSPECIFIED;
  194. pLink->Gen.hClientHandle = hClientStation;
  195. pLink->Gen.pAdapterContext = pAdapterContext;
  196. pLink->pSap = pSap;
  197. pLink->Gen.pLlcBinding = pSap->Gen.pLlcBinding;
  198. //
  199. // Save the node addresses used in link station
  200. //
  201. pDestinationAddress = pLink->auchLanHeader;
  202. if (pAdapterContext->NdisMedium == NdisMedium802_5) {
  203. pDestinationAddress += 2;
  204. } else if (pAdapterContext->NdisMedium == NdisMediumFddi) {
  205. ++pDestinationAddress;
  206. }
  207. memcpy(pLink->LinkAddr.Node.auchAddress, pDestinationAddress, 6);
  208. //
  209. // RLF 03/24/93
  210. //
  211. // if we're talking Ethernet or DIX, we need to report the bit-flipped
  212. // address at the DLC interface
  213. //
  214. SwapMemCpy((BOOLEAN)((AddressTranslation == LLC_SEND_802_3_TO_DIX)
  215. || (pAdapterContext->NdisMedium == NdisMediumFddi)),
  216. pLink->DlcStatus.auchRemoteNode,
  217. pDestinationAddress,
  218. 6
  219. );
  220. //
  221. // Four different local saps: my code would need a cleanup
  222. // (four bytes doesn't use very much memory on the other hand)
  223. //
  224. pLink->LinkAddr.Address.DestSap = pLink->DlcStatus.uchRemoteSap = pLink->Dsap = DestinationSap;
  225. pLink->LinkAddr.Address.SrcSap = pLink->DlcStatus.uchLocalSap = pLink->Ssap = (UCHAR)pSap->SourceSap;
  226. pLink->DlcStatus.hLlcLinkStation = (PVOID)pLink;
  227. pLink->SendQueue.pObject = pLink;
  228. InitializeListHead(&pLink->SendQueue.ListHead);
  229. InitializeListHead(&pLink->SentQueue);
  230. pLink->Flags |= DLC_SEND_DISABLED;
  231. //
  232. // The next procedure returns the pointer of the slot for the
  233. // new link station pointer. The address may be in the
  234. // hash table or it may be the address of pRigth or pLeft
  235. // field within another link station structure.
  236. //
  237. ppLink = SearchLinkAddress(pAdapterContext, pLink->LinkAddr);
  238. //
  239. // this link station must not yet be in the table
  240. // of active link stations. If its slot is
  241. // empty, then save the new link station to the
  242. // list of the active link stations.
  243. //
  244. if (*ppLink != NULL) {
  245. LlcStatus = DLC_STATUS_INVALID_SAP_VALUE;
  246. DEALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool, pLink);
  247. } else {
  248. pLink->Gen.pNext = (PLLC_OBJECT)pSap->pActiveLinks;
  249. pSap->pActiveLinks = pLink;
  250. //
  251. // Set the default link parameters,
  252. // Note: This creates the timer ticks. They must
  253. // be deleted with the terminate timer function,
  254. // when the link station is closed.
  255. //
  256. LlcStatus = SetLinkParameters(pLink, (PUCHAR)&pSap->DefaultParameters);
  257. if (LlcStatus != STATUS_SUCCESS) {
  258. //
  259. // We may have been started T1 and T2 timers.
  260. //
  261. TerminateTimer(pAdapterContext, &pLink->T1);
  262. TerminateTimer(pAdapterContext, &pLink->T2);
  263. DEALLOCATE_PACKET_LLC_LNK(pAdapterContext->hLinkPool, pLink);
  264. } else {
  265. //
  266. // N2 is never initilaized by IBM state machine, when
  267. // the link is created by a remote connect request.
  268. // The link can be killed by this combination of state
  269. // transmitions:
  270. // (LINK_OPENED),
  271. // (RNR-r => REMOTE_BUSY),
  272. // (RR-c => CHECKPOINTING)
  273. // (T1 timeout => DISCONNECTED) !!!!!
  274. //
  275. // This will fix the bug in IBM state machine:
  276. //
  277. pLink->P_Ct = pLink->N2;
  278. *ppLink = *phLlcHandle = (PVOID)pLink;
  279. pAdapterContext->ObjectCount++;
  280. }
  281. }
  282. ErrorExit:
  283. RELEASE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
  284. RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
  285. return LlcStatus;
  286. }
  287. VOID
  288. LlcBindLinkStation(
  289. IN PDATA_LINK pStation,
  290. IN PVOID hClientHandle
  291. )
  292. {
  293. pStation->Gen.hClientHandle = hClientHandle;
  294. }
  295. VOID
  296. LlcConnectStation(
  297. IN PDATA_LINK pStation,
  298. IN PLLC_PACKET pPacket,
  299. IN PVOID pSourceRouting OPTIONAL,
  300. IN PUSHORT pusMaxInformationField
  301. )
  302. /*++
  303. Routine Description:
  304. The upper level protocol may call this primitive to initiate
  305. the connection negotiation with a remote link station,
  306. to accept the connection request or to reconnect a link station
  307. that have been disconnected for some reason with a new source
  308. routing information.
  309. The command is completed asynchronously and the status
  310. is returned as an event.
  311. The primitive is the same as SET_ABME primitive in "IBM TR Architecture
  312. reference".
  313. The function implements also CONNECT_REQUEST and CONNECT_RESPONSE
  314. primitives of IEEE 802.2.
  315. Arguments:
  316. pStation - address of link station
  317. pPacket - command completion packet
  318. pSourceRouting - optional source routing information. This must
  319. be NULL if the source routing information is not
  320. used
  321. pusMaxInformationField - the maximum data size possible to use with this
  322. connection. The source routing bridges may
  323. decrease the maximum information field size.
  324. Otherwise the maximum length is used
  325. Return Value:
  326. None.
  327. --*/
  328. {
  329. NDIS_MEDIUM NdisMedium = pStation->Gen.pAdapterContext->NdisMedium;
  330. if (pSourceRouting) {
  331. //
  332. // We first read the destination address from the
  333. // lan header and then extend the source routing
  334. // field in the LAN header of link.
  335. //
  336. if (NdisMedium == NdisMedium802_5) {
  337. //
  338. // RLF 10/01/92. If RemoteOpen is TRUE then the link was opened
  339. // due to receiving a SABME and we ignore the source routing info
  340. // (we already got it from the SABME packet)
  341. //
  342. if (!pStation->RemoteOpen) {
  343. pStation->cbLanHeaderLength = (UCHAR)LlcBuildAddress(
  344. NdisMedium,
  345. &pStation->auchLanHeader[2],
  346. pSourceRouting,
  347. pStation->auchLanHeader
  348. );
  349. }
  350. } else {
  351. pSourceRouting = NULL;
  352. }
  353. }
  354. *pusMaxInformationField = LlcGetMaxInfoField(NdisMedium,
  355. pStation->Gen.pLlcBinding,
  356. pStation->auchLanHeader
  357. );
  358. pStation->MaxIField = *pusMaxInformationField;
  359. pStation->Flags &= ~DLC_ACTIVE_REMOTE_CONNECT_REQUEST;
  360. //
  361. // Activate the link station at first, the remotely connected
  362. // link station is already active and in that case the state
  363. // machine return logical error from ACTIVATE_LS input.
  364. //
  365. RunInterlockedStateMachineCommand(pStation, ACTIVATE_LS);
  366. InitiateAsyncLinkCommand(pStation, pPacket, SET_ABME, LLC_CONNECT_COMPLETION);
  367. }
  368. VOID
  369. InitiateAsyncLinkCommand(
  370. IN PDATA_LINK pLink,
  371. IN PLLC_PACKET pPacket,
  372. IN UINT StateMachineCommand,
  373. IN UINT CompletionCode
  374. )
  375. /*++
  376. Routine Description:
  377. Initiates or removes an LLC link. We have a link station in the DISCONNECTED
  378. state. We are either sending a SABME or DISC
  379. Arguments:
  380. pLink - pointer to LLC link station structure ('object')
  381. pPacket - pointer to packet to use for transmission
  382. StateMachineCommand - command given to the state machine
  383. CompletionCode - completion command type returned asynchronously
  384. Return Value:
  385. None.
  386. --*/
  387. {
  388. PADAPTER_CONTEXT pAdapterContext = pLink->Gen.pAdapterContext;
  389. UINT Status;
  390. //
  391. // link will return an error status if it is already connected.
  392. //
  393. ACQUIRE_SPIN_LOCK(&pAdapterContext->SendSpinLock);
  394. AllocateCompletionPacket(pLink, CompletionCode, pPacket);
  395. //
  396. // After RunStateMachineCommand
  397. // the link may be deleted in any time by an NDIS command completion
  398. // indication (send or receive) => we must not use link after this
  399. //
  400. Status = RunStateMachineCommand(pLink, StateMachineCommand);
  401. //
  402. // IBM state machine does not stop the send process => we
  403. // must do it here we will get a system bug check.
  404. //
  405. if (StateMachineCommand == SET_ADM) {
  406. DisableSendProcess(pLink);
  407. }
  408. //
  409. // disconnect or connect commands may fail, because there are
  410. // not enough memory to allocate packets for them.
  411. // In that case we must complete the command here with an error code.
  412. //
  413. if (Status != STATUS_SUCCESS) {
  414. QueueCommandCompletion((PLLC_OBJECT)pLink, CompletionCode, Status);
  415. }
  416. BackgroundProcessAndUnlock(pAdapterContext);
  417. }
  418. VOID
  419. LlcDisconnectStation(
  420. IN PDATA_LINK pLink,
  421. IN PLLC_PACKET pPacket
  422. )
  423. /*++
  424. Routine Description:
  425. The primtive initiates the disconnection handshaking. The upper
  426. protocol must wait LLC_EVENT_DISCONNECTED event before it can close
  427. the link station. The link station must either be closed or
  428. reconnected after a disconnection event. The DLC driver
  429. disconnects the link only when it is closed.
  430. This operation is the same as SET_ADM primitive in IBM TR Arch. ref.
  431. Arguments:
  432. hStation - link station handle.
  433. hRequestHandle - opaque handle returned when the command completes
  434. Return Value:
  435. None
  436. Complete always asynchronously by calling the
  437. command completion routine.
  438. --*/
  439. {
  440. //
  441. // We don't want send yet another DM, if the link station has
  442. // already disconnected. We don't modify the state machine,
  443. // because the state machine should be as orginal as possible.
  444. //
  445. if (pLink->State == DISCONNECTED) {
  446. pPacket->Data.Completion.CompletedCommand = LLC_DISCONNECT_COMPLETION;
  447. pPacket->Data.Completion.Status = STATUS_SUCCESS;
  448. pLink->Gen.pLlcBinding->pfCommandComplete(
  449. pLink->Gen.pLlcBinding->hClientContext,
  450. pLink->Gen.hClientHandle,
  451. pPacket
  452. );
  453. } else {
  454. InitiateAsyncLinkCommand(
  455. pLink,
  456. pPacket,
  457. SET_ADM,
  458. LLC_DISCONNECT_COMPLETION
  459. );
  460. }
  461. }
  462. DLC_STATUS
  463. LlcFlowControl(
  464. IN PLLC_OBJECT pStation,
  465. IN UCHAR FlowControlState
  466. )
  467. /*++
  468. Routine Description:
  469. The primitive sets or resets the local busy state of a single
  470. link station or all link stations of a sap.
  471. The routine also maintains the local busy user
  472. and local busy buffer states, that are returned in link station
  473. status query, because the IBM state machine support only one buffer
  474. busy state.
  475. Arguments:
  476. pStation - link station handle.
  477. FlowControlState - new flow control command bits set for the link station.
  478. The parameter is a bit field:
  479. 0 => Sets LOCAL_BUSY_USER state
  480. 0x80 => resets LOCAL_BUSY_USER state
  481. 0x40 => resets LOCAL_BUSY_BUFFER state
  482. 0xC0 => resets both local busy states
  483. Return Value:
  484. STATUS_SUCCESS
  485. --*/
  486. {
  487. PDATA_LINK pLink;
  488. UINT Status = STATUS_SUCCESS;
  489. PADAPTER_CONTEXT pAdapterContext = pStation->Gen.pAdapterContext;
  490. ASSUME_IRQL(DISPATCH_LEVEL);
  491. //
  492. // We must prevent any LLC object to be deleted, while we
  493. // are updating the flow control states
  494. //
  495. ACQUIRE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
  496. if (pStation->Gen.ObjectType != LLC_LINK_OBJECT) {
  497. if (pStation->Gen.ObjectType == LLC_SAP_OBJECT) {
  498. for (pLink = pStation->Sap.pActiveLinks;
  499. pLink != NULL;
  500. pLink = (PDATA_LINK)pLink->Gen.pNext) {
  501. Status |= LinkFlowControl(pLink, FlowControlState);
  502. }
  503. } else {
  504. Status = DLC_STATUS_INVALID_STATION_ID;
  505. }
  506. } else {
  507. Status = LinkFlowControl((PDATA_LINK)pStation, FlowControlState);
  508. }
  509. RELEASE_SPIN_LOCK(&pAdapterContext->ObjectDataBase);
  510. BackgroundProcess(pAdapterContext);
  511. return Status;
  512. }
  513. DLC_STATUS
  514. LinkFlowControl(
  515. IN PDATA_LINK pLink,
  516. IN UCHAR FlowControlState
  517. )
  518. /*++
  519. Routine Description:
  520. The primitive sets or resets the local busy state for a
  521. single link. The routine also maintains the local busy user
  522. and local busy buffer states.
  523. This level do not care about the interlocking.
  524. It is done on the upper level.
  525. Arguments:
  526. hStation - link station handle.
  527. FlowControlState - new flow control command bits set for the link station.
  528. Return Value:
  529. STATUS_SUCCESS
  530. --*/
  531. {
  532. if ((FlowControlState & 0x80) == 0) {
  533. //
  534. // Bit5 is used as an undocumented flag, that sets
  535. // the link local busy buffer state. We need this
  536. // in the DOS DLC emulation.
  537. //
  538. ACQUIRE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
  539. if (FlowControlState == LLC_SET_LOCAL_BUSY_BUFFER) {
  540. pLink->Flags |= DLC_LOCAL_BUSY_BUFFER;
  541. } else {
  542. pLink->Flags |= DLC_LOCAL_BUSY_USER;
  543. }
  544. RELEASE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
  545. return RunInterlockedStateMachineCommand(pLink, ENTER_LCL_Busy);
  546. } else {
  547. //
  548. // Optimize the buffer enabling, because RECEICE for a
  549. // SAP station should disable any non user busy states of
  550. // all link stations defined for sap (may take a long
  551. // time if a sap has very may links)
  552. //
  553. if (FlowControlState == LLC_RESET_LOCAL_BUSY_BUFFER) {
  554. FlowControlState = DLC_LOCAL_BUSY_BUFFER;
  555. } else {
  556. FlowControlState = DLC_LOCAL_BUSY_USER;
  557. }
  558. if (pLink->Flags & FlowControlState) {
  559. ACQUIRE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
  560. pLink->Flags &= ~FlowControlState;
  561. RELEASE_SPIN_LOCK(&pLink->Gen.pAdapterContext->SendSpinLock);
  562. if ((pLink->Flags & (DLC_LOCAL_BUSY_USER | DLC_LOCAL_BUSY_BUFFER)) == 0) {
  563. return RunInterlockedStateMachineCommand(pLink, EXIT_LCL_Busy);
  564. }
  565. } else {
  566. return DLC_STATUS_LINK_PROTOCOL_ERROR;
  567. }
  568. }
  569. return STATUS_SUCCESS;
  570. }
  571. #if LLC_DBG >= 2
  572. PDATA_LINK
  573. SearchLink(
  574. IN PADAPTER_CONTEXT pAdapterContext,
  575. IN LAN802_ADDRESS LanAddr
  576. )
  577. /*++
  578. Routine Description:
  579. The routine searches a link from the hash table.
  580. All links in the same hash node has been saved to a simple
  581. link list.
  582. Note: the full link address is actually 61 bits long =
  583. 7 (SSAP) + 7 (DSAP) + 47 (any non-broadcast source address).
  584. We save the address information into two ULONGs, that are used
  585. in the actual search. The hash key will be calculated by xoring
  586. all 8 bytes in the address.
  587. Arguments:
  588. pAdapterContext - MAC adapter context of data link driver
  589. LanAddr - the complete 64 bit address of link (48 bit source addr + saps)
  590. Return Value:
  591. PDATA_LINK - pointer to LLC link object or NULL if not found
  592. --*/
  593. {
  594. USHORT usHash;
  595. PDATA_LINK pLink;
  596. // this is a very simple hash algorithm, but result is modified
  597. // by all bits => it should be good enough for us.
  598. usHash =
  599. LanAddr.aus.Raw[0] ^ LanAddr.aus.Raw[1] ^
  600. LanAddr.aus.Raw[2] ^ LanAddr.aus.Raw[3];
  601. pLink =
  602. pAdapterContext->aLinkHash[
  603. ((((PUCHAR)&usHash)[0] ^ ((PUCHAR)&usHash)[1]) % LINK_HASH_SIZE)];
  604. //
  605. // Search the first matching link in the link list.
  606. //
  607. while (pLink != NULL &&
  608. (pLink->LinkAddr.ul.Low != LanAddr.ul.Low ||
  609. pLink->LinkAddr.ul.High != LanAddr.ul.High))
  610. {
  611. pLink = pLink->pNextNode;
  612. }
  613. return pLink;
  614. }
  615. #endif
  616. PDATA_LINK*
  617. SearchLinkAddress(
  618. IN PADAPTER_CONTEXT pAdapterContext,
  619. IN LAN802_ADDRESS LanAddr
  620. )
  621. /*++
  622. Routine Description:
  623. The routine searches the address of a link pointer in the hash table.
  624. All links in the same hash node has been saved to a simple
  625. link list.
  626. Note: the full link address is actually 61 bits long =
  627. 7 (SSAP) + 7 (DSAP) + 47 (any non-broadcast source address).
  628. We save the address information into two ULONGs, that are used
  629. in the actual search. The hash key will be calculated by xoring
  630. all 8 bytes in the address.
  631. Arguments:
  632. pAdapterContext - MAC adapter context of data link driver
  633. LanAddr - the complete 64 bits address of link (48 bit source addr + saps)
  634. Return Value:
  635. PDATA_LINK - pointer to LLC link object or NULL if not found
  636. --*/
  637. {
  638. USHORT usHash;
  639. PDATA_LINK *ppLink;
  640. //
  641. // this is a very simple hash algorithm, but result is modified
  642. // by all bits => it should be quite good enough
  643. //
  644. usHash = LanAddr.aus.Raw[0]
  645. ^ LanAddr.aus.Raw[1]
  646. ^ LanAddr.aus.Raw[2]
  647. ^ LanAddr.aus.Raw[3];
  648. ppLink = &pAdapterContext->aLinkHash[((((PUCHAR)&usHash)[0]
  649. ^ ((PUCHAR)&usHash)[1])
  650. % LINK_HASH_SIZE)];
  651. //
  652. // BUG-BUG-BUG Check, that the C- compliler produces optimal
  653. // dword compare for this.
  654. //
  655. while (*ppLink != NULL
  656. && ((*ppLink)->LinkAddr.ul.Low != LanAddr.ul.Low
  657. || (*ppLink)->LinkAddr.ul.High != LanAddr.ul.High)) {
  658. ppLink = &(*ppLink)->pNextNode;
  659. }
  660. return ppLink;
  661. }
  662. DLC_STATUS
  663. SetLinkParameters(
  664. IN OUT PDATA_LINK pLink,
  665. IN PUCHAR pNewParameters
  666. )
  667. /*++
  668. Routine Description:
  669. Updates new parameters for a link station and reinitializes the
  670. timers and window counters.
  671. Arguments:
  672. pLink - LLC link station object
  673. pNewParameters - new parameters set to a link station
  674. Return Value:
  675. None.
  676. --*/
  677. {
  678. DLC_STATUS LlcStatus;
  679. USHORT MaxInfoField;
  680. CopyLinkParameters((PUCHAR)&pLink->TimerT1,
  681. pNewParameters,
  682. (PUCHAR)&pLink->pSap->DefaultParameters
  683. );
  684. //
  685. // The application cannot set bigger information field than
  686. // supported by adapter and source routing bridges.
  687. //
  688. MaxInfoField = LlcGetMaxInfoField(pLink->Gen.pAdapterContext->NdisMedium,
  689. pLink->Gen.pLlcBinding,
  690. pLink->auchLanHeader
  691. );
  692. if (pLink->MaxIField > MaxInfoField) {
  693. pLink->MaxIField = MaxInfoField;
  694. }
  695. //
  696. // The initial transmit and receive window size (Ww) has
  697. // a fixed initial value, because it is dynamic, but we must
  698. // set it always smaller than maxout.
  699. // The maxin value is fixed. The dynamic management of N3
  700. // is not really worth of the effort. By default, when it is
  701. // set to maximum 127, the sender searches the optimal window
  702. // size using the pool-bit.
  703. //
  704. pLink->N3 = pLink->RW;
  705. pLink->Ww = 16; // 8 * 2;
  706. pLink->MaxOut *= 2;
  707. pLink->TW = pLink->MaxOut;
  708. if (pLink->TW < pLink->Ww) {
  709. pLink->Ww = pLink->TW;
  710. }
  711. LlcStatus = InitializeLinkTimers(pLink);
  712. return LlcStatus;
  713. }
  714. DLC_STATUS
  715. CheckLinkParameters(
  716. PDLC_LINK_PARAMETERS pParms
  717. )
  718. /*++
  719. Routine Description:
  720. Procedure checks the new parameters to be set for a link and returns
  721. error status if any of them is invalid.
  722. Arguments:
  723. pLink - LLC link station object
  724. pNewParameters - new parameters set to a link station
  725. Return Value:
  726. None
  727. --*/
  728. {
  729. //
  730. // These maximum values have been defined in IBM LAN Tech-Ref
  731. //
  732. if (pParms->TimerT1 > 10
  733. || pParms->TimerT2 > 10
  734. || pParms->TimerTi > 10
  735. || pParms->MaxOut > 127
  736. || pParms->MaxIn > 127
  737. || pParms->TokenRingAccessPriority > 3) {
  738. return DLC_STATUS_PARMETERS_EXCEEDED_MAX;
  739. } else {
  740. return STATUS_SUCCESS;
  741. }
  742. }
  743. //
  744. // Copies all non-null new link parameters, the default values are
  745. // used when the new values are nul. Used by SetLinkParameters and
  746. // and SetInfo call of sap station.
  747. //
  748. VOID
  749. CopyLinkParameters(
  750. OUT PUCHAR pOldParameters,
  751. IN PUCHAR pNewParameters,
  752. IN PUCHAR pDefaultParameters
  753. )
  754. {
  755. //
  756. // We must use the default value, if somebody has set nul.
  757. // All parameters are UCHARs => we can do the check for a byte stream
  758. //
  759. CopyNonZeroBytes(pOldParameters,
  760. pNewParameters,
  761. pDefaultParameters,
  762. sizeof(DLC_LINK_PARAMETERS) - sizeof(USHORT)
  763. );
  764. //
  765. // The information field is the only non-UCHAR value among the
  766. // link station parameters.
  767. //
  768. if (((PDLC_LINK_PARAMETERS)pNewParameters)->MaxInformationField != 0) {
  769. ((PDLC_LINK_PARAMETERS)pOldParameters)->MaxInformationField =
  770. ((PDLC_LINK_PARAMETERS)pNewParameters)->MaxInformationField;
  771. } else if (((PDLC_LINK_PARAMETERS)pOldParameters)->MaxInformationField == 0) {
  772. ((PDLC_LINK_PARAMETERS)pOldParameters)->MaxInformationField =
  773. ((PDLC_LINK_PARAMETERS)pDefaultParameters)->MaxInformationField;
  774. }
  775. }
  776. VOID
  777. CopyNonZeroBytes(
  778. OUT PUCHAR pOldParameters,
  779. IN PUCHAR pNewParameters,
  780. IN PUCHAR pDefaultParameters,
  781. IN UINT Length
  782. )
  783. /*++
  784. Routine Description:
  785. Copies and filters DLC parameter values. If the value is 0, the corresponding
  786. default is used, else the supplied value
  787. Arguments:
  788. pOldParameters - pointer to set of UCHAR values
  789. pNewParameters - pointer to array of output values
  790. pDefaultParameters - pointer to corresponding default values
  791. Length - size of values in bytes (UCHARs)
  792. Return Value:
  793. None.
  794. --*/
  795. {
  796. UINT i;
  797. for (i = 0; i < Length; i++) {
  798. if (pNewParameters[i] != 0) {
  799. pOldParameters[i] = pNewParameters[i];
  800. } else if (pOldParameters[i] == 0) {
  801. pOldParameters[i] = pDefaultParameters[i];
  802. }
  803. }
  804. }
  805. UINT
  806. RunInterlockedStateMachineCommand(
  807. IN PDATA_LINK pStation,
  808. IN USHORT Command
  809. )
  810. /*++
  811. Routine Description:
  812. Runs the state machine for a link, within the adapter's SendSpinLock (&
  813. therefore at DPC)
  814. Arguments:
  815. pStation - pointer to DATA_LINK structure describing this link station
  816. Command - state machine command to be run
  817. Return Value:
  818. UINT
  819. Status from RunStateMachineCommand
  820. --*/
  821. {
  822. UINT Status;
  823. ACQUIRE_SPIN_LOCK(&pStation->Gen.pAdapterContext->SendSpinLock);
  824. Status = RunStateMachineCommand(pStation, Command);
  825. RELEASE_SPIN_LOCK(&pStation->Gen.pAdapterContext->SendSpinLock);
  826. return Status;
  827. }