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.

1971 lines
47 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. if(NULL != pFirstRecvServiceNameValue)
  489. {
  490. NdisMoveMemory( pCall->ServiceName,
  491. pFirstRecvServiceNameValue,
  492. pCall->nServiceNameLength );
  493. }
  494. fFound = TRUE;
  495. }
  496. }
  497. }
  498. if ( !fFound )
  499. {
  500. //
  501. // We could not find a matching service name tag, so drop the packet
  502. //
  503. TRACE( TL_A, TM_Fsm, ("FsmRun: PADO does not contain the service-name tag we requested") );
  504. break;
  505. }
  506. }
  507. }
  508. //
  509. // Received packet is validated, so set the dest addr in the call.
  510. // The source address will be copied on the call in PrAddCallToBinding() below.
  511. //
  512. NdisMoveMemory( pCall->DestAddr, PacketGetSrcAddr( pRecvPacket ), 6 * sizeof( CHAR ) );
  513. //
  514. // Received packet is validated, so proceed to next state
  515. //
  516. pCall->stateCall = CL_stateSendPadr;
  517. fFallThru = TRUE;
  518. //
  519. // As we are done with the last sent packet, free it
  520. //
  521. pCall->pSendPacket = NULL;
  522. PacketFree( pPacket );
  523. //
  524. // Cancel the timeout handler and attach call to binding
  525. //
  526. NdisReleaseSpinLock( &pCall->lockCall );
  527. TimerQCancelItem( &gl_TimerQ, &pCall->timerTimeout );
  528. PrAddCallToBinding( pBinding, pCall );
  529. //
  530. // Notify TAPI that our call is in proceeding state
  531. //
  532. TpCallStateChangeHandler( pCall, LINECALLSTATE_PROCEEDING, 0 );
  533. NdisAcquireSpinLock( &pCall->lockCall );
  534. //
  535. // Make sure state was not changed when we released the lock to cancel the timer queue item
  536. //
  537. if ( pCall->stateCall != CL_stateSendPadr )
  538. {
  539. TRACE( TL_A, TM_Fsm, ("FsmRun: State changed unexpectedly from CL_stateSendPadr") );
  540. break;
  541. }
  542. //
  543. // Fall thru to case CL_stateSendPadr
  544. //
  545. }
  546. case CL_stateSendPadr:
  547. //
  548. // In this state, we have received a valid PADO packet, and we need to respond to it
  549. // with a PADR packet
  550. //
  551. {
  552. NDIS_STATUS status;
  553. PPPOE_PACKET* pPacket = NULL;
  554. CHAR tagHostUniqueValue[16];
  555. USHORT tagHostUniqueLength;
  556. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateSendPadr") );
  557. if ( !fFallThru )
  558. {
  559. TRACE( TL_N, TM_Fsm, ("FsmRun: Non fall thru entry into a fall thru state") );
  560. break;
  561. }
  562. CreateUniqueValue( pCall->hdCall,
  563. tagHostUniqueValue,
  564. &tagHostUniqueLength );
  565. //
  566. // Create a PADR packet to send
  567. //
  568. status = PacketInitializePADRToSend( pRecvPacket,
  569. &pPacket,
  570. pCall->nServiceNameLength,
  571. pCall->ServiceName,
  572. tagHostUniqueLength,
  573. tagHostUniqueValue );
  574. if ( status != NDIS_STATUS_SUCCESS )
  575. {
  576. TRACE( TL_A, TM_Fsm, ("FsmRun: Failed to initialize PADR to send") );
  577. fDropCall = TRUE;
  578. ulLineDisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  579. break;
  580. }
  581. //
  582. // Attach packet to call context
  583. //
  584. pCall->pSendPacket = pPacket;
  585. ReferencePacket( pPacket );
  586. //
  587. // Reference binding for PrSend()
  588. //
  589. ReferenceBinding( pBinding, TRUE );
  590. //
  591. // Initialize and schedule the timeout handler
  592. //
  593. pCall->nNumTimeouts = 0;
  594. TimerQInitializeItem( &pCall->timerTimeout );
  595. TimerQScheduleItem( &gl_TimerQ,
  596. &pCall->timerTimeout,
  597. pCall->pLine->pAdapter->ulSendTimeout,
  598. FsmSendPADRTimeout,
  599. (PVOID) pCall );
  600. //
  601. // Reference call for the timeout handler
  602. //
  603. ReferenceCall( pCall, FALSE );
  604. //
  605. // Advance the state to next
  606. //
  607. pCall->stateCall = CL_stateWaitPads;
  608. //
  609. // Release the lock to send the packet
  610. //
  611. NdisReleaseSpinLock( &pCall->lockCall );
  612. fLockReleased = TRUE;
  613. //
  614. // Packet is ready, so send it
  615. //
  616. status = PrSend( pBinding, pPacket );
  617. if ( status != NDIS_STATUS_PENDING )
  618. {
  619. if ( status != NDIS_STATUS_SUCCESS )
  620. {
  621. //
  622. // Send operation was not succesful, so drop the call
  623. //
  624. TRACE( TL_A, TM_Fsm, ("FsmRun: PrSend() failed to send PADR") );
  625. fDropCall = TRUE;
  626. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  627. }
  628. }
  629. }
  630. break;
  631. case CL_stateWaitPads:
  632. //
  633. // In this state, we have sent a PADR packet and waiting for a PADS packet to establish
  634. // a session
  635. //
  636. {
  637. PPPOE_PACKET* pPacket;
  638. USHORT usRecvHostUniqueLength;
  639. USHORT usSendHostUniqueLength;
  640. CHAR* pRecvHostUniqueValue = NULL;
  641. CHAR* pSendHostUniqueValue = NULL;
  642. USHORT usRecvServiceNameLength;
  643. USHORT usSendServiceNameLength;
  644. CHAR* pRecvServiceNameValue = NULL;
  645. CHAR* pSendServiceNameValue = NULL;
  646. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateWaitPads") );
  647. //
  648. // Make sure that we received a packet
  649. //
  650. if ( pRecvPacket == NULL )
  651. {
  652. TRACE( TL_A, TM_Fsm, ("FsmRun: No packets received") );
  653. break;
  654. }
  655. //
  656. // Make sure that we received a PADO packet
  657. //
  658. if ( PacketGetCode( pRecvPacket ) != PACKET_CODE_PADS )
  659. {
  660. TRACE( TL_A, TM_Fsm, ("FsmRun: Packet not PADS") );
  661. break;
  662. }
  663. //
  664. // Check for errors
  665. //
  666. if ( PacketAnyErrorTagsReceived( pRecvPacket ) )
  667. {
  668. PACKET_TAGS tagType;
  669. USHORT tagLength;
  670. CHAR* tagValue = NULL;
  671. TRACE( TL_A, TM_Fsm, ("FsmRun: Error tag received in the packet") );
  672. fDropCall = TRUE;
  673. //
  674. // Set the line disconnect mode looking at the error tag
  675. //
  676. PacketRetrieveErrorTag( pRecvPacket,
  677. &tagType,
  678. &tagLength,
  679. &tagValue );
  680. switch( tagType ) {
  681. case tagServiceNameError:
  682. ulLineDisconnectMode = LINEDISCONNECTMODE_BADADDRESS;
  683. break;
  684. case tagACSystemError:
  685. ulLineDisconnectMode = LINEDISCONNECTMODE_INCOMPATIBLE;
  686. break;
  687. case tagGenericError:
  688. ulLineDisconnectMode = LINEDISCONNECTMODE_REJECT;
  689. break;
  690. }
  691. break;
  692. }
  693. //
  694. // Verify the host unique tag
  695. //
  696. if ( pCall->pSendPacket == NULL )
  697. {
  698. //
  699. // Something is wrong, the last send packet is freed, just return
  700. //
  701. TRACE( TL_A, TM_Fsm, ("FsmRun: Last sent packet is freed") );
  702. fDropCall = TRUE;
  703. ulLineDisconnectMode = LINEDISCONNECTMODE_UNKNOWN;
  704. break;
  705. }
  706. pPacket = pCall->pSendPacket;
  707. PacketRetrieveHostUniqueTag( pPacket,
  708. &usSendHostUniqueLength,
  709. &pSendHostUniqueValue );
  710. PacketRetrieveHostUniqueTag( pRecvPacket,
  711. &usRecvHostUniqueLength,
  712. &pRecvHostUniqueValue );
  713. if ( usSendHostUniqueLength != usRecvHostUniqueLength )
  714. {
  715. //
  716. // Lengths of host unique tags mismatch, drop the packet
  717. //
  718. TRACE( TL_A, TM_Fsm, ("FsmRun: Host Unique tag lengths mismatch") );
  719. break;
  720. }
  721. if ( !NdisEqualMemory( pSendHostUniqueValue, pRecvHostUniqueValue, usSendHostUniqueLength ) )
  722. {
  723. //
  724. // Host unique tag values mismatch, drop the packet
  725. //
  726. TRACE( TL_A, TM_Fsm, ("FsmRun: Host Unique tag values mismatch") );
  727. break;
  728. }
  729. //
  730. // Host unique id is validated, verify the service name
  731. //
  732. PacketRetrieveServiceNameTag( pPacket,
  733. &usSendServiceNameLength,
  734. &pSendServiceNameValue,
  735. 0,
  736. NULL );
  737. PacketRetrieveServiceNameTag( pRecvPacket,
  738. &usRecvServiceNameLength,
  739. &pRecvServiceNameValue,
  740. 0,
  741. NULL );
  742. //
  743. // Make sure we have received a service-name at least
  744. //
  745. if ( pRecvServiceNameValue == NULL )
  746. {
  747. TRACE( TL_A, TM_Fsm, ("FsmRun: No service-name tag in a received PADS") );
  748. break;
  749. }
  750. //
  751. // Search for the specific service-name we requested
  752. //
  753. {
  754. BOOLEAN fFound = FALSE;
  755. //
  756. // We have asked for a specific service name, so let's
  757. // see if the server responded with it
  758. //
  759. while ( usRecvServiceNameLength >= 0 && pRecvServiceNameValue != NULL )
  760. {
  761. if ( usRecvServiceNameLength == usSendServiceNameLength )
  762. {
  763. if ( NdisEqualMemory( pSendServiceNameValue,
  764. pRecvServiceNameValue,
  765. usSendServiceNameLength ) )
  766. {
  767. fFound = TRUE;
  768. break;
  769. }
  770. }
  771. PacketRetrieveServiceNameTag( pRecvPacket,
  772. &usRecvServiceNameLength,
  773. &pRecvServiceNameValue,
  774. usRecvServiceNameLength,
  775. pRecvServiceNameValue );
  776. }
  777. if ( !fFound )
  778. {
  779. //
  780. // We could not find a matching service name tag, so drop the packet
  781. //
  782. TRACE( TL_A, TM_Fsm, ("FsmRun: PADS does not contain the service-name tag we requested") );
  783. break;
  784. }
  785. }
  786. //
  787. // Set the session id on the call context
  788. //
  789. pCall->usSessionId = PacketGetSessionId( pRecvPacket );
  790. //
  791. // As we are done with the last sent packet, free it
  792. //
  793. pCall->pSendPacket = NULL;
  794. PacketFree( pPacket );
  795. //
  796. // Cancel the timeout handler and attach call to binding
  797. //
  798. NdisReleaseSpinLock( &pCall->lockCall );
  799. fLockReleased = TRUE;
  800. TimerQCancelItem( &gl_TimerQ, &pCall->timerTimeout );
  801. //
  802. // Notify call connect event
  803. //
  804. TpCallStateChangeHandler( pCall, LINECALLSTATE_CONNECTED, 0 );
  805. }
  806. break;
  807. case CL_stateRecvdPadr:
  808. //
  809. // In this state, we have been received a PADR packet.
  810. // We will indicate the call to Tapi, and change the state to CL_stateOffering
  811. // and wait for the application to answer the call.
  812. //
  813. {
  814. NDIS_STATUS status;
  815. PPPOE_PACKET* pPacket;
  816. USHORT usRecvServiceNameLength;
  817. CHAR* pRecvServiceNameValue = NULL;
  818. USHORT usSessionId;
  819. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateWaitPadr") );
  820. //
  821. // Make sure that we received a packet
  822. //
  823. if ( pRecvPacket == NULL )
  824. {
  825. TRACE( TL_A, TM_Fsm, ("FsmRun: No packets received") );
  826. break;
  827. }
  828. //
  829. // Make sure that we received a PADR packet
  830. //
  831. if ( PacketGetCode( pRecvPacket ) != PACKET_CODE_PADR )
  832. {
  833. TRACE( TL_A, TM_Fsm, ("FsmRun: Packet not PADR") );
  834. break;
  835. }
  836. //
  837. // Set the dest addr in the call.
  838. // The source address will be copied on to the call in PrAddCallToBinding() below.
  839. //
  840. NdisMoveMemory( pCall->DestAddr, PacketGetSrcAddr( pRecvPacket ), 6 * sizeof( CHAR ) );
  841. //
  842. // Retrieve the service name and copy it onto the call context
  843. //
  844. PacketRetrieveServiceNameTag( pRecvPacket,
  845. &usRecvServiceNameLength,
  846. &pRecvServiceNameValue,
  847. 0,
  848. NULL );
  849. pCall->nServiceNameLength = ( MAX_SERVICE_NAME_LENGTH < usRecvServiceNameLength ) ?
  850. MAX_SERVICE_NAME_LENGTH : usRecvServiceNameLength;
  851. NdisMoveMemory( pCall->ServiceName,
  852. pRecvServiceNameValue,
  853. pCall->nServiceNameLength );
  854. //
  855. // Copy the AC-Name onto call context, before connection is established
  856. //
  857. pCall->nACNameLength = pCall->pLine->pAdapter->nACNameLength;
  858. NdisMoveMemory( pCall->ACName,
  859. pCall->pLine->pAdapter->ACName,
  860. pCall->nACNameLength );
  861. //
  862. // Retrieve the session id from the call handle and create a PADS packet to send
  863. //
  864. usSessionId = RetrieveSessionIdFromHandle( (NDIS_HANDLE) pCall->hdCall );
  865. status = PacketInitializePADSToSend( pRecvPacket,
  866. &pPacket,
  867. usSessionId );
  868. if ( status != NDIS_STATUS_SUCCESS )
  869. {
  870. TRACE( TL_A, TM_Fsm, ("FsmRun: Failed to initialize PADS to send") );
  871. fCloseCall = TRUE;
  872. break;
  873. }
  874. //
  875. // This PADS packet will be sent if application answers the call
  876. //
  877. pCall->pSendPacket = pPacket;
  878. //
  879. // Proceed to next state
  880. //
  881. pCall->stateCall = CL_stateOffering;
  882. //
  883. // Initialize and schedule the timeout handler
  884. //
  885. pCall->nNumTimeouts = 0;
  886. TimerQInitializeItem( &pCall->timerTimeout );
  887. TimerQScheduleItem( &gl_TimerQ,
  888. &pCall->timerTimeout,
  889. pCall->pLine->pAdapter->ulRecvTimeout,
  890. FsmOfferingTimeout,
  891. (PVOID) pCall );
  892. //
  893. // Reference call for the timeout handler
  894. //
  895. ReferenceCall( pCall, FALSE );
  896. //
  897. // Release the lock
  898. //
  899. NdisReleaseSpinLock( &pCall->lockCall );
  900. fLockReleased = TRUE;
  901. //
  902. // Notify TAPI about the state change
  903. //
  904. if ( TpIndicateNewCall( pCall ) )
  905. {
  906. //
  907. // Add call to binding
  908. //
  909. PrAddCallToBinding( pBinding, pCall );
  910. TpCallStateChangeHandler( pCall, LINECALLSTATE_OFFERING, 0 );
  911. }
  912. }
  913. break;
  914. case CL_stateSendPads:
  915. //
  916. // In this state, TAPI has accepted the call, so we should send the PADS packet and create
  917. // the session.
  918. //
  919. {
  920. NDIS_STATUS status;
  921. PPPOE_PACKET* pPacket = NULL;
  922. TRACE( TL_N, TM_Fsm, ("FsmRun: CL_stateSendPads") );
  923. if ( pRecvPacket != NULL )
  924. {
  925. TRACE( TL_A, TM_Fsm, ("FsmRun: Can not process packets in this state") );
  926. break;
  927. }
  928. //
  929. // Make sure we still have the PADS packet to send
  930. //
  931. if ( pCall->pSendPacket == NULL )
  932. {
  933. //
  934. // Something is wrong, the last send packet is freed, drop the call
  935. //
  936. TRACE( TL_A, TM_Fsm, ("FsmRun: Last sent packet is freed") );
  937. fDropCall = TRUE;
  938. *pStatus = NDIS_STATUS_FAILURE;
  939. break;
  940. }
  941. pPacket = pCall->pSendPacket;
  942. if ( pCall->pBinding == NULL )
  943. {
  944. //
  945. // Binding is gone, we should drop the call
  946. //
  947. TRACE( TL_A, TM_Fsm, ("FsmRun: No binding found") );
  948. fDropCall = TRUE;
  949. *pStatus = NDIS_STATUS_FAILURE;
  950. break;
  951. }
  952. pBinding = pCall->pBinding;
  953. //
  954. // Reference packet and binding for PrSend()
  955. //
  956. ReferencePacket( pPacket );
  957. ReferenceBinding( pBinding, TRUE );
  958. //
  959. // Set the session id on the call context
  960. //
  961. pCall->usSessionId = RetrieveSessionIdFromHandle( (NDIS_HANDLE) pCall->hdCall );
  962. //
  963. // Release the lock and send the packet
  964. //
  965. NdisReleaseSpinLock( &pCall->lockCall );
  966. fLockReleased = TRUE;
  967. //
  968. // Cancel the timeout handler
  969. //
  970. TimerQCancelItem( &gl_TimerQ, &pCall->timerTimeout );
  971. //
  972. // Packet is ready, so send it
  973. //
  974. status = PrSend( pBinding, pPacket );
  975. if ( status != NDIS_STATUS_PENDING )
  976. {
  977. if ( status != NDIS_STATUS_SUCCESS )
  978. {
  979. //
  980. // Send operation was not succesful, so drop the call
  981. //
  982. TRACE( TL_A, TM_Fsm, ("FsmRun: PrSend() failed to send PADS") );
  983. fDropCall = TRUE;
  984. *pStatus = NDIS_STATUS_FAILURE;
  985. break;
  986. }
  987. }
  988. //
  989. // Notify call connect event, since we sent the PADS packet
  990. //
  991. TpCallStateChangeHandler( pCall, LINECALLSTATE_CONNECTED, 0 );
  992. *pStatus = NDIS_STATUS_SUCCESS;
  993. }
  994. break;
  995. default:
  996. TRACE( TL_A, TM_Fsm, ("FsmRun: Ignoring irrelevant state notification") );
  997. break;
  998. }
  999. if ( !fLockReleased )
  1000. {
  1001. NdisReleaseSpinLock( &pCall->lockCall );
  1002. }
  1003. if ( fCloseCall )
  1004. {
  1005. NDIS_TAPI_CLOSE_CALL DummyRequest;
  1006. TRACE( TL_N, TM_Fsm, ("FsmRun: Closing call") );
  1007. DummyRequest.hdCall = pCall->hdCall;
  1008. //
  1009. // Close will take care of unbinding and cancelling the timer
  1010. //
  1011. TpCloseCall( pCall->pLine->pAdapter, &DummyRequest, FALSE );
  1012. }
  1013. if ( fDropCall )
  1014. {
  1015. NDIS_TAPI_DROP DummyRequest;
  1016. TRACE( TL_N, TM_Fsm, ("FsmRun: Dropping call") );
  1017. DummyRequest.hdCall = pCall->hdCall;
  1018. //
  1019. // Drop will take care of unbinding and cancelling the timer
  1020. //
  1021. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, ulLineDisconnectMode );
  1022. }
  1023. TRACE( TL_N, TM_Fsm, ("-FsmRun") );
  1024. }
  1025. VOID
  1026. FsmSendPADITimeout(
  1027. IN TIMERQITEM* pTqi,
  1028. IN VOID* pContext,
  1029. IN TIMERQEVENT event
  1030. )
  1031. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1032. Functional Description:
  1033. This function is the timeout handler for a sent PADI packet.
  1034. If the timeout period expires before a valid PADO packet is received,
  1035. this function will be called with TE_Expire. In this case we check for
  1036. a few conditions, and schedule another timeout event if necesarry.
  1037. If it was cancelled -because a PADO packet was received - or timer queue
  1038. is terminating then it will be called with TE_Cancel and TE_Terminate codes
  1039. respectively. In this case, we do not do anything, just remove the reference
  1040. and return.
  1041. Parameters:
  1042. pTqi _ A pointer to our timer queue item information structure.
  1043. pContext _ A pointer to a our call information structure.
  1044. event _ Indicates the type of event: TE_Expire, TE_Cancel or TE_Terminate.
  1045. Return Values:
  1046. None
  1047. ---------------------------------------------------------------------------*/
  1048. {
  1049. CALL* pCall = (CALL*) pContext;
  1050. BOOLEAN fDropCall = FALSE;
  1051. ULONG ulLineDisconnectMode = 0;
  1052. TRACE( TL_N, TM_Fsm, ("+FsmSendPADITimeout") );
  1053. switch ( event )
  1054. {
  1055. case TE_Expire:
  1056. //
  1057. // Timeout period expired, take necesarry actions
  1058. //
  1059. {
  1060. NDIS_STATUS status;
  1061. PPPOE_PACKET* pPacket = NULL;
  1062. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Timer expired") );
  1063. NdisAcquireSpinLock( &pCall->lockCall );
  1064. if ( pCall->stateCall != CL_stateWaitPado )
  1065. {
  1066. //
  1067. // State has changed, no need further processing of this event
  1068. //
  1069. TRACE( TL_A, TM_Fsm, ("FsmSendPADITimeout: State already changed") );
  1070. NdisReleaseSpinLock( &pCall->lockCall );
  1071. break;
  1072. }
  1073. //
  1074. // Check if we have reached the max number of time outs
  1075. //
  1076. if ( pCall->nNumTimeouts == pCall->pLine->pAdapter->nMaxTimeouts )
  1077. {
  1078. //
  1079. // We did not receive any answers, drop the call
  1080. //
  1081. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Max number of timeouts reached") );
  1082. NdisReleaseSpinLock( &pCall->lockCall );
  1083. fDropCall = TRUE;
  1084. ulLineDisconnectMode = LINEDISCONNECTMODE_NOANSWER;
  1085. break;
  1086. }
  1087. pPacket = pCall->pSendPacket;
  1088. if ( pPacket == NULL )
  1089. {
  1090. //
  1091. // We are probably in a ver small timing window where FsmRun() is also
  1092. // working on the same call, and has just freed the packet, so it probably
  1093. // cancelled the timer, but we did not get the cancel, and instead we were
  1094. // called with TE_Expire, so let's just act like we were cancelled.
  1095. //
  1096. TRACE( TL_A, TM_Fsm, ("FsmSendPADITimeout: Can not find last sent packet for re-send") );
  1097. NdisReleaseSpinLock( &pCall->lockCall );
  1098. break;
  1099. }
  1100. ReferencePacket( pPacket );
  1101. //
  1102. // Schedule another timeout event
  1103. //
  1104. TimerQInitializeItem( &pCall->timerTimeout );
  1105. TimerQScheduleItem( &gl_TimerQ,
  1106. &pCall->timerTimeout,
  1107. pCall->pLine->pAdapter->ulSendTimeout,
  1108. FsmSendPADITimeout,
  1109. (PVOID) pCall );
  1110. //
  1111. // Reference call for the new timeout handler
  1112. //
  1113. ReferenceCall( pCall, FALSE );
  1114. //
  1115. // Increment the timeout counter
  1116. //
  1117. pCall->nNumTimeouts++;
  1118. NdisReleaseSpinLock( &pCall->lockCall );
  1119. //
  1120. // Packet is ready, so broadcast it
  1121. //
  1122. status = PrBroadcast( pPacket );
  1123. if ( status != NDIS_STATUS_SUCCESS )
  1124. {
  1125. //
  1126. // Broadcast unsuccesfull, drop the call
  1127. //
  1128. TRACE( TL_A, TM_Fsm, ("FsmSendPADITimeout: Broadcast failed") );
  1129. fDropCall = TRUE;
  1130. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  1131. }
  1132. DereferencePacket( pPacket );
  1133. }
  1134. break;
  1135. case TE_Cancel:
  1136. case TE_Terminate:
  1137. {
  1138. //
  1139. // Reset the timeout counter and reference will be removed below
  1140. //
  1141. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Timer cancelled or terminated") );
  1142. NdisAcquireSpinLock( &pCall->lockCall );
  1143. pCall->nNumTimeouts = 0;
  1144. NdisReleaseSpinLock( &pCall->lockCall );
  1145. }
  1146. break;
  1147. }
  1148. if ( fDropCall )
  1149. {
  1150. NDIS_TAPI_DROP DummyRequest;
  1151. TRACE( TL_N, TM_Fsm, ("FsmSendPADITimeout: Dropping call") );
  1152. DummyRequest.hdCall = pCall->hdCall;
  1153. //
  1154. // Drop will take care of unbinding and cancelling the timer
  1155. //
  1156. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, ulLineDisconnectMode );
  1157. }
  1158. DereferenceCall( pCall );
  1159. TRACE( TL_N, TM_Fsm, ("-FsmSendPADITimeout") );
  1160. }
  1161. VOID
  1162. FsmSendPADRTimeout(
  1163. IN TIMERQITEM* pTqi,
  1164. IN VOID* pContext,
  1165. IN TIMERQEVENT event
  1166. )
  1167. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1168. Functional Description:
  1169. This function is the timeout handler for a sent PADR packet.
  1170. If the timeout period expires before a valid PADS packet is received,
  1171. this function will be called with TE_Expire. In this case we check for
  1172. a few conditions, and schedule another timeout event if necesarry.
  1173. If it was cancelled - because a PADS packet was received - or timer queue
  1174. is terminating then it will be called with TE_Cancel and TE_Terminate codes
  1175. respectively. In this case, we do not do anything, just remove the reference
  1176. and return.
  1177. Parameters:
  1178. pTqi _ A pointer to our timer queue item information structure.
  1179. pContext _ A pointer to a our call information structure.
  1180. event _ Indicates the type of event: TE_Expire, TE_Cancel or TE_Terminate.
  1181. Return Values:
  1182. None
  1183. ---------------------------------------------------------------------------*/
  1184. {
  1185. CALL* pCall = (CALL*) pContext;
  1186. BOOLEAN fDropCall = FALSE;
  1187. ULONG ulLineDisconnectMode = 0;
  1188. TRACE( TL_N, TM_Fsm, ("+FsmSendPADRTimeout") );
  1189. switch ( event )
  1190. {
  1191. case TE_Expire:
  1192. //
  1193. // Timeout period expired, take necesarry actions
  1194. //
  1195. {
  1196. NDIS_STATUS status;
  1197. PPPOE_PACKET* pPacket = NULL;
  1198. BINDING* pBinding = NULL;
  1199. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Timer expired") );
  1200. NdisAcquireSpinLock( &pCall->lockCall );
  1201. if ( pCall->stateCall != CL_stateWaitPads )
  1202. {
  1203. //
  1204. // State has changed, no need further processing of this event
  1205. //
  1206. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: State already changed") );
  1207. NdisReleaseSpinLock( &pCall->lockCall );
  1208. break;
  1209. }
  1210. //
  1211. // Check if we have reached the max number of time outs
  1212. //
  1213. if ( pCall->nNumTimeouts == pCall->pLine->pAdapter->nMaxTimeouts )
  1214. {
  1215. //
  1216. // We did not receive any answers, drop the call
  1217. //
  1218. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Max number of timeouts reached") );
  1219. NdisReleaseSpinLock( &pCall->lockCall );
  1220. fDropCall = TRUE;
  1221. ulLineDisconnectMode = LINEDISCONNECTMODE_BUSY;
  1222. break;
  1223. }
  1224. //
  1225. // Save the binding for send operation
  1226. //
  1227. pBinding = pCall->pBinding;
  1228. if ( pBinding == NULL )
  1229. {
  1230. //
  1231. // The binding was removed, drop the call
  1232. //
  1233. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: Binding not found") );
  1234. NdisReleaseSpinLock( &pCall->lockCall );
  1235. fDropCall = TRUE;
  1236. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  1237. break;
  1238. }
  1239. //
  1240. // Save the packet for send operation
  1241. //
  1242. pPacket = pCall->pSendPacket;
  1243. if ( pPacket == NULL )
  1244. {
  1245. //
  1246. // We are probably in a ver small timing window where FsmRun() is also
  1247. // working on the same call, and has just freed the packet, so it probably
  1248. // cancelled the timer, but we did not get the cancel, and instead we were
  1249. // called with TE_Expire, so let's just act like we were cancelled.
  1250. //
  1251. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: Can not find last sent packet for re-send") );
  1252. NdisReleaseSpinLock( &pCall->lockCall );
  1253. break;
  1254. }
  1255. //
  1256. // Reference both binding and the packet as PrSend() might pend, in which case
  1257. // PrSendComplete() will remove these references
  1258. //
  1259. ReferenceBinding ( pBinding, TRUE );
  1260. ReferencePacket( pPacket );
  1261. //
  1262. // Schedule another timeout event
  1263. //
  1264. TimerQInitializeItem( &pCall->timerTimeout );
  1265. TimerQScheduleItem( &gl_TimerQ,
  1266. &pCall->timerTimeout,
  1267. pCall->pLine->pAdapter->ulSendTimeout,
  1268. FsmSendPADRTimeout,
  1269. (PVOID) pCall );
  1270. //
  1271. // Reference call for the new timeout handler
  1272. //
  1273. ReferenceCall( pCall, FALSE );
  1274. //
  1275. // Increment the timeout counter
  1276. //
  1277. pCall->nNumTimeouts++;
  1278. NdisReleaseSpinLock( &pCall->lockCall );
  1279. //
  1280. // Send the packet once more
  1281. //
  1282. status = PrSend( pBinding, pPacket );
  1283. if ( status != NDIS_STATUS_PENDING )
  1284. {
  1285. if ( status != NDIS_STATUS_SUCCESS )
  1286. {
  1287. //
  1288. // Send operation was not succesful, so drop the call
  1289. //
  1290. TRACE( TL_A, TM_Fsm, ("FsmSendPADRTimeout: PrSend() failed to send PADR") );
  1291. fDropCall = TRUE;
  1292. ulLineDisconnectMode = LINEDISCONNECTMODE_UNREACHABLE;
  1293. }
  1294. }
  1295. }
  1296. break;
  1297. case TE_Cancel:
  1298. case TE_Terminate:
  1299. {
  1300. //
  1301. // Reset the timeout counter and reference will be removed below
  1302. //
  1303. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Timer cancelled or terminated") );
  1304. NdisAcquireSpinLock( &pCall->lockCall );
  1305. pCall->nNumTimeouts = 0;
  1306. NdisReleaseSpinLock( &pCall->lockCall );
  1307. }
  1308. break;
  1309. }
  1310. if ( fDropCall )
  1311. {
  1312. NDIS_TAPI_DROP DummyRequest;
  1313. TRACE( TL_N, TM_Fsm, ("FsmSendPADRTimeout: Dropping call") );
  1314. DummyRequest.hdCall = pCall->hdCall;
  1315. //
  1316. // Drop will take care of unbinding and cancelling the timer
  1317. //
  1318. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, ulLineDisconnectMode );
  1319. }
  1320. DereferenceCall( pCall );
  1321. TRACE( TL_N, TM_Fsm, ("-FsmSendPADRTimeout") );
  1322. }
  1323. VOID
  1324. FsmOfferingTimeout(
  1325. IN TIMERQITEM* pTqi,
  1326. IN VOID* pContext,
  1327. IN TIMERQEVENT event
  1328. )
  1329. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1330. Functional Description:
  1331. This function is the timeout handler for a received PADI packet.
  1332. The call is in LINECALLSTATE_OFFERING according to TAPI, and we are
  1333. waiting for an OID_TAPI_ACCEPT on the call.
  1334. If the timeout period expires before a TAPI request is received,
  1335. this function will be called with TE_Expire. In this case we check for
  1336. a few conditions, and schedule another timeout event if necesarry.
  1337. If it was cancelled - because a TAPI request was received - or timer queue
  1338. is terminating then it will be called with TE_Cancel and TE_Terminate codes
  1339. respectively. In this case, we do not do anything, just remove the reference
  1340. and return.
  1341. Parameters:
  1342. pTqi _ A pointer to our timer queue item information structure.
  1343. pContext _ A pointer to a our call information structure.
  1344. event _ Indicates the type of event: TE_Expire, TE_Cancel or TE_Terminate.
  1345. Return Values:
  1346. None
  1347. ---------------------------------------------------------------------------*/
  1348. {
  1349. CALL* pCall = (CALL*) pContext;
  1350. BOOLEAN fDropCall = FALSE;
  1351. TRACE( TL_N, TM_Fsm, ("+FsmOfferingTimeout") );
  1352. switch ( event )
  1353. {
  1354. case TE_Expire:
  1355. //
  1356. // Timeout period expired, take necesarry actions
  1357. //
  1358. {
  1359. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Timer expired") );
  1360. NdisAcquireSpinLock( &pCall->lockCall );
  1361. if ( pCall->stateCall != CL_stateOffering )
  1362. {
  1363. //
  1364. // State has changed, no need further processing of this event
  1365. //
  1366. TRACE( TL_A, TM_Fsm, ("FsmOfferingTimeout: State already changed") );
  1367. NdisReleaseSpinLock( &pCall->lockCall );
  1368. break;
  1369. }
  1370. //
  1371. // Check if we have reached the max number of time outs
  1372. //
  1373. if ( pCall->nNumTimeouts == pCall->pLine->pAdapter->nMaxTimeouts )
  1374. {
  1375. //
  1376. // We did not receive any answers, drop the call
  1377. //
  1378. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Max number of timeouts reached") );
  1379. NdisReleaseSpinLock( &pCall->lockCall );
  1380. fDropCall = TRUE;
  1381. break;
  1382. }
  1383. //
  1384. // Schedule another timeout event
  1385. //
  1386. TimerQInitializeItem( &pCall->timerTimeout );
  1387. TimerQScheduleItem( &gl_TimerQ,
  1388. &pCall->timerTimeout,
  1389. pCall->pLine->pAdapter->ulRecvTimeout,
  1390. FsmOfferingTimeout,
  1391. (PVOID) pCall );
  1392. //
  1393. // Reference call for the new timeout handler
  1394. //
  1395. ReferenceCall( pCall, FALSE );
  1396. //
  1397. // Increment the timeout counter
  1398. //
  1399. pCall->nNumTimeouts++;
  1400. NdisReleaseSpinLock( &pCall->lockCall );
  1401. }
  1402. break;
  1403. case TE_Cancel:
  1404. case TE_Terminate:
  1405. {
  1406. //
  1407. // Reset the timeout counter and reference will be removed below
  1408. //
  1409. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Timer cancelled or terminated") );
  1410. NdisAcquireSpinLock( &pCall->lockCall );
  1411. pCall->nNumTimeouts = 0;
  1412. NdisReleaseSpinLock( &pCall->lockCall );
  1413. }
  1414. break;
  1415. }
  1416. if ( fDropCall )
  1417. {
  1418. NDIS_TAPI_DROP DummyRequest;
  1419. TRACE( TL_N, TM_Fsm, ("FsmOfferingTimeout: Dropping call") );
  1420. DummyRequest.hdCall = pCall->hdCall;
  1421. //
  1422. // Drop will take care of unbinding and cancelling the timer
  1423. //
  1424. TpDropCall( pCall->pLine->pAdapter, &DummyRequest, 0 );
  1425. }
  1426. DereferenceCall( pCall );
  1427. TRACE( TL_N, TM_Fsm, ("-FsmOfferingTimeout") );
  1428. }