/** **************************************************************************************** * * @file rwnx_msg_rx.c * * @brief RX function definitions * * Copyright (C) RivieraWaves 2012-2019 * **************************************************************************************** */ #include "co_utils.h" #include "lmac_msg.h" #include "cfgrwnx.h" #include "fhost.h" #include "fhost_tx.h" #include "fhost_cntrl.h" #include "fhost_config.h" #include "rwnx_defs.h" #include "rwnx_utils.h" #include "aic_plat_log.h" #include "sys_al.h" extern uint8_t mac_vif_index; static int rwnx_freq_to_idx(struct rwnx_hw *rwnx_hw, int freq) { int i, nb_chan, idx = 0; struct mac_chan_def *chans; if (freq < PHY_FREQ_5G) { chans = fhost_chan.chan2G4; nb_chan = fhost_chan.chan2G4_cnt; } else { chans = fhost_chan.chan5G; nb_chan = fhost_chan.chan5G_cnt; idx = fhost_chan.chan2G4_cnt; } for (i = 0; i < nb_chan; i++, chans++) { if (freq == chans->freq) { idx += i; break; } } return idx; } /*************************************************************************** * Messages from MM task **************************************************************************/ static inline int rwnx_rx_chan_pre_switch_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 1 RWNX_DBG(RWNX_FN_ENTRY_STR); //struct mm_channel_pre_switch_ind *ind = (struct mm_channel_pre_switch_ind *)msg->param; //int chan_idx = ind->chan_index; fhost_txq_vif_stop(0, TXQ_STOP_CHAN); // TODO: #endif return 0; } static inline int rwnx_rx_chan_switch_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 1 RWNX_DBG(RWNX_FN_ENTRY_STR); struct mm_channel_switch_ind *ind = (struct mm_channel_switch_ind *)msg->param; int chan_idx = ind->chan_index; bool roc = ind->roc; bool roc_tdls = ind->roc_tdls; uint8_t vif_index = ind->vif_index; struct fhost_vif_tag *vif = NULL; vif = &fhost_env.vif[vif_index]; if (roc_tdls) { } else if (!roc) { fhost_txq_vif_start(0, TXQ_STOP_CHAN); // TODO: } else { } vif->chan_index = chan_idx; fhost_tx_env.to_times = 0; #endif return 0; } static inline int rwnx_rx_tdls_chan_switch_cfm(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { // RWNX_DBG(RWNX_FN_ENTRY_STR); return 0; } static inline int rwnx_rx_tdls_chan_switch_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { // RWNX_DBG(RWNX_FN_ENTRY_STR); // Enable traffic on OFF channel queue //rwnx_txq_offchan_start(rwnx_hw); return 0; } static inline int rwnx_rx_tdls_chan_switch_base_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 RWNX_DBG(RWNX_FN_ENTRY_STR); struct rwnx_vif *rwnx_vif; u8 vif_index = ((struct tdls_chan_switch_base_ind *)msg->param)->vif_index; list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) { if (rwnx_vif->vif_index == vif_index) { rwnx_vif->roc_tdls = false; rwnx_txq_tdls_sta_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw); } } #endif return 0; } static inline int rwnx_rx_tdls_peer_ps_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 RWNX_DBG(RWNX_FN_ENTRY_STR); struct rwnx_vif *rwnx_vif; u8 vif_index = ((struct tdls_peer_ps_ind *)msg->param)->vif_index; bool ps_on = ((struct tdls_peer_ps_ind *)msg->param)->ps_on; list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) { if (rwnx_vif->vif_index == vif_index) { rwnx_vif->sta.tdls_sta->tdls.ps_on = ps_on; // Update PS status for the TDLS station rwnx_ps_bh_enable(rwnx_hw, rwnx_vif->sta.tdls_sta, ps_on); } } #endif return 0; } static inline int rwnx_rx_remain_on_channel_exp_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 aic_dbg(RWNX_FN_ENTRY_STR); /* Retrieve the allocated RoC element */ struct rwnx_roc_elem *roc_elem = rwnx_hw->roc_elem; /* Get VIF on which RoC has been started */ struct rwnx_vif *rwnx_vif = netdev_priv(roc_elem->wdev->netdev); /* For debug purpose (use ftrace kernel option) */ trace_roc_exp(rwnx_vif->vif_index); /* If mgmt_roc is true, remain on channel has been started by ourself */ /* If RoC has been cancelled before we switched on channel, do not call cfg80211 */ if (!roc_elem->mgmt_roc && roc_elem->on_chan) { /* Inform the host that off-channel period has expired */ cfg80211_remain_on_channel_expired(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt), roc_elem->chan, GFP_ATOMIC); } /* De-init offchannel TX queue */ rwnx_txq_offchan_deinit(rwnx_vif); /* Increase the cookie counter cannot be zero */ rwnx_hw->roc_cookie_cnt++; if (rwnx_hw->roc_cookie_cnt == 0) { rwnx_hw->roc_cookie_cnt = 1; } /* Free the allocated RoC element */ kfree(roc_elem); rwnx_hw->roc_elem = NULL; #endif return 0; } static inline int rwnx_rx_p2p_vif_ps_change_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 RWNX_DBG(RWNX_FN_ENTRY_STR); int vif_idx = ((struct mm_p2p_vif_ps_change_ind *)msg->param)->vif_index; int ps_state = ((struct mm_p2p_vif_ps_change_ind *)msg->param)->ps_state; struct rwnx_vif *vif_entry; vif_entry = rwnx_hw->vif_table[vif_idx]; if (vif_entry) { goto found_vif; } goto exit; found_vif: if (ps_state == MM_PS_MODE_OFF) { // Start TX queues for provided VIF rwnx_txq_vif_start(vif_entry, RWNX_TXQ_STOP_VIF_PS, rwnx_hw); } else { // Stop TX queues for provided VIF rwnx_txq_vif_stop(vif_entry, RWNX_TXQ_STOP_VIF_PS, rwnx_hw); } exit: #endif return 0; } static inline int rwnx_rx_channel_survey_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { RWNX_DBG(RWNX_FN_ENTRY_STR); struct mm_channel_survey_ind *ind = (struct mm_channel_survey_ind *)msg->param; // Get the channel index int idx = rwnx_freq_to_idx(rwnx_hw, ind->freq); // Get the survey struct rwnx_survey_info *rwnx_survey = &rwnx_hw->survey[idx]; // Store the received parameters rwnx_survey->chan_time_ms = ind->chan_time_ms; rwnx_survey->chan_time_busy_ms = ind->chan_time_busy_ms; rwnx_survey->noise_dbm = ind->noise_dbm; rwnx_survey->filled = (SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY); if (ind->noise_dbm != 0) { rwnx_survey->filled |= SURVEY_INFO_NOISE_DBM; } return 0; } static inline int rwnx_rx_p2p_noa_upd_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); return 0; } static inline int rwnx_rx_rssi_status_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 RWNX_DBG(RWNX_FN_ENTRY_STR); struct mm_rssi_status_ind *ind = (struct mm_rssi_status_ind *)msg->param; int vif_idx = ind->vif_index; bool rssi_status = ind->rssi_status; struct rwnx_vif *vif_entry; vif_entry = rwnx_hw->vif_table[vif_idx]; if (vif_entry) { cfg80211_cqm_rssi_notify(vif_entry->ndev, rssi_status ? NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, ind->rssi, GFP_ATOMIC); } #endif return 0; } static inline int rwnx_rx_pktloss_notify_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 aic_dbg(RWNX_FN_ENTRY_STR); struct mm_pktloss_ind *ind = (struct mm_pktloss_ind *)msg->param; struct rwnx_vif *vif_entry; int vif_idx = ind->vif_index; vif_entry = rwnx_hw->vif_table[vif_idx]; if (vif_entry) { cfg80211_cqm_pktloss_notify(vif_entry->ndev, (const u8 *)ind->mac_addr.array, ind->num_packets, GFP_ATOMIC); } #endif /* CONFIG_RWNX_FULLMAC */ return 0; } extern int rwnx_apm_staloss_notify(struct mm_apm_staloss_ind *ind); static inline int rwnx_apm_staloss_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { struct mm_apm_staloss_ind *ind = (struct mm_apm_staloss_ind *)msg->param; int ret; RWNX_DBG(RWNX_FN_ENTRY_STR); //queue_work(rwnx_hw->apmStaloss_wq, &rwnx_hw->apmStalossWork); rwnx_apm_staloss_notify(ind); return 0; } static inline int rwnx_rx_csa_counter_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 aic_dbg(RWNX_FN_ENTRY_STR); struct mm_csa_counter_ind *ind = (struct mm_csa_counter_ind *)msg->param; if(mac_vif_index != ind->vif_index) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, ind->vif_index); return -1; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(ind->vif_index); if(ind->vif_index >= NX_VIRT_DEV_MAX) { return -1; } fhost_vif->mac_vif->u.ap.csa_count = ind->csa_count; #endif return 0; } static inline int rwnx_rx_csa_finish_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 aic_dbg(RWNX_FN_ENTRY_STR); struct fhost_vif_tag *vif = NULL; struct mm_csa_finish_ind *ind = (struct mm_csa_finish_ind *)msg->param; if(ind->vif_index >= NX_VIRT_DEV_MAX) { return -1; } vif = &fhost_env.vif[ind->vif_index]; if(VIF_AP == vif->mac_vif->type) { if(!ind->status) { vif->chan_index = ind->chan_idx; rtos_semaphore_signal(vif->mac_vif->u.ap.csa_semaphore, false); } else { aic_dbg("rwnx_rx_csa_finish_ind fail\r\n"); } } else { if (ind->status == 0) { if (vif->chan_index == ind->chan_idx) { fhost_txq_vif_start(ind->vif_index, TXQ_STOP_CHAN); } else { fhost_txq_vif_stop(ind->vif_index, TXQ_STOP_CHAN); } } } #endif return 0; } static inline int rwnx_rx_csa_traffic_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 aic_dbg(RWNX_FN_ENTRY_STR); struct mm_csa_traffic_ind *ind = (struct mm_csa_traffic_ind *)msg->param; if(ind->vif_index >= NX_VIRT_DEV_MAX) { return -1; } if (ind->enable) { fhost_txq_vif_start(ind->vif_index, TXQ_STOP_CSA); } else { fhost_txq_vif_stop(ind->vif_index, TXQ_STOP_CSA); } #endif return 0; } #ifdef CFG_SOFTAP static inline int rwnx_rx_ps_change_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); if ((rwnx_hw->chipid == PRODUCT_ID_AIC8800DC) || (rwnx_hw->chipid == PRODUCT_ID_AIC8800DW) || (rwnx_hw->chipid == PRODUCT_ID_AIC8800D80)) { //aic_dbg("%s, wifi driver do not handle ps_change_ind\r\n", __func__); return 0; } struct mm_ps_change_ind *ind = (struct mm_ps_change_ind *)msg->param; fhost_tx_sta_ps_enable(ind->sta_idx, ind->ps_state); return 0; } static inline int rwnx_rx_traffic_req_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); struct mm_traffic_req_ind *ind = (struct mm_traffic_req_ind *)msg->param; fhost_tx_do_ps_traffic_req(ind->sta_idx, ind->pkt_cnt, (enum fhost_tx_ps_type)ind->uapsd); return 0; } #endif /* CFG_SOFTAP */ /*************************************************************************** * Messages from SCANU task **************************************************************************/ static inline int rwnx_rx_scanu_start_cfm(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 1 RWNX_DBG(RWNX_FN_ENTRY_STR); struct cfgrwnx_scan_completed resp; struct scanu_start_cfm *cfm = (struct scanu_start_cfm *)msg->param; if(mac_vif_index != cfm->vif_idx) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, cfm->vif_idx); return -1; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(cfm->vif_idx); resp.hdr.id = CFGRWNX_SCAN_DONE_EVENT; resp.hdr.len = sizeof(resp); resp.result_cnt = cfm->result_cnt; if (cfm->status == CO_OK) resp.status = CFGRWNX_SUCCESS; else resp.status = CFGRWNX_ERROR; fhost_cntrl_cfgrwnx_event_send(&resp.hdr, fhost_vif->scan_sock); #endif return 0; } static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 1 RWNX_DBG(RWNX_FN_ENTRY_STR); struct cfgrwnx_scan_result result; struct scanu_result_ind *ind = (struct scanu_result_ind *)msg->param; if(mac_vif_index != ind->inst_nbr) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, ind->inst_nbr); return 0; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(ind->inst_nbr); result.hdr.id = CFGRWNX_SCAN_RESULT_EVENT; result.hdr.len = sizeof(struct cfgrwnx_scan_result); result.fhost_vif_idx = CO_GET_INDEX(fhost_vif, fhost_env.vif); result.freq = ind->center_freq; result.rssi = ind->rssi; result.length = ind->length; result.payload = rtos_malloc(ind->length); if (result.payload == NULL) return 0; fhost_scan_frame_handler(ind); memcpy(result.payload, ind->payload, ind->length); if (fhost_cntrl_cfgrwnx_event_send(&result.hdr, fhost_vif->scan_sock)) { rtos_free(result.payload); } #endif return 0; } /*************************************************************************** * Messages from ME task **************************************************************************/ static inline int rwnx_rx_me_tkip_mic_failure_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 0 RWNX_DBG(RWNX_FN_ENTRY_STR); struct cfgrwnx_mic_failure_event event; struct me_tkip_mic_failure_ind *ind = (struct me_tkip_mic_failure_ind *)msg->param; if(mac_vif_index != ind->vif_idx) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, ind->vif_idx); return -1; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(ind->vif_idx); event.hdr.id = CFGRWNX_MIC_FAILURE_EVENT; event.hdr.len = sizeof(event); MAC_ADDR_CPY(&event.addr, &ind->addr); event.ga = ind->ga; event.fhost_vif_idx = CO_GET_INDEX(fhost_vif, fhost_env.vif); fhost_cntrl_cfgrwnx_event_send(&event.hdr, fhost_vif->conn_sock); #endif return 0; } static inline int rwnx_rx_me_tx_credits_update_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); //struct me_tx_credits_update_ind *ind = (struct me_tx_credits_update_ind *)msg->param; //fhost_tx_do_credits_update(ind->sta_idx, ind->tid, ind->credits); return 0; } uint8_t sta_index = 0; /*************************************************************************** * Messages from SM task **************************************************************************/ static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 1 RWNX_DBG(RWNX_FN_ENTRY_STR); struct cfgrwnx_connect_event event; struct sm_connect_ind *param = (struct sm_connect_ind *)msg->param; if(mac_vif_index != param->vif_idx) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, param->vif_idx); return -1; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(param->vif_idx); int req_resp_ies_len = param->assoc_req_ie_len + param->assoc_rsp_ie_len; event.hdr.id = CFGRWNX_CONNECT_EVENT; event.hdr.len = sizeof(event); MAC_ADDR_CPY(&event.bssid, ¶m->bssid); event.status_code = param->status_code; event.freq = param->center_freq; event.assoc_req_ie_len = param->assoc_req_ie_len; event.assoc_resp_ie_len = param->assoc_rsp_ie_len; event.sta_idx = param->ap_idx; if (req_resp_ies_len) { event.req_resp_ies = rtos_malloc(req_resp_ies_len); if (event.req_resp_ies == NULL) { TRACE_FHOST("Failed to allocate assoc IE"); return 0; } memcpy(event.req_resp_ies, param->assoc_ie_buf, req_resp_ies_len); } else { event.req_resp_ies = NULL; } if (fhost_cntrl_cfgrwnx_event_send(&event.hdr, fhost_vif->conn_sock) && event.req_resp_ies) { rtos_free(event.req_resp_ies); return 0; } if (param->status_code == MAC_ST_SUCCESSFUL) { fhost_vif->ap_id = param->ap_idx; fhost_vif->acm = param->acm; //fhost_tx_sta_add(fhost_vif->ap_id); fhost_vif->mac_vif->u.sta.ap_id = param->ap_idx; struct sta_info_tag *sta = (struct sta_info_tag*)co_list_pop_front(&free_sta_list); sta->inst_nbr = fhost_vif->mac_vif->index; sta->staid = param->ap_idx; sta->valid = true; MAC_ADDR_CPY(&sta->mac_addr, ¶m->bssid); MAC_ADDR_CPY(&(vif_info_tab[fhost_vif->mac_vif->index].bss_info.bssid), ¶m->bssid); sta_index = CO_GET_INDEX(fhost_vif->mac_vif, vif_info_tab); aic_dbg("Connect %d %x:%x:%x, sta_index %d\n", fhost_vif->ap_id, sta->mac_addr.array[0], sta->mac_addr.array[1],sta->mac_addr.array[2], sta_index); fhost_vif->mac_vif->active = true; fhost_tx_do_sta_add(fhost_vif->ap_id); } #endif return 0; } static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { RWNX_DBG(RWNX_FN_ENTRY_STR); struct cfgrwnx_disconnect_event event; struct sm_disconnect_ind *param = (struct sm_disconnect_ind *)msg->param; if(mac_vif_index != param->vif_idx) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, param->vif_idx); return -1; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(param->vif_idx); event.hdr.id = CFGRWNX_DISCONNECT_EVENT; event.hdr.len = sizeof(event); event.fhost_vif_idx = CO_GET_INDEX(fhost_vif, fhost_env.vif); event.reason_code = param->reason_code; fhost_tx_do_sta_del(fhost_vif->ap_id); fhost_cntrl_cfgrwnx_event_send(&event.hdr, fhost_vif->conn_sock); fhost_vif->conn_sock = -1; fhost_vif->mac_vif->active = false; struct sta_info_tag *sta = vif_mgmt_get_sta_by_staid(fhost_vif->ap_id); if (sta) { #if (AICWF_RX_REORDER) reord_deinit_sta_by_mac((uint8_t *)(sta->mac_addr.array)); #endif aic_dbg("Disconnect %d %x:%x:%x\n", fhost_vif->ap_id, sta->mac_addr.array[0], sta->mac_addr.array[1],sta->mac_addr.array[2]); sta->valid = false; memset(sta, 0, sizeof *sta); sta->staid = 0xFF; co_list_push_back(&free_sta_list, (struct co_list_hdr*)sta); } fhost_vif->ap_id = INVALID_STA_IDX; wlan_connected = 0; if (fhost_mac_status_get_callback) fhost_mac_status_get_callback(WIFI_MAC_STATUS_DISCONNECTED); return 0; } static inline int rwnx_rx_sm_external_auth_required_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { #if 1 RWNX_DBG(RWNX_FN_ENTRY_STR); struct cfgrwnx_external_auth_event event; struct sm_external_auth_required_ind *param = (struct sm_external_auth_required_ind *)msg->param; if(mac_vif_index != param->vif_idx) { aic_dbg("%s %d %d\r\n", __func__, mac_vif_index, param->vif_idx); return -1; } struct fhost_vif_tag *fhost_vif = fhost_from_mac_vif(param->vif_idx); event.hdr.id = CFGRWNX_EXTERNAL_AUTH_EVENT; event.hdr.len = sizeof(event); event.fhost_vif_idx = CO_GET_INDEX(fhost_vif, fhost_env.vif); event.bssid = param->bssid; event.ssid = param->ssid; event.akm = param->akm; fhost_cntrl_cfgrwnx_event_send(&event.hdr, fhost_vif->conn_sock); #endif return 0; } static inline int rwnx_rx_mesh_path_create_cfm(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); #if 0 struct mesh_path_create_cfm *cfm = (struct mesh_path_create_cfm *)msg->param; struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[cfm->vif_idx]; /* Check we well have a Mesh Point Interface */ if (rwnx_vif && (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT)) { rwnx_vif->ap.create_path = false; } #endif return 0; } static inline int rwnx_rx_mesh_peer_update_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); #if 0 struct mesh_peer_update_ind *ind = (struct mesh_peer_update_ind *)msg->param; struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; struct rwnx_sta *rwnx_sta = &rwnx_hw->sta_table[ind->sta_idx]; if ((ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX)) || (rwnx_vif && (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)) || (ind->sta_idx >= NX_REMOTE_STA_MAX)) return 1; /* Check we well have a Mesh Point Interface */ if (!rwnx_vif->user_mpm) { /* Check if peer link has been established or lost */ if (ind->estab) { if (!rwnx_sta->valid) { u8 txq_status; rwnx_sta->valid = true; rwnx_sta->sta_idx = ind->sta_idx; rwnx_sta->ch_idx = rwnx_vif->ch_index; rwnx_sta->vif_idx = ind->vif_idx; rwnx_sta->vlan_idx = rwnx_sta->vif_idx; rwnx_sta->ps.active = false; rwnx_sta->qos = true; rwnx_sta->aid = ind->sta_idx + 1; //rwnx_sta->acm = ind->acm; memcpy(rwnx_sta->mac_addr, ind->peer_addr.array, ETH_ALEN); rwnx_chanctx_link(rwnx_vif, rwnx_sta->ch_idx, NULL); /* Add the station in the list of VIF's stations */ INIT_LIST_HEAD(&rwnx_sta->list); list_add_tail(&rwnx_sta->list, &rwnx_vif->ap.sta_list); /* Initialize the TX queues */ if (rwnx_sta->ch_idx == rwnx_hw->cur_chanctx) { txq_status = 0; } else { txq_status = RWNX_TXQ_STOP_CHAN; } rwnx_txq_sta_init(rwnx_hw, rwnx_sta, txq_status); rwnx_dbgfs_register_rc_stat(rwnx_hw, rwnx_sta); #ifdef CONFIG_RWNX_BFMER // TODO: update indication to contains vht capabilties if (rwnx_hw->mod_params->bfmer) rwnx_send_bfmer_enable(rwnx_hw, rwnx_sta, NULL); rwnx_mu_group_sta_init(rwnx_sta, NULL); #endif /* CONFIG_RWNX_BFMER */ } else { WARN_ON(0); } } else { if (rwnx_sta->valid) { rwnx_sta->ps.active = false; rwnx_sta->valid = false; /* Remove the station from the list of VIF's station */ list_del_init(&rwnx_sta->list); rwnx_txq_sta_deinit(rwnx_hw, rwnx_sta); rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_sta); } else { WARN_ON(0); } } } else { if (!ind->estab && rwnx_sta->valid) { /* There is no way to inform upper layer for lost of peer, still clean everything in the driver */ rwnx_sta->ps.active = false; rwnx_sta->valid = false; /* Remove the station from the list of VIF's station */ list_del_init(&rwnx_sta->list); rwnx_txq_sta_deinit(rwnx_hw, rwnx_sta); rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_sta); } else { WARN_ON(0); } } #endif return 0; } static inline int rwnx_rx_mesh_path_update_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); #if 0 struct mesh_path_update_ind *ind = (struct mesh_path_update_ind *)msg->param; struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; struct rwnx_mesh_path *mesh_path; bool found = false; if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX)) return 1; if (!rwnx_vif || (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)) return 0; /* Look for path with provided target address */ list_for_each_entry(mesh_path, &rwnx_vif->ap.mpath_list, list) { if (mesh_path->path_idx == ind->path_idx) { found = true; break; } } /* Check if element has been deleted */ if (ind->delete) { if (found) { trace_mesh_delete_path(mesh_path); /* Remove element from list */ list_del_init(&mesh_path->list); /* Free the element */ kfree(mesh_path); } } else { if (found) { // Update the Next Hop STA mesh_path->p_nhop_sta = &rwnx_hw->sta_table[ind->nhop_sta_idx]; trace_mesh_update_path(mesh_path); } else { // Allocate a Mesh Path structure mesh_path = (struct rwnx_mesh_path *)kmalloc(sizeof(struct rwnx_mesh_path), GFP_ATOMIC); if (mesh_path) { INIT_LIST_HEAD(&mesh_path->list); mesh_path->path_idx = ind->path_idx; mesh_path->p_nhop_sta = &rwnx_hw->sta_table[ind->nhop_sta_idx]; memcpy(&mesh_path->tgt_mac_addr, &ind->tgt_mac_addr, MAC_ADDR_LEN); // Insert the path in the list of path list_add_tail(&mesh_path->list, &rwnx_vif->ap.mpath_list); trace_mesh_create_path(mesh_path); } } } #endif return 0; } static inline int rwnx_rx_mesh_proxy_update_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { //RWNX_DBG(RWNX_FN_ENTRY_STR); #if 0 struct mesh_proxy_update_ind *ind = (struct mesh_proxy_update_ind *)msg->param; struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; struct rwnx_mesh_proxy *mesh_proxy; bool found = false; if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX)) return 1; if (!rwnx_vif || (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)) return 0; /* Look for path with provided external STA address */ list_for_each_entry(mesh_proxy, &rwnx_vif->ap.proxy_list, list) { if (!memcmp(&ind->ext_sta_addr, &mesh_proxy->ext_sta_addr, ETH_ALEN)) { found = true; break; } } if (ind->delete && found) { /* Delete mesh path */ list_del_init(&mesh_proxy->list); kfree(mesh_proxy); } else if (!ind->delete && !found) { /* Allocate a Mesh Path structure */ mesh_proxy = (struct rwnx_mesh_proxy *)kmalloc(sizeof(*mesh_proxy), GFP_ATOMIC); if (mesh_proxy) { INIT_LIST_HEAD(&mesh_proxy->list); memcpy(&mesh_proxy->ext_sta_addr, &ind->ext_sta_addr, MAC_ADDR_LEN); mesh_proxy->local = ind->local; if (!ind->local) { memcpy(&mesh_proxy->proxy_addr, &ind->proxy_mac_addr, MAC_ADDR_LEN); } /* Insert the path in the list of path */ list_add_tail(&mesh_proxy->list, &rwnx_vif->ap.proxy_list); } } #endif return 0; } /*************************************************************************** * Messages from APM task **************************************************************************/ /*************************************************************************** * Messages from DEBUG task **************************************************************************/ static inline int rwnx_rx_dbg_error_ind(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, struct e2a_msg *msg) { // RWNX_DBG(RWNX_FN_ENTRY_STR); //rwnx_error_ind(rwnx_hw); return 0; } static msg_cb_fct mm_hdlrs[MSG_I(MM_MAX)] = { [MSG_I(MM_CHANNEL_SWITCH_IND)] = rwnx_rx_chan_switch_ind, [MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = rwnx_rx_chan_pre_switch_ind, [MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = rwnx_rx_remain_on_channel_exp_ind, #ifdef CFG_SOFTAP [MSG_I(MM_PS_CHANGE_IND)] = rwnx_rx_ps_change_ind, [MSG_I(MM_TRAFFIC_REQ_IND)] = rwnx_rx_traffic_req_ind, [MSG_I(MM_CSA_COUNTER_IND)] = rwnx_rx_csa_counter_ind, [MSG_I(MM_CSA_FINISH_IND)] = rwnx_rx_csa_finish_ind, [MSG_I(MM_CSA_TRAFFIC_IND)] = rwnx_rx_csa_traffic_ind, #endif /* CFG_SOFTAP */ [MSG_I(MM_CHANNEL_SURVEY_IND)] = rwnx_rx_channel_survey_ind, #if NX_P2P [MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = rwnx_rx_p2p_vif_ps_change_ind, [MSG_I(MM_P2P_NOA_UPD_IND)] = rwnx_rx_p2p_noa_upd_ind, #endif [MSG_I(MM_RSSI_STATUS_IND)] = rwnx_rx_rssi_status_ind, [MSG_I(MM_PKTLOSS_IND)] = rwnx_rx_pktloss_notify_ind, [MSG_I(MM_APM_STALOSS_IND)] = rwnx_apm_staloss_ind, }; static msg_cb_fct scan_hdlrs[MSG_I(SCANU_MAX)] = { [MSG_I(SCANU_START_CFM)] = rwnx_rx_scanu_start_cfm, [MSG_I(SCANU_RESULT_IND)] = rwnx_rx_scanu_result_ind, }; static msg_cb_fct me_hdlrs[MSG_I(ME_MAX)] = { [MSG_I(ME_TKIP_MIC_FAILURE_IND)] = rwnx_rx_me_tkip_mic_failure_ind, //[MSG_I(ME_TX_CREDITS_UPDATE_IND)] = rwnx_rx_me_tx_credits_update_ind, }; static msg_cb_fct sm_hdlrs[MSG_I(SM_MAX)] = { [MSG_I(SM_CONNECT_IND)] = rwnx_rx_sm_connect_ind, [MSG_I(SM_DISCONNECT_IND)] = rwnx_rx_sm_disconnect_ind, [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] = rwnx_rx_sm_external_auth_required_ind, }; #if 1 static msg_cb_fct apm_hdlrs[MSG_I(APM_MAX)] = { }; static msg_cb_fct mesh_hdlrs[MSG_I(MESH_MAX)] = { [MSG_I(MESH_PATH_CREATE_CFM)] = rwnx_rx_mesh_path_create_cfm, [MSG_I(MESH_PEER_UPDATE_IND)] = rwnx_rx_mesh_peer_update_ind, [MSG_I(MESH_PATH_UPDATE_IND)] = rwnx_rx_mesh_path_update_ind, [MSG_I(MESH_PROXY_UPDATE_IND)] = rwnx_rx_mesh_proxy_update_ind, }; #endif static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = { [MSG_I(DBG_ERROR_IND)] = rwnx_rx_dbg_error_ind, }; #if 0 static msg_cb_fct tdls_hdlrs[MSG_I(TDLS_MAX)] = { [MSG_I(TDLS_CHAN_SWITCH_CFM)] = rwnx_rx_tdls_chan_switch_cfm, [MSG_I(TDLS_CHAN_SWITCH_IND)] = rwnx_rx_tdls_chan_switch_ind, [MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = rwnx_rx_tdls_chan_switch_base_ind, [MSG_I(TDLS_PEER_PS_IND)] = rwnx_rx_tdls_peer_ps_ind, }; #endif static msg_cb_fct *msg_hdlrs[] = { [TASK_MM] = mm_hdlrs, [TASK_DBG] = dbg_hdlrs, //[TASK_TDLS] = tdls_hdlrs, [TASK_SCANU] = scan_hdlrs, [TASK_ME] = me_hdlrs, [TASK_SM] = sm_hdlrs, [TASK_APM] = apm_hdlrs, //[TASK_MESH] = mesh_hdlrs, }; /** * */ void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct e2a_msg *msg) { // RWNX_DBG(RWNX_FN_ENTRY_STR); //aic_dbg("T %d, I %d\r\n", MSG_T(msg->id), MSG_I(msg->id)); rwnx_hw->cmd_mgr.msgind(&rwnx_hw->cmd_mgr, msg, msg_hdlrs[MSG_T(msg->id)][MSG_I(msg->id)]); }