00001
00013
00014
00015
00016
00017
00018
00019 #include "co_endian.h"
00020
00021 #include "co_utils.h"
00022 #include "bam.h"
00023 #include "bam_task.h"
00024 #include "mac_frame.h"
00025 #include "me_mgmtframe.h"
00026 #include "ke_timer.h"
00027 #include "mm.h"
00028 #include "mm_task.h"
00029 #include "rxu_task.h"
00030 #include "sta_mgmt.h"
00031 #include "me.h"
00032 #include "ps.h"
00033
00039
00040
00041
00042
00043
00044 #if NX_AMPDU_TX
00045
00056 static int bam_add_ba_rsp_timeout_ind_handler(ke_msg_id_t const msgid,
00057 void const *param,
00058 ke_task_id_t const dest_id,
00059 ke_task_id_t const src_id)
00060 {
00061 if (ke_state_get(dest_id) == BAM_WAIT_RSP)
00062 {
00063 uint16_t bam_idx = KE_IDX_GET(dest_id);
00064
00065
00066 bam_param_sta_info_tab_reset(bam_idx);
00067
00068
00069 ke_state_set(dest_id, BAM_IDLE);
00070
00071 TRACE_LMAC(BA, "{BAM-%d} no response from STA, drop agreement", bam_idx);
00072 }
00073
00074
00075 return (KE_MSG_CONSUMED);
00076 }
00077 #endif
00078
00079 #if NX_AMPDU_TX || NX_REORD
00080
00092 static void bam_delba_status(void *env, uint32_t status)
00093 {
00094 struct bam_env_tag *bam = env;
00095 uint16_t bam_idx = 0;
00096
00097 while ((bam_idx < BAM_IDX_MAX) && (bam != &bam_env[bam_idx]))
00098 {
00099 bam_idx++;
00100 }
00101
00102
00103
00104 if ((bam_idx == BAM_IDX_MAX)||
00105 (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) != BAM_DELETE))
00106 {
00107 return;
00108 }
00109
00110 if (!(status & FRAME_SUCCESSFUL_TX_BIT) &&
00111 (bam->delba_count < BAM_DELBA_MAX_TRY))
00112 {
00113 bam->delba_count++;
00114 bam_send_air_action_frame(bam->sta_idx, bam, MAC_BA_ACTION_DELBA,
00115 0, 0, MAC_RS_TIMEOUT, bam_delba_status);
00116 }
00117 else
00118 {
00119 bam_send_mm_ba_del_req(bam->sta_idx, bam_idx);
00120 }
00121 }
00122
00134 static int bam_inactivity_timeout_ind_handler(ke_msg_id_t const msgid,
00135 void const *param,
00136 ke_task_id_t const dest_id,
00137 ke_task_id_t const src_id)
00138 {
00139
00140 if (ke_state_get(dest_id) == BAM_ACTIVE)
00141 {
00142 uint16_t bam_idx = KE_IDX_GET(dest_id);
00143 struct bam_env_tag *bam = &bam_env[bam_idx];
00144
00145
00146 if (!bam_env[bam_idx].pkt_cnt &&
00147 hal_machw_time_past(bam->last_activity_time + bam->ba_timeout * TU_DURATION))
00148 {
00149 uint16_t sta_idx = bam_env[bam_idx].sta_idx;
00150
00151 TRACE_LMAC(BA, "{BAM-%d} delete agreement with {STA-%d} because of inactivity",
00152 bam_idx, sta_idx);
00153
00154
00155 ke_state_set(dest_id, BAM_DELETE);
00156
00157 bam->delba_count = 0;
00158 bam_send_air_action_frame(sta_idx, &bam_env[bam_idx], MAC_BA_ACTION_DELBA, 0, 0,
00159 MAC_RS_TIMEOUT, bam_delba_status);
00160 }
00161 else
00162 {
00163
00164 bam_start_inactivity_timer(bam_idx);
00165 }
00166 }
00167
00168 return (KE_MSG_CONSUMED);
00169 }
00170
00183 static int mm_ba_add_cfm_handler(ke_msg_id_t const msgid,
00184 struct mm_ba_add_cfm const *param,
00185 ke_task_id_t const dest_id,
00186 ke_task_id_t const src_id)
00187 {
00188 uint16_t bam_idx = KE_IDX_GET(dest_id);
00189
00190 if (ke_state_get(dest_id) != BAM_CHECK_ADMISSION)
00191 {
00192 ASSERT_WARN(0);
00193 return KE_MSG_CONSUMED;
00194 }
00195
00196
00197 switch (bam_env[bam_idx].dev_type)
00198 {
00199 #if NX_AMPDU_TX
00200 case BA_ORIGINATOR:
00201 {
00202 if (param->status == BA_AGMT_ESTABLISHED)
00203 {
00204 int8_t credit_oft = (int8_t)bam_env[bam_idx].buffer_size -
00205 NX_DEFAULT_TX_CREDIT_CNT;
00206
00207
00208 bam_baw_init(&bam_env[bam_idx]);
00209
00210
00211 bam_env[bam_idx].last_activity_time = hal_machw_time();
00212
00213
00214 me_credits_update_ind(param->sta_idx, param->tid, credit_oft);
00215
00216
00217 bam_start_inactivity_timer(bam_idx);
00218
00219
00220 ke_state_set(dest_id, BAM_ACTIVE);
00221
00222 TRACE_LMAC(BA, "{BAM-%d} TX agreement with {STA-%d} successfully created",
00223 bam_idx, param->sta_idx);
00224 }
00225 else
00226 {
00227
00228 bam_param_sta_info_tab_reset(bam_idx);
00229
00230
00231 ke_state_set(dest_id, BAM_IDLE);
00232
00233 TRACE_LMAC(BA, "{BAM-%d} failed to create TX agreement with {STA-%d}",
00234 bam_idx, param->sta_idx);
00235 }
00236 } break;
00237 #endif
00238
00239 #if NX_REORD
00240 case BA_RESPONDER:
00241 {
00242 if (param->status == BA_AGMT_ESTABLISHED)
00243 {
00244
00245 bam_send_air_action_frame(bam_env[bam_idx].sta_idx, &bam_env[bam_idx],
00246 MAC_BA_ACTION_ADDBA_RSP,
00247 bam_env[bam_idx].dialog_token,
00248 bam_build_baparamset(&bam_env[bam_idx]),
00249 MAC_BA_ST_SUCCESS, NULL);
00250
00251
00252 sta_info_tab[param->sta_idx].ba_info[param->tid].bam_idx_rx = bam_idx;
00253
00254
00255 bam_env[bam_idx].last_activity_time = hal_machw_time();
00256
00257
00258 bam_start_inactivity_timer(bam_idx);
00259
00260
00261 ke_state_set(dest_id, BAM_ACTIVE);
00262
00263 TRACE_LMAC(BA, "{BAM-%d} RX agreement with {STA-%d} successfully created",
00264 bam_idx, param->sta_idx);
00265 }
00266 else
00267 {
00268
00269 bam_send_air_action_frame(bam_env[bam_idx].sta_idx, &bam_env[bam_idx],
00270 MAC_BA_ACTION_ADDBA_RSP,
00271 bam_env[bam_idx].dialog_token,
00272 bam_build_baparamset(&bam_env[bam_idx]),
00273 MAC_BA_ST_REQUEST_REFUSED, NULL);
00274
00275
00276 ke_state_set(dest_id, BAM_IDLE);
00277
00278 TRACE_LMAC(BA, "{BAM-%d} failed to create RX agreement with {STA-%d}",
00279 bam_idx, param->sta_idx);
00280 }
00281 } break;
00282 #endif
00283
00284 default:
00285 {
00286
00287 ASSERT_WARN(0);
00288 } break;
00289 }
00290
00291 return KE_MSG_CONSUMED;
00292 }
00293
00305 static int mm_ba_del_cfm_handler(ke_msg_id_t const msgid,
00306 struct mm_ba_del_cfm const *param,
00307 ke_task_id_t const dest_id,
00308 ke_task_id_t const src_id)
00309 {
00310 uint16_t bam_idx = KE_IDX_GET(dest_id);
00311
00312 if ((param->status == BA_AGMT_DELETED) &&
00313 (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_DELETE))
00314 {
00315 #if NX_AMPDU_TX
00316 if (bam_env[bam_idx].dev_type == BA_ORIGINATOR)
00317 {
00318 int8_t credit_oft = NX_DEFAULT_TX_CREDIT_CNT -
00319 (int8_t)bam_env[bam_idx].buffer_size +
00320 bam_flush_baw(bam_env[bam_idx].baw);
00321
00322
00323 me_credits_update_ind(param->sta_idx, param->tid, credit_oft);
00324 }
00325 #endif
00326
00327 bam_delete_ba_agg(bam_idx);
00328 }
00329
00330 return (KE_MSG_CONSUMED);
00331 }
00332 #endif
00333
00346 static int rxu_mgt_ind_handler(ke_msg_id_t const msgid,
00347 struct rxu_mgt_ind const *param,
00348 ke_task_id_t const dest_id,
00349 ke_task_id_t const src_id)
00350 {
00351
00352 uint32_t frame = CPU2HW(param->payload);
00353 uint8_t action = co_read8p(frame + MAC_ACTION_ACTION_OFT);
00354
00355
00356 switch (action)
00357 {
00358 case MAC_BA_ACTION_ADDBA_REQ:
00359 {
00360 uint16_t sta_idx = param->sta_idx;
00361 #if (NX_REORD)
00362 uint16_t bam_idx = 0;
00363 struct sta_info_tag *sta = &sta_info_tab[sta_idx];
00364 #endif //(NX_REORD)
00365 uint8_t dialog_token = co_read8p(frame + MAC_ACTION_TOKEN_OFT);
00366 uint16_t ba_param = co_read16p(frame + BAM_ADDBAREQ_BA_PARAM_OFFSET);
00367 uint8_t status = MAC_BA_ST_REQUEST_REFUSED;
00368
00369 #if NX_REORD
00370 do
00371 {
00372 uint8_t tid = BAM_BA_PARAM_GET(ba_param, TID);
00373
00374
00375 if (tid >= TID_MAX)
00376 {
00377 break;
00378 }
00379
00380
00381 if (mm_ba_agmt_rx_exists(sta_idx, tid))
00382 {
00383
00384 bam_idx = sta_mgmt_get_rx_bam_idx(sta_idx, tid);
00385
00386
00387 if (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_ACTIVE)
00388 {
00389
00390 if (bam_env[bam_idx].buffer_size == co_min(BAM_BA_PARAM_GET(ba_param, BUFF_SIZE), NX_REORD_BUF_SIZE))
00391 {
00392
00393 status = MAC_BA_ST_SUCCESS;
00394 }
00395 else
00396 {
00397
00398 status = MAC_BA_ST_REQUEST_REFUSED;
00399
00400
00401 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_DELETE);
00402
00403
00404 bam_send_mm_ba_del_req(param->sta_idx, bam_idx);
00405 }
00406 }
00407 break;
00408 }
00409
00410
00411 if (sta->ps_state == PS_MODE_ON)
00412 {
00413 TRACE_LMAC(BA, "Refuse RX agreement with {STA-%d} in PS mode",
00414 sta_idx);
00415 status = MAC_BA_ST_REQUEST_REFUSED;
00416 break;
00417 }
00418
00419
00420 bam_idx = bam_alloc_new_task(false);
00421
00422 if (bam_idx == BAM_INVALID_TASK_IDX)
00423 {
00424
00425 status = MAC_BA_ST_REQUEST_REFUSED;
00426 break;
00427 }
00428
00429 bam_env[bam_idx].tid = tid;
00430 bam_env[bam_idx].sta_idx = sta_idx;
00431 bam_env[bam_idx].dialog_token = dialog_token;
00432 bam_env[bam_idx].ba_policy = BAM_BA_PARAM_GET(ba_param, BA_POL);
00433 bam_env[bam_idx].dev_type = BA_RESPONDER;
00434 bam_env[bam_idx].ba_timeout = co_read16p(frame + BAM_ADDBAREQ_BA_TIMEOUT_OFFSET);
00435 bam_env[bam_idx].buffer_size = co_min(BAM_BA_PARAM_GET(ba_param, BUFF_SIZE), NX_REORD_BUF_SIZE);
00436 bam_env[bam_idx].ssn = co_read16p(frame + BAM_ADDBAREQ_BA_SSC_OFFSET)>>MAC_SEQCTRL_NUM_OFT;
00437 bam_env[bam_idx].pkt_cnt = 0;
00438
00439 if (!bam_env[bam_idx].ba_timeout)
00440 {
00441
00442 bam_env[bam_idx].ba_timeout = BAM_INACTIVITY_TO_DURATION;
00443 }
00444
00445 TRACE_LMAC(BA, "{BAM-%d} Start RX agreement with {STA-%d}: tid=%d ssn=%d",
00446 bam_idx, sta_idx, tid, bam_env[bam_idx].ssn)
00447
00448
00449 bam_send_mm_ba_add_req(sta_idx, bam_idx);
00450
00451
00452 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_CHECK_ADMISSION);
00453
00454 return (KE_MSG_CONSUMED);
00455 } while (0);
00456 #endif
00457
00458
00459 bam_send_air_action_frame(sta_idx, NULL, MAC_BA_ACTION_ADDBA_RSP, dialog_token,
00460 ba_param, status, NULL);
00461 break;
00462 }
00463
00464 #if NX_AMPDU_TX
00465 case MAC_BA_ACTION_ADDBA_RSP:
00466 {
00467 uint16_t status;
00468 uint16_t ba_param;
00469 uint8_t bam_idx;
00470 uint8_t tid;
00471
00472 do
00473 {
00474 ba_param = co_read16p(frame + BAM_ADDBARSP_BA_PARAM_OFFSET);
00475 tid = BAM_BA_PARAM_GET(ba_param, TID);
00476
00477
00478 if (tid >= TID_MAX)
00479 {
00480
00481 status = MAC_BA_ST_SUCCESS;
00482 break;
00483 }
00484
00485
00486 bam_idx = sta_mgmt_get_tx_bam_idx(param->sta_idx, tid);
00487
00488 if (bam_idx == BAM_INVALID_TASK_IDX)
00489 {
00490
00491 status = MAC_BA_ST_SUCCESS;
00492 break;
00493 }
00494
00495
00496 if (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) != BAM_WAIT_RSP)
00497 {
00498
00499 status = MAC_BA_ST_SUCCESS;
00500 break;
00501 }
00502
00503 status = MAC_BA_ST_INVALID_PARAMETERS;
00504
00505
00506 ke_timer_clear(BAM_ADD_BA_RSP_TIMEOUT_IND, KE_BUILD_ID(TASK_BAM, bam_idx));
00507
00508
00509 if (co_read8p(frame + MAC_ACTION_TOKEN_OFT) != bam_env[bam_idx].dialog_token)
00510 {
00511 status = MAC_BA_ST_INVALID_PARAMETERS;
00512 break;
00513 }
00514
00515
00516 if (tid != bam_env[bam_idx].tid)
00517 {
00518 status = MAC_BA_ST_INVALID_PARAMETERS;
00519 break;
00520 }
00521
00522 status = co_read16p(frame + BAM_ADDBARSP_STATUS_OFFSET);
00523
00524
00525 if (status != MAC_BA_ST_SUCCESS)
00526 {
00527 break;
00528 }
00529
00530
00531
00532
00533
00534
00535
00536 if (BAM_BA_PARAM_GET(ba_param, BUFF_SIZE) < bam_env[bam_idx].buffer_size)
00537 {
00538 bam_env[bam_idx].buffer_size = BAM_BA_PARAM_GET(ba_param, BUFF_SIZE);
00539 }
00540
00541 bam_env[bam_idx].amsdu=BAM_BA_PARAM_GET(ba_param, AMSDU_SUP);
00542
00543
00544 bam_send_mm_ba_add_req(param->sta_idx, bam_idx);
00545
00546
00547 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_CHECK_ADMISSION);
00548 } while (0);
00549
00550 if (status != MAC_BA_ST_SUCCESS)
00551 {
00552
00553
00554
00555
00556
00557 bam_param_sta_info_tab_reset(bam_idx);
00558
00559 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_IDLE);
00560 TRACE_LMAC(BA, "{BAM-%d} STA refused the TX agreement", bam_idx);
00561 }
00562 break;
00563 }
00564 #endif
00565
00566 #if NX_AMPDU_TX || NX_REORD
00567 case MAC_BA_ACTION_DELBA:
00568 {
00569 uint16_t delba_param = co_read16p(frame + BAM_DELBA_PARAM_OFFSET);
00570 uint8_t tid = BAM_DELBA_PARAM_GET(delba_param, TID);
00571 uint16_t bam_idx;
00572
00573 do
00574 {
00575
00576 if ((tid >= TID_MAX) || (param->sta_idx == INVALID_STA_IDX))
00577 {
00578 break;
00579 }
00580
00581
00582 if (BAM_DELBA_PARAM_GET(delba_param, INITIATOR))
00583 {
00584 bam_idx = sta_mgmt_get_rx_bam_idx(param->sta_idx, tid);
00585 }
00586 else
00587 {
00588 bam_idx = sta_mgmt_get_tx_bam_idx(param->sta_idx, tid);
00589 }
00590
00591 if (bam_idx == BAM_INVALID_TASK_IDX)
00592 {
00593 break;
00594 }
00595
00596
00597
00598 if (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_DELETE)
00599 {
00600 break;
00601 }
00602
00603
00604 ke_timer_clear(BAM_INACTIVITY_TIMEOUT_IND, KE_BUILD_ID(TASK_BAM, bam_idx));
00605
00606 if ((ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_ACTIVE) ||
00607 (ke_state_get(KE_BUILD_ID(TASK_BAM, bam_idx)) == BAM_CHECK_ADMISSION))
00608 {
00609
00610 ke_state_set(KE_BUILD_ID(TASK_BAM, bam_idx), BAM_DELETE);
00611
00612 TRACE_LMAC(BA, "{BAM-%d} Delete agreement after receiving DELBA",
00613 bam_idx);
00614
00615
00616 bam_send_mm_ba_del_req(param->sta_idx, bam_idx);
00617 }
00618 else
00619 {
00620
00621 bam_delete_ba_agg(bam_idx);
00622 }
00623 } while (0);
00624 break;
00625 }
00626 #endif
00627
00628 default:
00629 break;
00630 }
00631
00632 return (KE_MSG_CONSUMED);
00633 }
00634
00635
00636
00637
00638
00639
00641 const struct ke_msg_handler bam_default_state[] =
00642 {
00643
00644 #if NX_AMPDU_TX
00645 {BAM_ADD_BA_RSP_TIMEOUT_IND, (ke_msg_func_t)bam_add_ba_rsp_timeout_ind_handler},
00646 #endif
00647 #if NX_AMPDU_TX || NX_REORD
00648 {BAM_INACTIVITY_TIMEOUT_IND, (ke_msg_func_t)bam_inactivity_timeout_ind_handler},
00649 {MM_BA_DEL_CFM, (ke_msg_func_t)mm_ba_del_cfm_handler},
00650 {MM_BA_ADD_CFM, (ke_msg_func_t)mm_ba_add_cfm_handler},
00651 #endif
00652 {RXU_MGT_IND, (ke_msg_func_t)rxu_mgt_ind_handler},
00653 };
00654
00656 const struct ke_state_handler bam_default_handler = KE_STATE_HANDLER(bam_default_state);
00657
00659 ke_state_t bam_state[BAM_IDX_MAX];
00660