/** * \fn txMgmtQ_QueuesNotEmpty * \brief Context-Engine Callback * * Context-Engine Callback for processing queues in driver's context. * Called after driver's context scheduling was requested in txMgmtQ_Xmit(). * Calls the SM with QUEUES_NOT_EMPTY event. * * \note * \param hTxMgmtQ - The module's object * \return void * \sa txMgmtQ_Xmit */ void txMgmtQ_QueuesNotEmpty (TI_HANDLE hTxMgmtQ) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; /* Call the SM with QUEUES_NOT_EMPTY event. */ mgmtQueuesSM(pTxMgmtQ, SM_EVENT_QUEUES_NOT_EMPTY); }
/** * \fn txMgmtQ_SetConnState * \brief Enable all queues transmission * * Called by the connection SM and updates the connection state from Tx perspective * (i.e. which packet types are permitted). * Calls the local SM to handle this state change. * * \note * \param hTxMgmtQ - The module's object * \param eTxConnState - The new Tx connection state * \return void * \sa mgmtQueuesSM */ void txMgmtQ_SetConnState (TI_HANDLE hTxMgmtQ, ETxConnState eTxConnState) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; pTxMgmtQ->eTxConnState = eTxConnState; /* Call the SM with the current event. */ switch (eTxConnState) { case TX_CONN_STATE_CLOSE: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_CLOSE); break; case TX_CONN_STATE_MGMT: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_MGMT); break; case TX_CONN_STATE_EAPOL: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_EAPOL); break; case TX_CONN_STATE_OPEN: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_OPEN); break; default: TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, ": Unknown eTxConnState = %d\n", eTxConnState); } }
/** * \fn txMgmtQ_Xmit * \brief Insert non-data packet for transmission * * This function is used by the driver applications to send Tx packets other than the * regular data traffic, including the following packet types: * - Management * - EAPOL * - NULL * - IAPP * The managment packets are enqueued to the Mgmt-queue and the others to the Eapol-queue. * EAPOL packets may be inserted from the network stack context, so it requires switching * to the driver's context (after the packet is enqueued). * If the selected queue was empty before the packet insertion, the SM is called * with QUEUES_NOT_EMPTY event (in case of external context, only after the context switch). * * \note * \param hTxMgmtQ - The module's object * \param pPktCtrlBlk - Pointer to the packet CtrlBlk * \param bExternalContext - Indicates if called from non-driver context * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. * \sa txMgmtQ_QueuesNotEmpty */ TI_STATUS txMgmtQ_Xmit (TI_HANDLE hTxMgmtQ, TTxCtrlBlk *pPktCtrlBlk, TI_BOOL bExternalContext) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; /* Always set highest TID for mgmt-queues packets. */ pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; /* Select queue asccording to the packet type */ uQueId = (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) ? QUEUE_TYPE_MGMT : QUEUE_TYPE_EAPOL ; /* Enter critical section to protect queue access */ context_EnterCriticalSection (pTxMgmtQ->hContext); /* Enqueue the packet in the appropriate Queue */ eStatus = que_Enqueue (pTxMgmtQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pTxMgmtQ->aQueues[uQueId]); /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If packet enqueued successfully */ if (eStatus == TI_OK) { pTxMgmtQ->tDbgCounters.aEnqueuePackets[uQueId]++; /* If selected queue was empty before packet insertion */ if (uQueSize == 1) { /* If called from external context (EAPOL from network), request switch to the driver's context. */ if (bExternalContext) { context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId); } /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */ else { mgmtQueuesSM(pTxMgmtQ, SM_EVENT_QUEUES_NOT_EMPTY); } } } else { /* If the packet can't be queued so drop it */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); pTxMgmtQ->tDbgCounters.aDroppedPackets[uQueId]++; } return eStatus; }
/** * \fn txMgmtQ_SetConnState * \brief Enable all queues transmission * * Called by the connection SM and updates the connection state from Tx perspective * (i.e. which packet types are permitted). * Calls the local SM to handle this state change. * * \note * \param hTxMgmtQ - The module's object * \param eTxConnState - The new Tx connection state * \return void * \sa mgmtQueuesSM */ void txMgmtQ_SetConnState (TI_HANDLE hTxMgmtQ, ETxConnState eTxConnState) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TMgmtLinkQ *pLinkQ; TI_UINT32 uHlid = 0; /* TODO[ilanb]: move to parameter, this API is for STA */ pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ pLinkQ->eTxConnState = eTxConnState; /* Call the SM with the current event. */ switch (eTxConnState) { case TX_CONN_STATE_CLOSE: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_CLOSE); break; case TX_CONN_STATE_MGMT: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_MGMT); break; case TX_CONN_STATE_EAPOL: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_EAPOL); break; case TX_CONN_STATE_OPEN: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_OPEN); break; default: TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, ": Unknown eTxConnState = %d\n", eTxConnState); } }
/** * \fn runSchedulerNotFromSm * \brief Run scheduler due to other events then from SM (static function) * * To comply with the SM behavior, this function is used for any case where the * Mgmt-Queues scheduler may have work to do due to events external to the SM. * If the queues are not empty, this function runs the scheduler. * If the scheduler emptied the queues, update the SM. * * \note * \param pTxMgmtQ - The module's object * \return void * \sa */ static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ) { /* If the queues are not empty, run the scheduler. */ if ( !ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) { runScheduler (pTxMgmtQ); /* If the queues are now both empty, call the SM with QUEUES_EMPTY event. */ if ( ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) { mgmtQueuesSM (pTxMgmtQ, SM_EVENT_QUEUES_EMPTY); } } }
/** * \fn txMgmtQ_SetLinkState * \brief set link state (enable/not) * * \note * \param hTxMgmtQ - The module's object * \param uHlid - link id * \param eTxConnState - The new Tx connection state * \return void * \sa mgmtQueuesSM */ TI_STATUS txMgmtQ_SetLinkState (TI_HANDLE hTxMgmtQ, TI_UINT32 uHlid, ETxConnState eTxConnState) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TMgmtLinkQ *pLinkQ; pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ pLinkQ->eTxConnState = eTxConnState; TRACE4(pTxMgmtQ->hReport, REPORT_SEVERITY_INFORMATION,"%s: link %d, LinkState %d, ConnState %d\n", __FUNCTION__, uHlid, pLinkQ->eState, pLinkQ->eTxConnState); /* Call the SM with the current event. */ switch (eTxConnState) { case TX_CONN_STATE_CLOSE: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_CLOSE); break; case TX_CONN_STATE_MGMT: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_MGMT); break; case TX_CONN_STATE_EAPOL: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_EAPOL); break; case TX_CONN_STATE_OPEN: mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_OPEN); break; default: TRACE2(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, ": Unknown eTxConnState = %d, for link %d\n", eTxConnState, uHlid); } return TI_OK; }
/** * \fn txMgmtQ_QueuesNotEmpty * \brief Context-Engine Callback * * Context-Engine Callback for processing queues in driver's context. * Called after driver's context scheduling was requested in txMgmtQ_Xmit(). * Calls the SM with QUEUES_NOT_EMPTY event. * * \note * \param hTxMgmtQ - The module's object * \return void * \sa txMgmtQ_Xmit */ void txMgmtQ_QueuesNotEmpty (TI_HANDLE hTxMgmtQ) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TI_UINT32 uHlid; /* Call the SM with QUEUES_NOT_EMPTY event. */ for (uHlid=0; uHlid<WLANLINKS_MAX_LINKS; uHlid++) { /* Call every link that is not in CLOSE state */ if (pTxMgmtQ->aMgmtLinkQ[uHlid].bSendEvent_NotEmpty) { /* reset bSendEvent_NotEmpty flag to use in driver context */ pTxMgmtQ->aMgmtLinkQ[uHlid].bSendEvent_NotEmpty = TI_FALSE; /* handle the event in the link state machine */ mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_QUEUES_NOT_EMPTY); } } }
/** * \fn runSchedulerNotFromSm * \brief Run scheduler due to other events then from SM (static function) * * To comply with the SM behavior, this function is used for any case where the * Mgmt-Queues scheduler may have work to do due to events external to the SM. * If the queues are not empty, this function runs the scheduler. * If the scheduler emptied the queues, update the SM. * * \note * \param pTxMgmtQ - The module's object * \return void * \sa */ static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ) { TMgmtLinkQ *pLinkQ; TI_UINT32 uHlid; for (uHlid=0; uHlid<WLANLINKS_MAX_LINKS; uHlid++) { pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ /* If the queues are not empty, run the scheduler. */ if ( !ARE_LINK_MGMT_QUEUES_EMPTY(pLinkQ->aQueues) ) { runScheduler (pTxMgmtQ); /* If the queues are now both empty, call the SM with QUEUES_EMPTY event. */ if ( ARE_LINK_MGMT_QUEUES_EMPTY(pLinkQ->aQueues) ) { mgmtQueuesSM (pTxMgmtQ, uHlid, SM_EVENT_QUEUES_EMPTY); } } } }
/** * \fn txMgmtQ_Xmit * \brief Insert non-data packet for transmission * * This function is used by the driver applications to send Tx packets other than the * regular data traffic, including the following packet types: * - Management * - EAPOL * - NULL * - IAPP * The managment packets are enqueued to the Mgmt-queue and the others to the Eapol-queue. * EAPOL packets may be inserted from the network stack context, so it requires switching * to the driver's context (after the packet is enqueued). * If the selected queue was empty before the packet insertion, the SM is called * with QUEUES_NOT_EMPTY event (in case of external context, only after the context switch). * * \note * \param hTxMgmtQ - The module's object * \param pPktCtrlBlk - Pointer to the packet CtrlBlk * \param bExternalContext - Indicates if called from non-driver context * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. * \sa txMgmtQ_QueuesNotEmpty */ TI_STATUS txMgmtQ_Xmit (TI_HANDLE hTxMgmtQ, TTxCtrlBlk *pPktCtrlBlk, TI_BOOL bExternalContext) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; TI_UINT32 uHlid; TMgmtLinkQ *pLinkQ; /* Find link id by destination MAC address, if not found use global link id */ if (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) { /* MGMT packet, use destination MAC address from WLAN header, aBuf[0] is the WLAN header */ if ((txDataQ_LinkMacFind( pTxMgmtQ->hTxDataQ, &uHlid ,((dot11_header_t *)(pPktCtrlBlk->tTxnStruct.aBuf[0]))->address1 )) != TI_OK) { uHlid = pTxMgmtQ->uGlobalHlid; } } else { /* EAPOL packet, use destination MAC address from ETHERNET header, aBuf[0] is the ETHERNET header */ if ((txDataQ_LinkMacFind( pTxMgmtQ->hTxDataQ, &uHlid, ((TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]))->dst)) != TI_OK) { uHlid = pTxMgmtQ->uGlobalHlid; } } pPktCtrlBlk->tTxDescriptor.hlid = uHlid; pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ /* Always set highest TID for mgmt-queues packets. */ pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; if ((pLinkQ->bEncrypt)&& (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_EAPOL)) { SET_PKT_TYPE_ENCRYPT(pPktCtrlBlk); } /* Select queue asccording to the packet type */ uQueId = (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) ? QUEUE_TYPE_MGMT : QUEUE_TYPE_EAPOL ; /* Enter critical section to protect queue access */ context_EnterCriticalSection (pTxMgmtQ->hContext); /* Check resources per LINK and per MGMT AC (VOICE)*/ if (txDataQ_AllocCheckResources( pTxMgmtQ->hTxDataQ, pPktCtrlBlk) != TI_OK) { pLinkQ->tDbgCounters.aDroppedPackets[uQueId]++; pLinkQ->tDbgCounters.uNoResourcesCount++; /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If the packet can't be queued drop it */ /* !!! This call should be out of the critical section */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); return TI_NOK; } /* Enqueue the packet in the appropriate Queue */ eStatus = que_Enqueue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pLinkQ->aQueues[uQueId]); /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If packet enqueued successfully */ if (eStatus == TI_OK) { pLinkQ->tDbgCounters.aEnqueuePackets[uQueId]++; /* If selected queue was empty before packet insertion */ if (uQueSize == 1 ) if (uQueSize ) { /* If called from external context (EAPOL from network), request switch to the driver's context. */ if (bExternalContext) { /* Set bSendEvent_NotEmpty flag to use in driver context */ pLinkQ->bSendEvent_NotEmpty = TI_TRUE; context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId); } /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */ else { mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_QUEUES_NOT_EMPTY); } } } else { /* If the packet can't be queued so drop it */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); pLinkQ->tDbgCounters.aDroppedPackets[uQueId]++; } return eStatus; }