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.

1968 lines
45 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Module Name:
  3. fsm.c
  4. Abstract:
  5. This module contains the routines for the PPPoE finite state machine.
  6. Author:
  7. Hakan Berk - Microsoft, Inc. (hakanb@microsoft.com) Feb-2000
  8. Environment:
  9. Windows 2000 kernel mode Miniport driver or equivalent.
  10. Revision History:
  11. ---------------------------------------------------------------------------*/
  12. #include <ntddk.h>
  13. #include <ntddndis.h>
  14. #include <ndis.h>
  15. #include <ndiswan.h>
  16. #include <ndistapi.h>
  17. #include <ntverp.h>
  18. #include "debug.h"
  19. #include "timer.h"
  20. #include "bpool.h"
  21. #include "ppool.h"
  22. #include "util.h"
  23. #include "packet.h"
  24. #include "protocol.h"
  25. #include "miniport.h"
  26. #include "tapi.h"
  27. #include "fsm.h"
  28. extern TIMERQ gl_TimerQ;
  29. VOID
  30. FsmMakeCall(
  31. IN CALL* pCall
  32. )
  33. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  34. Functional Description:
  35. This function kicks the PPPoE FSM for an outbound call.
  36. It is called at IRQL_PASSIVE level as a scheduled operation.
  37. When this function is entered, the call has 3 references on it:
  38. 1. One for scheduling this function.
  39. 2. One for dropping the call.
  40. 3. One for closing the call.
  41. The removal of the reference will be handled by the caller.
  42. The call will be in stateIdle when this function is entered.
  43. Parameters:
  44. pCall _ A pointer to our call information structure.
  45. Return Values:
  46. None
  47. ---------------------------------------------------------------------------*/
  48. {
  49. ASSERT( VALIDATE_CALL( pCall ) );
  50. TRACE( TL_N, TM_Fsm, ("+FsmMakeCall") );
  51. //
  52. // Notify TAPI that our call is in dialing state
  53. //
  54. TpCallStateChangeHandler( pCall, LINECALLSTATE_DIALING, 0 );
  55. NdisAcquireSpinLock( &pCall->lockCall );
  56. //
  57. // If call is already dropped or close is pending,
  58. // do not proceed.
  59. //
  60. if ( pCall->ulClFlags & CLBF_CallClosePending ||
  61. pCall->ulClFlags & CLBF_CallDropped )
  62. {
  63. TRACE( TL_N, TM_Fsm, ("FsmMakeCall: Call already dropped or close pending") );
  64. NdisReleaseSpinLock( &pCall->lockCall );
  65. TRACE( TL_N, TM_Fsm, ("-FsmMakeCall") );
  66. return;
  67. }
  68. pCall->stateCall = CL_stateSendPadi;
  69. NdisReleaseSpinLock( &pCall->lockCall );
  70. FsmRun( pCall, NULL, NULL, NULL );
  71. TRACE( TL_N, TM_Fsm, ("-FsmMakeCall") );
  72. }
  73. VOID
  74. FsmReceiveCall(
  75. IN CALL* pCall,
  76. IN BINDING* pBinding,
  77. IN PPPOE_PACKET* pPacket
  78. )
  79. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  80. Functional Description:
  81. This function kicks the PPPoE FSM for an inbound call.
  82. It is called at IRQL_DISPATCH level.
  83. When this function is entered, the call has 3 references on it:
  84. 1. One for running this function.
  85. 2. One for dropping the call.
  86. 3. One for closing the call.
  87. The removal of the reference will be handled by the caller.
  88. The call will be in stateIdle when this function is entered.
  89. This function will be called when a valid PADR packet is received and
  90. a new call context is created. It will initialize the state of call context
  91. to CL_stateRecvdPadr, and call FsmRun() to run the state machine.
  92. Parameters:
  93. pCall _ A pointer to our call information structure.
  94. pBinding _ Binding over which the packet is received.
  95. pPacket _ A PADR packet received.
  96. Return Values:
  97. None
  98. ---------------------------------------------------------------------------*/
  99. {
  100. ASSERT( VALIDATE_CALL( pCall ) );
  101. TRACE( TL_N, TM_Fsm, ("+FsmReceiveCall") );
  102. NdisAcquireSpinLock( &pCall->lockCall );
  103. //
  104. // If call is already dropped or close is pending,
  105. // do not proceed.
  106. //
  107. if ( pCall->ulClFlags & CLBF_CallClosePending ||
  108. pCall->ulClFlags & CLBF_CallDropped )
  109. {
  110. TRACE( TL_N, TM_Fsm, ("FsmReceiveCall: Call already dropped or close pending") );
  111. NdisReleaseSpinLock( &pCall->lockCall );
  112. TRACE( TL_N, TM_Fsm, ("-FsmReceiveCall") );
  113. return;
  114. }
  115. pCall->stateCall = CL_stateRecvdPadr;
  116. NdisReleaseSpinLock( &pCall->lockCall );
  117. FsmRun( pCall, pBinding, pPacket, NULL );
  118. TRACE( TL_N, TM_Fsm, ("-FsmReceiveCall") );
  119. }
  120. NDIS_STATUS
  121. FsmAnswerCall(
  122. IN CALL* pCall
  123. )
  124. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  125. Functional Description:
  126. This function will be called when a call indicated to TAPI in
  127. LINECALLSTATE_OFFERING state is accepted by TAPI with an OID_TAPI_ANSWER.
  128. It will change the state of the call to CL_stateSendPads, and run FSM.
  129. Parameters:
  130. pCall _ A pointer to our call information structure.
  131. Return Values:
  132. NDIS_STATUS_SUCCESS
  133. NDIS_STATUS_FAILURE
  134. NDIS_STATUS_XXXXXXX
  135. ---------------------------------------------------------------------------*/
  136. {
  137. NDIS_STATUS status = NDIS_STATUS_FAILURE;
  138. ASSERT( VALIDATE_CALL( pCall ) );
  139. TRACE( TL_N, TM_Fsm, ("+FsmAnswerCall") );
  140. NdisAcquireSpinLock( &pCall->lockCall );
  141. //
  142. // If call is already dropped or close is pending,
  143. // do not proceed.
  144. //
  145. if ( pCall->ulClFlags & CLBF_CallClosePending ||
  146. pCall->ulClFlags & CLBF_CallDropped )
  147. {
  148. TRACE( TL_N, TM_Fsm, ("FsmAnswerCall: Call already dropped or close pending") );
  149. NdisReleaseSpinLock( &pCall->lockCall );
  150. TRACE( TL_N, TM_Fsm, ("-FsmAnswerCall=$%x",status) );
  151. return status;
  152. }
  153. if ( pCall->stateCall != CL_stateOffering )
  154. {
  155. TRACE( TL_A, TM_Fsm, ("FsmAnswerCall: Call state changed unexpectedly from CL_stateOffering") );
  156. NdisReleaseSpinLock( &pCall->lockCall );
  157. TRACE( TL_N, TM_Fsm, ("-FsmAnswerCall=$%x",status) );
  158. return status;
  159. }
  160. pCall->stateCall = CL_stateSendPads;
  161. NdisReleaseSpinLock( &pCall->lockCall );
  162. FsmRun( pCall, NULL, NULL, &status );
  163. TRACE( TL_N, TM_Fsm, ("-FsmAnswerCall=$%x",status) );
  164. return status;
  165. }
  166. VOID
  167. FsmRun(
  168. IN CALL* pCall,
  169. IN BINDING* pBinding,
  170. IN PPPOE_PACKET* pRecvPacket,
  171. IN NDIS_STATUS* pStatus
  172. )
  173. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  174. Functional Description:
  175. This function is the heart of the FSM. It looks at the call context's information
  176. and takes necesarry actions.
  177. It will be called at both IRQL_PASSIVE and IRQL_DISPATCH level.
  178. If this function is entered, then the call must have a reference on it just for
  179. running this function.
  180. The removal of the reference must be handled by the caller.
  181. Parameters:
  182. pCall _ A pointer to our call information structure.
  183. pBinding _ A pointer to the binding context over which a packet was received.
  184. Must be NULL if no packets were received.
  185. pRecvPacket _ A pointer to a received packet context.
  186. Must be NULL if no packets were received.
  187. pStatus _ An optional parameter when the caller requests status about the
  188. operations performed.
  189. Return Values:
  190. None
  191. ---------------------------------------------------------------------------*/
  192. {
  193. BOOLEAN fLockReleased = FALSE;
  194. BOOLEAN fDropCall = FALSE;
  195. BOOLEAN fCloseCall = FALSE;
  196. BOOLEAN fFallThru = FALSE;
  197. ULONG ulLineDisconnectMode = 0;
  198. TRACE( TL_N, TM_Fsm, ("+FsmRun") );
  199. NdisAcquireSpinLock( &pCall->lockCall );
  200. //
  201. // If call is already dropped or close is pending,
  202. // do not proceed; just remove the reference for FSM and return.
  203. //
  204. if ( pCall->ulClFlags & CLBF_CallClosePending ||
  205. pCall->ulClFlags & CLBF_CallDropped )
  206. {
  207. TRACE( TL_N, TM_Fsm, ("FsmRun: Call already dropped or close pending") );
  208. NdisReleaseSpinLock( &pCall->lockCall );
  209. TRACE( TL_N, TM_Fsm, ("-FsmRun") );
  210. return;
  211. }
  212. switch ( pCall->stateCall )
  213. {
  214. case CL_stateSendPadi:
  215. //
  216. // In this state, we are making a new outbound call, and we should broadcast
  217. // a PADI packet
  218. //
  219. {
  220. NDIS_STATUS status;
  221. PPPOE_PACKET* pPacket = NULL;
  222. CHAR tagHostUniqueValue[16];
  223. USHORT tagHostUniqueLength;
  224. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateSendPadi") );
  225. if ( pRecvPacket != NULL )
  226. {
  227. TRACE( TL_A, TM_Fsm, ("FsmRun: Can not process packets in this state") );
  228. break;
  229. }
  230. CreateUniqueValue( pCall->hdCall,
  231. tagHostUniqueValue,
  232. &tagHostUniqueLength );
  233. //
  234. // Create a PADI packet to send
  235. //
  236. status = PacketInitializePADIToSend( &pPacket,
  237. pCall->nServiceNameLength,
  238. pCall->ServiceName,
  239. tagHostUniqueLength,
  240. tagHostUniqueValue );
  241. if ( status != NDIS_STATUS_SUCCESS )
  242. {
  243. TRACE( TL_A, TM_Fsm, ("FsmRun: Failed to initialize PADI to send") );
  244. fDropCall = TRUE;
  245. ulLineDisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  246. break;
  247. }
  248. //
  249. // Attach packet to call context
  250. //
  251. pCall->pSendPacket = pPacket;
  252. ReferencePacket( pPacket );
  253. //
  254. // Initialize and schedule the timeout handler
  255. //
  256. pCall->nNumTimeouts = 0;
  257. TimerQInitializeItem( &pCall->timerTimeout );
  258. TimerQScheduleItem( &gl_TimerQ,
  259. &pCall->timerTimeout,
  260. pCall->pLine->pAdapter->ulSendTimeout,
  261. FsmSendPADITimeout,
  262. (PVOID) pCall );
  263. //
  264. // Reference call for the timeout handler
  265. //
  266. ReferenceCall( pCall, FALSE );
  267. //
  268. // Advance the state to next
  269. //
  270. pCall->stateCall = CL_stateWaitPado;
  271. NdisReleaseSpinLock( &pCall->lockCall );
  272. fLockReleased = TRUE;
  273. //
  274. // Packet is ready, so broadcast it
  275. //
  276. status = PrBroadcast( pPacket );
  277. if ( status != NDIS_STATUS_SUCCESS )
  278. {
  279. //
  280. // Broadcast unsuccesfull, drop the call
  281. //
  282. TRACE( TL_A, TM_Fsm, ("FsmRun: Failed to broadcast PADI") );
  283. fDropCall = TRUE;
  284. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  285. }
  286. DereferencePacket( pPacket );
  287. }
  288. break;
  289. case CL_stateWaitPado:
  290. //
  291. // In this state, we are waiting for a PADO packet, and it seems like we have
  292. // received a packet to process
  293. //
  294. {
  295. PPPOE_PACKET* pPacket;
  296. USHORT usRecvHostUniqueLength;
  297. USHORT usSendHostUniqueLength;
  298. CHAR* pRecvHostUniqueValue = NULL;
  299. CHAR* pSendHostUniqueValue = NULL;
  300. USHORT usRecvACNameLength;
  301. CHAR* pRecvACNameValue = NULL;
  302. USHORT usRecvServiceNameLength;
  303. USHORT usSendServiceNameLength;
  304. CHAR* pRecvServiceNameValue = NULL;
  305. CHAR* pSendServiceNameValue = NULL;
  306. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateWaitPado") );
  307. //
  308. // Make sure that we received a packet
  309. //
  310. if ( pRecvPacket == NULL )
  311. {
  312. TRACE( TL_A, TM_Fsm, ("FsmRun: No packets received") );
  313. break;
  314. }
  315. //
  316. // Make sure that we received a PADO packet
  317. //
  318. if ( PacketGetCode( pRecvPacket ) != PACKET_CODE_PADO )
  319. {
  320. TRACE( TL_A, TM_Fsm, ("FsmRun: Packet not PADO") );
  321. break;
  322. }
  323. //
  324. // Check for errors
  325. //
  326. if ( PacketAnyErrorTagsReceived( pRecvPacket ) )
  327. {
  328. TRACE( TL_A, TM_Fsm, ("FsmRun: Error tag received in the packet") );
  329. //
  330. // We do not need to drop the call since we might receive other
  331. // PADO packets from different servers.
  332. //
  333. break;
  334. }
  335. //
  336. // Verify the host unique tag
  337. //
  338. if ( pCall->pSendPacket == NULL )
  339. {
  340. //
  341. // Something is wrong, the last send packet is freed, just return
  342. //
  343. TRACE( TL_A, TM_Fsm, ("FsmRun: Last sent packet is freed") );
  344. fDropCall = TRUE;
  345. ulLineDisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  346. break;
  347. }
  348. pPacket = pCall->pSendPacket;
  349. PacketRetrieveHostUniqueTag( pPacket,
  350. &usSendHostUniqueLength,
  351. &pSendHostUniqueValue );
  352. PacketRetrieveHostUniqueTag( pRecvPacket,
  353. &usRecvHostUniqueLength,
  354. &pRecvHostUniqueValue );
  355. if ( usSendHostUniqueLength != usRecvHostUniqueLength )
  356. {
  357. //
  358. // Lengths of host unique tags mismatch, drop the packet
  359. //
  360. TRACE( TL_A, TM_Fsm, ("FsmRun: Host Unique tag lengths mismatch") );
  361. break;
  362. }
  363. if ( !NdisEqualMemory( pSendHostUniqueValue, pRecvHostUniqueValue, usSendHostUniqueLength ) )
  364. {
  365. //
  366. // Host unique tag values mismatch, drop the packet
  367. //
  368. TRACE( TL_A, TM_Fsm, ("FsmRun: Host Unique tag values mismatch") );
  369. break;
  370. }
  371. //
  372. // Host unique id is validated, retrieve the AC-name tag
  373. //
  374. PacketRetrieveACNameTag( pRecvPacket,
  375. &usRecvACNameLength,
  376. &pRecvACNameValue );
  377. if ( usRecvACNameLength == 0 )
  378. {
  379. //
  380. // AC name is invalid, drop the packet
  381. //
  382. TRACE( TL_A, TM_Fsm, ("FsmRun: Invalid AC-Name tag") );
  383. break;
  384. }
  385. if ( pCall->fACNameSpecified )
  386. {
  387. //
  388. // Caller specified an AC Name, so validate it
  389. //
  390. if ( pCall->nACNameLength != usRecvACNameLength )
  391. {
  392. //
  393. // Received AC name does not match the specified one, drop the packet
  394. //
  395. TRACE( TL_A, TM_Fsm, ("FsmRun: AC Name Length mismatch") );
  396. break;
  397. }
  398. if ( !NdisEqualMemory( pRecvACNameValue, pCall->ACName, usRecvACNameLength ) )
  399. {
  400. //
  401. // Host unique tag values mismatch, drop the packet
  402. //
  403. TRACE( TL_A, TM_Fsm, ("FsmRun: AC Name mismatch") );
  404. break;
  405. }
  406. }
  407. else
  408. {
  409. //
  410. // No AC Name was specified so copy the AC Name from the received packet
  411. //
  412. pCall->nACNameLength = ( MAX_AC_NAME_LENGTH < usRecvACNameLength ) ?
  413. MAX_AC_NAME_LENGTH : usRecvACNameLength;
  414. NdisMoveMemory( pCall->ACName, pRecvACNameValue, pCall->nACNameLength );
  415. }
  416. //
  417. // AC-Name is validated, verify the service-name tag
  418. //
  419. PacketRetrieveServiceNameTag( pPacket,
  420. &usSendServiceNameLength,
  421. &pSendServiceNameValue,
  422. 0,
  423. NULL );
  424. PacketRetrieveServiceNameTag( pRecvPacket,
  425. &usRecvServiceNameLength,
  426. &pRecvServiceNameValue,
  427. 0,
  428. NULL );
  429. //
  430. // Make sure we have received a service-name at least
  431. //
  432. if ( pRecvServiceNameValue == NULL )
  433. {
  434. TRACE( TL_A, TM_Fsm, ("FsmRun: No service-name tag in a received PADO") );
  435. break;
  436. }
  437. //
  438. // If fAcceptAnyService is FALSE, then make sure the requested service is in the PADO
  439. // received, otherwise if we have requested an empty service name, then try to find it
  440. // in the PADO, if not use the first service name from it.
  441. //
  442. {
  443. BOOLEAN fFound = FALSE;
  444. CHAR* pFirstRecvServiceNameValue = NULL;
  445. USHORT usFirstRecvServiceNameLength = 0;
  446. BOOLEAN fAcceptAnyService = pCall->pLine->pAdapter->fAcceptAnyService;
  447. //
  448. // We have asked for a specific service name, so let's
  449. // see if the server responded with it
  450. //
  451. while ( usRecvServiceNameLength >= 0 && pRecvServiceNameValue != NULL )
  452. {
  453. if ( pFirstRecvServiceNameValue == NULL )
  454. {
  455. pFirstRecvServiceNameValue = pRecvServiceNameValue;
  456. usFirstRecvServiceNameLength = usRecvServiceNameLength;
  457. }
  458. if ( usRecvServiceNameLength == usSendServiceNameLength )
  459. {
  460. if ( NdisEqualMemory( pSendServiceNameValue,
  461. pRecvServiceNameValue,
  462. usSendServiceNameLength ) )
  463. {
  464. fFound = TRUE;
  465. break;
  466. }
  467. }
  468. PacketRetrieveServiceNameTag( pRecvPacket,
  469. &usRecvServiceNameLength,
  470. &pRecvServiceNameValue,
  471. usRecvServiceNameLength,
  472. pRecvServiceNameValue );
  473. }
  474. if ( !fFound )
  475. {
  476. if ( fAcceptAnyService )
  477. {
  478. //
  479. // Use the first service in the PADO, if we have requested an
  480. // empty service-name
  481. //
  482. if ( usSendServiceNameLength == 0 )
  483. {
  484. pCall->nServiceNameLength = ( MAX_SERVICE_NAME_LENGTH < usFirstRecvServiceNameLength ) ?
  485. MAX_SERVICE_NAME_LENGTH : usFirstRecvServiceNameLength;
  486. if ( pCall->nServiceNameLength > 0 )
  487. {
  488. NdisMoveMemory( pCall->ServiceName,
  489. pFirstRecvServiceNameValue,
  490. pCall->nServiceNameLength );
  491. fFound = TRUE;
  492. }
  493. }
  494. }
  495. if ( !fFound )
  496. {
  497. //
  498. // We could not find a matching service name tag, so drop the packet
  499. //
  500. TRACE( TL_A, TM_Fsm, ("FsmRun: PADO does not contain the service-name tag we requested") );
  501. break;
  502. }
  503. }
  504. }
  505. //
  506. // Received packet is validated, so set the dest addr in the call.
  507. // The source address will be copied on the call in PrAddCallToBinding() below.
  508. //
  509. NdisMoveMemory( pCall->DestAddr, PacketGetSrcAddr( pRecvPacket ), 6 * sizeof( CHAR ) );
  510. //
  511. // Received packet is validated, so proceed to next state
  512. //
  513. pCall->stateCall = CL_stateSendPadr;
  514. fFallThru = TRUE;
  515. //
  516. // As we are done with the last sent packet, free it
  517. //
  518. pCall->pSendPacket = NULL;
  519. PacketFree( pPacket );
  520. //
  521. // Cancel the timeout handler and attach call to binding
  522. //
  523. NdisReleaseSpinLock( &pCall->lockCall );
  524. TimerQCancelItem( &gl_TimerQ, &pCall->timerTimeout );
  525. PrAddCallToBinding( pBinding, pCall );
  526. //
  527. // Notify TAPI that our call is in proceeding state
  528. //
  529. TpCallStateChangeHandler( pCall, LINECALLSTATE_PROCEEDING, 0 );
  530. NdisAcquireSpinLock( &pCall->lockCall );
  531. //
  532. // Make sure state was not changed when we released the lock to cancel the timer queue item
  533. //
  534. if ( pCall->stateCall != CL_stateSendPadr )
  535. {
  536. TRACE( TL_A, TM_Fsm, ("FsmRun: State changed unexpectedly from CL_stateSendPadr") );
  537. break;
  538. }
  539. //
  540. // Fall thru to case CL_stateSendPadr
  541. //
  542. }
  543. case CL_stateSendPadr:
  544. //
  545. // In this state, we have received a valid PADO packet, and we need to respond to it
  546. // with a PADR packet
  547. //
  548. {
  549. NDIS_STATUS status;
  550. PPPOE_PACKET* pPacket = NULL;
  551. CHAR tagHostUniqueValue[16];
  552. USHORT tagHostUniqueLength;
  553. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateSendPadr") );
  554. if ( !fFallThru )
  555. {
  556. TRACE( TL_N, TM_Fsm, ("FsmRun: Non fall thru entry into a fall thru state") );
  557. break;
  558. }
  559. CreateUniqueValue( pCall->hdCall,
  560. tagHostUniqueValue,
  561. &tagHostUniqueLength );
  562. //
  563. // Create a PADR packet to send
  564. //
  565. status = PacketInitializePADRToSend( pRecvPacket,
  566. &pPacket,
  567. pCall->nServiceNameLength,
  568. pCall->ServiceName,
  569. tagHostUniqueLength,
  570. tagHostUniqueValue );
  571. if ( status != NDIS_STATUS_SUCCESS )
  572. {
  573. TRACE( TL_A, TM_Fsm, ("FsmRun: Failed to initialize PADR to send") );
  574. fDropCall = TRUE;
  575. ulLineDisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  576. break;
  577. }
  578. //
  579. // Attach packet to call context
  580. //
  581. pCall->pSendPacket = pPacket;
  582. ReferencePacket( pPacket );
  583. //
  584. // Reference binding for PrSend()
  585. //
  586. ReferenceBinding( pBinding, TRUE );
  587. //
  588. // Initialize and schedule the timeout handler
  589. //
  590. pCall->nNumTimeouts = 0;
  591. TimerQInitializeItem( &pCall->timerTimeout );
  592. TimerQScheduleItem( &gl_TimerQ,
  593. &pCall->timerTimeout,
  594. pCall->pLine->pAdapter->ulSendTimeout,
  595. FsmSendPADRTimeout,
  596. (PVOID) pCall );
  597. //
  598. // Reference call for the timeout handler
  599. //
  600. ReferenceCall( pCall, FALSE );
  601. //
  602. // Advance the state to next
  603. //
  604. pCall->stateCall = CL_stateWaitPads;
  605. //
  606. // Release the lock to send the packet
  607. //
  608. NdisReleaseSpinLock( &pCall->lockCall );
  609. fLockReleased = TRUE;
  610. //
  611. // Packet is ready, so send it
  612. //
  613. status = PrSend( pBinding, pPacket );
  614. if ( status != NDIS_STATUS_PENDING )
  615. {
  616. if ( status != NDIS_STATUS_SUCCESS )
  617. {
  618. //
  619. // Send operation was not succesful, so drop the call
  620. //
  621. TRACE( TL_A, TM_Fsm, ("FsmRun: PrSend() failed to send PADR") );
  622. fDropCall = TRUE;
  623. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  624. }
  625. }
  626. }
  627. break;
  628. case CL_stateWaitPads:
  629. //
  630. // In this state, we have sent a PADR packet and waiting for a PADS packet to establish
  631. // a session
  632. //
  633. {
  634. PPPOE_PACKET* pPacket;
  635. USHORT usRecvHostUniqueLength;
  636. USHORT usSendHostUniqueLength;
  637. CHAR* pRecvHostUniqueValue = NULL;
  638. CHAR* pSendHostUniqueValue = NULL;
  639. USHORT usRecvServiceNameLength;
  640. USHORT usSendServiceNameLength;
  641. CHAR* pRecvServiceNameValue = NULL;
  642. CHAR* pSendServiceNameValue = NULL;
  643. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateWaitPads") );
  644. //
  645. // Make sure that we received a packet
  646. //
  647. if ( pRecvPacket == NULL )
  648. {
  649. TRACE( TL_A, TM_Fsm, ("FsmRun: No packets received") );
  650. break;
  651. }
  652. //
  653. // Make sure that we received a PADO packet
  654. //
  655. if ( PacketGetCode( pRecvPacket ) != PACKET_CODE_PADS )
  656. {
  657. TRACE( TL_A, TM_Fsm, ("FsmRun: Packet not PADS") );
  658. break;
  659. }
  660. //
  661. // Check for errors
  662. //
  663. if ( PacketAnyErrorTagsReceived( pRecvPacket ) )
  664. {
  665. PACKET_TAGS tagType;
  666. USHORT tagLength;
  667. CHAR* tagValue = NULL;
  668. TRACE( TL_A, TM_Fsm, ("FsmRun: Error tag received in the packet") );
  669. fDropCall = TRUE;
  670. //
  671. // Set the line disconnect mode looking at the error tag
  672. //
  673. PacketRetrieveErrorTag( pRecvPacket,
  674. &tagType,
  675. &tagLength,
  676. &tagValue );
  677. switch( tagType ) {
  678. case tagServiceNameError:
  679. ulLineDisconnectMode = LINEDISCONNECTMODE_BADADDRESS;
  680. break;
  681. case tagACSystemError:
  682. ulLineDisconnectMode = LINEDISCONNECTMODE_INCOMPATIBLE;
  683. break;
  684. case tagGenericError:
  685. ulLineDisconnectMode = LINEDISCONNECTMODE_REJECT;
  686. break;
  687. }
  688. break;
  689. }
  690. //
  691. // Verify the host unique tag
  692. //
  693. if ( pCall->pSendPacket == NULL )
  694. {
  695. //
  696. // Something is wrong, the last send packet is freed, just return
  697. //
  698. TRACE( TL_A, TM_Fsm, ("FsmRun: Last sent packet is freed") );
  699. fDropCall = TRUE;
  700. ulLineDisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  701. break;
  702. }
  703. pPacket = pCall->pSendPacket;
  704. PacketRetrieveHostUniqueTag( pPacket,
  705. &usSendHostUniqueLength,
  706. &pSendHostUniqueValue );
  707. PacketRetrieveHostUniqueTag( pRecvPacket,
  708. &usRecvHostUniqueLength,
  709. &pRecvHostUniqueValue );
  710. if ( usSendHostUniqueLength != usRecvHostUniqueLength )
  711. {
  712. //
  713. // Lengths of host unique tags mismatch, drop the packet
  714. //
  715. TRACE( TL_A, TM_Fsm, ("FsmRun: Host Unique tag lengths mismatch") );
  716. break;
  717. }
  718. if ( !NdisEqualMemory( pSendHostUniqueValue, pRecvHostUniqueValue, usSendHostUniqueLength ) )
  719. {
  720. //
  721. // Host unique tag values mismatch, drop the packet
  722. //
  723. TRACE( TL_A, TM_Fsm, ("FsmRun: Host Unique tag values mismatch") );
  724. break;
  725. }
  726. //
  727. // Host unique id is validated, verify the service name
  728. //
  729. PacketRetrieveServiceNameTag( pPacket,
  730. &usSendServiceNameLength,
  731. &pSendServiceNameValue,
  732. 0,
  733. NULL );
  734. PacketRetrieveServiceNameTag( pRecvPacket,
  735. &usRecvServiceNameLength,
  736. &pRecvServiceNameValue,
  737. 0,
  738. NULL );
  739. //
  740. // Make sure we have received a service-name at least
  741. //
  742. if ( pRecvServiceNameValue == NULL )
  743. {
  744. TRACE( TL_A, TM_Fsm, ("FsmRun: No service-name tag in a received PADS") );
  745. break;
  746. }
  747. //
  748. // Search for the specific service-name we requested
  749. //
  750. {
  751. BOOLEAN fFound = FALSE;
  752. //
  753. // We have asked for a specific service name, so let's
  754. // see if the server responded with it
  755. //
  756. while ( usRecvServiceNameLength >= 0 && pRecvServiceNameValue != NULL )
  757. {
  758. if ( usRecvServiceNameLength == usSendServiceNameLength )
  759. {
  760. if ( NdisEqualMemory( pSendServiceNameValue,
  761. pRecvServiceNameValue,
  762. usSendServiceNameLength ) )
  763. {
  764. fFound = TRUE;
  765. break;
  766. }
  767. }
  768. PacketRetrieveServiceNameTag( pRecvPacket,
  769. &usRecvServiceNameLength,
  770. &pRecvServiceNameValue,
  771. usRecvServiceNameLength,
  772. pRecvServiceNameValue );
  773. }
  774. if ( !fFound )
  775. {
  776. //
  777. // We could not find a matching service name tag, so drop the packet
  778. //
  779. TRACE( TL_A, TM_Fsm, ("FsmRun: PADS does not contain the service-name tag we requested") );
  780. break;
  781. }
  782. }
  783. //
  784. // Set the session id on the call context
  785. //
  786. pCall->usSessionId = PacketGetSessionId( pRecvPacket );
  787. //
  788. // As we are done with the last sent packet, free it
  789. //
  790. pCall->pSendPacket = NULL;
  791. PacketFree( pPacket );
  792. //
  793. // Cancel the timeout handler and attach call to binding
  794. //
  795. NdisReleaseSpinLock( &pCall->lockCall );
  796. fLockReleased = TRUE;
  797. TimerQCancelItem( &gl_TimerQ, &pCall->timerTimeout );
  798. //
  799. // Notify call connect event
  800. //
  801. TpCallStateChangeHandler( pCall, LINECALLSTATE_CONNECTED, 0 );
  802. }
  803. break;
  804. case CL_stateRecvdPadr:
  805. //
  806. // In this state, we have been received a PADR packet.
  807. // We will indicate the call to Tapi, and change the state to CL_stateOffering
  808. // and wait for the application to answer the call.
  809. //
  810. {
  811. NDIS_STATUS status;
  812. PPPOE_PACKET* pPacket;
  813. USHORT usRecvServiceNameLength;
  814. CHAR* pRecvServiceNameValue = NULL;
  815. USHORT usSessionId;
  816. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateWaitPadr") );
  817. //
  818. // Make sure that we received a packet
  819. //
  820. if ( pRecvPacket == NULL )
  821. {
  822. TRACE( TL_A, TM_Fsm, ("FsmRun: No packets received") );
  823. break;
  824. }
  825. //
  826. // Make sure that we received a PADR packet
  827. //
  828. if ( PacketGetCode( pRecvPacket ) != PACKET_CODE_PADR )
  829. {
  830. TRACE( TL_A, TM_Fsm, ("FsmRun: Packet not PADR") );
  831. break;
  832. }
  833. //
  834. // Set the dest addr in the call.
  835. // The source address will be copied on to the call in PrAddCallToBinding() below.
  836. //
  837. NdisMoveMemory( pCall->DestAddr, PacketGetSrcAddr( pRecvPacket ), 6 * sizeof( CHAR ) );
  838. //
  839. // Retrieve the service name and copy it onto the call context
  840. //
  841. PacketRetrieveServiceNameTag( pRecvPacket,
  842. &usRecvServiceNameLength,
  843. &pRecvServiceNameValue,
  844. 0,
  845. NULL );
  846. pCall->nServiceNameLength = ( MAX_SERVICE_NAME_LENGTH < usRecvServiceNameLength ) ?
  847. MAX_SERVICE_NAME_LENGTH : usRecvServiceNameLength;
  848. NdisMoveMemory( pCall->ServiceName,
  849. pRecvServiceNameValue,
  850. pCall->nServiceNameLength );
  851. //
  852. // Copy the AC-Name onto call context, before connection is established
  853. //
  854. pCall->nACNameLength = pCall->pLine->pAdapter->nACNameLength;
  855. NdisMoveMemory( pCall->ACName,
  856. pCall->pLine->pAdapter->ACName,
  857. pCall->nACNameLength );
  858. //
  859. // Retrieve the session id from the call handle and create a PADS packet to send
  860. //
  861. usSessionId = RetrieveSessionIdFromHandle( (NDIS_HANDLE) pCall->hdCall );
  862. status = PacketInitializePADSToSend( pRecvPacket,
  863. &pPacket,
  864. usSessionId );
  865. if ( status != NDIS_STATUS_SUCCESS )
  866. {
  867. TRACE( TL_A, TM_Fsm, ("FsmRun: Failed to initialize PADS to send") );
  868. fCloseCall = TRUE;
  869. break;
  870. }
  871. //
  872. // This PADS packet will be sent if application answers the call
  873. //
  874. pCall->pSendPacket = pPacket;
  875. //
  876. // Proceed to next state
  877. //
  878. pCall->stateCall = CL_stateOffering;
  879. //
  880. // Initialize and schedule the timeout handler
  881. //
  882. pCall->nNumTimeouts = 0;
  883. TimerQInitializeItem( &pCall->timerTimeout );
  884. TimerQScheduleItem( &gl_TimerQ,
  885. &pCall->timerTimeout,
  886. pCall->pLine->pAdapter->ulRecvTimeout,
  887. FsmOfferingTimeout,
  888. (PVOID) pCall );
  889. //
  890. // Reference call for the timeout handler
  891. //
  892. ReferenceCall( pCall, FALSE );
  893. //
  894. // Release the lock
  895. //
  896. NdisReleaseSpinLock( &pCall->lockCall );
  897. fLockReleased = TRUE;
  898. //
  899. // Notify TAPI about the state change
  900. //
  901. if ( TpIndicateNewCall( pCall ) )
  902. {
  903. //
  904. // Add call to binding
  905. //
  906. PrAddCallToBinding( pBinding, pCall );
  907. TpCallStateChangeHandler( pCall, LINECALLSTATE_OFFERING, 0 );
  908. }
  909. }
  910. break;
  911. case CL_stateSendPads:
  912. //
  913. // In this state, TAPI has accepted the call, so we should send the PADS packet and create
  914. // the session.
  915. //
  916. {
  917. NDIS_STATUS status;
  918. PPPOE_PACKET* pPacket = NULL;
  919. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateSendPads") );
  920. if ( pRecvPacket != NULL )
  921. {
  922. TRACE( TL_A, TM_Fsm, ("FsmRun: Can not process packets in this state") );
  923. break;
  924. }
  925. //
  926. // Make sure we still have the PADS packet to send
  927. //
  928. if ( pCall->pSendPacket == NULL )
  929. {
  930. //
  931. // Something is wrong, the last send packet is freed, drop the call
  932. //
  933. TRACE( TL_A, TM_Fsm, ("FsmRun: Last sent packet is freed") );
  934. fDropCall = TRUE;
  935. *pStatus = NDIS_STATUS_FAILURE;
  936. break;
  937. }
  938. pPacket = pCall->pSendPacket;
  939. if ( pCall->pBinding == NULL )
  940. {
  941. //
  942. // Binding is gone, we should drop the call
  943. //
  944. TRACE( TL_A, TM_Fsm, ("FsmRun: No binding found") );
  945. fDropCall = TRUE;
  946. *pStatus = NDIS_STATUS_FAILURE;
  947. break;
  948. }
  949. pBinding = pCall->pBinding;
  950. //
  951. // Reference packet and binding for PrSend()
  952. //
  953. ReferencePacket( pPacket );
  954. ReferenceBinding( pBinding, TRUE );
  955. //
  956. // Set the session id on the call context
  957. //
  958. pCall->usSessionId = RetrieveSessionIdFromHandle( (NDIS_HANDLE) pCall->hdCall );
  959. //
  960. // Release the lock and send the packet
  961. //
  962. NdisReleaseSpinLock( &pCall->lockCall );
  963. fLockReleased = TRUE;
  964. //
  965. // Cancel the timeout handler
  966. //
  967. TimerQCancelItem( &gl_TimerQ, &pCall->timerTimeout );
  968. //
  969. // Packet is ready, so send it
  970. //
  971. status = PrSend( pBinding, pPacket );
  972. if ( status != NDIS_STATUS_PENDING )
  973. {
  974. if ( status != NDIS_STATUS_SUCCESS )
  975. {
  976. //
  977. // Send operation was not succesful, so drop the call
  978. //
  979. TRACE( TL_A, TM_Fsm, ("FsmRun: PrSend() failed to send PADS") );
  980. fDropCall = TRUE;
  981. *pStatus = NDIS_STATUS_FAILURE;
  982. break;
  983. }
  984. }
  985. //
  986. // Notify call connect event, since we sent the PADS packet
  987. //
  988. TpCallStateChangeHandler( pCall, LINECALLSTATE_CONNECTED, 0 );
  989. *pStatus = NDIS_STATUS_SUCCESS;
  990. }
  991. break;
  992. default:
  993. TRACE( TL_A, TM_Fsm, ("FsmRun: Ignoring irrelevant state notification") );
  994. break;
  995. }
  996. if ( !fLockReleased )
  997. {
  998. NdisReleaseSpinLock( &pCall->lockCall );
  999. }
  1000. if ( fCloseCall )
  1001. {
  1002. NDIS_TAPI_CLOSE_CALL DummyRequest;
  1003. TRACE( TL_N, TM_Fsm, ("FsmRun: Closing call") );
  1004. DummyRequest.hdCall = pCall->hdCall;
  1005. //
  1006. // Close will take care of unbinding and cancelling the timer
  1007. //
  1008. TpCloseCall( pCall->pLine->pAdapter, &DummyRequest, FALSE );
  1009. }
  1010. if ( fDropCall )
  1011. {
  1012. NDIS_TAPI_DROP DummyRequest;
  1013. TRACE( TL_N, TM_Fsm, ("FsmRun: Dropping call") );
  1014. DummyRequest.hdCall = pCall->hdCall;
  1015. //
  1016. // Drop will take care of unbinding and cancelling the timer
  1017. //
  1018. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, ulLineDisconnectMode );
  1019. }
  1020. TRACE( TL_N, TM_Fsm, ("-FsmRun") );
  1021. }
  1022. VOID
  1023. FsmSendPADITimeout(
  1024. IN TIMERQITEM* pTqi,
  1025. IN VOID* pContext,
  1026. IN TIMERQEVENT event
  1027. )
  1028. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1029. Functional Description:
  1030. This function is the timeout handler for a sent PADI packet.
  1031. If the timeout period expires before a valid PADO packet is received,
  1032. this function will be called with TE_Expire. In this case we check for
  1033. a few conditions, and schedule another timeout event if necesarry.
  1034. If it was cancelled -because a PADO packet was received - or timer queue
  1035. is terminating then it will be called with TE_Cancel and TE_Terminate codes
  1036. respectively. In this case, we do not do anything, just remove the reference
  1037. and return.
  1038. Parameters:
  1039. pTqi _ A pointer to our timer queue item information structure.
  1040. pContext _ A pointer to a our call information structure.
  1041. event _ Indicates the type of event: TE_Expire, TE_Cancel or TE_Terminate.
  1042. Return Values:
  1043. None
  1044. ---------------------------------------------------------------------------*/
  1045. {
  1046. CALL* pCall = (CALL*) pContext;
  1047. BOOLEAN fDropCall = FALSE;
  1048. ULONG ulLineDisconnectMode = 0;
  1049. TRACE( TL_N, TM_Fsm, ("+FsmSendPADITimeout") );
  1050. switch ( event )
  1051. {
  1052. case TE_Expire:
  1053. //
  1054. // Timeout period expired, take necesarry actions
  1055. //
  1056. {
  1057. NDIS_STATUS status;
  1058. PPPOE_PACKET* pPacket = NULL;
  1059. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Timer expired") );
  1060. NdisAcquireSpinLock( &pCall->lockCall );
  1061. if ( pCall->stateCall != CL_stateWaitPado )
  1062. {
  1063. //
  1064. // State has changed, no need further processing of this event
  1065. //
  1066. TRACE( TL_A, TM_Fsm, ("FsmSendPADITimeout: State already changed") );
  1067. NdisReleaseSpinLock( &pCall->lockCall );
  1068. break;
  1069. }
  1070. //
  1071. // Check if we have reached the max number of time outs
  1072. //
  1073. if ( pCall->nNumTimeouts == pCall->pLine->pAdapter->nMaxTimeouts )
  1074. {
  1075. //
  1076. // We did not receive any answers, drop the call
  1077. //
  1078. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Max number of timeouts reached") );
  1079. NdisReleaseSpinLock( &pCall->lockCall );
  1080. fDropCall = TRUE;
  1081. ulLineDisconnectMode = LINEDISCONNECTMODE_NOANSWER;
  1082. break;
  1083. }
  1084. pPacket = pCall->pSendPacket;
  1085. if ( pPacket == NULL )
  1086. {
  1087. //
  1088. // We are probably in a ver small timing window where FsmRun() is also
  1089. // working on the same call, and has just freed the packet, so it probably
  1090. // cancelled the timer, but we did not get the cancel, and instead we were
  1091. // called with TE_Expire, so let's just act like we were cancelled.
  1092. //
  1093. TRACE( TL_A, TM_Fsm, ("FsmSendPADITimeout: Can not find last sent packet for re-send") );
  1094. NdisReleaseSpinLock( &pCall->lockCall );
  1095. break;
  1096. }
  1097. ReferencePacket( pPacket );
  1098. //
  1099. // Schedule another timeout event
  1100. //
  1101. TimerQInitializeItem( &pCall->timerTimeout );
  1102. TimerQScheduleItem( &gl_TimerQ,
  1103. &pCall->timerTimeout,
  1104. pCall->pLine->pAdapter->ulSendTimeout,
  1105. FsmSendPADITimeout,
  1106. (PVOID) pCall );
  1107. //
  1108. // Reference call for the new timeout handler
  1109. //
  1110. ReferenceCall( pCall, FALSE );
  1111. //
  1112. // Increment the timeout counter
  1113. //
  1114. pCall->nNumTimeouts++;
  1115. NdisReleaseSpinLock( &pCall->lockCall );
  1116. //
  1117. // Packet is ready, so broadcast it
  1118. //
  1119. status = PrBroadcast( pPacket );
  1120. if ( status != NDIS_STATUS_SUCCESS )
  1121. {
  1122. //
  1123. // Broadcast unsuccesfull, drop the call
  1124. //
  1125. TRACE( TL_A, TM_Fsm, ("FsmSendPADITimeout: Broadcast failed") );
  1126. fDropCall = TRUE;
  1127. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  1128. }
  1129. DereferencePacket( pPacket );
  1130. }
  1131. break;
  1132. case TE_Cancel:
  1133. case TE_Terminate:
  1134. {
  1135. //
  1136. // Reset the timeout counter and reference will be removed below
  1137. //
  1138. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Timer cancelled or terminated") );
  1139. NdisAcquireSpinLock( &pCall->lockCall );
  1140. pCall->nNumTimeouts = 0;
  1141. NdisReleaseSpinLock( &pCall->lockCall );
  1142. }
  1143. break;
  1144. }
  1145. if ( fDropCall )
  1146. {
  1147. NDIS_TAPI_DROP DummyRequest;
  1148. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Dropping call") );
  1149. DummyRequest.hdCall = pCall->hdCall;
  1150. //
  1151. // Drop will take care of unbinding and cancelling the timer
  1152. //
  1153. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, ulLineDisconnectMode );
  1154. }
  1155. DereferenceCall( pCall );
  1156. TRACE( TL_N, TM_Fsm, ("-FsmSendPADITimeout") );
  1157. }
  1158. VOID
  1159. FsmSendPADRTimeout(
  1160. IN TIMERQITEM* pTqi,
  1161. IN VOID* pContext,
  1162. IN TIMERQEVENT event
  1163. )
  1164. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1165. Functional Description:
  1166. This function is the timeout handler for a sent PADR packet.
  1167. If the timeout period expires before a valid PADS packet is received,
  1168. this function will be called with TE_Expire. In this case we check for
  1169. a few conditions, and schedule another timeout event if necesarry.
  1170. If it was cancelled - because a PADS packet was received - or timer queue
  1171. is terminating then it will be called with TE_Cancel and TE_Terminate codes
  1172. respectively. In this case, we do not do anything, just remove the reference
  1173. and return.
  1174. Parameters:
  1175. pTqi _ A pointer to our timer queue item information structure.
  1176. pContext _ A pointer to a our call information structure.
  1177. event _ Indicates the type of event: TE_Expire, TE_Cancel or TE_Terminate.
  1178. Return Values:
  1179. None
  1180. ---------------------------------------------------------------------------*/
  1181. {
  1182. CALL* pCall = (CALL*) pContext;
  1183. BOOLEAN fDropCall = FALSE;
  1184. ULONG ulLineDisconnectMode = 0;
  1185. TRACE( TL_N, TM_Fsm, ("+FsmSendPADRTimeout") );
  1186. switch ( event )
  1187. {
  1188. case TE_Expire:
  1189. //
  1190. // Timeout period expired, take necesarry actions
  1191. //
  1192. {
  1193. NDIS_STATUS status;
  1194. PPPOE_PACKET* pPacket = NULL;
  1195. BINDING* pBinding = NULL;
  1196. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Timer expired") );
  1197. NdisAcquireSpinLock( &pCall->lockCall );
  1198. if ( pCall->stateCall != CL_stateWaitPads )
  1199. {
  1200. //
  1201. // State has changed, no need further processing of this event
  1202. //
  1203. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: State already changed") );
  1204. NdisReleaseSpinLock( &pCall->lockCall );
  1205. break;
  1206. }
  1207. //
  1208. // Check if we have reached the max number of time outs
  1209. //
  1210. if ( pCall->nNumTimeouts == pCall->pLine->pAdapter->nMaxTimeouts )
  1211. {
  1212. //
  1213. // We did not receive any answers, drop the call
  1214. //
  1215. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Max number of timeouts reached") );
  1216. NdisReleaseSpinLock( &pCall->lockCall );
  1217. fDropCall = TRUE;
  1218. ulLineDisconnectMode = LINEDISCONNECTMODE_BUSY;
  1219. break;
  1220. }
  1221. //
  1222. // Save the binding for send operation
  1223. //
  1224. pBinding = pCall->pBinding;
  1225. if ( pBinding == NULL )
  1226. {
  1227. //
  1228. // The binding was removed, drop the call
  1229. //
  1230. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: Binding not found") );
  1231. NdisReleaseSpinLock( &pCall->lockCall );
  1232. fDropCall = TRUE;
  1233. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  1234. break;
  1235. }
  1236. //
  1237. // Save the packet for send operation
  1238. //
  1239. pPacket = pCall->pSendPacket;
  1240. if ( pPacket == NULL )
  1241. {
  1242. //
  1243. // We are probably in a ver small timing window where FsmRun() is also
  1244. // working on the same call, and has just freed the packet, so it probably
  1245. // cancelled the timer, but we did not get the cancel, and instead we were
  1246. // called with TE_Expire, so let's just act like we were cancelled.
  1247. //
  1248. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: Can not find last sent packet for re-send") );
  1249. NdisReleaseSpinLock( &pCall->lockCall );
  1250. break;
  1251. }
  1252. //
  1253. // Reference both binding and the packet as PrSend() might pend, in which case
  1254. // PrSendComplete() will remove these references
  1255. //
  1256. ReferenceBinding ( pBinding, TRUE );
  1257. ReferencePacket( pPacket );
  1258. //
  1259. // Schedule another timeout event
  1260. //
  1261. TimerQInitializeItem( &pCall->timerTimeout );
  1262. TimerQScheduleItem( &gl_TimerQ,
  1263. &pCall->timerTimeout,
  1264. pCall->pLine->pAdapter->ulSendTimeout,
  1265. FsmSendPADRTimeout,
  1266. (PVOID) pCall );
  1267. //
  1268. // Reference call for the new timeout handler
  1269. //
  1270. ReferenceCall( pCall, FALSE );
  1271. //
  1272. // Increment the timeout counter
  1273. //
  1274. pCall->nNumTimeouts++;
  1275. NdisReleaseSpinLock( &pCall->lockCall );
  1276. //
  1277. // Send the packet once more
  1278. //
  1279. status = PrSend( pBinding, pPacket );
  1280. if ( status != NDIS_STATUS_PENDING )
  1281. {
  1282. if ( status != NDIS_STATUS_SUCCESS )
  1283. {
  1284. //
  1285. // Send operation was not succesful, so drop the call
  1286. //
  1287. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: PrSend() failed to send PADR") );
  1288. fDropCall = TRUE;
  1289. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  1290. }
  1291. }
  1292. }
  1293. break;
  1294. case TE_Cancel:
  1295. case TE_Terminate:
  1296. {
  1297. //
  1298. // Reset the timeout counter and reference will be removed below
  1299. //
  1300. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Timer cancelled or terminated") );
  1301. NdisAcquireSpinLock( &pCall->lockCall );
  1302. pCall->nNumTimeouts = 0;
  1303. NdisReleaseSpinLock( &pCall->lockCall );
  1304. }
  1305. break;
  1306. }
  1307. if ( fDropCall )
  1308. {
  1309. NDIS_TAPI_DROP DummyRequest;
  1310. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Dropping call") );
  1311. DummyRequest.hdCall = pCall->hdCall;
  1312. //
  1313. // Drop will take care of unbinding and cancelling the timer
  1314. //
  1315. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, ulLineDisconnectMode );
  1316. }
  1317. DereferenceCall( pCall );
  1318. TRACE( TL_N, TM_Fsm, ("-FsmSendPADRTimeout") );
  1319. }
  1320. VOID
  1321. FsmOfferingTimeout(
  1322. IN TIMERQITEM* pTqi,
  1323. IN VOID* pContext,
  1324. IN TIMERQEVENT event
  1325. )
  1326. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1327. Functional Description:
  1328. This function is the timeout handler for a received PADI packet.
  1329. The call is in LINECALLSTATE_OFFERING according to TAPI, and we are
  1330. waiting for an OID_TAPI_ACCEPT on the call.
  1331. If the timeout period expires before a TAPI request is received,
  1332. this function will be called with TE_Expire. In this case we check for
  1333. a few conditions, and schedule another timeout event if necesarry.
  1334. If it was cancelled - because a TAPI request was received - or timer queue
  1335. is terminating then it will be called with TE_Cancel and TE_Terminate codes
  1336. respectively. In this case, we do not do anything, just remove the reference
  1337. and return.
  1338. Parameters:
  1339. pTqi _ A pointer to our timer queue item information structure.
  1340. pContext _ A pointer to a our call information structure.
  1341. event _ Indicates the type of event: TE_Expire, TE_Cancel or TE_Terminate.
  1342. Return Values:
  1343. None
  1344. ---------------------------------------------------------------------------*/
  1345. {
  1346. CALL* pCall = (CALL*) pContext;
  1347. BOOLEAN fDropCall = FALSE;
  1348. TRACE( TL_N, TM_Fsm, ("+FsmOfferingTimeout") );
  1349. switch ( event )
  1350. {
  1351. case TE_Expire:
  1352. //
  1353. // Timeout period expired, take necesarry actions
  1354. //
  1355. {
  1356. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Timer expired") );
  1357. NdisAcquireSpinLock( &pCall->lockCall );
  1358. if ( pCall->stateCall != CL_stateOffering )
  1359. {
  1360. //
  1361. // State has changed, no need further processing of this event
  1362. //
  1363. TRACE( TL_A, TM_Fsm, ("FsmOfferingTimeout: State already changed") );
  1364. NdisReleaseSpinLock( &pCall->lockCall );
  1365. break;
  1366. }
  1367. //
  1368. // Check if we have reached the max number of time outs
  1369. //
  1370. if ( pCall->nNumTimeouts == pCall->pLine->pAdapter->nMaxTimeouts )
  1371. {
  1372. //
  1373. // We did not receive any answers, drop the call
  1374. //
  1375. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Max number of timeouts reached") );
  1376. NdisReleaseSpinLock( &pCall->lockCall );
  1377. fDropCall = TRUE;
  1378. break;
  1379. }
  1380. //
  1381. // Schedule another timeout event
  1382. //
  1383. TimerQInitializeItem( &pCall->timerTimeout );
  1384. TimerQScheduleItem( &gl_TimerQ,
  1385. &pCall->timerTimeout,
  1386. pCall->pLine->pAdapter->ulRecvTimeout,
  1387. FsmOfferingTimeout,
  1388. (PVOID) pCall );
  1389. //
  1390. // Reference call for the new timeout handler
  1391. //
  1392. ReferenceCall( pCall, FALSE );
  1393. //
  1394. // Increment the timeout counter
  1395. //
  1396. pCall->nNumTimeouts++;
  1397. NdisReleaseSpinLock( &pCall->lockCall );
  1398. }
  1399. break;
  1400. case TE_Cancel:
  1401. case TE_Terminate:
  1402. {
  1403. //
  1404. // Reset the timeout counter and reference will be removed below
  1405. //
  1406. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Timer cancelled or terminated") );
  1407. NdisAcquireSpinLock( &pCall->lockCall );
  1408. pCall->nNumTimeouts = 0;
  1409. NdisReleaseSpinLock( &pCall->lockCall );
  1410. }
  1411. break;
  1412. }
  1413. if ( fDropCall )
  1414. {
  1415. NDIS_TAPI_DROP DummyRequest;
  1416. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Dropping call") );
  1417. DummyRequest.hdCall = pCall->hdCall;
  1418. //
  1419. // Drop will take care of unbinding and cancelling the timer
  1420. //
  1421. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, 0 );
  1422. }
  1423. DereferenceCall( pCall );
  1424. TRACE( TL_N, TM_Fsm, ("-FsmOfferingTimeout") );
  1425. }