00001
00017
00018
00019
00020
00021
00022 #include "txl_cfm.h"
00023 #include "txu_cntrl.h"
00024 #include "ke_task.h"
00025 #include "mac.h"
00026 #include "mac_frame.h"
00027 #include "sta_mgmt.h"
00028 #include "llc.h"
00029 #include "co_utils.h"
00030 #include "co_endian.h"
00031 #include "vif_mgmt.h"
00032 #include "me_utils.h"
00033 #include "bam.h"
00034 #include "mm.h"
00035 #include "tpc.h"
00036 #if NX_MFP
00037 #include "mfp.h"
00038 #endif
00039 #if (RW_MESH_EN)
00040 #include "mesh.h"
00041 #include "mesh_hwmp.h"
00042 #include "mesh_ps.h"
00043 #endif //(RW_MESH_EN)
00044
00045
00046
00047
00048
00062 static bool txu_cntrl_logic_port_filter(uint8_t sta_idx, uint16_t eth_type,
00063 uint16_t *flags)
00064 {
00065 uint8_t port_state = sta_mgmt_get_port_state(sta_idx);
00066 uint16_t port_proto = sta_mgmt_get_port_ethertype(sta_idx);
00067 bool is_port_proto = false;
00068
00069 if (eth_type == port_proto)
00070 {
00071 is_port_proto = true;
00072
00073 *flags &= ~(TXU_CNTRL_USE_4ADDR);
00074 }
00075
00076
00077 if (port_state == PORT_OPEN)
00078 return true;
00079
00080
00081 if ((port_state == PORT_CONTROLED) && (is_port_proto))
00082 {
00083 return true;
00084 }
00085
00086
00087 return false;
00088 }
00089
00102 static int txu_cntrl_sechdr_len_compute(struct txdesc *txdesc, int *tail_len)
00103 {
00104 struct hostdesc *host = &txdesc->host;
00105 struct sta_info_tag *sta = &sta_info_tab[host->staid];
00106 struct key_info_tag *key = *sta->sta_sec_info.cur_key;
00107 struct vif_info_tag *vif = &vif_info_tab[host->vif_idx];
00108 int head_len = 0;
00109
00110
00111 *tail_len = 0;
00112
00113
00114 if (!key || (vif->flags & CONTROL_PORT_NO_ENC &&
00115 co_ntohs(host->ethertype) == sta_mgmt_get_port_ethertype(host->staid)))
00116 return 0;
00117
00118
00119 switch(key->cipher)
00120 {
00121 case MAC_CIPHER_WEP40:
00122 case MAC_CIPHER_WEP104:
00123 head_len = IV_LEN;
00124 *tail_len = ICV_LEN;
00125
00126 if (!(host->flags & TXU_CNTRL_RETRY))
00127 {
00128 key->tx_pn++;
00129 memcpy(host->pn, &key->tx_pn, 2 * sizeof(host->pn[0]));
00130 }
00131 break;
00132 case MAC_CIPHER_TKIP:
00133 head_len = IV_LEN + EIV_LEN;
00134 *tail_len = MIC_LEN + ICV_LEN;
00135
00136 if (!(host->flags & TXU_CNTRL_RETRY))
00137 {
00138 key->tx_pn++;
00139 memcpy(host->pn, &key->tx_pn, 3 * sizeof(host->pn[0]));
00140 }
00141 break;
00142 case MAC_CIPHER_CCMP:
00143 head_len = IV_LEN + EIV_LEN;
00144 *tail_len = MIC_LEN;
00145
00146 if (!(host->flags & TXU_CNTRL_RETRY))
00147 {
00148 key->tx_pn++;
00149 memcpy(host->pn, &key->tx_pn, 3 * sizeof(host->pn[0]));
00150 }
00151 break;
00152 #if RW_WAPI_EN
00153 case MAC_CIPHER_WPI_SMS4:
00154 head_len = WPI_IV_LEN;
00155 *tail_len = WPI_MIC_LEN;
00156 if (!(host->flags & TXU_CNTRL_RETRY))
00157 {
00158 if (key->hw_key_idx < MM_SEC_DEFAULT_KEY_COUNT) {
00159
00160 key->tx_pn++;
00161 } else {
00162
00163 key->tx_pn+=2;
00164 }
00165 memcpy(host->pn, &key->tx_pn, 4 * sizeof(host->pn[0]));
00166 }
00167 break;
00168 #endif
00169 default:
00170 ASSERT_ERR(0);
00171 break;
00172 }
00173
00174 return (head_len);
00175 }
00176
00185 static void txu_cntrl_umacdesc_prep(struct txdesc *txdesc)
00186 {
00187 struct hostdesc *host = &txdesc->host;
00188 struct umacdesc *umac = &txdesc->umac;
00189 #if NX_HE
00190 struct sta_info_tag *sta = &sta_info_tab[host->staid];
00191 #endif
00192 #if RW_MESH_EN || NX_HE
00193
00194 struct vif_info_tag *vif = &vif_info_tab[host->vif_idx];
00195 #endif //(RW_MESH_EN)
00196 int head_len, tail_len, hdr_len_802_2 = 0;
00197 uint16_t payl_len;
00198
00199
00200 if (host->tid != 0xFF)
00201 {
00202
00203 head_len = MAC_SHORT_QOS_MAC_HDR_LEN;
00204
00205 if (!(host->flags & TXU_CNTRL_RETRY))
00206 host->sn = sta_mgmt_get_tx_ssn_and_inc(host->staid, host->tid);
00207
00208 #if (RW_MESH_EN)
00209 if (vif->type == VIF_MESH_POINT)
00210 {
00211
00212 head_len += mesh_tx_data_prepare(vif, host, umac);
00213 }
00214 #endif //(RW_MESH_EN)
00215 }
00216 else
00217 {
00218 head_len = MAC_SHORT_MAC_HDR_LEN;
00219 }
00220
00221 if (host->flags & TXU_CNTRL_USE_4ADDR)
00222 {
00223 head_len += (MAC_LONG_MAC_HDR_LEN - MAC_SHORT_MAC_HDR_LEN);
00224 }
00225
00226 #if NX_HE
00227
00228
00229
00230 if ((vif->type == VIF_STA) && (STA_CAPA(sta, HE)))
00231 head_len += MAC_HTC_LEN;
00232 #endif
00233
00234 umac->machead_len = head_len;
00235
00236
00237 head_len += txu_cntrl_sechdr_len_compute(txdesc, &tail_len);
00238
00239 #if (RW_MESH_EN)
00240 if (!(host->flags & TXU_CNTRL_MESH_FWD))
00241 #endif //(RW_MESH_EN)
00242 {
00243
00244 if (co_ntohs(host->ethertype) > LLC_FRAMELENGTH_MAXVALUE)
00245 {
00246
00247 head_len += LLC_802_2_HDR_LEN;
00248 hdr_len_802_2 = LLC_802_2_HDR_LEN;
00249 }
00250 }
00251
00252
00253 #if NX_AMSDU_TX
00254 if (host->flags & TXU_CNTRL_AMSDU)
00255 {
00256 head_len += sizeof_b(struct amsdu_hdr);
00257 }
00258
00259 payl_len = 0;
00260 for (int i = 0; i < host->packet_cnt; i++)
00261 {
00262 payl_len += host->packet_len[i];
00263 }
00264 #else
00265 payl_len = host->packet_len;
00266 #endif
00267
00268
00269 umac->payl_len = payl_len;
00270 umac->head_len = head_len;
00271 umac->tail_len = tail_len;
00272 umac->hdr_len_802_2 = hdr_len_802_2;
00273
00274 #if NX_AMPDU_TX
00275 umac->phy_flags = 0;
00276 umac->flags = 0;
00277 #endif
00278 }
00279
00289 static void txu_cntrl_umacdesc_mgmt_prep(struct txdesc *txdesc, struct vif_info_tag *vif)
00290 {
00291 struct hostdesc *host = &txdesc->host;
00292 struct umacdesc *umac = &txdesc->umac;
00293 int head_len = 0, tail_len = 0;
00294 uint8_t pwr_idx, i;
00295
00296
00297 if ((host->flags & TXU_CNTRL_MGMT_NO_CCK)
00298 #if (NX_P2P)
00299 || vif->p2p
00300 #endif
00301 )
00302 {
00303 umac->buf_control = &txl_buffer_control_5G;
00304 }
00305 else
00306 {
00307 uint8_t band = vif->chan_ctxt->channel.band;
00308
00309 umac->buf_control = (band == PHY_BAND_2G4) ? &txl_buffer_control_24G : &txl_buffer_control_5G;
00310 }
00311
00312 #if NX_MFP
00313 if (host->flags & TXU_CNTRL_MGMT_ROBUST)
00314 {
00315 enum mfp_protection mfp;
00316
00317
00318
00319 mfp = mfp_protect_mgmt_frame(txdesc, MAC_FCTRL_DEAUTHENT, 0);
00320
00321 if (mfp == MFP_UNICAST_PROT)
00322 {
00323 head_len = txu_cntrl_sechdr_len_compute(txdesc, &tail_len);
00324
00325 }
00326 else if (mfp == MFP_MULTICAST_PROT)
00327 {
00328 tail_len = MAC_MGMT_MIC_LEN;
00329 }
00330 else
00331 {
00332 host->flags &= ~TXU_CNTRL_MGMT_ROBUST;
00333 }
00334 }
00335 #endif
00336
00337
00338 tpc_get_vif_tx_power(vif, NULL, &pwr_idx);
00339 for (i = 0; i < RATE_CONTROL_STEPS; i++)
00340 {
00341 umac->buf_control->policy_tbl.powercntrlinfo[i] = TX_PWR_LEVEL_SET(pwr_idx);
00342 }
00343
00344
00345 umac->machead_len = 0;
00346 umac->head_len = head_len;
00347 umac->tail_len = tail_len;
00348
00349 #if (NX_AMPDU_TX)
00350 umac->phy_flags = 0;
00351 umac->flags = 0;
00352 #endif //(NX_AMPDU_TX)
00353 }
00354
00365 static uint32_t txu_cntrl_mac_hdr_append(struct txdesc *txdesc, uint32_t buf)
00366 {
00367 struct hostdesc *host = &txdesc->host;
00368 #if (RW_MESH_EN)
00369 struct umacdesc *umac_desc = &txdesc->umac;
00370 #endif //(RW_MESH_EN)
00371 struct vif_info_tag *vif = &vif_info_tab[host->vif_idx];
00372 struct sta_info_tag *sta = &sta_info_tab[host->staid];
00373 struct key_info_tag *key = *sta->sta_sec_info.cur_key;
00374 struct mac_hdr_qos *machdr;
00375 struct mac_hdr_long_qos *machdr_4a;
00376 uint16_t *qos;
00377 uint16_t order = 0;
00378
00379 #if NX_HE
00380
00381 if ((vif->type == VIF_STA) && (STA_CAPA(sta, HE)))
00382 {
00383 buf -= MAC_HTC_LEN;
00384 co_write32p(buf, txl_he_htc_get(txdesc, sta));
00385 order = MAC_FCTRL_ORDER;
00386 }
00387 #endif
00388
00389 buf -= MAC_SHORT_MAC_HDR_LEN;
00390 if (host->tid != 0xFF)
00391 {
00392 buf -= MAC_HDR_QOS_CTRL_LEN;
00393
00394 #if (RW_MESH_EN)
00395 if ((vif->type == VIF_MESH_POINT) && umac_desc->has_mesh_ctrl)
00396 {
00397 buf -= (MESH_CTRL_MIN_LEN + (umac_desc->nb_ext_addr * MAC_ADDR_LEN));
00398 }
00399 #endif //(RW_MESH_EN)
00400 }
00401
00402 if (host->flags & TXU_CNTRL_USE_4ADDR)
00403 {
00404 buf -= (MAC_LONG_MAC_HDR_LEN - MAC_SHORT_MAC_HDR_LEN);
00405 machdr = HW2CPU(buf);
00406 machdr_4a = HW2CPU(buf);
00407 qos = &(machdr_4a->qos);
00408 }
00409 else
00410 {
00411 machdr = HW2CPU(buf);
00412 machdr_4a = NULL;
00413 qos = &(machdr->qos);
00414 }
00415
00416
00417 if (host->tid != 0xFF)
00418 {
00419
00420 machdr->fctl = MAC_QOS_ST_BIT;
00421 *qos = host->tid << MAC_QOSCTRL_UP_OFT;
00422 machdr->seq = host->sn << MAC_SEQCTRL_NUM_OFT;
00423 #if NX_AMSDU_TX
00424 if (host->flags & TXU_CNTRL_AMSDU)
00425 *qos |= MAC_QOSCTRL_AMSDU_PRESENT;
00426 #endif
00427 if (host->flags & TXU_CNTRL_EOSP)
00428 {
00429 *qos |= MAC_QOSCTRL_EOSP;
00430 }
00431
00432 #if (RW_MESH_EN)
00433 if (vif->type == VIF_MESH_POINT)
00434 {
00435 if (umac_desc->has_mesh_ctrl)
00436 {
00437 *qos |= MAC_QOSCTRL_MESH_CTRL_PRESENT;
00438
00439
00440 mesh_tx_data_fill_mesh_ctrl(vif, CPU2HW(qos) + MAC_HDR_QOS_CTRL_LEN, host, umac_desc);
00441 }
00442 else if (host->flags & TXU_CNTRL_MESH_FWD)
00443 {
00444 *qos |= MAC_QOSCTRL_MESH_CTRL_PRESENT;
00445 }
00446
00447 if (txdesc->host.staid < NX_REMOTE_STA_MAX)
00448 {
00449
00450 mesh_ps_fill_qos(sta, qos);
00451 }
00452 }
00453 #endif //(RW_MESH_EN)
00454 }
00455 else
00456 {
00457 machdr->fctl = 0;
00458 machdr->seq = 0;
00459 }
00460
00461
00462 machdr->fctl |= MAC_FCTRL_DATA_T | order;
00463
00464 if (txdesc->host.flags & TXU_CNTRL_TDLS)
00465 machdr->fctl &= ~MAC_FCTRL_TODS_FROMDS;
00466 else if (host->flags & TXU_CNTRL_USE_4ADDR)
00467 machdr->fctl |= MAC_FCTRL_TODS_FROMDS;
00468 else if (vif->type == VIF_STA)
00469 machdr->fctl |= MAC_FCTRL_TODS;
00470 else if (vif->type == VIF_AP)
00471 machdr->fctl |= MAC_FCTRL_FROMDS;
00472 #if (RW_MESH_EN)
00473 else if (vif->type == VIF_MESH_POINT)
00474 {
00475 machdr->fctl |= MAC_FCTRL_FROMDS;
00476 }
00477 #endif //(RW_MESH_EN)
00478
00479
00480 if (host->flags & TXU_CNTRL_MORE_DATA)
00481 machdr->fctl |= MAC_FCTRL_MOREDATA;
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 MAC_ADDR_CPY(&machdr->addr2, &vif->mac_addr);
00497 #if (RW_MESH_EN)
00498 if (vif->type == VIF_MESH_POINT)
00499 {
00500 if (host->flags & TXU_CNTRL_USE_4ADDR)
00501 {
00502
00503 struct mesh_hwmp_path_tag *mpath = &mesh_hwmp_path_pool[umac_desc->path_idx];
00504
00505 MAC_ADDR_CPY(&machdr_4a->addr3, &mpath->tgt_mac_addr);
00506 MAC_ADDR_CPY(&machdr_4a->addr1, &sta->mac_addr);
00507
00508 if (host->flags & TXU_CNTRL_MESH_FWD)
00509 {
00510 MAC_ADDR_CPY(&machdr_4a->addr4, &host->eth_src_addr);
00511 }
00512 else
00513 {
00514 MAC_ADDR_CPY(&machdr_4a->addr4, &vif->mac_addr);
00515 }
00516 }
00517 else if ((machdr->fctl & MAC_FCTRL_TODS_FROMDS) == MAC_FCTRL_FROMDS)
00518 {
00519 MAC_ADDR_CPY(&machdr->addr1, &host->eth_dest_addr);
00520 MAC_ADDR_CPY(&machdr->addr3, &vif->mac_addr);
00521 }
00522 }
00523 else
00524 #endif //(RW_MESH_EN)
00525 {
00526 if ((machdr->fctl & MAC_FCTRL_TODS_FROMDS) == MAC_FCTRL_TODS)
00527 {
00528 MAC_ADDR_CPY(&machdr->addr1, &sta->mac_addr);
00529 MAC_ADDR_CPY(&machdr->addr3, &host->eth_dest_addr);
00530 }
00531 else if ((machdr->fctl & MAC_FCTRL_TODS_FROMDS) == MAC_FCTRL_FROMDS)
00532 {
00533 MAC_ADDR_CPY(&machdr->addr1, &host->eth_dest_addr);
00534 MAC_ADDR_CPY(&machdr->addr3, &host->eth_src_addr);
00535 }
00536 else if ((machdr->fctl & MAC_FCTRL_TODS_FROMDS) == 0)
00537 {
00538 MAC_ADDR_CPY(&machdr->addr1, &host->eth_dest_addr);
00539 MAC_ADDR_CPY(&machdr->addr3, &vif->bss_info.bssid);
00540 }
00541 else
00542 {
00543 MAC_ADDR_CPY(&machdr_4a->addr1, &sta->mac_addr);
00544 MAC_ADDR_CPY(&machdr_4a->addr3, &host->eth_dest_addr);
00545 MAC_ADDR_CPY(&machdr_4a->addr4, &host->eth_src_addr);
00546 }
00547 }
00548
00549
00550 if (key && !(vif->flags & CONTROL_PORT_NO_ENC &&
00551 co_ntohs(host->ethertype) == sta_mgmt_get_port_ethertype(host->staid)))
00552 {
00553 machdr->fctl |= MAC_FCTRL_PROTECTEDFRAME;
00554 }
00555
00556 return buf;
00557 }
00558
00578 static uint32_t txu_cntrl_sec_hdr_append(struct txdesc *txdesc, uint32_t buf, bool umac_pol)
00579 {
00580 struct hostdesc *host = &txdesc->host;
00581 struct umacdesc *umac = &txdesc->umac;
00582 struct sta_info_tag *sta = &sta_info_tab[host->staid];
00583 struct key_info_tag *key = *sta->sta_sec_info.cur_key;
00584 struct vif_info_tag *vif = &vif_info_tab[host->vif_idx];
00585 struct tx_policy_tbl *pol;
00586 uint32_t mac_control_info1;
00587 uint16_t *iv;
00588
00589
00590 if (!key || (vif->flags & CONTROL_PORT_NO_ENC &&
00591 co_ntohs(host->ethertype) == sta_mgmt_get_port_ethertype(host->staid)))
00592 return buf;
00593
00594
00595
00596 switch(key->cipher)
00597 {
00598 case MAC_CIPHER_WEP40:
00599 case MAC_CIPHER_WEP104:
00600
00601 buf -= IV_LEN;
00602 iv = HW2CPU(buf);
00603 iv[0] = host->pn[0];
00604 iv[1] = host->pn[1] | (key->key_idx << 14);
00605 break;
00606 case MAC_CIPHER_TKIP:
00607
00608 buf -= IV_LEN + EIV_LEN;
00609 iv = HW2CPU(buf);
00610 iv[0] = (host->pn[0] >> 8) | ((host->pn[0] | 0x2000) & 0x7F00);
00611 iv[1] = (host->pn[0] & 0xFF) | (key->key_idx << 14) | EIV_PRESENT;
00612 iv[2] = host->pn[1];
00613 iv[3] = host->pn[2];
00614 break;
00615 case MAC_CIPHER_CCMP:
00616 {
00617 #if (RW_MESH_EN)
00618 uint32_t offset = 0;
00619
00620 if ((vif->type == VIF_MESH_POINT) && umac->has_mesh_ctrl)
00621 {
00622
00623 struct mesh_vif_info_tag *mvif = &mesh_vif_info_tab[vif->mvif_idx];
00624
00625 if (mvif->is_auth)
00626 {
00627 offset += (MESH_CTRL_MIN_LEN + (umac->nb_ext_addr * MAC_ADDR_LEN));
00628 }
00629 }
00630 #endif //(RW_MESH_EN)
00631
00632
00633 buf -= IV_LEN + EIV_LEN;
00634 #if (RW_MESH_EN)
00635 iv = HW2CPU(buf - offset);
00636 #else
00637 iv = HW2CPU(buf);
00638 #endif //(RW_MESH_EN)
00639 iv[0] = host->pn[0];
00640 iv[1] = EIV_PRESENT | (key->key_idx << 14);
00641 iv[2] = host->pn[1];
00642 iv[3] = host->pn[2];
00643 } break;
00644 #if RW_WAPI_EN
00645 case MAC_CIPHER_WPI_SMS4:
00646 buf -= WPI_IV_LEN;
00647 iv = HW2CPU(buf);
00648 iv[0] = key->key_idx;
00649 iv[1] = host->pn[0];
00650 iv[2] = host->pn[1];
00651 iv[3] = host->pn[2];
00652 iv[4] = host->pn[3];
00653 iv[5] = 0x5c36;
00654 iv[6] = 0x5c36;
00655 iv[7] = 0x5c36;
00656 iv[8] = 0x5c36;
00657 break;
00658 #endif
00659 default:
00660 ASSERT_ERR(0);
00661 break;
00662 }
00663
00664
00665 if (umac_pol)
00666 {
00667 pol = &umac->buf_control->policy_tbl;
00668 }
00669 else
00670 {
00671 struct txl_buffer_control *bufctrl = txl_buffer_control_get(txdesc);
00672 pol = &bufctrl->policy_tbl;
00673 }
00674 mac_control_info1 = pol->maccntrlinfo1 & KEYSRAM_INDEX_RA_MASK;
00675 pol->maccntrlinfo1 = mac_control_info1 | key->hw_key_idx;
00676
00677 return (buf);
00678 }
00679
00690 static uint32_t txu_cntrl_llc_hdr_append(struct txdesc *txdesc, uint32_t buf)
00691 {
00692 struct hostdesc *host = &txdesc->host;
00693 struct llc_snap *llc_snap_ptr;
00694
00695
00696 if (co_ntohs(host->ethertype) < LLC_FRAMELENGTH_MAXVALUE)
00697 return buf;
00698
00699
00700 buf -= sizeof_b(struct llc_snap);
00701 llc_snap_ptr = HW2CPU(buf);
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717 llc_snap_ptr->dsap_ssap = (LLC_DSAP | LLC_SSAP << 8);
00718 llc_snap_ptr->control_oui0 = LLC_CTRL;
00719 llc_snap_ptr->oui1_2 = 0;
00720 llc_snap_ptr->proto_id = host->ethertype;
00721
00722 return buf;
00723 }
00724
00725 #if NX_AMSDU_TX
00726
00736 static uint32_t txu_cntrl_amsdu_hdr_append(struct txdesc *txdesc, uint32_t buf)
00737 {
00738 struct hostdesc *host = &txdesc->host;
00739 struct umacdesc *umac = &txdesc->umac;
00740 struct amsdu_hdr *amsdu_hdr;
00741 uint16_t length;
00742
00743 if (!(host->flags & TXU_CNTRL_AMSDU))
00744 return buf;
00745
00746 buf -= sizeof_b(struct amsdu_hdr);
00747 amsdu_hdr = HW2CPU(buf);
00748
00749 MAC_ADDR_CPY(&amsdu_hdr->da, &host->eth_dest_addr);
00750 MAC_ADDR_CPY(&amsdu_hdr->sa, &host->eth_src_addr);
00751 length = host->packet_len[0] + umac->hdr_len_802_2;
00752 amsdu_hdr->len= co_htons(length);
00753
00754 return buf;
00755 }
00756 #endif
00757
00767 static void txu_cntrl_check_rate(struct txdesc *txdesc)
00768 {
00769
00770 struct hostdesc *host = &txdesc->host;
00771
00772
00773 rc_check(txdesc);
00774
00775
00776 txdesc->umac.buf_control = me_update_buffer_control(&sta_info_tab[host->staid]);
00777
00778 #if NX_AMPDU_TX
00779
00780 txdesc->umac.phy_flags = txdesc->umac.buf_control->policy_tbl.ratecntrlinfo[RC_CONTROL_GET(txdesc->umac.rc_control, SW_RETRY_STEP)];
00781 #endif
00782 }
00783
00794 static void txu_cntrl_discard(struct txdesc *txdesc, uint8_t access_category, uint32_t status)
00795 {
00796
00797 txl_cntrl_inc_pck_cnt();
00798
00799
00800 GLOBAL_INT_DISABLE();
00801 txl_cfm_push(txdesc, status, access_category);
00802 GLOBAL_INT_RESTORE();
00803 }
00804
00805
00806 #if NX_FULLY_HOSTED
00807
00820 static void txu_cntrl_sec_tail_append(struct txdesc *txdesc)
00821 {
00822 struct hostdesc *host = &txdesc->host;
00823 struct umacdesc *umac = &txdesc->umac;
00824 struct sta_info_tag *sta = &sta_info_tab[host->staid];
00825 struct key_info_tag *key = *sta->sta_sec_info.cur_key;
00826 struct mic_calc mic;
00827 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
00828 struct tx_pbd *pbd;
00829 struct tx_pbd *pbd_tail;
00830 uint32_t offset;
00831 uint32_t data_addr;
00832 uint32_t data_len;
00833
00834
00835 if (!key)
00836 return;
00837
00838 pbd_tail = &txdesc->lmac.buffer->pbd_tail;
00839
00840
00841 if (key->cipher == MAC_CIPHER_TKIP)
00842 {
00843
00844 me_mic_init(&mic, key->u.mic.tx_key, &host->eth_dest_addr, &host->eth_src_addr, host->tid);
00845
00846
00847
00848 thd = &txdesc->lmac.hw_desc->thd;
00849 offset = umac->hdr_len_802_2;
00850
00851
00852 pbd = HW2CPU(thd->first_pbd_ptr);
00853
00854 while (1)
00855 {
00856 data_addr = pbd->datastartptr - offset;
00857 data_len = pbd->dataendptr + 1 - data_addr;
00858 me_mic_calc(&mic, data_addr, data_len);
00859 if (pbd->next)
00860 {
00861 pbd = HW2CPU(pbd->next);
00862 }
00863 else
00864 {
00865 pbd->next = CPU2HW(pbd_tail);
00866 break;
00867 }
00868 offset = 0;
00869 }
00870
00871
00872 me_mic_end(&mic);
00873
00874
00875 memcpy(&txdesc->lmac.buffer->sec_tail[0], &mic.mic_key_least, MIC_LEN);
00876 }
00877 else
00878 {
00879
00880 pbd = HW2CPU(thd->first_pbd_ptr);
00881 while (pbd->next)
00882 pbd = HW2CPU(pbd->next);
00883 pbd->next = CPU2HW(pbd_tail);
00884 }
00885
00886
00887 pbd_tail->upatterntx = TX_PAYLOAD_DESC_PATTERN;
00888 pbd_tail->datastartptr = CPU2HW(&txdesc->lmac.buffer->sec_tail[0]);
00889 pbd_tail->dataendptr = pbd_tail->datastartptr + umac->tail_len - 1;
00890 pbd_tail->next = 0;
00891 pbd_tail->bufctrlinfo = 0;
00892 }
00893
00913 static uint32_t txu_cntrl_mgmt_sec_pbd_add(struct txdesc *txdesc, int machdr_len)
00914 {
00915 struct tx_hd *thd = &txdesc->lmac.hw_desc->thd;
00916 struct tx_pbd *pbd = (struct tx_pbd *)HW2CPU(thd->first_pbd_ptr);
00917 uint32_t payload_start, payload_end, sec_hdr_end;
00918
00919
00920 ASSERT_ERR(pbd && (pbd->next == 0) &&
00921 (pbd == &txdesc->lmac.buffer->pbd[0]));
00922
00923 payload_start = pbd->datastartptr + machdr_len;
00924 payload_end = pbd->dataendptr;
00925
00926
00927 pbd->dataendptr = payload_start - 1;
00928 pbd->next = CPU2HW(&txdesc->lmac.buffer->pbd[1]);
00929
00930
00931 pbd = &txdesc->lmac.buffer->pbd[1];
00932 pbd->upatterntx = TX_PAYLOAD_DESC_PATTERN;
00933 pbd->datastartptr = CPU2HW(&txdesc->lmac.buffer->headers[0]);
00934 pbd->dataendptr = pbd->datastartptr + txdesc->umac.head_len - 1;
00935 pbd->bufctrlinfo = 0;
00936 pbd->next = CPU2HW(&txdesc->lmac.buffer->pbd[2]);
00937
00938 sec_hdr_end = pbd->dataendptr + 1;
00939
00940
00941 pbd = &txdesc->lmac.buffer->pbd[2];
00942 pbd->upatterntx = TX_PAYLOAD_DESC_PATTERN;
00943 pbd->datastartptr = payload_start;
00944 pbd->dataendptr = payload_end;
00945 pbd->bufctrlinfo = 0;
00946 pbd->next = CPU2HW(&txdesc->lmac.buffer->pbd_tail);
00947
00949 pbd = &txdesc->lmac.buffer->pbd_tail;
00950 pbd->upatterntx = TX_PAYLOAD_DESC_PATTERN;
00951 pbd->datastartptr = CPU2HW(&txdesc->lmac.buffer->sec_tail[0]);
00952 pbd->dataendptr = pbd->datastartptr + txdesc->umac.tail_len - 1;
00953 pbd->next = 0;
00954 pbd->bufctrlinfo = 0;
00955
00956 return sec_hdr_end;
00957 }
00958
00959 #endif //NX_FULLY_HOSTED
00960
00961
00962
00963
00964
00965
00966 void txu_cntrl_frame_build(struct txdesc *txdesc, uint32_t buf)
00967 {
00968 #if (RW_MESH_EN)
00969 if (!(txdesc->host.flags & TXU_CNTRL_MESH_FWD))
00970 #endif //(RW_MESH_EN)
00971 {
00972
00973 buf = txu_cntrl_llc_hdr_append(txdesc, buf);
00974 }
00975
00976 #if NX_AMSDU_TX
00977 buf = txu_cntrl_amsdu_hdr_append(txdesc, buf);
00978 #endif
00979
00980
00981 buf = txu_cntrl_sec_hdr_append(txdesc, buf, true);
00982
00983
00984 buf = txu_cntrl_mac_hdr_append(txdesc, buf);
00985
00986 #if NX_FULLY_HOSTED
00987
00988 txu_cntrl_sec_tail_append(txdesc);
00989
00990
00991 txdesc->lmac.hw_desc->thd.datastartptr = buf;
00992 txdesc->lmac.hw_desc->thd.dataendptr = buf + txdesc->umac.machead_len - 1;
00993
00994 txl_buffer_get(txdesc)->pbd[0].datastartptr = txdesc->lmac.hw_desc->thd.dataendptr + 1;
00995 #endif
00996 }
00997
00998 bool txu_cntrl_push(struct txdesc *txdesc, uint8_t access_category)
00999 {
01000
01001 struct vif_info_tag *vif;
01002 bool queue_stop = false;
01003 uint32_t discard_status = DESC_DONE_TX_BIT;
01004
01005 do
01006 {
01007 vif = &vif_info_tab[txdesc->host.vif_idx];
01008
01009 if (!vif)
01010 {
01011 break;
01012 }
01013
01014
01015 if (!txl_cntrl_tx_check(vif))
01016 {
01017
01018
01019 discard_status |= DESC_DONE_SW_TX_BIT;
01020 break;
01021 }
01022
01023
01024 if ((txdesc->host.flags & TXU_CNTRL_MGMT))
01025 {
01026
01027 txu_cntrl_umacdesc_mgmt_prep(txdesc, vif);
01028 }
01029 else
01030 {
01031
01032 if (!txu_cntrl_logic_port_filter(txdesc->host.staid, co_ntohs(txdesc->host.ethertype),
01033 &txdesc->host.flags))
01034 {
01035 break;
01036 }
01037
01038
01039 PROF_TX_AC_BG_SET(access_category);
01040
01041 #if (RW_MESH_EN)
01042
01043 if (vif->type == VIF_MESH_POINT)
01044 {
01045 if (txdesc->host.staid < NX_REMOTE_STA_MAX)
01046 {
01047
01048 if (!mesh_ps_tx_data_handle(vif, txdesc->host.staid))
01049 {
01050 break;
01051 }
01052 }
01053
01054 if (!mesh_hwmp_path_check(vif, &txdesc->host.eth_dest_addr, &txdesc->umac))
01055 {
01056 break;
01057 }
01058 }
01059 #endif //(RW_MESH_EN)
01060
01061
01062 txu_cntrl_umacdesc_prep(txdesc);
01063
01064 #if (NX_AMPDU_TX)
01065
01066 bam_check_ba_agg(txdesc);
01067 #endif
01068
01069
01070 txu_cntrl_check_rate(txdesc);
01071
01072 #if NX_FULLY_HOSTED
01073 if (!(txdesc->host.flags & TXU_CNTRL_RETRY))
01074
01075 txu_cntrl_frame_build(txdesc, txl_buffer_get(txdesc)->pbd[0].datastartptr);
01076 #endif
01077
01078 }
01079
01080
01081 queue_stop = txl_cntrl_push(txdesc, access_category);
01082
01083
01084 return (queue_stop);
01085 } while(0);
01086
01087
01088 txu_cntrl_discard(txdesc, access_category, discard_status);
01089
01090 return false;
01091 }
01092
01093 #if !NX_FULLY_HOSTED
01094 void txu_cntrl_tkip_mic_append(struct txdesc *txdesc, uint8_t ac)
01095 {
01096 struct hostdesc *host = &txdesc->host;
01097 struct umacdesc *umac = &txdesc->umac;
01098 struct sta_info_tag *sta = &sta_info_tab[host->staid];
01099 struct key_info_tag *key = *sta->sta_sec_info.cur_key;
01100 struct txl_buffer_tag *buffer = txl_buffer_get(txdesc);
01101 uint32_t buf = CPU2HW(buffer->payload) + umac->head_len - umac->hdr_len_802_2;
01102
01103
01104 if (!key)
01105 return;
01106
01107
01108
01109 switch(key->cipher)
01110 {
01111 case MAC_CIPHER_TKIP:
01112
01113 txl_buffer_mic_compute(txdesc, key->u.mic.tx_key, buf,
01114 umac->hdr_len_802_2 + umac->payl_len, ac);
01115 break;
01116 default:
01117 return;
01118 break;
01119 }
01120 }
01121 #endif
01122
01123 void txu_cntrl_cfm(struct txdesc *txdesc)
01124 {
01125 int8_t credits = 1;
01126 struct hostdesc *host = &txdesc->host;
01127 struct tx_cfm_tag *cfm = txl_cfm_tag_get(txdesc);
01128
01129 bool success = ((cfm->status & FRAME_SUCCESSFUL_TX_BIT) != 0);
01130
01131 bool sw_retry = ((cfm->status & (DESC_DONE_SW_TX_BIT | DESC_DONE_TX_BIT)) ==
01132 (DESC_DONE_SW_TX_BIT | DESC_DONE_TX_BIT));
01133
01134
01135 cfm->status = 0;
01136
01137 #if !NX_FULLY_HOSTED
01138
01139 cfm->sn = host->sn;
01140 #endif
01141
01142
01143 if (host->flags & TXU_CNTRL_MGMT)
01144 {
01145
01146 if ((host->flags & TXU_CNTRL_MGMT_PM_MON) && !success)
01147 {
01148
01149 rxu_cntrl_get_pm();
01150 }
01151
01152
01153 if (host->flags & TXU_CNTRL_EOSP)
01154 {
01155 uint16_t qos = MAC_QOSCTRL_EOSP | (0x07 << MAC_QOSCTRL_UP_OFT);
01156
01157
01158 ASSERT_ERR(host->staid != INVALID_STA_IDX);
01159
01160
01161 TRACE_AP(PS, "{VIF-%d} Send Qos NULL frame as EOSP to STA-%d as last"
01162 " frame was MGMT (sn=%d)", host->vif_idx, host->staid, host->sn);
01163 txl_frame_send_qosnull_frame(host->staid, qos, NULL, NULL);
01164 sta_info_tab[host->staid].ps_service_period = NO_SERVICE_PERIOD;
01165 }
01166 }
01167 else if (txdesc->host.flags & TXU_CNTRL_EOSP)
01168 {
01169 sta_info_tab[host->staid].ps_service_period = NO_SERVICE_PERIOD;
01170 TRACE_AP(PS, "{VIF-%d} EOSP to STA-%d was data frame sn=%d",
01171 host->vif_idx, host->staid, host->sn);
01172 }
01173
01174 if (sw_retry)
01175 {
01176 cfm->status |= TX_STATUS_SW_RETRY_REQUIRED;
01177 }
01178 #if (NX_AMPDU_TX)
01179
01180 else if (host->tid != 0xFF)
01181 {
01182
01183 credits = bam_tx_cfm(txdesc, success);
01184 if (is_mpdu_agg(txdesc) && !is_mpdu_last(txdesc)) {
01185 cfm->ampdu_size = 0;
01186 }
01187 }
01188
01189 if (success)
01190 cfm->status |= TX_STATUS_ACKNOWLEDGED;
01191
01192 if (!is_mpdu_agg(txdesc)) {
01193 cfm->ampdu_size = 1;
01194 }
01195 #else
01196 cfm->ampdu_size = 1;
01197 #endif //(NX_AMPDU_TX)
01198
01199
01200 cfm->status |= TX_STATUS_DONE;
01201 cfm->credits = credits;
01202 #if NX_AMSDU_TX
01203 cfm->amsdu_size = me_tx_cfm_amsdu(txdesc);
01204 #endif
01205 }
01206
01207 void txu_cntrl_protect_mgmt_frame(struct txdesc *txdesc, struct mac_hdr *mac_hdr,
01208 uint16_t hdr_len)
01209 {
01210 uint32_t sec_end;
01211
01212 if (txdesc->umac.head_len == 0)
01213 {
01214 int tail_len, head_len;
01215 head_len = txu_cntrl_sechdr_len_compute(txdesc, &tail_len);
01216 txdesc->umac.head_len = head_len;
01217 txdesc->umac.tail_len = tail_len;
01218
01219 sec_end = CPU2HW(mac_hdr) + hdr_len + head_len;
01220 }
01221 else
01222 {
01223 #if NX_FULLY_HOSTED
01224 sec_end = txu_cntrl_mgmt_sec_pbd_add(txdesc, hdr_len);
01225 #else
01226 sec_end = CPU2HW(mac_hdr) + hdr_len + txdesc->umac.head_len;
01227 #endif
01228 }
01229
01230 mac_hdr->fctl |= MAC_FCTRL_PROTECTEDFRAME;
01231 txu_cntrl_sec_hdr_append(txdesc, sec_end, false);
01232 }
01233
01234 #if NX_FULLY_HOSTED
01235 uint32_t txu_cntrl_mgmt_mic_pbd_append(struct txdesc *txdesc)
01236 {
01237 struct tx_pbd *pbd_mmic = &txdesc->lmac.buffer->pbd_tail;
01238 pbd_mmic = &txdesc->lmac.buffer->pbd_tail;
01239 pbd_mmic->upatterntx = TX_PAYLOAD_DESC_PATTERN;
01240 pbd_mmic->datastartptr = CPU2HW(&txdesc->lmac.buffer->headers[0]);
01241 pbd_mmic->dataendptr = pbd_mmic->datastartptr + MAC_MGMT_MIC_LEN;
01242 pbd_mmic->next = 0;
01243 pbd_mmic->bufctrlinfo = 0;
01244
01245
01246 ASSERT_ERR(txdesc->lmac.buffer->pbd[0].next == 0);
01247 txdesc->lmac.buffer->pbd[0].next = CPU2HW(pbd_mmic);
01248
01249 return pbd_mmic->datastartptr;
01250 }
01251 #endif