static struct sk_buff* ieee80211_DELBA( struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, TR_SELECT TxRxSelect, u16 ReasonCode ) { DELBA_PARAM_SET DelbaParamSet; struct sk_buff *skb = NULL; struct ieee80211_hdr_3addr* Delba = NULL; u8* tag = NULL; u16 tmp = 0; // u16 len = 6 + ieee->tx_headroom; if (net_ratelimit()) IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __FUNCTION__, ReasonCode, dst); memset(&DelbaParamSet, 0, 2); DelbaParamSet.field.Initiator = (TxRxSelect==TX_DIR)?1:0; DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); // if (skb == NULL) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); return NULL; } // skb_reserve(skb, ieee->tx_headroom); Delba = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); memcpy(Delba->addr1, dst, ETH_ALEN); memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); // tag = (u8*)skb_put(skb, 6); *tag ++= ACT_CAT_BA; *tag ++= ACT_DELBA; // tmp = cpu_to_le16(DelbaParamSet.shortData); memcpy(tag, (u8*)&tmp, 2); tag += 2; // tmp = cpu_to_le16(ReasonCode); memcpy(tag, (u8*)&tmp, 2); tag += 2; IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); if (net_ratelimit()) IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __FUNCTION__); return skb; }
/******************************************************************************************************************** *function: RX DELBA * input: struct sk_buff * skb //incoming ADDBAReq skb. * return: 0(pass), other(fail) * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. ********************************************************************************************************************/ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb) { struct rtl_80211_hdr_3addr *delba = NULL; PDELBA_PARAM_SET pDelBaParamSet = NULL; u8 *dst = NULL; if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 6) { IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof(struct rtl_80211_hdr_3addr) + 6)); return -1; } if (ieee->current_network.qos_data.active == 0 || !ieee->pHTInfo->bCurrentHTSupport) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "received DELBA while QOS or HT is not supported(%d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); return -1; } IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); delba = (struct rtl_80211_hdr_3addr *)skb->data; dst = &delba->addr2[0]; pDelBaParamSet = (PDELBA_PARAM_SET)&delba->payload[2]; if(pDelBaParamSet->field.Initiator == 1) { PRX_TS_RECORD pRxTs; if (!GetTs( ieee, (PTS_COMMON_INFO *)&pRxTs, dst, (u8)pDelBaParamSet->field.TID, RX_DIR, false) ) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for RXTS in %s()\n", __func__); return -1; } RxTsDeleteBA(ieee, pRxTs); } else { PTX_TS_RECORD pTxTs; if (!GetTs( ieee, (PTS_COMMON_INFO *)&pTxTs, dst, (u8)pDelBaParamSet->field.TID, TX_DIR, false) ) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for TXTS in %s()\n", __func__); return -1; } pTxTs->bUsingBa = false; pTxTs->bAddBaReqInProgress = false; pTxTs->bAddBaReqDelayed = false; del_timer_sync(&pTxTs->TsAddBaTimer); //PlatformCancelTimer(Adapter, &pTxTs->TsAddBaTimer); TxTsDeleteBA(ieee, pTxTs); } return 0; }
/******************************************************************************************************************** *function: RX ADDBAReq * input: struct sk_buff * skb //incoming ADDBAReq skb. * return: 0(pass), other(fail) * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. ********************************************************************************************************************/ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb) { struct rtl_80211_hdr_3addr *req = NULL; u16 rc = 0; u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; PBA_RECORD pBA = NULL; PBA_PARAM_SET pBaParamSet = NULL; u16 *pBaTimeoutVal = NULL; PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL; PRX_TS_RECORD pTS = NULL; if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 9) { IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof(struct rtl_80211_hdr_3addr) + 9)); return -1; } IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); req = (struct rtl_80211_hdr_3addr *) skb->data; tag = (u8 *)req; dst = &req->addr2[0]; tag += sizeof(struct rtl_80211_hdr_3addr); pDialogToken = tag + 2; //category+action pBaParamSet = (PBA_PARAM_SET)(tag + 3); //+DialogToken pBaTimeoutVal = (u16 *)(tag + 5); pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7); printk(KERN_INFO "====================>rx ADDBAREQ from :%pM\n", dst); //some other capability is not ready now. if ((ieee->current_network.qos_data.active == 0) || (!ieee->pHTInfo->bCurrentHTSupport)) //|| // (!ieee->pStaQos->bEnableRxImmBA) ) { rc = ADDBA_STATUS_REFUSED; IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); goto OnADDBAReq_Fail; } // Search for related traffic stream. // If there is no matched TS, reject the ADDBA request. if (!GetTs( ieee, (PTS_COMMON_INFO *)(&pTS), dst, (u8)(pBaParamSet->field.TID), RX_DIR, true) ) { rc = ADDBA_STATUS_REFUSED; IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __func__); goto OnADDBAReq_Fail; } pBA = &pTS->RxAdmittedBARecord; // To Determine the ADDBA Req content // We can do much more check here, including BufferSize, AMSDU_Support, Policy, StartSeqCtrl... // I want to check StartSeqCtrl to make sure when we start aggregation!!! // if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { rc = ADDBA_STATUS_INVALID_PARAM; IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __func__); goto OnADDBAReq_Fail; } // Admit the ADDBA Request // DeActivateBAEntry(ieee, pBA); pBA->DialogToken = *pDialogToken; pBA->BaParamSet = *pBaParamSet; pBA->BaTimeoutValue = *pBaTimeoutVal; pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; //for half N mode we only aggregate 1 frame if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) pBA->BaParamSet.field.BufferSize = 1; else pBA->BaParamSet.field.BufferSize = 32; ActivateBAEntry(ieee, pBA, pBA->BaTimeoutValue); ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); // End of procedure. return 0; OnADDBAReq_Fail: { BA_RECORD BA; BA.BaParamSet = *pBaParamSet; BA.BaTimeoutValue = *pBaTimeoutVal; BA.DialogToken = *pDialogToken; BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; ieee80211_send_ADDBARsp(ieee, dst, &BA, rc); return 0; //we send RSP out. } }
/******************************************************************************************************************************* *function: construct ADDBAREQ and ADDBARSP frame here together. * input: u8* Dst //ADDBA frame's destination * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA. * u16 StatusCode //status code in RSP and I will use it to indicate whether it's RSP or REQ(will I?) * u8 type //indicate whether it's RSP(ACT_ADDBARSP) ow REQ(ACT_ADDBAREQ) * output: none * return: sk_buff* skb //return constructed skb to xmit *******************************************************************************************************************************/ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, PBA_RECORD pBA, u16 StatusCode, u8 type) { struct sk_buff *skb = NULL; struct rtl_80211_hdr_3addr *BAReq = NULL; u8 *tag = NULL; u16 len = ieee->tx_headroom + 9; //category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2)) IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __func__, type, Dst, ieee->dev); if (pBA == NULL) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA is NULL\n"); return NULL; } skb = dev_alloc_skb(len + sizeof( struct rtl_80211_hdr_3addr)); //need to add something others? FIXME if (skb == NULL) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); return NULL; } memset(skb->data, 0, sizeof( struct rtl_80211_hdr_3addr)); //I wonder whether it's necessary. Apparently kernel will not do it when alloc a skb. skb_reserve(skb, ieee->tx_headroom); BAReq = ( struct rtl_80211_hdr_3addr *) skb_put(skb,sizeof( struct rtl_80211_hdr_3addr)); memcpy(BAReq->addr1, Dst, ETH_ALEN); memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame //tag += sizeof( struct rtl_80211_hdr_3addr); //move to action field tag = (u8 *)skb_put(skb, 9); *tag ++= ACT_CAT_BA; *tag ++= type; // Dialog Token *tag ++= pBA->DialogToken; if (ACT_ADDBARSP == type) { // Status Code printk(KERN_INFO "=====>to send ADDBARSP\n"); put_unaligned_le16(StatusCode, tag); tag += 2; } // BA Parameter Set put_unaligned_le16(pBA->BaParamSet.shortData, tag); tag += 2; // BA Timeout Value put_unaligned_le16(pBA->BaTimeoutValue, tag); tag += 2; if (ACT_ADDBAREQ == type) { // BA Start SeqCtrl memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2); tag += 2; } IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); return skb; //return NULL; }
int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb) { struct ieee80211_hdr_3addr* req = NULL; u16 rc = 0; u8 * dst = NULL, *pDialogToken = NULL, *tag = NULL; PBA_RECORD pBA = NULL; PBA_PARAM_SET pBaParamSet = NULL; u16* pBaTimeoutVal = NULL; PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL; PRX_TS_RECORD pTS = NULL; if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) { IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); return -1; } IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); req = ( struct ieee80211_hdr_3addr*) skb->data; tag = (u8*)req; dst = (u8*)(&req->addr2[0]); tag += sizeof( struct ieee80211_hdr_3addr); pDialogToken = tag + 2; // pBaParamSet = (PBA_PARAM_SET)(tag + 3); // pBaTimeoutVal = (u16*)(tag + 5); pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7); printk("====================>rx ADDBAREQ from :%pM\n", dst); // if( (ieee->current_network.qos_data.active == 0) || (ieee->pHTInfo->bCurrentHTSupport == false)) // // { rc = ADDBA_STATUS_REFUSED; IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); goto OnADDBAReq_Fail; } // // if( !GetTs( ieee, (PTS_COMMON_INFO*)(&pTS), dst, (u8)(pBaParamSet->field.TID), RX_DIR, true) ) { rc = ADDBA_STATUS_REFUSED; IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); goto OnADDBAReq_Fail; } pBA = &pTS->RxAdmittedBARecord; // // // // if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { rc = ADDBA_STATUS_INVALID_PARAM; IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __FUNCTION__); goto OnADDBAReq_Fail; } // // DeActivateBAEntry(ieee, pBA); pBA->DialogToken = *pDialogToken; pBA->BaParamSet = *pBaParamSet; pBA->BaTimeoutValue = *pBaTimeoutVal; pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; // if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) pBA->BaParamSet.field.BufferSize = 1; else pBA->BaParamSet.field.BufferSize = 32; ActivateBAEntry(ieee, pBA, pBA->BaTimeoutValue); ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); // return 0; OnADDBAReq_Fail: { BA_RECORD BA; BA.BaParamSet = *pBaParamSet; BA.BaTimeoutValue = *pBaTimeoutVal; BA.DialogToken = *pDialogToken; BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; ieee80211_send_ADDBARsp(ieee, dst, &BA, rc); return 0; // } }
static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, PBA_RECORD pBA, u16 StatusCode, u8 type) { struct sk_buff *skb = NULL; struct ieee80211_hdr_3addr* BAReq = NULL; u8* tag = NULL; u16 tmp = 0; u16 len = ieee->tx_headroom + 9; // IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __FUNCTION__, type, Dst, ieee->dev); if (pBA == NULL||ieee == NULL) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee); return NULL; } skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); // if (skb == NULL) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); return NULL; } memset(skb->data, 0, sizeof( struct ieee80211_hdr_3addr)); // skb_reserve(skb, ieee->tx_headroom); BAReq = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); memcpy(BAReq->addr1, Dst, ETH_ALEN); memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); // // tag = (u8*)skb_put(skb, 9); *tag ++= ACT_CAT_BA; *tag ++= type; // *tag ++= pBA->DialogToken; if (ACT_ADDBARSP == type) { // printk("=====>to send ADDBARSP\n"); tmp = cpu_to_le16(StatusCode); memcpy(tag, (u8*)&tmp, 2); tag += 2; } // tmp = cpu_to_le16(pBA->BaParamSet.shortData); memcpy(tag, (u8*)&tmp, 2); tag += 2; // tmp = cpu_to_le16(pBA->BaTimeoutValue); memcpy(tag, (u8*)&tmp, 2); tag += 2; if (ACT_ADDBAREQ == type) { // memcpy(tag,(u8*)&(pBA->BaStartSeqCtrl), 2); tag += 2; } IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); return skb; // }