Path: blob/master/ALFA-W1F1/RTL8814AU/core/mesh/rtw_mesh.c
1307 views
/******************************************************************************1*2* Copyright(c) 2007 - 2017 Realtek Corporation.3*4* This program is free software; you can redistribute it and/or modify it5* under the terms of version 2 of the GNU General Public License as6* published by the Free Software Foundation.7*8* This program is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for11* more details.12*13*****************************************************************************/14#define _RTW_MESH_C_1516#ifdef CONFIG_RTW_MESH17#include <drv_types.h>1819const char *_rtw_mesh_plink_str[] = {20"UNKNOWN",21"LISTEN",22"OPN_SNT",23"OPN_RCVD",24"CNF_RCVD",25"ESTAB",26"HOLDING",27"BLOCKED",28};2930const char *_rtw_mesh_ps_str[] = {31"UNKNOWN",32"ACTIVE",33"LSLEEP",34"DSLEEP",35};3637const char *_action_self_protected_str[] = {38"ACT_SELF_PROTECTED_RSVD",39"MESH_OPEN",40"MESH_CONF",41"MESH_CLOSE",42"MESH_GK_INFORM",43"MESH_GK_ACK",44};4546inline u8 *rtw_set_ie_mesh_id(u8 *buf, u32 *buf_len, const char *mesh_id, u8 id_len)47{48return rtw_set_ie(buf, WLAN_EID_MESH_ID, id_len, mesh_id, buf_len);49}5051inline u8 *rtw_set_ie_mesh_config(u8 *buf, u32 *buf_len52, u8 path_sel_proto, u8 path_sel_metric, u8 congest_ctl_mode, u8 sync_method, u8 auth_proto53, u8 num_of_peerings, bool cto_mgate, bool cto_as54, bool accept_peerings, bool mcca_sup, bool mcca_en, bool forwarding55, bool mbca_en, bool tbtt_adj, bool ps_level)56{5758u8 conf[7] = {0};5960SET_MESH_CONF_ELE_PATH_SEL_PROTO_ID(conf, path_sel_proto);61SET_MESH_CONF_ELE_PATH_SEL_METRIC_ID(conf, path_sel_metric);62SET_MESH_CONF_ELE_CONGEST_CTRL_MODE_ID(conf, congest_ctl_mode);63SET_MESH_CONF_ELE_SYNC_METHOD_ID(conf, sync_method);64SET_MESH_CONF_ELE_AUTH_PROTO_ID(conf, auth_proto);6566SET_MESH_CONF_ELE_CTO_MGATE(conf, cto_mgate);67SET_MESH_CONF_ELE_NUM_OF_PEERINGS(conf, num_of_peerings);68SET_MESH_CONF_ELE_CTO_AS(conf, cto_as);6970SET_MESH_CONF_ELE_ACCEPT_PEERINGS(conf, accept_peerings);71SET_MESH_CONF_ELE_MCCA_SUP(conf, mcca_sup);72SET_MESH_CONF_ELE_MCCA_EN(conf, mcca_en);73SET_MESH_CONF_ELE_FORWARDING(conf, forwarding);74SET_MESH_CONF_ELE_MBCA_EN(conf, mbca_en);75SET_MESH_CONF_ELE_TBTT_ADJ(conf, tbtt_adj);76SET_MESH_CONF_ELE_PS_LEVEL(conf, ps_level);7778return rtw_set_ie(buf, WLAN_EID_MESH_CONFIG, 7, conf, buf_len);79}8081inline u8 *rtw_set_ie_mpm(u8 *buf, u32 *buf_len82, u8 proto_id, u16 llid, u16 *plid, u16 *reason, u8 *chosen_pmk)83{84u8 data[24] = {0};85u8 *pos = data;8687RTW_PUT_LE16(pos, proto_id);88pos += 2;8990RTW_PUT_LE16(pos, llid);91pos += 2;9293if (plid) {94RTW_PUT_LE16(pos, *plid);95pos += 2;96}9798if (reason) {99RTW_PUT_LE16(pos, *reason);100pos += 2;101}102103if (chosen_pmk) {104_rtw_memcpy(pos, chosen_pmk, 16);105pos += 16;106}107108return rtw_set_ie(buf, WLAN_EID_MPM, pos - data, data, buf_len);109}110111bool rtw_bss_is_forwarding(WLAN_BSSID_EX *bss)112{113u8 *ie;114int ie_len;115bool ret = 0;116117ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,118BSS_EX_TLV_IES_LEN(bss));119if (!ie || ie_len != 7)120goto exit;121122ret = GET_MESH_CONF_ELE_FORWARDING(ie + 2);123124exit:125return ret;126}127128bool rtw_bss_is_cto_mgate(WLAN_BSSID_EX *bss)129{130u8 *ie;131int ie_len;132bool ret = 0;133134ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,135BSS_EX_TLV_IES_LEN(bss));136if (!ie || ie_len != 7)137goto exit;138139ret = GET_MESH_CONF_ELE_CTO_MGATE(ie + 2);140141exit:142return ret;143}144145int rtw_bss_is_same_mbss(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b)146{147int ret = 0;148u8 *a_mconf_ie, *b_mconf_ie;149sint a_mconf_ie_len, b_mconf_ie_len;150151if (a->InfrastructureMode != Ndis802_11_mesh)152goto exit;153a_mconf_ie = rtw_get_ie(BSS_EX_TLV_IES(a), WLAN_EID_MESH_CONFIG, &a_mconf_ie_len, BSS_EX_TLV_IES_LEN(a));154if (!a_mconf_ie || a_mconf_ie_len != 7)155goto exit;156if (b->InfrastructureMode != Ndis802_11_mesh)157goto exit;158b_mconf_ie = rtw_get_ie(BSS_EX_TLV_IES(b), WLAN_EID_MESH_CONFIG, &b_mconf_ie_len, BSS_EX_TLV_IES_LEN(b));159if (!b_mconf_ie || b_mconf_ie_len != 7)160goto exit;161162if (a->mesh_id.SsidLength != b->mesh_id.SsidLength163|| _rtw_memcmp(a->mesh_id.Ssid, b->mesh_id.Ssid, a->mesh_id.SsidLength) == _FALSE)164goto exit;165166if (_rtw_memcmp(a_mconf_ie + 2, b_mconf_ie + 2, 5) == _FALSE)167goto exit;168169ret = 1;170171exit:172return ret;173}174175int rtw_bss_is_candidate_mesh_peer(WLAN_BSSID_EX *self, WLAN_BSSID_EX *target, u8 ch, u8 add_peer)176{177int ret = 0;178u8 *mconf_ie;179sint mconf_ie_len;180int i, j;181182if (!rtw_bss_is_same_mbss(self, target))183goto exit;184185if (ch && self->Configuration.DSConfig != target->Configuration.DSConfig)186goto exit;187188if (add_peer) {189/* Accept additional mesh peerings */190mconf_ie = rtw_get_ie(BSS_EX_TLV_IES(target), WLAN_EID_MESH_CONFIG, &mconf_ie_len, BSS_EX_TLV_IES_LEN(target));191if (!mconf_ie || mconf_ie_len != 7)192goto exit;193if (GET_MESH_CONF_ELE_ACCEPT_PEERINGS(mconf_ie + 2) == 0)194goto exit;195}196197/* BSSBasicRateSet */198for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {199if (target->SupportedRates[i] == 0)200break;201if (target->SupportedRates[i] & 0x80) {202u8 match = 0;203204if (!ch) {205/* off-channel, check target with our hardcode capability */206if (target->Configuration.DSConfig > 14)207match = rtw_is_basic_rate_ofdm(target->SupportedRates[i]);208else209match = rtw_is_basic_rate_mix(target->SupportedRates[i]);210} else {211for (j = 0; j < NDIS_802_11_LENGTH_RATES_EX; j++) {212if (self->SupportedRates[j] == 0)213break;214if (self->SupportedRates[j] == target->SupportedRates[i]) {215match = 1;216break;217}218}219}220if (!match)221goto exit;222}223}224225/* BSSBasicMCSSet */226227/* 802.1X connected to AS ? */228229ret = 1;230231exit:232return ret;233}234235void rtw_mesh_bss_peering_status(WLAN_BSSID_EX *bss, u8 *nop, u8 *accept)236{237u8 *ie;238int ie_len;239240if (nop)241*nop = 0;242if (accept)243*accept = 0;244245ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,246BSS_EX_TLV_IES_LEN(bss));247if (!ie || ie_len != 7)248goto exit;249250if (nop)251*nop = GET_MESH_CONF_ELE_NUM_OF_PEERINGS(ie + 2);252if (accept)253*accept = GET_MESH_CONF_ELE_ACCEPT_PEERINGS(ie + 2);254255exit:256return;257}258259#if CONFIG_RTW_MESH_ACNODE_PREVENT260void rtw_mesh_update_scanned_acnode_status(_adapter *adapter, struct wlan_network *scanned)261{262bool acnode;263u8 nop, accept;264265rtw_mesh_bss_peering_status(&scanned->network, &nop, &accept);266267acnode = !nop && accept;268269if (acnode && scanned->acnode_stime == 0) {270scanned->acnode_stime = rtw_get_current_time();271if (scanned->acnode_stime == 0)272scanned->acnode_stime++;273} else if (!acnode) {274scanned->acnode_stime = 0;275scanned->acnode_notify_etime = 0;276}277}278279bool rtw_mesh_scanned_is_acnode_confirmed(_adapter *adapter, struct wlan_network *scanned)280{281return scanned->acnode_stime282&& rtw_get_passing_time_ms(scanned->acnode_stime)283> adapter->mesh_cfg.peer_sel_policy.acnode_conf_timeout_ms;284}285286static bool rtw_mesh_scanned_is_acnode_allow_notify(_adapter *adapter, struct wlan_network *scanned)287{288return scanned->acnode_notify_etime289&& rtw_time_after(scanned->acnode_notify_etime, rtw_get_current_time());290}291292bool rtw_mesh_acnode_prevent_allow_sacrifice(_adapter *adapter)293{294struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;295struct sta_priv *stapriv = &adapter->stapriv;296bool allow = 0;297298if (!mcfg->peer_sel_policy.acnode_prevent299|| mcfg->max_peer_links <= 1300|| stapriv->asoc_list_cnt < mcfg->max_peer_links)301goto exit;302303#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST304if (rtw_mesh_cto_mgate_required(adapter))305goto exit;306#endif307308allow = 1;309310exit:311return allow;312}313314static bool rtw_mesh_acnode_candidate_exist(_adapter *adapter)315{316struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;317struct sta_priv *stapriv = &adapter->stapriv;318struct mlme_priv *mlme = &adapter->mlmepriv;319_queue *queue = &(mlme->scanned_queue);320_list *head, *list;321_irqL irqL;322struct wlan_network *scanned = NULL;323struct sta_info *sta = NULL;324bool need = 0;325326_enter_critical_bh(&(mlme->scanned_queue.lock), &irqL);327328head = get_list_head(queue);329list = get_next(head);330while (!rtw_end_of_queue_search(head, list)) {331scanned = LIST_CONTAINOR(list, struct wlan_network, list);332list = get_next(list);333334if (rtw_get_passing_time_ms(scanned->last_scanned) < mcfg->peer_sel_policy.scanr_exp_ms335&& rtw_mesh_scanned_is_acnode_confirmed(adapter, scanned)336&& (!mcfg->rssi_threshold || mcfg->rssi_threshold <= scanned->network.Rssi)337#if CONFIG_RTW_MACADDR_ACL338&& rtw_access_ctrl(adapter, scanned->network.MacAddress) == _TRUE339#endif340&& rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 1, 1)341#if CONFIG_RTW_MESH_PEER_BLACKLIST342&& !rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)343#endif344#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST345&& rtw_mesh_cto_mgate_network_filter(adapter, scanned)346#endif347) {348need = 1;349break;350}351}352353_exit_critical_bh(&(mlme->scanned_queue.lock), &irqL);354355return need;356}357358static int rtw_mesh_acnode_prevent_sacrifice_chk(_adapter *adapter, struct sta_info **sac, struct sta_info *com)359{360struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;361int updated = 0;362363/*364* TODO: compare next_hop reference cnt of forwarding info365* don't sacrifice working next_hop or choose sta with least cnt366*/367368if (*sac == NULL) {369updated = 1;370goto exit;371}372373#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST374if (mcfg->peer_sel_policy.cto_mgate_require375&& !mcfg->dot11MeshGateAnnouncementProtocol376) {377if (IS_CTO_MGATE_CONF_TIMEOUT(com->plink)) {378if (!IS_CTO_MGATE_CONF_TIMEOUT((*sac)->plink)) {379/* blacklist > not blacklist */380updated = 1;381goto exit;382}383} else if (!IS_CTO_MGATE_CONF_DISABLED(com->plink)) {384if (IS_CTO_MGATE_CONF_DISABLED((*sac)->plink)) {385/* confirming > disabled */386updated = 1;387goto exit;388}389}390}391#endif392393exit:394if (updated)395*sac = com;396397return updated;398}399400struct sta_info *_rtw_mesh_acnode_prevent_pick_sacrifice(_adapter *adapter)401{402struct sta_priv *stapriv = &adapter->stapriv;403_list *head, *list;404struct sta_info *sta, *sacrifice = NULL;405u8 nop;406407head = &stapriv->asoc_list;408list = get_next(head);409while (rtw_end_of_queue_search(head, list) == _FALSE) {410sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);411list = get_next(list);412413if (!sta->plink || !sta->plink->scanned) {414rtw_warn_on(1);415continue;416}417418rtw_mesh_bss_peering_status(&sta->plink->scanned->network, &nop, NULL);419if (nop < 2)420continue;421422rtw_mesh_acnode_prevent_sacrifice_chk(adapter, &sacrifice, sta);423}424425return sacrifice;426}427428struct sta_info *rtw_mesh_acnode_prevent_pick_sacrifice(_adapter *adapter)429{430struct sta_priv *stapriv = &adapter->stapriv;431struct sta_info *sacrifice = NULL;432433enter_critical_bh(&stapriv->asoc_list_lock);434435sacrifice = _rtw_mesh_acnode_prevent_pick_sacrifice(adapter);436437exit_critical_bh(&stapriv->asoc_list_lock);438439return sacrifice;440}441442static void rtw_mesh_acnode_rsvd_chk(_adapter *adapter)443{444struct rtw_mesh_info *minfo = &adapter->mesh_info;445struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;446u8 acnode_rsvd = 0;447448if (rtw_mesh_acnode_prevent_allow_sacrifice(adapter)449&& rtw_mesh_acnode_prevent_pick_sacrifice(adapter)450&& rtw_mesh_acnode_candidate_exist(adapter))451acnode_rsvd = 1;452453if (plink_ctl->acnode_rsvd != acnode_rsvd) {454plink_ctl->acnode_rsvd = acnode_rsvd;455RTW_INFO(FUNC_ADPT_FMT" acnode_rsvd = %d\n", FUNC_ADPT_ARG(adapter), plink_ctl->acnode_rsvd);456update_beacon(adapter, WLAN_EID_MESH_CONFIG, NULL, 1, 0);457}458}459460static void rtw_mesh_acnode_set_notify_etime(_adapter *adapter, u8 *rframe_whdr)461{462if (adapter->mesh_info.plink_ctl.acnode_rsvd) {463struct wlan_network *scanned = rtw_find_network(&adapter->mlmepriv.scanned_queue, get_addr2_ptr(rframe_whdr));464465if (rtw_mesh_scanned_is_acnode_confirmed(adapter, scanned)) {466scanned->acnode_notify_etime = rtw_get_current_time()467+ rtw_ms_to_systime(adapter->mesh_cfg.peer_sel_policy.acnode_notify_timeout_ms);468if (scanned->acnode_notify_etime == 0)469scanned->acnode_notify_etime++;470}471}472}473474void dump_mesh_acnode_prevent_settings(void *sel, _adapter *adapter)475{476struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;477478RTW_PRINT_SEL(sel, "%-6s %-12s %-14s\n"479, "enable", "conf_timeout", "nofity_timeout");480RTW_PRINT_SEL(sel, "%6u %12u %14u\n"481, peer_sel_policy->acnode_prevent482, peer_sel_policy->acnode_conf_timeout_ms483, peer_sel_policy->acnode_notify_timeout_ms);484}485#endif /* CONFIG_RTW_MESH_ACNODE_PREVENT */486487#if CONFIG_RTW_MESH_PEER_BLACKLIST488int rtw_mesh_peer_blacklist_add(_adapter *adapter, const u8 *addr)489{490struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;491struct rtw_mesh_info *minfo = &adapter->mesh_info;492struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;493494return rtw_blacklist_add(&plink_ctl->peer_blacklist, addr495, mcfg->peer_sel_policy.peer_blacklist_timeout_ms);496}497498int rtw_mesh_peer_blacklist_del(_adapter *adapter, const u8 *addr)499{500struct rtw_mesh_info *minfo = &adapter->mesh_info;501struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;502503return rtw_blacklist_del(&plink_ctl->peer_blacklist, addr);504}505506int rtw_mesh_peer_blacklist_search(_adapter *adapter, const u8 *addr)507{508struct rtw_mesh_info *minfo = &adapter->mesh_info;509struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;510511return rtw_blacklist_search(&plink_ctl->peer_blacklist, addr);512}513514void rtw_mesh_peer_blacklist_flush(_adapter *adapter)515{516struct rtw_mesh_info *minfo = &adapter->mesh_info;517struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;518519rtw_blacklist_flush(&plink_ctl->peer_blacklist);520}521522void dump_mesh_peer_blacklist(void *sel, _adapter *adapter)523{524struct rtw_mesh_info *minfo = &adapter->mesh_info;525struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;526527dump_blacklist(sel, &plink_ctl->peer_blacklist, "blacklist");528}529530void dump_mesh_peer_blacklist_settings(void *sel, _adapter *adapter)531{532struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;533534RTW_PRINT_SEL(sel, "%-12s %-17s\n"535, "conf_timeout", "blacklist_timeout");536RTW_PRINT_SEL(sel, "%12u %17u\n"537, peer_sel_policy->peer_conf_timeout_ms538, peer_sel_policy->peer_blacklist_timeout_ms);539}540#endif /* CONFIG_RTW_MESH_PEER_BLACKLIST */541542#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST543u8 rtw_mesh_cto_mgate_required(_adapter *adapter)544{545struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;546struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;547548return mcfg->peer_sel_policy.cto_mgate_require549&& !rtw_bss_is_cto_mgate(&(mlmeext->mlmext_info.network));550}551552u8 rtw_mesh_cto_mgate_network_filter(_adapter *adapter, struct wlan_network *scanned)553{554struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;555struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;556557return !rtw_mesh_cto_mgate_required(adapter)558|| (rtw_bss_is_cto_mgate(&scanned->network)559&& !rtw_mesh_cto_mgate_blacklist_search(adapter, scanned->network.MacAddress));560}561562int rtw_mesh_cto_mgate_blacklist_add(_adapter *adapter, const u8 *addr)563{564struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;565struct rtw_mesh_info *minfo = &adapter->mesh_info;566struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;567568return rtw_blacklist_add(&plink_ctl->cto_mgate_blacklist, addr569, mcfg->peer_sel_policy.cto_mgate_blacklist_timeout_ms);570}571572int rtw_mesh_cto_mgate_blacklist_del(_adapter *adapter, const u8 *addr)573{574struct rtw_mesh_info *minfo = &adapter->mesh_info;575struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;576577return rtw_blacklist_del(&plink_ctl->cto_mgate_blacklist, addr);578}579580int rtw_mesh_cto_mgate_blacklist_search(_adapter *adapter, const u8 *addr)581{582struct rtw_mesh_info *minfo = &adapter->mesh_info;583struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;584585return rtw_blacklist_search(&plink_ctl->cto_mgate_blacklist, addr);586}587588void rtw_mesh_cto_mgate_blacklist_flush(_adapter *adapter)589{590struct rtw_mesh_info *minfo = &adapter->mesh_info;591struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;592593rtw_blacklist_flush(&plink_ctl->cto_mgate_blacklist);594}595596void dump_mesh_cto_mgate_blacklist(void *sel, _adapter *adapter)597{598struct rtw_mesh_info *minfo = &adapter->mesh_info;599struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;600601dump_blacklist(sel, &plink_ctl->cto_mgate_blacklist, "blacklist");602}603604void dump_mesh_cto_mgate_blacklist_settings(void *sel, _adapter *adapter)605{606struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;607608RTW_PRINT_SEL(sel, "%-12s %-17s\n"609, "conf_timeout", "blacklist_timeout");610RTW_PRINT_SEL(sel, "%12u %17u\n"611, peer_sel_policy->cto_mgate_conf_timeout_ms612, peer_sel_policy->cto_mgate_blacklist_timeout_ms);613}614615static void rtw_mesh_cto_mgate_blacklist_chk(_adapter *adapter)616{617struct rtw_mesh_info *minfo = &adapter->mesh_info;618struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;619_queue *blist = &plink_ctl->cto_mgate_blacklist;620_list *list, *head;621struct blacklist_ent *ent = NULL;622struct wlan_network *scanned = NULL;623624enter_critical_bh(&blist->lock);625head = &blist->queue;626list = get_next(head);627while (rtw_end_of_queue_search(head, list) == _FALSE) {628ent = LIST_CONTAINOR(list, struct blacklist_ent, list);629list = get_next(list);630631if (rtw_time_after(rtw_get_current_time(), ent->exp_time)) {632rtw_list_delete(&ent->list);633rtw_mfree(ent, sizeof(struct blacklist_ent));634continue;635}636637scanned = rtw_find_network(&adapter->mlmepriv.scanned_queue, ent->addr);638if (!scanned)639continue;640641if (rtw_bss_is_forwarding(&scanned->network)) {642rtw_list_delete(&ent->list);643rtw_mfree(ent, sizeof(struct blacklist_ent));644}645}646647exit_critical_bh(&blist->lock);648}649#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */650651void rtw_chk_candidate_peer_notify(_adapter *adapter, struct wlan_network *scanned)652{653struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);654struct mlme_priv *mlme = &adapter->mlmepriv;655struct rtw_mesh_info *minfo = &adapter->mesh_info;656struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;657struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;658bool acnode = 0;659660if (IS_CH_WAITING(rfctl) && !IS_UNDER_CAC(rfctl))661goto exit;662663if (plink_ctl->num >= RTW_MESH_MAX_PEER_CANDIDATES)664goto exit;665666#if CONFIG_RTW_MESH_ACNODE_PREVENT667if (plink_ctl->acnode_rsvd) {668acnode = rtw_mesh_scanned_is_acnode_confirmed(adapter, scanned);669if (acnode && !rtw_mesh_scanned_is_acnode_allow_notify(adapter, scanned))670goto exit;671}672#endif673674/* wpa_supplicant's auto peer will initiate peering when candidate peer is reported without max_peer_links consideration */675if (plink_ctl->num >= mcfg->max_peer_links + acnode ? 1 : 0)676goto exit;677678if (rtw_get_passing_time_ms(scanned->last_scanned) >= mcfg->peer_sel_policy.scanr_exp_ms679|| (mcfg->rssi_threshold && mcfg->rssi_threshold > scanned->network.Rssi)680|| !rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 1, 1)681#if CONFIG_RTW_MACADDR_ACL682|| rtw_access_ctrl(adapter, scanned->network.MacAddress) == _FALSE683#endif684|| rtw_mesh_plink_get(adapter, scanned->network.MacAddress)685#if CONFIG_RTW_MESH_PEER_BLACKLIST686|| rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)687#endif688#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST689|| !rtw_mesh_cto_mgate_network_filter(adapter, scanned)690#endif691)692goto exit;693694#if CONFIG_RTW_MESH_ACNODE_PREVENT695if (acnode) {696scanned->acnode_notify_etime = 0;697RTW_INFO(FUNC_ADPT_FMT" acnode "MAC_FMT"\n"698, FUNC_ADPT_ARG(adapter), MAC_ARG(scanned->network.MacAddress));699}700#endif701702#ifdef CONFIG_IOCTL_CFG80211703rtw_cfg80211_notify_new_peer_candidate(adapter->rtw_wdev704, scanned->network.MacAddress705, BSS_EX_TLV_IES(&scanned->network)706, BSS_EX_TLV_IES_LEN(&scanned->network)707, GFP_ATOMIC708);709#endif710711exit:712return;713}714715void rtw_mesh_peer_status_chk(_adapter *adapter)716{717struct mlme_priv *mlme = &adapter->mlmepriv;718struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;719struct rtw_mesh_info *minfo = &adapter->mesh_info;720struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;721struct mesh_plink_ent *plink;722_list *head, *list;723struct sta_info *sta = NULL;724struct sta_priv *stapriv = &adapter->stapriv;725int stainfo_offset;726#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST727u8 cto_mgate, forwarding, mgate;728#endif729u8 flush;730s8 flush_list[NUM_STA];731u8 flush_num = 0;732int i;733734#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST735if (rtw_mesh_cto_mgate_required(adapter)) {736/* active scan on operating channel */737issue_probereq_ex(adapter, &adapter->mlmepriv.cur_network.network.mesh_id, NULL, 0, 0, 0, 0);738}739#endif740741enter_critical_bh(&(plink_ctl->lock));742743/* check established peers */744enter_critical_bh(&stapriv->asoc_list_lock);745746head = &stapriv->asoc_list;747list = get_next(head);748while (rtw_end_of_queue_search(head, list) == _FALSE) {749sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);750list = get_next(list);751752if (!sta->plink || !sta->plink->scanned) {753rtw_warn_on(1);754continue;755}756plink = sta->plink;757flush = 0;758759/* remove unsuitable peer */760if (!rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &plink->scanned->network, 1, 0)761#if CONFIG_RTW_MACADDR_ACL762|| rtw_access_ctrl(adapter, plink->addr) == _FALSE763#endif764) {765flush = 1;766goto flush_add;767}768769#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST770cto_mgate = rtw_bss_is_cto_mgate(&(plink->scanned->network));771forwarding = rtw_bss_is_forwarding(&(plink->scanned->network));772mgate = rtw_mesh_gate_search(minfo->mesh_paths, sta->cmn.mac_addr);773774/* CTO_MGATE required, remove peer without CTO_MGATE */775if (rtw_mesh_cto_mgate_required(adapter) && !cto_mgate) {776flush = 1;777goto flush_add;778}779780/* cto_mgate_conf status update */781if (IS_CTO_MGATE_CONF_DISABLED(plink)) {782if (cto_mgate && !forwarding && !mgate)783SET_CTO_MGATE_CONF_END_TIME(plink, mcfg->peer_sel_policy.cto_mgate_conf_timeout_ms);784else785rtw_mesh_cto_mgate_blacklist_del(adapter, sta->cmn.mac_addr);786} else {787/* cto_mgate_conf ongoing */788if (cto_mgate && !forwarding && !mgate) {789if (IS_CTO_MGATE_CONF_TIMEOUT(plink)) {790rtw_mesh_cto_mgate_blacklist_add(adapter, sta->cmn.mac_addr);791792/* CTO_MGATE required, remove peering can't achieve CTO_MGATE */793if (rtw_mesh_cto_mgate_required(adapter)) {794flush = 1;795goto flush_add;796}797}798} else {799SET_CTO_MGATE_CONF_DISABLED(plink);800rtw_mesh_cto_mgate_blacklist_del(adapter, sta->cmn.mac_addr);801}802}803#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */804805flush_add:806if (flush) {807rtw_list_delete(&sta->asoc_list);808stapriv->asoc_list_cnt--;809STA_SET_MESH_PLINK(sta, NULL);810811stainfo_offset = rtw_stainfo_offset(stapriv, sta);812if (stainfo_offset_valid(stainfo_offset))813flush_list[flush_num++] = stainfo_offset;814else815rtw_warn_on(1);816}817}818819exit_critical_bh(&stapriv->asoc_list_lock);820821/* check non-established peers */822for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {823plink = &plink_ctl->ent[i];824if (plink->valid != _TRUE || plink->plink_state == RTW_MESH_PLINK_ESTAB)825continue;826827/* remove unsuitable peer */828if (!rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &plink->scanned->network, 1, 1)829#if CONFIG_RTW_MACADDR_ACL830|| rtw_access_ctrl(adapter, plink->addr) == _FALSE831#endif832) {833_rtw_mesh_expire_peer_ent(adapter, plink);834continue;835}836837#if CONFIG_RTW_MESH_PEER_BLACKLIST838/* peer confirm check timeout, add to black list */839if (IS_PEER_CONF_TIMEOUT(plink)) {840rtw_mesh_peer_blacklist_add(adapter, plink->addr);841_rtw_mesh_expire_peer_ent(adapter, plink);842}843#endif844}845846exit_critical_bh(&(plink_ctl->lock));847848if (flush_num) {849u8 sta_addr[ETH_ALEN];850u8 updated = _FALSE;851852for (i = 0; i < flush_num; i++) {853sta = rtw_get_stainfo_by_offset(stapriv, flush_list[i]);854_rtw_memcpy(sta_addr, sta->cmn.mac_addr, ETH_ALEN);855856updated |= ap_free_sta(adapter, sta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, _FALSE);857rtw_mesh_expire_peer(adapter, sta_addr);858}859860associated_clients_update(adapter, updated, STA_INFO_UPDATE_ALL);861}862863#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST864/* loop cto_mgate_blacklist to remove ent according to scan_r */865rtw_mesh_cto_mgate_blacklist_chk(adapter);866#endif867868#if CONFIG_RTW_MESH_ACNODE_PREVENT869rtw_mesh_acnode_rsvd_chk(adapter);870#endif871872return;873}874875#if CONFIG_RTW_MESH_OFFCH_CAND876static u8 rtw_mesh_offch_cto_mgate_required(_adapter *adapter)877{878#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST879struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;880struct mlme_priv *mlme = &adapter->mlmepriv;881_queue *queue = &(mlme->scanned_queue);882_list *head, *pos;883struct wlan_network *scanned = NULL;884u8 ret = 0;885886if (!rtw_mesh_cto_mgate_required(adapter))887goto exit;888889enter_critical_bh(&(mlme->scanned_queue.lock));890891head = get_list_head(queue);892pos = get_next(head);893while (!rtw_end_of_queue_search(head, pos)) {894scanned = LIST_CONTAINOR(pos, struct wlan_network, list);895896if (rtw_get_passing_time_ms(scanned->last_scanned) < mcfg->peer_sel_policy.scanr_exp_ms897&& (!mcfg->rssi_threshold || mcfg->rssi_threshold <= scanned->network.Rssi)898#if CONFIG_RTW_MACADDR_ACL899&& rtw_access_ctrl(adapter, scanned->network.MacAddress) == _TRUE900#endif901&& rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 1, 1)902&& rtw_bss_is_cto_mgate(&scanned->network)903#if CONFIG_RTW_MESH_PEER_BLACKLIST904&& !rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)905#endif906&& !rtw_mesh_cto_mgate_blacklist_search(adapter, scanned->network.MacAddress)907)908break;909910pos = get_next(pos);911}912913if (rtw_end_of_queue_search(head, pos))914ret = 1;915916exit_critical_bh(&(mlme->scanned_queue.lock));917918exit:919return ret;920#else921return 0;922#endif /* CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST */923}924925u8 rtw_mesh_offch_candidate_accepted(_adapter *adapter)926{927struct rtw_mesh_info *minfo = &adapter->mesh_info;928struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;929u8 ret = 0;930931if (!adapter->mesh_cfg.peer_sel_policy.offch_cand)932goto exit;933934ret = MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter)935&& (!plink_ctl->num || rtw_mesh_offch_cto_mgate_required(adapter))936;937938#ifdef CONFIG_CONCURRENT_MODE939if (ret) {940struct mi_state mstate_no_self;941942rtw_mi_status_no_self(adapter, &mstate_no_self);943if (MSTATE_STA_LD_NUM(&mstate_no_self))944ret = 0;945}946#endif947948exit:949return ret;950}951952/*953* this function is called under off channel candidate is required954* the channel with maximum candidate count is selected955*/956u8 rtw_mesh_select_operating_ch(_adapter *adapter)957{958struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);959struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;960struct mlme_priv *mlme = &adapter->mlmepriv;961_queue *queue = &(mlme->scanned_queue);962_list *head, *pos;963_irqL irqL;964struct wlan_network *scanned = NULL;965int i;966/* statistics for candidate accept peering */967u8 cand_ap_cnt[MAX_CHANNEL_NUM] = {0};968u8 max_cand_ap_ch = 0;969u8 max_cand_ap_cnt = 0;970/* statistics for candidate including not accept peering */971u8 cand_cnt[MAX_CHANNEL_NUM] = {0};972u8 max_cand_ch = 0;973u8 max_cand_cnt = 0;974975_enter_critical_bh(&(mlme->scanned_queue.lock), &irqL);976977head = get_list_head(queue);978pos = get_next(head);979while (!rtw_end_of_queue_search(head, pos)) {980scanned = LIST_CONTAINOR(pos, struct wlan_network, list);981pos = get_next(pos);982983if (rtw_get_passing_time_ms(scanned->last_scanned) < mcfg->peer_sel_policy.scanr_exp_ms984&& (!mcfg->rssi_threshold || mcfg->rssi_threshold <= scanned->network.Rssi)985#if CONFIG_RTW_MACADDR_ACL986&& rtw_access_ctrl(adapter, scanned->network.MacAddress) == _TRUE987#endif988&& rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &scanned->network, 0, 0)989#if CONFIG_RTW_MESH_PEER_BLACKLIST990&& !rtw_mesh_peer_blacklist_search(adapter, scanned->network.MacAddress)991#endif992#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST993&& rtw_mesh_cto_mgate_network_filter(adapter, scanned)994#endif995) {996int ch_set_idx = rtw_chset_search_ch(rfctl->channel_set, scanned->network.Configuration.DSConfig);997998if (ch_set_idx >= 0999&& !CH_IS_NON_OCP(&rfctl->channel_set[ch_set_idx])1000) {1001u8 nop, accept;10021003rtw_mesh_bss_peering_status(&scanned->network, &nop, &accept);1004cand_cnt[ch_set_idx]++;1005if (max_cand_cnt < cand_cnt[ch_set_idx]) {1006max_cand_cnt = cand_cnt[ch_set_idx];1007max_cand_ch = rfctl->channel_set[ch_set_idx].ChannelNum;1008}1009if (accept) {1010cand_ap_cnt[ch_set_idx]++;1011if (max_cand_ap_cnt < cand_ap_cnt[ch_set_idx]) {1012max_cand_ap_cnt = cand_ap_cnt[ch_set_idx];1013max_cand_ap_ch = rfctl->channel_set[ch_set_idx].ChannelNum;1014}1015}1016}1017}1018}10191020_exit_critical_bh(&(mlme->scanned_queue.lock), &irqL);10211022return max_cand_ap_ch ? max_cand_ap_ch : max_cand_ch;1023}10241025void dump_mesh_offch_cand_settings(void *sel, _adapter *adapter)1026{1027struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;10281029RTW_PRINT_SEL(sel, "%-6s %-11s\n"1030, "enable", "find_int_ms");1031RTW_PRINT_SEL(sel, "%6u %11u\n"1032, peer_sel_policy->offch_cand, peer_sel_policy->offch_find_int_ms);1033}1034#endif /* CONFIG_RTW_MESH_OFFCH_CAND */10351036void dump_mesh_peer_sel_policy(void *sel, _adapter *adapter)1037{1038struct mesh_peer_sel_policy *peer_sel_policy = &adapter->mesh_cfg.peer_sel_policy;10391040RTW_PRINT_SEL(sel, "%-12s\n", "scanr_exp_ms");1041RTW_PRINT_SEL(sel, "%12u\n", peer_sel_policy->scanr_exp_ms);1042}10431044void dump_mesh_networks(void *sel, _adapter *adapter)1045{1046#if CONFIG_RTW_MESH_ACNODE_PREVENT1047#define NSTATE_TITLE_FMT_ACN " %-5s"1048#define NSTATE_VALUE_FMT_ACN " %5d"1049#define NSTATE_TITLE_ARG_ACN , "acn"1050#define NSTATE_VALUE_ARG_ACN , (acn_ms < 99999 ? acn_ms : 99999)1051#else1052#define NSTATE_TITLE_FMT_ACN ""1053#define NSTATE_VALUE_FMT_ACN ""1054#define NSTATE_TITLE_ARG_ACN1055#define NSTATE_VALUE_ARG_ACN1056#endif10571058struct mlme_priv *mlme = &(adapter->mlmepriv);1059_queue *queue = &(mlme->scanned_queue);1060struct wlan_network *network;1061_list *list, *head;1062u8 same_mbss;1063u8 candidate;1064struct mesh_plink_ent *plink;1065u8 blocked;1066u8 established;1067s32 age_ms;1068#if CONFIG_RTW_MESH_ACNODE_PREVENT1069s32 acn_ms;1070#endif1071u8 *mesh_conf_ie;1072sint mesh_conf_ie_len;1073struct wlan_network **mesh_networks;1074u8 mesh_network_cnt = 0;1075int i;10761077mesh_networks = rtw_zvmalloc(mlme->max_bss_cnt * sizeof(struct wlan_network *));1078if (!mesh_networks)1079return;10801081enter_critical_bh(&queue->lock);1082head = get_list_head(queue);1083list = get_next(head);10841085while (rtw_end_of_queue_search(head, list) == _FALSE) {1086network = LIST_CONTAINOR(list, struct wlan_network, list);1087list = get_next(list);10881089if (network->network.InfrastructureMode != Ndis802_11_mesh)1090continue;10911092mesh_conf_ie = rtw_get_ie(BSS_EX_TLV_IES(&network->network), WLAN_EID_MESH_CONFIG1093, &mesh_conf_ie_len, BSS_EX_TLV_IES_LEN(&network->network));1094if (!mesh_conf_ie || mesh_conf_ie_len != 7)1095continue;10961097mesh_networks[mesh_network_cnt++] = network;1098}10991100exit_critical_bh(&queue->lock);11011102RTW_PRINT_SEL(sel, " %-17s %-3s %-4s %-5s %-32s %-3s %-3s %-3s"1103NSTATE_TITLE_FMT_ACN1104"\n"1105, "bssid", "ch", "rssi", "age", "mesh_id", "nop", "fwd", "cto"1106NSTATE_TITLE_ARG_ACN1107);11081109for (i = 0; i < mesh_network_cnt; i++) {1110network = mesh_networks[i];11111112if (network->network.InfrastructureMode != Ndis802_11_mesh)1113continue;11141115mesh_conf_ie = rtw_get_ie(BSS_EX_TLV_IES(&network->network), WLAN_EID_MESH_CONFIG1116, &mesh_conf_ie_len, BSS_EX_TLV_IES_LEN(&network->network));1117if (!mesh_conf_ie || mesh_conf_ie_len != 7)1118continue;11191120age_ms = rtw_get_passing_time_ms(network->last_scanned);1121#if CONFIG_RTW_MESH_ACNODE_PREVENT1122if (network->acnode_stime == 0)1123acn_ms = 0;1124else1125acn_ms = rtw_get_passing_time_ms(network->acnode_stime);1126#endif1127same_mbss = 0;1128candidate = 0;1129plink = NULL;1130blocked = 0;1131established = 0;11321133if (MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter)) {1134plink = rtw_mesh_plink_get(adapter, network->network.MacAddress);1135if (plink && plink->plink_state == RTW_MESH_PLINK_ESTAB)1136established = 1;1137else if (plink && plink->plink_state == RTW_MESH_PLINK_BLOCKED)1138blocked = 1;1139else if (plink)1140;1141else if (rtw_bss_is_candidate_mesh_peer(&mlme->cur_network.network, &network->network, 0, 1))1142candidate = 1;1143else if (rtw_bss_is_same_mbss(&mlme->cur_network.network, &network->network))1144same_mbss = 1;1145}11461147RTW_PRINT_SEL(sel, "%c "MAC_FMT" %3d %4ld %5d %-32s %c%2u %3u %c%c "1148NSTATE_VALUE_FMT_ACN1149"\n"1150, established ? 'E' : (blocked ? 'B' : (plink ? 'N' : (candidate ? 'C' : (same_mbss ? 'S' : ' '))))1151, MAC_ARG(network->network.MacAddress)1152, network->network.Configuration.DSConfig1153, network->network.Rssi1154, age_ms < 99999 ? age_ms : 999991155, network->network.mesh_id.Ssid1156, GET_MESH_CONF_ELE_ACCEPT_PEERINGS(mesh_conf_ie + 2) ? '+' : ' '1157, GET_MESH_CONF_ELE_NUM_OF_PEERINGS(mesh_conf_ie + 2)1158, GET_MESH_CONF_ELE_FORWARDING(mesh_conf_ie + 2)1159, GET_MESH_CONF_ELE_CTO_MGATE(mesh_conf_ie + 2) ? 'G' : ' '1160, GET_MESH_CONF_ELE_CTO_AS(mesh_conf_ie + 2) ? 'A' : ' '1161NSTATE_VALUE_ARG_ACN1162);1163}11641165rtw_vmfree(mesh_networks, mlme->max_bss_cnt * sizeof(struct wlan_network *));1166}11671168void rtw_mesh_adjust_chbw(u8 req_ch, u8 *req_bw, u8 *req_offset)1169{1170if (req_ch >= 5 && req_ch <= 9) {1171/* prevent secondary channel offset mismatch */1172if (*req_bw > CHANNEL_WIDTH_20) {1173*req_bw = CHANNEL_WIDTH_20;1174*req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;1175}1176}1177}11781179void rtw_mesh_sae_check_frames(_adapter *adapter, const u8 *buf, u32 len, u8 tx, u16 alg, u16 seq, u16 status)1180{1181#if CONFIG_RTW_MESH_PEER_BLACKLIST1182if (tx && seq == 1)1183rtw_mesh_plink_set_peer_conf_timeout(adapter, GetAddr1Ptr(buf));1184#endif1185}11861187#if CONFIG_RTW_MPM_TX_IES_SYNC_BSS1188#ifdef CONFIG_RTW_MESH_AEK1189static int rtw_mpm_ampe_dec(_adapter *adapter, struct mesh_plink_ent *plink1190, u8 *fhead, size_t flen, u8* fbody, u8 *mic_ie, u8 *ampe_buf)1191{1192int ret = _FAIL, verify_ret;1193const u8 *aad[] = {adapter_mac_addr(adapter), plink->addr, fbody};1194const size_t aad_len[] = {ETH_ALEN, ETH_ALEN, mic_ie - fbody};1195u8 *iv_crypt;1196size_t iv_crypt_len = flen - (mic_ie + 2 - fhead);11971198iv_crypt = rtw_malloc(iv_crypt_len);1199if (!iv_crypt)1200goto exit;12011202_rtw_memcpy(iv_crypt, mic_ie + 2, iv_crypt_len);12031204verify_ret = aes_siv_decrypt(plink->aek, iv_crypt, iv_crypt_len1205, 3, aad, aad_len, ampe_buf);12061207rtw_mfree(iv_crypt, iv_crypt_len);12081209if (verify_ret) {1210RTW_WARN("verify error, aek_valid=%u\n", plink->aek_valid);1211goto exit;1212} else if (*ampe_buf != WLAN_EID_AMPE) {1213RTW_WARN("plaintext is not AMPE IE\n");1214goto exit;1215} else if (AES_BLOCK_SIZE + 2 + *(ampe_buf + 1) > iv_crypt_len) {1216RTW_WARN("plaintext AMPE IE length is not valid\n");1217goto exit;1218}12191220ret = _SUCCESS;12211222exit:1223return ret;1224}12251226static int rtw_mpm_ampe_enc(_adapter *adapter, struct mesh_plink_ent *plink1227, u8* fbody, u8 *mic_ie, u8 *ampe_buf, bool inverse)1228{1229int ret = _FAIL, protect_ret;1230const u8 *aad[3];1231const size_t aad_len[3] = {ETH_ALEN, ETH_ALEN, mic_ie - fbody};1232u8 *ampe_ie;1233size_t ampe_ie_len = *(ampe_buf + 1) + 2; /* including id & len */12341235if (inverse) {1236aad[0] = plink->addr;1237aad[1] = adapter_mac_addr(adapter);1238} else {1239aad[0] = adapter_mac_addr(adapter);1240aad[1] = plink->addr;1241}1242aad[2] = fbody;12431244ampe_ie = rtw_malloc(ampe_ie_len);1245if (!ampe_ie)1246goto exit;12471248_rtw_memcpy(ampe_ie, ampe_buf, ampe_ie_len);12491250protect_ret = aes_siv_encrypt(plink->aek, ampe_ie, ampe_ie_len1251, 3, aad, aad_len, mic_ie + 2);12521253rtw_mfree(ampe_ie, ampe_ie_len);12541255if (protect_ret) {1256RTW_WARN("protect error, aek_valid=%u\n", plink->aek_valid);1257goto exit;1258}12591260ret = _SUCCESS;12611262exit:1263return ret;1264}1265#endif /* CONFIG_RTW_MESH_AEK */12661267static int rtw_mpm_tx_ies_sync_bss(_adapter *adapter, struct mesh_plink_ent *plink1268, u8 *fhead, size_t flen, u8* fbody, u8 tlv_ies_offset, u8 *mpm_ie, u8 *mic_ie1269, u8 **nbuf, size_t *nlen)1270{1271int ret = _FAIL;1272struct mlme_priv *mlme = &(adapter->mlmepriv);1273struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;1274struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info);1275WLAN_BSSID_EX *network = &(mlmeinfo->network);1276uint left;1277u8 *pos;12781279uint mpm_ielen = *(mpm_ie + 1);1280u8 *fpos;1281u8 *new_buf = NULL;1282size_t new_len = 0;12831284u8 *new_fhead;1285size_t new_flen;1286u8 *new_fbody;1287u8 *new_mic_ie;12881289#ifdef CONFIG_RTW_MESH_AEK1290u8 *ampe_buf = NULL;1291size_t ampe_buf_len = 0;12921293/* decode */1294if (mic_ie) {1295ampe_buf_len = flen - (mic_ie + 2 + AES_BLOCK_SIZE - fhead);1296ampe_buf = rtw_malloc(ampe_buf_len);1297if (!ampe_buf)1298goto exit;12991300if (rtw_mpm_ampe_dec(adapter, plink, fhead, flen, fbody, mic_ie, ampe_buf) != _SUCCESS)1301goto exit;13021303if (*(ampe_buf + 1) >= 68) {1304_rtw_memcpy(plink->sel_pcs, ampe_buf + 2, 4);1305_rtw_memcpy(plink->l_nonce, ampe_buf + 6, 32);1306_rtw_memcpy(plink->p_nonce, ampe_buf + 38, 32);1307}1308}1309#endif13101311/* count for new frame length */1312new_len = sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset;1313left = BSS_EX_TLV_IES_LEN(network);1314pos = BSS_EX_TLV_IES(network);1315while (left >= 2) {1316u8 id, elen;13171318id = *pos++;1319elen = *pos++;1320left -= 2;13211322if (elen > left)1323break;13241325switch (id) {1326case WLAN_EID_SSID:1327case WLAN_EID_DS_PARAMS:1328case WLAN_EID_TIM:1329break;1330default:1331new_len += 2 + elen;1332}13331334left -= elen;1335pos += elen;1336}1337new_len += mpm_ielen + 2;1338if (mic_ie)1339new_len += AES_BLOCK_SIZE + 2 + ampe_buf_len;13401341/* alloc new frame */1342new_buf = rtw_malloc(new_len);1343if (!new_buf) {1344rtw_warn_on(1);1345goto exit;1346}13471348/* build new frame */1349_rtw_memcpy(new_buf, fhead, sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset);1350new_fhead = new_buf;1351new_flen = new_len;1352new_fbody = new_fhead + sizeof(struct rtw_ieee80211_hdr_3addr);13531354fpos = new_fbody + tlv_ies_offset;1355left = BSS_EX_TLV_IES_LEN(network);1356pos = BSS_EX_TLV_IES(network);1357while (left >= 2) {1358u8 id, elen;13591360id = *pos++;1361elen = *pos++;1362left -= 2;13631364if (elen > left)1365break;13661367switch (id) {1368case WLAN_EID_SSID:1369case WLAN_EID_DS_PARAMS:1370case WLAN_EID_TIM:1371break;1372default:1373fpos = rtw_set_ie(fpos, id, elen, pos, NULL);1374if (id == WLAN_EID_MESH_CONFIG)1375fpos = rtw_set_ie(fpos, WLAN_EID_MPM, mpm_ielen, mpm_ie + 2, NULL);1376}13771378left -= elen;1379pos += elen;1380}1381if (mic_ie) {1382new_mic_ie = fpos;1383*fpos++ = WLAN_EID_MIC;1384*fpos++ = AES_BLOCK_SIZE;1385}13861387#ifdef CONFIG_RTW_MESH_AEK1388/* encode */1389if (mic_ie) {1390int enc_ret = rtw_mpm_ampe_enc(adapter, plink, new_fbody, new_mic_ie, ampe_buf, 0);1391if (enc_ret != _SUCCESS)1392goto exit;1393}1394#endif13951396*nlen = new_len;1397*nbuf = new_buf;13981399ret = _SUCCESS;14001401exit:1402if (ret != _SUCCESS && new_buf)1403rtw_mfree(new_buf, new_len);14041405#ifdef CONFIG_RTW_MESH_AEK1406if (ampe_buf)1407rtw_mfree(ampe_buf, ampe_buf_len);1408#endif14091410return ret;1411}1412#endif /* CONFIG_RTW_MPM_TX_IES_SYNC_BSS */14131414struct mpm_frame_info {1415u8 *aid;1416u16 aid_v;1417u8 *pid;1418u16 pid_v;1419u8 *llid;1420u16 llid_v;1421u8 *plid;1422u16 plid_v;1423u8 *reason;1424u16 reason_v;1425u8 *chosen_pmk;1426};14271428/*1429* pid:00000 llid:00000 chosen_pmk:0x000000000000000000000000000000001430* aid:00000 pid:00000 llid:00000 plid:00000 chosen_pmk:0x000000000000000000000000000000001431* pid:00000 llid:00000 plid:00000 reason:00000 chosen_pmk:0x000000000000000000000000000000001432*/1433#define MPM_LOG_BUF_LEN 92 /* this length is limited for legal combination */1434static void rtw_mpm_info_msg(struct mpm_frame_info *mpm_info, u8 *mpm_log_buf)1435{1436int cnt = 0;14371438if (mpm_info->aid) {1439cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "aid:%u ", mpm_info->aid_v);1440if (cnt >= MPM_LOG_BUF_LEN - 1)1441goto exit;1442}1443if (mpm_info->pid) {1444cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "pid:%u ", mpm_info->pid_v);1445if (cnt >= MPM_LOG_BUF_LEN - 1)1446goto exit;1447}1448if (mpm_info->llid) {1449cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "llid:%u ", mpm_info->llid_v);1450if (cnt >= MPM_LOG_BUF_LEN - 1)1451goto exit;1452}1453if (mpm_info->plid) {1454cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "plid:%u ", mpm_info->plid_v);1455if (cnt >= MPM_LOG_BUF_LEN - 1)1456goto exit;1457}1458if (mpm_info->reason) {1459cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "reason:%u ", mpm_info->reason_v);1460if (cnt >= MPM_LOG_BUF_LEN - 1)1461goto exit;1462}1463if (mpm_info->chosen_pmk) {1464cnt += snprintf(mpm_log_buf + cnt, MPM_LOG_BUF_LEN - cnt - 1, "chosen_pmk:0x"KEY_FMT, KEY_ARG(mpm_info->chosen_pmk));1465if (cnt >= MPM_LOG_BUF_LEN - 1)1466goto exit;1467}14681469exit:1470return;1471}14721473static int rtw_mpm_check_frames(_adapter *adapter, u8 action, const u8 **buf, size_t *len, u8 tx)1474{1475struct rtw_mesh_info *minfo = &adapter->mesh_info;1476struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;1477struct mesh_plink_ent *plink = NULL;1478u8 *nbuf = NULL;1479size_t nlen = 0;1480u8 *fhead = (u8 *)*buf;1481size_t flen = *len;1482u8 *peer_addr = tx ? GetAddr1Ptr(fhead) : get_addr2_ptr(fhead);1483u8 *frame_body = fhead + sizeof(struct rtw_ieee80211_hdr_3addr);1484struct mpm_frame_info mpm_info;1485u8 tlv_ies_offset;1486u8 *mpm_ie = NULL;1487uint mpm_ielen = 0;1488u8 *mic_ie = NULL;1489uint mic_ielen = 0;1490int ret = 0;1491u8 mpm_log_buf[MPM_LOG_BUF_LEN] = {0};14921493if (action == RTW_ACT_SELF_PROTECTED_MESH_OPEN)1494tlv_ies_offset = 4;1495else if (action == RTW_ACT_SELF_PROTECTED_MESH_CONF)1496tlv_ies_offset = 6;1497else if (action == RTW_ACT_SELF_PROTECTED_MESH_CLOSE)1498tlv_ies_offset = 2;1499else {1500rtw_warn_on(1);1501goto exit;1502}15031504plink = rtw_mesh_plink_get(adapter, peer_addr);1505if (!plink && (tx == _TRUE || action == RTW_ACT_SELF_PROTECTED_MESH_CONF)) {1506/* warning message if no plink when: 1.TX all MPM or 2.RX CONF */1507RTW_WARN("RTW_%s:%s without plink of "MAC_FMT"\n"1508, (tx == _TRUE) ? "Tx" : "Rx", action_self_protected_str(action), MAC_ARG(peer_addr));1509goto exit;1510}15111512_rtw_memset(&mpm_info, 0, sizeof(struct mpm_frame_info));15131514if (action == RTW_ACT_SELF_PROTECTED_MESH_CONF) {1515mpm_info.aid = (u8 *)frame_body + 4;1516mpm_info.aid_v = RTW_GET_LE16(mpm_info.aid);1517}15181519mpm_ie = rtw_get_ie(fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset1520, WLAN_EID_MPM, &mpm_ielen1521, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);1522if (!mpm_ie || mpm_ielen < 2 + 2)1523goto exit;15241525mpm_info.pid = mpm_ie + 2;1526mpm_info.pid_v = RTW_GET_LE16(mpm_info.pid);1527mpm_info.llid = mpm_info.pid + 2;1528mpm_info.llid_v = RTW_GET_LE16(mpm_info.llid);15291530switch (action) {1531case RTW_ACT_SELF_PROTECTED_MESH_OPEN:1532/* pid:2, llid:2, (chosen_pmk:16) */1533if (mpm_info.pid_v == 0 && mpm_ielen == 4)1534;1535else if (mpm_info.pid_v == 1 && mpm_ielen == 20)1536mpm_info.chosen_pmk = mpm_info.llid + 2;1537else1538goto exit;1539break;1540case RTW_ACT_SELF_PROTECTED_MESH_CONF:1541/* pid:2, llid:2, plid:2, (chosen_pmk:16) */1542mpm_info.plid = mpm_info.llid + 2;1543mpm_info.plid_v = RTW_GET_LE16(mpm_info.plid);1544if (mpm_info.pid_v == 0 && mpm_ielen == 6)1545;1546else if (mpm_info.pid_v == 1 && mpm_ielen == 22)1547mpm_info.chosen_pmk = mpm_info.plid + 2;1548else1549goto exit;1550break;1551case RTW_ACT_SELF_PROTECTED_MESH_CLOSE:1552/* pid:2, llid:2, (plid:2), reason:2, (chosen_pmk:16) */1553if (mpm_info.pid_v == 0 && mpm_ielen == 6) {1554/* MPM, without plid */1555mpm_info.reason = mpm_info.llid + 2;1556mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);1557} else if (mpm_info.pid_v == 0 && mpm_ielen == 8) {1558/* MPM, with plid */1559mpm_info.plid = mpm_info.llid + 2;1560mpm_info.plid_v = RTW_GET_LE16(mpm_info.plid);1561mpm_info.reason = mpm_info.plid + 2;1562mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);1563} else if (mpm_info.pid_v == 1 && mpm_ielen == 22) {1564/* AMPE, without plid */1565mpm_info.reason = mpm_info.llid + 2;1566mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);1567mpm_info.chosen_pmk = mpm_info.reason + 2;1568} else if (mpm_info.pid_v == 1 && mpm_ielen == 24) {1569/* AMPE, with plid */1570mpm_info.plid = mpm_info.llid + 2;1571mpm_info.plid_v = RTW_GET_LE16(mpm_info.plid);1572mpm_info.reason = mpm_info.plid + 2;1573mpm_info.reason_v = RTW_GET_LE16(mpm_info.reason);1574mpm_info.chosen_pmk = mpm_info.reason + 2;1575} else1576goto exit;1577break;1578};15791580if (mpm_info.pid_v == 1) {1581mic_ie = rtw_get_ie(fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset1582, WLAN_EID_MIC, &mic_ielen1583, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);1584if (!mic_ie || mic_ielen != AES_BLOCK_SIZE)1585goto exit;1586}15871588#if CONFIG_RTW_MPM_TX_IES_SYNC_BSS1589if ((action == RTW_ACT_SELF_PROTECTED_MESH_OPEN || action == RTW_ACT_SELF_PROTECTED_MESH_CONF)1590&& tx == _TRUE1591) {1592#define DBG_RTW_MPM_TX_IES_SYNC_BSS 015931594if (mpm_info.pid_v == 1 && (!plink || !MESH_PLINK_AEK_VALID(plink))) {1595RTW_WARN("AEK not ready, IEs can't sync with BSS\n");1596goto bypass_sync_bss;1597}15981599if (DBG_RTW_MPM_TX_IES_SYNC_BSS) {1600RTW_INFO(FUNC_ADPT_FMT" before:\n", FUNC_ADPT_ARG(adapter));1601dump_ies(RTW_DBGDUMP1602, fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset1603, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);1604}16051606rtw_mpm_tx_ies_sync_bss(adapter, plink1607, fhead, flen, frame_body, tlv_ies_offset, mpm_ie, mic_ie1608, &nbuf, &nlen);1609if (!nbuf)1610goto exit;16111612/* update pointer & len for new frame */1613fhead = nbuf;1614flen = nlen;1615frame_body = fhead + sizeof(struct rtw_ieee80211_hdr_3addr);1616if (mpm_info.pid_v == 1) {1617mic_ie = rtw_get_ie(fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset1618, WLAN_EID_MIC, &mic_ielen1619, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);1620}16211622if (DBG_RTW_MPM_TX_IES_SYNC_BSS) {1623RTW_INFO(FUNC_ADPT_FMT" after:\n", FUNC_ADPT_ARG(adapter));1624dump_ies(RTW_DBGDUMP1625, fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + tlv_ies_offset1626, flen - sizeof(struct rtw_ieee80211_hdr_3addr) - tlv_ies_offset);1627}1628}1629bypass_sync_bss:1630#endif /* CONFIG_RTW_MPM_TX_IES_SYNC_BSS */16311632if (!plink)1633goto mpm_log;16341635#if CONFIG_RTW_MESH_PEER_BLACKLIST1636if (action == RTW_ACT_SELF_PROTECTED_MESH_OPEN) {1637if (tx)1638rtw_mesh_plink_set_peer_conf_timeout(adapter, peer_addr);16391640} else1641#endif1642#if CONFIG_RTW_MESH_ACNODE_PREVENT1643if (action == RTW_ACT_SELF_PROTECTED_MESH_CLOSE) {1644if (tx && mpm_info.reason && mpm_info.reason_v == WLAN_REASON_MESH_MAX_PEERS) {1645if (rtw_mesh_scanned_is_acnode_confirmed(adapter, plink->scanned)1646&& rtw_mesh_acnode_prevent_allow_sacrifice(adapter)1647) {1648struct sta_info *sac = rtw_mesh_acnode_prevent_pick_sacrifice(adapter);16491650if (sac) {1651struct sta_priv *stapriv = &adapter->stapriv;1652_irqL irqL;1653u8 sta_addr[ETH_ALEN];1654u8 updated = _FALSE;16551656_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);1657if (!rtw_is_list_empty(&sac->asoc_list)) {1658rtw_list_delete(&sac->asoc_list);1659stapriv->asoc_list_cnt--;1660STA_SET_MESH_PLINK(sac, NULL);1661}1662_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);1663RTW_INFO(FUNC_ADPT_FMT" sacrifice "MAC_FMT" for acnode\n"1664, FUNC_ADPT_ARG(adapter), MAC_ARG(sac->cmn.mac_addr));16651666_rtw_memcpy(sta_addr, sac->cmn.mac_addr, ETH_ALEN);1667updated = ap_free_sta(adapter, sac, 0, 0, 1);1668rtw_mesh_expire_peer(stapriv->padapter, sta_addr);16691670associated_clients_update(adapter, updated, STA_INFO_UPDATE_ALL);1671}1672}1673}1674} else1675#endif1676if (action == RTW_ACT_SELF_PROTECTED_MESH_CONF) {1677_irqL irqL;1678u8 *ies = NULL;1679u16 ies_len = 0;16801681_enter_critical_bh(&(plink_ctl->lock), &irqL);16821683plink = _rtw_mesh_plink_get(adapter, peer_addr);1684if (!plink)1685goto release_plink_ctl;16861687if (tx == _FALSE) {1688ies = plink->rx_conf_ies;1689ies_len = plink->rx_conf_ies_len;1690plink->rx_conf_ies = NULL;1691plink->rx_conf_ies_len = 0;16921693plink->llid = mpm_info.plid_v;1694plink->plid = mpm_info.llid_v;1695plink->peer_aid = mpm_info.aid_v;1696if (mpm_info.pid_v == 1)1697_rtw_memcpy(plink->chosen_pmk, mpm_info.chosen_pmk, 16);1698}1699#ifdef CONFIG_RTW_MESH_DRIVER_AID1700else {1701ies = plink->tx_conf_ies;1702ies_len = plink->tx_conf_ies_len;1703plink->tx_conf_ies = NULL;1704plink->tx_conf_ies_len = 0;1705}1706#endif17071708if (ies && ies_len)1709rtw_mfree(ies, ies_len);17101711#ifndef CONFIG_RTW_MESH_DRIVER_AID1712if (tx == _TRUE)1713goto release_plink_ctl; /* no need to copy tx conf ies */1714#endif17151716/* copy mesh confirm IEs */1717if (mpm_info.pid_v == 1) /* not include MIC & encrypted AMPE */1718ies_len = (mic_ie - fhead) - sizeof(struct rtw_ieee80211_hdr_3addr) - 2;1719else1720ies_len = flen - sizeof(struct rtw_ieee80211_hdr_3addr) - 2;17211722ies = rtw_zmalloc(ies_len);1723if (ies) {1724_rtw_memcpy(ies, fhead + sizeof(struct rtw_ieee80211_hdr_3addr) + 2, ies_len);1725if (tx == _FALSE) {1726plink->rx_conf_ies = ies;1727plink->rx_conf_ies_len = ies_len;1728}1729#ifdef CONFIG_RTW_MESH_DRIVER_AID1730else {1731plink->tx_conf_ies = ies;1732plink->tx_conf_ies_len = ies_len;1733}1734#endif1735}17361737release_plink_ctl:1738_exit_critical_bh(&(plink_ctl->lock), &irqL);1739}17401741mpm_log:1742rtw_mpm_info_msg(&mpm_info, mpm_log_buf);1743RTW_INFO("RTW_%s:%s %s\n"1744, (tx == _TRUE) ? "Tx" : "Rx"1745, action_self_protected_str(action)1746, mpm_log_buf1747);17481749ret = 1;17501751exit:1752if (nbuf) {1753if (ret == 1) {1754*buf = nbuf;1755*len = nlen;1756} else1757rtw_mfree(nbuf, nlen);1758}17591760return ret;1761}17621763static int rtw_mesh_check_frames(_adapter *adapter, const u8 **buf, size_t *len, u8 tx)1764{1765int is_mesh_frame = -1;1766const u8 *frame_body;1767u8 category, action;17681769frame_body = *buf + sizeof(struct rtw_ieee80211_hdr_3addr);1770category = frame_body[0];17711772if (category == RTW_WLAN_CATEGORY_SELF_PROTECTED) {1773action = frame_body[1];1774switch (action) {1775case RTW_ACT_SELF_PROTECTED_MESH_OPEN:1776case RTW_ACT_SELF_PROTECTED_MESH_CONF:1777case RTW_ACT_SELF_PROTECTED_MESH_CLOSE:1778rtw_mpm_check_frames(adapter, action, buf, len, tx);1779is_mesh_frame = action;1780break;1781case RTW_ACT_SELF_PROTECTED_MESH_GK_INFORM:1782case RTW_ACT_SELF_PROTECTED_MESH_GK_ACK:1783RTW_INFO("RTW_%s:%s\n", (tx == _TRUE) ? "Tx" : "Rx", action_self_protected_str(action));1784is_mesh_frame = action;1785break;1786default:1787break;1788};1789}17901791return is_mesh_frame;1792}17931794int rtw_mesh_check_frames_tx(_adapter *adapter, const u8 **buf, size_t *len)1795{1796return rtw_mesh_check_frames(adapter, buf, len, _TRUE);1797}17981799int rtw_mesh_check_frames_rx(_adapter *adapter, const u8 *buf, size_t len)1800{1801return rtw_mesh_check_frames(adapter, &buf, &len, _FALSE);1802}18031804int rtw_mesh_on_auth(_adapter *adapter, union recv_frame *rframe)1805{1806u8 *whdr = rframe->u.hdr.rx_data;18071808#if CONFIG_RTW_MACADDR_ACL1809if (rtw_access_ctrl(adapter, get_addr2_ptr(whdr)) == _FALSE)1810return _SUCCESS;1811#endif18121813if (!rtw_mesh_plink_get(adapter, get_addr2_ptr(whdr))) {1814#if CONFIG_RTW_MESH_ACNODE_PREVENT1815rtw_mesh_acnode_set_notify_etime(adapter, whdr);1816#endif18171818if (adapter_to_rfctl(adapter)->offch_state == OFFCHS_NONE)1819issue_probereq(adapter, &adapter->mlmepriv.cur_network.network.mesh_id, get_addr2_ptr(whdr));18201821/* only peer being added (checked by notify conditions) is allowed */1822return _SUCCESS;1823}18241825rtw_cfg80211_rx_mframe(adapter, rframe, NULL);1826return _SUCCESS;1827}18281829unsigned int on_action_self_protected(_adapter *adapter, union recv_frame *rframe)1830{1831unsigned int ret = _FAIL;1832struct sta_info *sta = NULL;1833u8 *pframe = rframe->u.hdr.rx_data;1834uint frame_len = rframe->u.hdr.len;1835u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));1836u8 category;1837u8 action;18381839/* check RA matches or not */1840if (!_rtw_memcmp(adapter_mac_addr(adapter), GetAddr1Ptr(pframe), ETH_ALEN))1841goto exit;18421843category = frame_body[0];1844if (category != RTW_WLAN_CATEGORY_SELF_PROTECTED)1845goto exit;18461847action = frame_body[1];1848switch (action) {1849case RTW_ACT_SELF_PROTECTED_MESH_OPEN:1850case RTW_ACT_SELF_PROTECTED_MESH_CONF:1851case RTW_ACT_SELF_PROTECTED_MESH_CLOSE:1852case RTW_ACT_SELF_PROTECTED_MESH_GK_INFORM:1853case RTW_ACT_SELF_PROTECTED_MESH_GK_ACK:1854if (!(MLME_IS_MESH(adapter) && MLME_IS_ASOC(adapter)))1855goto exit;1856#ifdef CONFIG_IOCTL_CFG802111857#if CONFIG_RTW_MACADDR_ACL1858if (rtw_access_ctrl(adapter, get_addr2_ptr(pframe)) == _FALSE)1859goto exit;1860#endif1861#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST1862if (rtw_mesh_cto_mgate_required(adapter)1863/* only peer being added (checked by notify conditions) is allowed */1864&& !rtw_mesh_plink_get(adapter, get_addr2_ptr(pframe)))1865goto exit;1866#endif1867rtw_cfg80211_rx_action(adapter, rframe, NULL);1868ret = _SUCCESS;1869#endif /* CONFIG_IOCTL_CFG80211 */1870break;1871default:1872break;1873}18741875exit:1876return ret;1877}18781879const u8 ae_to_mesh_ctrl_len[] = {18806,188112, /* MESH_FLAGS_AE_A4 */188218, /* MESH_FLAGS_AE_A5_A6 */18830,1884};18851886unsigned int on_action_mesh(_adapter *adapter, union recv_frame *rframe)1887{1888unsigned int ret = _FAIL;1889struct sta_info *sta = NULL;1890struct sta_priv *stapriv = &adapter->stapriv;1891u8 *pframe = rframe->u.hdr.rx_data;1892uint frame_len = rframe->u.hdr.len;1893u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));1894u8 category;1895u8 action;18961897if (!MLME_IS_MESH(adapter))1898goto exit;18991900/* check stainfo exist? */19011902category = frame_body[0];1903if (category != RTW_WLAN_CATEGORY_MESH)1904goto exit;19051906action = frame_body[1];1907switch (action) {1908case RTW_ACT_MESH_HWMP_PATH_SELECTION:1909rtw_mesh_rx_path_sel_frame(adapter, rframe);1910ret = _SUCCESS;1911break;1912default:1913break;1914}19151916exit:1917return ret;1918}19191920bool rtw_mesh_update_bss_peering_status(_adapter *adapter, WLAN_BSSID_EX *bss)1921{1922struct sta_priv *stapriv = &adapter->stapriv;1923struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;1924struct rtw_mesh_info *minfo = &adapter->mesh_info;1925struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;1926u8 num_of_peerings = stapriv->asoc_list_cnt;1927bool accept_peerings = stapriv->asoc_list_cnt < mcfg->max_peer_links;1928u8 *ie;1929int ie_len;1930bool updated = 0;19311932#if CONFIG_RTW_MESH_ACNODE_PREVENT1933accept_peerings |= plink_ctl->acnode_rsvd;1934#endif19351936ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len, BSS_EX_TLV_IES_LEN(bss));1937if (!ie || ie_len != 7) {1938rtw_warn_on(1);1939goto exit;1940}19411942if (GET_MESH_CONF_ELE_NUM_OF_PEERINGS(ie + 2) != num_of_peerings) {1943SET_MESH_CONF_ELE_NUM_OF_PEERINGS(ie + 2, num_of_peerings);1944updated = 1;1945}19461947if (GET_MESH_CONF_ELE_ACCEPT_PEERINGS(ie + 2) != accept_peerings) {1948SET_MESH_CONF_ELE_ACCEPT_PEERINGS(ie + 2, accept_peerings);1949updated = 1;1950}19511952exit:1953return updated;1954}19551956bool rtw_mesh_update_bss_formation_info(_adapter *adapter, WLAN_BSSID_EX *bss)1957{1958struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;1959struct rtw_mesh_info *minfo = &adapter->mesh_info;1960u8 cto_mgate = (minfo->num_gates || mcfg->dot11MeshGateAnnouncementProtocol);1961u8 cto_as = 0;1962u8 *ie;1963int ie_len;1964bool updated = 0;19651966ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,1967BSS_EX_TLV_IES_LEN(bss));1968if (!ie || ie_len != 7) {1969rtw_warn_on(1);1970goto exit;1971}19721973if (GET_MESH_CONF_ELE_CTO_MGATE(ie + 2) != cto_mgate) {1974SET_MESH_CONF_ELE_CTO_MGATE(ie + 2, cto_mgate);1975updated = 1;1976}19771978if (GET_MESH_CONF_ELE_CTO_AS(ie + 2) != cto_as) {1979SET_MESH_CONF_ELE_CTO_AS(ie + 2, cto_as);1980updated = 1;1981}19821983exit:1984return updated;1985}19861987bool rtw_mesh_update_bss_forwarding_state(_adapter *adapter, WLAN_BSSID_EX *bss)1988{1989struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;1990u8 forward = mcfg->dot11MeshForwarding;1991u8 *ie;1992int ie_len;1993bool updated = 0;19941995ie = rtw_get_ie(BSS_EX_TLV_IES(bss), WLAN_EID_MESH_CONFIG, &ie_len,1996BSS_EX_TLV_IES_LEN(bss));1997if (!ie || ie_len != 7) {1998rtw_warn_on(1);1999goto exit;2000}20012002if (GET_MESH_CONF_ELE_FORWARDING(ie + 2) != forward) {2003SET_MESH_CONF_ELE_FORWARDING(ie + 2, forward);2004updated = 1;2005}20062007exit:2008return updated;2009}20102011struct mesh_plink_ent *_rtw_mesh_plink_get(_adapter *adapter, const u8 *hwaddr)2012{2013struct rtw_mesh_info *minfo = &adapter->mesh_info;2014struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2015struct mesh_plink_ent *ent = NULL;2016int i;20172018for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {2019if (plink_ctl->ent[i].valid == _TRUE2020&& _rtw_memcmp(plink_ctl->ent[i].addr, hwaddr, ETH_ALEN) == _TRUE2021) {2022ent = &plink_ctl->ent[i];2023break;2024}2025}20262027return ent;2028}20292030struct mesh_plink_ent *rtw_mesh_plink_get(_adapter *adapter, const u8 *hwaddr)2031{2032struct rtw_mesh_info *minfo = &adapter->mesh_info;2033struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2034struct mesh_plink_ent *ent = NULL;2035_irqL irqL;20362037_enter_critical_bh(&(plink_ctl->lock), &irqL);2038ent = _rtw_mesh_plink_get(adapter, hwaddr);2039_exit_critical_bh(&(plink_ctl->lock), &irqL);20402041return ent;2042}20432044struct mesh_plink_ent *rtw_mesh_plink_get_no_estab_by_idx(_adapter *adapter, u8 idx)2045{2046struct rtw_mesh_info *minfo = &adapter->mesh_info;2047struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2048struct mesh_plink_ent *ent = NULL;2049int i, j = 0;2050_irqL irqL;20512052_enter_critical_bh(&(plink_ctl->lock), &irqL);2053for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {2054if (plink_ctl->ent[i].valid == _TRUE2055&& plink_ctl->ent[i].plink_state != RTW_MESH_PLINK_ESTAB2056) {2057if (j == idx) {2058ent = &plink_ctl->ent[i];2059break;2060}2061j++;2062}2063}2064_exit_critical_bh(&(plink_ctl->lock), &irqL);20652066return ent;2067}20682069int _rtw_mesh_plink_add(_adapter *adapter, const u8 *hwaddr)2070{2071struct rtw_mesh_info *minfo = &adapter->mesh_info;2072struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2073struct mesh_plink_ent *ent = NULL;2074u8 exist = _FALSE;2075int i;20762077for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {2078if (plink_ctl->ent[i].valid == _TRUE2079&& _rtw_memcmp(plink_ctl->ent[i].addr, hwaddr, ETH_ALEN) == _TRUE2080) {2081ent = &plink_ctl->ent[i];2082exist = _TRUE;2083break;2084}20852086if (ent == NULL && plink_ctl->ent[i].valid == _FALSE)2087ent = &plink_ctl->ent[i];2088}20892090if (exist == _FALSE && ent) {2091_rtw_memcpy(ent->addr, hwaddr, ETH_ALEN);2092ent->valid = _TRUE;2093#ifdef CONFIG_RTW_MESH_AEK2094ent->aek_valid = 0;2095#endif2096ent->llid = 0;2097ent->plid = 0;2098_rtw_memset(ent->chosen_pmk, 0, 16);2099#ifdef CONFIG_RTW_MESH_AEK2100_rtw_memset(ent->sel_pcs, 0, 4);2101_rtw_memset(ent->l_nonce, 0, 32);2102_rtw_memset(ent->p_nonce, 0, 32);2103#endif2104ent->plink_state = RTW_MESH_PLINK_LISTEN;2105#ifndef CONFIG_RTW_MESH_DRIVER_AID2106ent->aid = 0;2107#endif2108ent->peer_aid = 0;2109SET_PEER_CONF_DISABLED(ent);2110SET_CTO_MGATE_CONF_DISABLED(ent);2111plink_ctl->num++;2112}21132114return exist == _TRUE ? RTW_ALREADY : (ent ? _SUCCESS : _FAIL);2115}21162117int rtw_mesh_plink_add(_adapter *adapter, const u8 *hwaddr)2118{2119struct rtw_mesh_info *minfo = &adapter->mesh_info;2120struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2121_irqL irqL;2122int ret;21232124_enter_critical_bh(&(plink_ctl->lock), &irqL);2125ret = _rtw_mesh_plink_add(adapter, hwaddr);2126_exit_critical_bh(&(plink_ctl->lock), &irqL);21272128return ret;2129}21302131int rtw_mesh_plink_set_state(_adapter *adapter, const u8 *hwaddr, u8 state)2132{2133struct rtw_mesh_info *minfo = &adapter->mesh_info;2134struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2135struct mesh_plink_ent *ent = NULL;2136_irqL irqL;21372138_enter_critical_bh(&(plink_ctl->lock), &irqL);2139ent = _rtw_mesh_plink_get(adapter, hwaddr);2140if (ent)2141ent->plink_state = state;2142_exit_critical_bh(&(plink_ctl->lock), &irqL);21432144return ent ? _SUCCESS : _FAIL;2145}21462147#ifdef CONFIG_RTW_MESH_AEK2148int rtw_mesh_plink_set_aek(_adapter *adapter, const u8 *hwaddr, const u8 *aek)2149{2150struct rtw_mesh_info *minfo = &adapter->mesh_info;2151struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2152struct mesh_plink_ent *ent = NULL;2153_irqL irqL;21542155_enter_critical_bh(&(plink_ctl->lock), &irqL);2156ent = _rtw_mesh_plink_get(adapter, hwaddr);2157if (ent) {2158_rtw_memcpy(ent->aek, aek, 32);2159ent->aek_valid = 1;2160}2161_exit_critical_bh(&(plink_ctl->lock), &irqL);21622163return ent ? _SUCCESS : _FAIL;2164}2165#endif21662167#if CONFIG_RTW_MESH_PEER_BLACKLIST2168int rtw_mesh_plink_set_peer_conf_timeout(_adapter *adapter, const u8 *hwaddr)2169{2170struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;2171struct rtw_mesh_info *minfo = &adapter->mesh_info;2172struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2173struct mesh_plink_ent *ent = NULL;2174_irqL irqL;21752176_enter_critical_bh(&(plink_ctl->lock), &irqL);2177ent = _rtw_mesh_plink_get(adapter, hwaddr);2178if (ent) {2179if (IS_PEER_CONF_DISABLED(ent))2180SET_PEER_CONF_END_TIME(ent, mcfg->peer_sel_policy.peer_conf_timeout_ms);2181}2182_exit_critical_bh(&(plink_ctl->lock), &irqL);21832184return ent ? _SUCCESS : _FAIL;2185}2186#endif21872188void _rtw_mesh_plink_del_ent(_adapter *adapter, struct mesh_plink_ent *ent)2189{2190struct rtw_mesh_info *minfo = &adapter->mesh_info;2191struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;21922193ent->valid = _FALSE;2194#ifdef CONFIG_RTW_MESH_DRIVER_AID2195if (ent->tx_conf_ies && ent->tx_conf_ies_len)2196rtw_mfree(ent->tx_conf_ies, ent->tx_conf_ies_len);2197ent->tx_conf_ies = NULL;2198ent->tx_conf_ies_len = 0;2199#endif2200if (ent->rx_conf_ies && ent->rx_conf_ies_len)2201rtw_mfree(ent->rx_conf_ies, ent->rx_conf_ies_len);2202ent->rx_conf_ies = NULL;2203ent->rx_conf_ies_len = 0;2204if (ent->scanned)2205ent->scanned = NULL;2206plink_ctl->num--;2207}22082209int rtw_mesh_plink_del(_adapter *adapter, const u8 *hwaddr)2210{2211struct rtw_mesh_info *minfo = &adapter->mesh_info;2212struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2213struct mesh_plink_ent *ent = NULL;2214u8 exist = _FALSE;2215int i;2216_irqL irqL;22172218_enter_critical_bh(&(plink_ctl->lock), &irqL);2219for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {2220if (plink_ctl->ent[i].valid == _TRUE2221&& _rtw_memcmp(plink_ctl->ent[i].addr, hwaddr, ETH_ALEN) == _TRUE2222) {2223ent = &plink_ctl->ent[i];2224exist = _TRUE;2225break;2226}2227}22282229if (exist == _TRUE)2230_rtw_mesh_plink_del_ent(adapter, ent);22312232_exit_critical_bh(&(plink_ctl->lock), &irqL);22332234return exist == _TRUE ? _SUCCESS : RTW_ALREADY;2235}22362237void rtw_mesh_plink_ctl_init(_adapter *adapter)2238{2239struct rtw_mesh_info *minfo = &adapter->mesh_info;2240struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2241int i;22422243_rtw_spinlock_init(&plink_ctl->lock);2244plink_ctl->num = 0;2245for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++)2246plink_ctl->ent[i].valid = _FALSE;22472248#if CONFIG_RTW_MESH_PEER_BLACKLIST2249_rtw_init_queue(&plink_ctl->peer_blacklist);2250#endif2251#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST2252_rtw_init_queue(&plink_ctl->cto_mgate_blacklist);2253#endif2254}22552256void rtw_mesh_plink_ctl_deinit(_adapter *adapter)2257{2258struct rtw_mesh_info *minfo = &adapter->mesh_info;2259struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2260struct mesh_plink_ent *ent;2261int i;2262_irqL irqL;22632264_enter_critical_bh(&(plink_ctl->lock), &irqL);2265for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {2266ent = &plink_ctl->ent[i];2267#ifdef CONFIG_RTW_MESH_DRIVER_AID2268if (ent->tx_conf_ies && ent->tx_conf_ies_len)2269rtw_mfree(ent->tx_conf_ies, ent->tx_conf_ies_len);2270#endif2271if (ent->rx_conf_ies && ent->rx_conf_ies_len)2272rtw_mfree(ent->rx_conf_ies, ent->rx_conf_ies_len);2273}2274_exit_critical_bh(&(plink_ctl->lock), &irqL);22752276_rtw_spinlock_free(&plink_ctl->lock);22772278#if CONFIG_RTW_MESH_PEER_BLACKLIST2279rtw_mesh_peer_blacklist_flush(adapter);2280_rtw_deinit_queue(&plink_ctl->peer_blacklist);2281#endif2282#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST2283rtw_mesh_cto_mgate_blacklist_flush(adapter);2284_rtw_deinit_queue(&plink_ctl->cto_mgate_blacklist);2285#endif2286}22872288void dump_mesh_plink_ctl(void *sel, _adapter *adapter)2289{2290struct rtw_mesh_info *minfo = &adapter->mesh_info;2291struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2292struct mesh_plink_ent *ent;2293int i;22942295RTW_PRINT_SEL(sel, "num:%u\n", plink_ctl->num);2296#if CONFIG_RTW_MESH_ACNODE_PREVENT2297RTW_PRINT_SEL(sel, "acnode_rsvd:%u\n", plink_ctl->acnode_rsvd);2298#endif22992300for (i = 0; i < RTW_MESH_MAX_PEER_CANDIDATES; i++) {2301ent = &plink_ctl->ent[i];2302if (!ent->valid)2303continue;23042305RTW_PRINT_SEL(sel, "\n");2306RTW_PRINT_SEL(sel, "peer:"MAC_FMT"\n", MAC_ARG(ent->addr));2307RTW_PRINT_SEL(sel, "plink_state:%s\n", rtw_mesh_plink_str(ent->plink_state));23082309#ifdef CONFIG_RTW_MESH_AEK2310if (ent->aek_valid)2311RTW_PRINT_SEL(sel, "aek:"KEY_FMT KEY_FMT"\n", KEY_ARG(ent->aek), KEY_ARG(ent->aek + 16));2312#endif23132314RTW_PRINT_SEL(sel, "llid:%u, plid:%u\n", ent->llid, ent->plid);2315#ifndef CONFIG_RTW_MESH_DRIVER_AID2316RTW_PRINT_SEL(sel, "aid:%u\n", ent->aid);2317#endif2318RTW_PRINT_SEL(sel, "peer_aid:%u\n", ent->peer_aid);23192320RTW_PRINT_SEL(sel, "chosen_pmk:"KEY_FMT"\n", KEY_ARG(ent->chosen_pmk));23212322#ifdef CONFIG_RTW_MESH_AEK2323RTW_PRINT_SEL(sel, "sel_pcs:%02x%02x%02x%02x\n"2324, ent->sel_pcs[0], ent->sel_pcs[1], ent->sel_pcs[2], ent->sel_pcs[3]);2325RTW_PRINT_SEL(sel, "l_nonce:"KEY_FMT KEY_FMT"\n", KEY_ARG(ent->l_nonce), KEY_ARG(ent->l_nonce + 16));2326RTW_PRINT_SEL(sel, "p_nonce:"KEY_FMT KEY_FMT"\n", KEY_ARG(ent->p_nonce), KEY_ARG(ent->p_nonce + 16));2327#endif23282329#ifdef CONFIG_RTW_MESH_DRIVER_AID2330RTW_PRINT_SEL(sel, "tx_conf_ies:%p, len:%u\n", ent->tx_conf_ies, ent->tx_conf_ies_len);2331#endif2332RTW_PRINT_SEL(sel, "rx_conf_ies:%p, len:%u\n", ent->rx_conf_ies, ent->rx_conf_ies_len);2333RTW_PRINT_SEL(sel, "scanned:%p\n", ent->scanned);23342335#if CONFIG_RTW_MESH_PEER_BLACKLIST2336if (!IS_PEER_CONF_DISABLED(ent)) {2337if (!IS_PEER_CONF_TIMEOUT(ent))2338RTW_PRINT_SEL(sel, "peer_conf:%d\n", rtw_systime_to_ms(ent->peer_conf_end_time - rtw_get_current_time()));2339else2340RTW_PRINT_SEL(sel, "peer_conf:TIMEOUT\n");2341}2342#endif23432344#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST2345if (!IS_CTO_MGATE_CONF_DISABLED(ent)) {2346if (!IS_CTO_MGATE_CONF_TIMEOUT(ent))2347RTW_PRINT_SEL(sel, "cto_mgate_conf:%d\n", rtw_systime_to_ms(ent->cto_mgate_conf_end_time - rtw_get_current_time()));2348else2349RTW_PRINT_SEL(sel, "cto_mgate_conf:TIMEOUT\n");2350}2351#endif2352}2353}23542355/* this function is called with plink_ctl being locked */2356int rtw_mesh_peer_establish(_adapter *adapter, struct mesh_plink_ent *plink, struct sta_info *sta)2357{2358#ifndef DBG_RTW_MESH_PEER_ESTABLISH2359#define DBG_RTW_MESH_PEER_ESTABLISH 02360#endif23612362struct sta_priv *stapriv = &adapter->stapriv;2363struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;2364struct rtw_mesh_info *minfo = &adapter->mesh_info;2365struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2366u8 *tlv_ies;2367u16 tlv_ieslen;2368struct rtw_ieee802_11_elems elems;2369_irqL irqL;2370int i;2371int ret = _FAIL;23722373if (!plink->rx_conf_ies || !plink->rx_conf_ies_len) {2374RTW_INFO(FUNC_ADPT_FMT" no rx confirm from sta "MAC_FMT"\n"2375, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));2376goto exit;2377}23782379if (plink->rx_conf_ies_len < 4) {2380RTW_INFO(FUNC_ADPT_FMT" confirm from sta "MAC_FMT" too short\n"2381, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));2382goto exit;2383}23842385#ifdef CONFIG_RTW_MESH_DRIVER_AID2386if (!plink->tx_conf_ies || !plink->tx_conf_ies_len) {2387RTW_INFO(FUNC_ADPT_FMT" no tx confirm to sta "MAC_FMT"\n"2388, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));2389goto exit;2390}23912392if (plink->tx_conf_ies_len < 4) {2393RTW_INFO(FUNC_ADPT_FMT" confirm to sta "MAC_FMT" too short\n"2394, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));2395goto exit;2396}2397#endif23982399tlv_ies = plink->rx_conf_ies + 4;2400tlv_ieslen = plink->rx_conf_ies_len - 4;24012402if (DBG_RTW_MESH_PEER_ESTABLISH)2403dump_ies(RTW_DBGDUMP, tlv_ies, tlv_ieslen);24042405if (rtw_ieee802_11_parse_elems(tlv_ies, tlv_ieslen, &elems, 1) == ParseFailed) {2406RTW_INFO(FUNC_ADPT_FMT" sta "MAC_FMT" sent invalid confirm\n"2407, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr));2408goto exit;2409}24102411SET_PEER_CONF_DISABLED(plink);2412if (rtw_bss_is_cto_mgate(&plink->scanned->network)2413&& !rtw_bss_is_forwarding(&plink->scanned->network))2414SET_CTO_MGATE_CONF_END_TIME(plink, mcfg->peer_sel_policy.cto_mgate_conf_timeout_ms);2415else2416SET_CTO_MGATE_CONF_DISABLED(plink);24172418sta->state &= (~WIFI_FW_AUTH_SUCCESS);2419sta->state |= WIFI_FW_ASSOC_STATE;24202421rtw_ap_parse_sta_capability(adapter, sta, plink->rx_conf_ies);24222423if (rtw_ap_parse_sta_supported_rates(adapter, sta, tlv_ies, tlv_ieslen) != _STATS_SUCCESSFUL_)2424goto exit;24252426if (rtw_ap_parse_sta_security_ie(adapter, sta, &elems) != _STATS_SUCCESSFUL_)2427goto exit;24282429rtw_ap_parse_sta_wmm_ie(adapter, sta, tlv_ies, tlv_ieslen);2430#ifdef CONFIG_RTS_FULL_BW2431/*check vendor IE*/2432rtw_parse_sta_vendor_ie_8812(adapter, sta, tlv_ies, tlv_ieslen);2433#endif/*CONFIG_RTS_FULL_BW*/24342435rtw_ap_parse_sta_ht_ie(adapter, sta, &elems);2436rtw_ap_parse_sta_vht_ie(adapter, sta, &elems);24372438/* AID */2439#ifdef CONFIG_RTW_MESH_DRIVER_AID2440sta->cmn.aid = RTW_GET_LE16(plink->tx_conf_ies + 2);2441#else2442sta->cmn.aid = plink->aid;2443#endif2444stapriv->sta_aid[sta->cmn.aid - 1] = sta;2445RTW_INFO(FUNC_ADPT_FMT" sta "MAC_FMT" aid:%u\n"2446, FUNC_ADPT_ARG(adapter), MAC_ARG(sta->cmn.mac_addr), sta->cmn.aid);24472448sta->state &= (~WIFI_FW_ASSOC_STATE);2449sta->state |= WIFI_FW_ASSOC_SUCCESS;24502451sta->local_mps = RTW_MESH_PS_ACTIVE;24522453rtw_ewma_err_rate_init(&sta->metrics.err_rate);2454rtw_ewma_err_rate_add(&sta->metrics.err_rate, 1);2455/* init data_rate to 1M */2456sta->metrics.data_rate = 10;2457sta->alive = _TRUE;24582459_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);2460if (rtw_is_list_empty(&sta->asoc_list)) {2461STA_SET_MESH_PLINK(sta, plink);2462/* TBD: up layer timeout mechanism */2463/* sta->expire_to = mcfg->plink_timeout / 2; */2464rtw_list_insert_tail(&sta->asoc_list, &stapriv->asoc_list);2465stapriv->asoc_list_cnt++;2466}2467_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);24682469bss_cap_update_on_sta_join(adapter, sta);2470sta_info_update(adapter, sta);2471report_add_sta_event(adapter, sta->cmn.mac_addr);24722473ret = _SUCCESS;24742475exit:2476return ret;2477}24782479void rtw_mesh_expire_peer_notify(_adapter *adapter, const u8 *peer_addr)2480{2481u8 null_ssid[2] = {0, 0};24822483#ifdef CONFIG_IOCTL_CFG802112484rtw_cfg80211_notify_new_peer_candidate(adapter->rtw_wdev2485, peer_addr2486, null_ssid2487, 22488, GFP_ATOMIC2489);2490#endif24912492return;2493}24942495static u8 *rtw_mesh_construct_peer_mesh_close(_adapter *adapter, struct mesh_plink_ent *plink, u16 reason, u32 *len)2496{2497struct rtw_mesh_info *minfo = &adapter->mesh_info;2498u8 *frame = NULL, *pos;2499u32 flen;2500struct rtw_ieee80211_hdr *whdr;25012502if (minfo->mesh_auth_id && !MESH_PLINK_AEK_VALID(plink))2503goto exit;25042505flen = sizeof(struct rtw_ieee80211_hdr_3addr)2506+ 2 /* category, action */2507+ 2 + minfo->mesh_id_len /* mesh id */2508+ 2 + 8 + (minfo->mesh_auth_id ? 16 : 0) /* mpm */2509+ (minfo->mesh_auth_id ? 2 + AES_BLOCK_SIZE : 0) /* mic */2510+ (minfo->mesh_auth_id ? 70 : 0) /* ampe */2511;25122513pos = frame = rtw_zmalloc(flen);2514if (!frame)2515goto exit;25162517whdr = (struct rtw_ieee80211_hdr *)frame;2518_rtw_memcpy(whdr->addr1, adapter_mac_addr(adapter), ETH_ALEN);2519_rtw_memcpy(whdr->addr2, plink->addr, ETH_ALEN);2520_rtw_memcpy(whdr->addr3, adapter_mac_addr(adapter), ETH_ALEN);25212522set_frame_sub_type(frame, WIFI_ACTION);25232524pos += sizeof(struct rtw_ieee80211_hdr_3addr);2525*(pos++) = RTW_WLAN_CATEGORY_SELF_PROTECTED;2526*(pos++) = RTW_ACT_SELF_PROTECTED_MESH_CLOSE;25272528pos = rtw_set_ie_mesh_id(pos, NULL, minfo->mesh_id, minfo->mesh_id_len);25292530pos = rtw_set_ie_mpm(pos, NULL2531, minfo->mesh_auth_id ? 1 : 02532, plink->plid2533, &plink->llid2534, &reason2535, minfo->mesh_auth_id ? plink->chosen_pmk : NULL);25362537#ifdef CONFIG_RTW_MESH_AEK2538if (minfo->mesh_auth_id) {2539u8 ampe_buf[70];2540int enc_ret;25412542*pos = WLAN_EID_MIC;2543*(pos + 1) = AES_BLOCK_SIZE;25442545ampe_buf[0] = WLAN_EID_AMPE;2546ampe_buf[1] = 68;2547_rtw_memcpy(ampe_buf + 2, plink->sel_pcs, 4);2548_rtw_memcpy(ampe_buf + 6, plink->p_nonce, 32);2549_rtw_memcpy(ampe_buf + 38, plink->l_nonce, 32);25502551enc_ret = rtw_mpm_ampe_enc(adapter, plink2552, frame + sizeof(struct rtw_ieee80211_hdr_3addr)2553, pos, ampe_buf, 1);2554if (enc_ret != _SUCCESS) {2555rtw_mfree(frame, flen);2556frame = NULL;2557goto exit;2558}2559}2560#endif25612562*len = flen;25632564exit:2565return frame;2566}25672568void _rtw_mesh_expire_peer_ent(_adapter *adapter, struct mesh_plink_ent *plink)2569{2570#if defined(CONFIG_RTW_MESH_STA_DEL_DISASOC)2571_rtw_mesh_plink_del_ent(adapter, plink);2572rtw_cfg80211_indicate_sta_disassoc(adapter, plink->addr, 0);2573#else2574u8 *frame = NULL;2575u32 flen;25762577if (plink->plink_state == RTW_MESH_PLINK_ESTAB)2578frame = rtw_mesh_construct_peer_mesh_close(adapter, plink, WLAN_REASON_MESH_CLOSE, &flen);25792580if (frame) {2581struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;2582struct wireless_dev *wdev = adapter->rtw_wdev;2583s32 freq = rtw_ch2freq(mlmeext->cur_channel);25842585#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)2586rtw_cfg80211_rx_mgmt(wdev, freq, 0, frame, flen, GFP_ATOMIC);2587#else2588cfg80211_rx_action(adapter->pnetdev, freq, frame, flen, GFP_ATOMIC);2589#endif25902591rtw_mfree(frame, flen);2592} else {2593rtw_mesh_expire_peer_notify(adapter, plink->addr);2594RTW_INFO(FUNC_ADPT_FMT" set "MAC_FMT" plink unknown\n"2595, FUNC_ADPT_ARG(adapter), MAC_ARG(plink->addr));2596plink->plink_state = RTW_MESH_PLINK_UNKNOWN;2597}2598#endif2599}26002601void rtw_mesh_expire_peer(_adapter *adapter, const u8 *peer_addr)2602{2603struct rtw_mesh_info *minfo = &adapter->mesh_info;2604struct mesh_plink_pool *plink_ctl = &minfo->plink_ctl;2605struct mesh_plink_ent *plink;2606_irqL irqL;26072608_enter_critical_bh(&(plink_ctl->lock), &irqL);26092610plink = _rtw_mesh_plink_get(adapter, peer_addr);2611if (!plink)2612goto exit;26132614_rtw_mesh_expire_peer_ent(adapter, plink);26152616exit:2617_exit_critical_bh(&(plink_ctl->lock), &irqL);2618}26192620u8 rtw_mesh_ps_annc(_adapter *adapter, u8 ps)2621{2622_irqL irqL;2623_list *head, *list;2624struct sta_info *sta;2625struct sta_priv *stapriv = &adapter->stapriv;2626u8 sta_alive_num = 0, i;2627char sta_alive_list[NUM_STA];2628u8 annc_cnt = 0;26292630if (rtw_linked_check(adapter) == _FALSE)2631goto exit;26322633_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);26342635head = &stapriv->asoc_list;2636list = get_next(head);2637while ((rtw_end_of_queue_search(head, list)) == _FALSE) {2638int stainfo_offset;26392640sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);2641list = get_next(list);26422643stainfo_offset = rtw_stainfo_offset(stapriv, sta);2644if (stainfo_offset_valid(stainfo_offset))2645sta_alive_list[sta_alive_num++] = stainfo_offset;2646}2647_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);26482649for (i = 0; i < sta_alive_num; i++) {2650sta = rtw_get_stainfo_by_offset(stapriv, sta_alive_list[i]);2651if (!sta)2652continue;26532654issue_qos_nulldata(adapter, sta->cmn.mac_addr, 7, ps, 3, 500);2655annc_cnt++;2656}26572658exit:2659return annc_cnt;2660}26612662static void mpath_tx_tasklet_hdl(void *priv)2663{2664_adapter *adapter = (_adapter *)priv;2665struct rtw_mesh_info *minfo = &adapter->mesh_info;2666struct xmit_frame *xframe;2667_list *list, *head;2668_list tmp;2669u32 tmp_len;2670s32 res;26712672_rtw_init_listhead(&tmp);26732674while (1) {2675tmp_len = 0;2676enter_critical_bh(&minfo->mpath_tx_queue.lock);2677if (minfo->mpath_tx_queue_len) {2678rtw_list_splice_init(&minfo->mpath_tx_queue.queue, &tmp);2679tmp_len = minfo->mpath_tx_queue_len;2680minfo->mpath_tx_queue_len = 0;2681}2682exit_critical_bh(&minfo->mpath_tx_queue.lock);26832684if (!tmp_len)2685break;26862687head = &tmp;2688list = get_next(head);2689while (rtw_end_of_queue_search(head, list) == _FALSE) {2690xframe = LIST_CONTAINOR(list, struct xmit_frame, list);2691list = get_next(list);2692rtw_list_delete(&xframe->list);2693res = rtw_xmit_posthandle(adapter, xframe, xframe->pkt);2694if (res < 0) {2695#ifdef DBG_TX_DROP_FRAME2696RTW_INFO("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __FUNCTION__);2697#endif2698adapter->xmitpriv.tx_drop++;2699}2700}2701}2702}27032704static void rtw_mpath_tx_queue_flush(_adapter *adapter)2705{2706struct rtw_mesh_info *minfo = &adapter->mesh_info;2707struct xmit_frame *xframe;2708_list *list, *head;2709_list tmp;27102711_rtw_init_listhead(&tmp);27122713enter_critical_bh(&minfo->mpath_tx_queue.lock);2714rtw_list_splice_init(&minfo->mpath_tx_queue.queue, &tmp);2715minfo->mpath_tx_queue_len = 0;2716exit_critical_bh(&minfo->mpath_tx_queue.lock);27172718head = &tmp;2719list = get_next(head);2720while (rtw_end_of_queue_search(head, list) == _FALSE) {2721xframe = LIST_CONTAINOR(list, struct xmit_frame, list);2722list = get_next(list);2723rtw_list_delete(&xframe->list);2724rtw_free_xmitframe(&adapter->xmitpriv, xframe);2725}2726}27272728#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */2729#if defined(CONFIG_SLUB)2730#include <linux/slub_def.h>2731#elif defined(CONFIG_SLAB)2732#include <linux/slab_def.h>2733#endif2734typedef struct kmem_cache rtw_mcache;2735#endif27362737rtw_mcache *rtw_mcache_create(const char *name, size_t size)2738{2739#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */2740return kmem_cache_create(name, size, 0, 0, NULL);2741#else2742#error "TBD\n";2743#endif2744}27452746void rtw_mcache_destroy(rtw_mcache *s)2747{2748#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */2749kmem_cache_destroy(s);2750#else2751#error "TBD\n";2752#endif2753}27542755void *_rtw_mcache_alloc(rtw_mcache *cachep)2756{2757#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */2758return kmem_cache_alloc(cachep, GFP_ATOMIC);2759#else2760#error "TBD\n";2761#endif2762}27632764void _rtw_mcache_free(rtw_mcache *cachep, void *objp)2765{2766#ifdef PLATFORM_LINUX /* 3.10 ~ 4.13 checked */2767kmem_cache_free(cachep, objp);2768#else2769#error "TBD\n";2770#endif2771}27722773#ifdef DBG_MEM_ALLOC2774inline void *dbg_rtw_mcache_alloc(rtw_mcache *cachep, const enum mstat_f flags, const char *func, const int line)2775{2776void *p;2777u32 sz = cachep->size;27782779if (match_mstat_sniff_rules(flags, sz))2780RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%u)\n", func, line, __func__, sz);27812782p = _rtw_mcache_alloc(cachep);27832784rtw_mstat_update(2785flags2786, p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL2787, sz2788);27892790return p;2791}27922793inline void dbg_rtw_mcache_free(rtw_mcache *cachep, void *pbuf, const enum mstat_f flags, const char *func, const int line)2794{2795u32 sz = cachep->size;27962797if (match_mstat_sniff_rules(flags, sz))2798RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%u)\n", func, line, __func__, sz);27992800_rtw_mcache_free(cachep, pbuf);28012802rtw_mstat_update(2803flags2804, MSTAT_FREE2805, sz2806);2807}28082809#define rtw_mcache_alloc(cachep) dbg_rtw_mcache_alloc(cachep, MSTAT_TYPE_PHY, __FUNCTION__, __LINE__)2810#define rtw_mcache_free(cachep, objp) dbg_rtw_mcache_free(cachep, objp, MSTAT_TYPE_PHY, __FUNCTION__, __LINE__)2811#else2812#define rtw_mcache_alloc(cachep) _rtw_mcache_alloc(cachep)2813#define rtw_mcache_free(cachep, objp) _rtw_mcache_free(cachep, objp)2814#endif /* DBG_MEM_ALLOC */28152816/* Mesh Received Cache */2817#define RTW_MRC_BUCKETS 256 /* must be a power of 2 */2818#define RTW_MRC_QUEUE_MAX_LEN 42819#define RTW_MRC_TIMEOUT_MS (3 * 1000)28202821/**2822* struct rtw_mrc_entry - entry in the Mesh Received Cache2823*2824* @seqnum: mesh sequence number of the frame2825* @exp_time: expiration time of the entry2826* @msa: mesh source address of the frame2827* @list: hashtable list pointer2828*2829* The Mesh Received Cache keeps track of the latest received frames that2830* have been received by a mesh interface and discards received frames2831* that are found in the cache.2832*/2833struct rtw_mrc_entry {2834rtw_hlist_node list;2835systime exp_time;2836u32 seqnum;2837u8 msa[ETH_ALEN];2838};28392840struct rtw_mrc {2841rtw_hlist_head bucket[RTW_MRC_BUCKETS];2842u32 idx_mask;2843rtw_mcache *cache;2844};28452846static int rtw_mrc_init(_adapter *adapter)2847{2848struct rtw_mesh_info *minfo = &adapter->mesh_info;2849char cache_name[IFNAMSIZ + 8 + 1];2850int i;28512852minfo->mrc = rtw_malloc(sizeof(struct rtw_mrc));2853if (!minfo->mrc)2854return -ENOMEM;2855minfo->mrc->idx_mask = RTW_MRC_BUCKETS - 1;2856for (i = 0; i < RTW_MRC_BUCKETS; i++)2857rtw_hlist_head_init(&minfo->mrc->bucket[i]);28582859sprintf(cache_name, "rtw_mrc_%s", ADPT_ARG(adapter));2860minfo->mrc->cache = rtw_mcache_create(cache_name, sizeof(struct rtw_mrc_entry));28612862return 0;2863}28642865static void rtw_mrc_free(_adapter *adapter)2866{2867struct rtw_mesh_info *minfo = &adapter->mesh_info;2868struct rtw_mrc *mrc = minfo->mrc;2869struct rtw_mrc_entry *p;2870rtw_hlist_node *np, *n;2871int i;28722873if (!mrc)2874return;28752876for (i = 0; i < RTW_MRC_BUCKETS; i++) {2877rtw_hlist_for_each_entry_safe(p, np, n, &mrc->bucket[i], list) {2878rtw_hlist_del(&p->list);2879rtw_mcache_free(mrc->cache, p);2880}2881}28822883rtw_mcache_destroy(mrc->cache);28842885rtw_mfree(mrc, sizeof(struct rtw_mrc));2886minfo->mrc = NULL;2887}28882889/**2890* rtw_mrc_check - Check frame in mesh received cache and add if absent.2891*2892* @adapter: interface2893* @msa: mesh source address2894* @seq: mesh seq number2895*2896* Returns: 0 if the frame is not in the cache, nonzero otherwise.2897*2898* Checks using the mesh source address and the mesh sequence number if we have2899* received this frame lately. If the frame is not in the cache, it is added to2900* it.2901*/2902static int rtw_mrc_check(_adapter *adapter, const u8 *msa, u32 seq)2903{2904struct rtw_mesh_info *minfo = &adapter->mesh_info;2905struct rtw_mrc *mrc = minfo->mrc;2906int entries = 0;2907u8 idx;2908struct rtw_mrc_entry *p;2909rtw_hlist_node *np, *n;2910u8 timeout;29112912if (!mrc)2913return -1;29142915idx = seq & mrc->idx_mask;2916rtw_hlist_for_each_entry_safe(p, np, n, &mrc->bucket[idx], list) {2917++entries;2918timeout = rtw_time_after(rtw_get_current_time(), p->exp_time);2919if (timeout || entries == RTW_MRC_QUEUE_MAX_LEN) {2920if (!timeout)2921minfo->mshstats.mrc_del_qlen++;29222923rtw_hlist_del(&p->list);2924rtw_mcache_free(mrc->cache, p);2925--entries;2926} else if ((seq == p->seqnum) && _rtw_memcmp(msa, p->msa, ETH_ALEN) == _TRUE)2927return -1;2928}29292930p = rtw_mcache_alloc(mrc->cache);2931if (!p)2932return 0;29332934p->seqnum = seq;2935p->exp_time = rtw_get_current_time() + rtw_ms_to_systime(RTW_MRC_TIMEOUT_MS);2936_rtw_memcpy(p->msa, msa, ETH_ALEN);2937rtw_hlist_add_head(&p->list, &mrc->bucket[idx]);2938return 0;2939}29402941static int rtw_mesh_decache(_adapter *adapter, const u8 *msa, u32 seq)2942{2943return rtw_mrc_check(adapter, msa, seq);2944}29452946#ifndef RTW_MESH_SCAN_RESULT_EXP_MS2947#define RTW_MESH_SCAN_RESULT_EXP_MS (10 * 1000)2948#endif29492950#ifndef RTW_MESH_ACNODE_PREVENT2951#define RTW_MESH_ACNODE_PREVENT 02952#endif2953#ifndef RTW_MESH_ACNODE_CONF_TIMEOUT_MS2954#define RTW_MESH_ACNODE_CONF_TIMEOUT_MS (20 * 1000)2955#endif2956#ifndef RTW_MESH_ACNODE_NOTIFY_TIMEOUT_MS2957#define RTW_MESH_ACNODE_NOTIFY_TIMEOUT_MS (2 * 1000)2958#endif29592960#ifndef RTW_MESH_OFFCH_CAND2961#define RTW_MESH_OFFCH_CAND 12962#endif2963#ifndef RTW_MESH_OFFCH_CAND_FIND_INT_MS2964#define RTW_MESH_OFFCH_CAND_FIND_INT_MS (10 * 1000)2965#endif29662967#ifndef RTW_MESH_PEER_CONF_TIMEOUT_MS2968#define RTW_MESH_PEER_CONF_TIMEOUT_MS (20 * 1000)2969#endif2970#ifndef RTW_MESH_PEER_BLACKLIST_TIMEOUT_MS2971#define RTW_MESH_PEER_BLACKLIST_TIMEOUT_MS (20 * 1000)2972#endif29732974#ifndef RTW_MESH_CTO_MGATE_REQUIRE2975#define RTW_MESH_CTO_MGATE_REQUIRE 02976#endif2977#ifndef RTW_MESH_CTO_MGATE_CONF_TIMEOUT_MS2978#define RTW_MESH_CTO_MGATE_CONF_TIMEOUT_MS (20 * 1000)2979#endif2980#ifndef RTW_MESH_CTO_MGATE_BLACKLIST_TIMEOUT_MS2981#define RTW_MESH_CTO_MGATE_BLACKLIST_TIMEOUT_MS (20 * 1000)2982#endif29832984void rtw_mesh_cfg_init_peer_sel_policy(struct rtw_mesh_cfg *mcfg)2985{2986struct mesh_peer_sel_policy *sel_policy = &mcfg->peer_sel_policy;29872988sel_policy->scanr_exp_ms = RTW_MESH_SCAN_RESULT_EXP_MS;29892990#if CONFIG_RTW_MESH_ACNODE_PREVENT2991sel_policy->acnode_prevent = RTW_MESH_ACNODE_PREVENT;2992sel_policy->acnode_conf_timeout_ms = RTW_MESH_ACNODE_CONF_TIMEOUT_MS;2993sel_policy->acnode_notify_timeout_ms = RTW_MESH_ACNODE_NOTIFY_TIMEOUT_MS;2994#endif29952996#if CONFIG_RTW_MESH_OFFCH_CAND2997sel_policy->offch_cand = RTW_MESH_OFFCH_CAND;2998sel_policy->offch_find_int_ms = RTW_MESH_OFFCH_CAND_FIND_INT_MS;2999#endif30003001#if CONFIG_RTW_MESH_PEER_BLACKLIST3002sel_policy->peer_conf_timeout_ms = RTW_MESH_PEER_CONF_TIMEOUT_MS;3003sel_policy->peer_blacklist_timeout_ms = RTW_MESH_PEER_BLACKLIST_TIMEOUT_MS;3004#endif30053006#if CONFIG_RTW_MESH_CTO_MGATE_BLACKLIST3007sel_policy->cto_mgate_require = RTW_MESH_CTO_MGATE_REQUIRE;3008sel_policy->cto_mgate_conf_timeout_ms = RTW_MESH_CTO_MGATE_CONF_TIMEOUT_MS;3009sel_policy->cto_mgate_blacklist_timeout_ms = RTW_MESH_CTO_MGATE_BLACKLIST_TIMEOUT_MS;3010#endif3011}30123013void rtw_mesh_cfg_init(_adapter *adapter)3014{3015struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;30163017mcfg->max_peer_links = RTW_MESH_MAX_PEER_LINKS;3018mcfg->plink_timeout = RTW_MESH_PEER_LINK_TIMEOUT;30193020mcfg->dot11MeshTTL = RTW_MESH_TTL;3021mcfg->element_ttl = RTW_MESH_DEFAULT_ELEMENT_TTL;3022mcfg->dot11MeshHWMPmaxPREQretries = RTW_MESH_MAX_PREQ_RETRIES;3023mcfg->path_refresh_time = RTW_MESH_PATH_REFRESH_TIME;3024mcfg->min_discovery_timeout = RTW_MESH_MIN_DISCOVERY_TIMEOUT;3025mcfg->dot11MeshHWMPactivePathTimeout = RTW_MESH_PATH_TIMEOUT;3026mcfg->dot11MeshHWMPpreqMinInterval = RTW_MESH_PREQ_MIN_INT;3027mcfg->dot11MeshHWMPperrMinInterval = RTW_MESH_PERR_MIN_INT;3028mcfg->dot11MeshHWMPnetDiameterTraversalTime = RTW_MESH_DIAM_TRAVERSAL_TIME;3029mcfg->dot11MeshHWMPRootMode = RTW_IEEE80211_ROOTMODE_NO_ROOT;3030mcfg->dot11MeshHWMPRannInterval = RTW_MESH_RANN_INTERVAL;3031mcfg->dot11MeshGateAnnouncementProtocol = _FALSE;3032mcfg->dot11MeshForwarding = _TRUE;3033mcfg->rssi_threshold = 0;3034mcfg->dot11MeshHWMPactivePathToRootTimeout = RTW_MESH_PATH_TO_ROOT_TIMEOUT;3035mcfg->dot11MeshHWMProotInterval = RTW_MESH_ROOT_INTERVAL;3036mcfg->dot11MeshHWMPconfirmationInterval = RTW_MESH_ROOT_CONFIRMATION_INTERVAL;3037mcfg->path_gate_timeout_factor = 3;3038rtw_mesh_cfg_init_peer_sel_policy(mcfg);3039#ifdef CONFIG_RTW_MESH_ADD_ROOT_CHK3040mcfg->sane_metric_delta = RTW_MESH_SANE_METRIC_DELTA;3041mcfg->max_root_add_chk_cnt = RTW_MESH_MAX_ROOT_ADD_CHK_CNT;3042#endif30433044#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3045mcfg->b2u_flags_msrc = 0;3046mcfg->b2u_flags_mfwd = RTW_MESH_B2U_GA_UCAST;3047#endif3048}30493050void rtw_mesh_cfg_init_max_peer_links(_adapter *adapter, u8 stack_conf)3051{3052struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;30533054mcfg->max_peer_links = RTW_MESH_MAX_PEER_LINKS;30553056if (mcfg->max_peer_links > stack_conf)3057mcfg->max_peer_links = stack_conf;3058}30593060void rtw_mesh_cfg_init_plink_timeout(_adapter *adapter, u32 stack_conf)3061{3062struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;30633064mcfg->plink_timeout = stack_conf;3065}30663067void rtw_mesh_init_mesh_info(_adapter *adapter)3068{3069struct rtw_mesh_info *minfo = &adapter->mesh_info;30703071_rtw_memset(minfo, 0, sizeof(struct rtw_mesh_info));30723073rtw_mesh_plink_ctl_init(adapter);30743075minfo->last_preq = rtw_get_current_time();3076/* minfo->last_sn_update = rtw_get_current_time(); */3077minfo->next_perr = rtw_get_current_time();30783079ATOMIC_SET(&minfo->mpaths, 0);3080rtw_mesh_pathtbl_init(adapter);30813082_rtw_init_queue(&minfo->mpath_tx_queue);3083tasklet_init(&minfo->mpath_tx_tasklet3084, (void(*))mpath_tx_tasklet_hdl3085, (unsigned long)adapter);30863087rtw_mrc_init(adapter);30883089_rtw_init_listhead(&minfo->preq_queue.list);3090_rtw_spinlock_init(&minfo->mesh_preq_queue_lock);30913092rtw_init_timer(&adapter->mesh_path_timer, adapter, rtw_ieee80211_mesh_path_timer, adapter);3093rtw_init_timer(&adapter->mesh_path_root_timer, adapter, rtw_ieee80211_mesh_path_root_timer, adapter);3094rtw_init_timer(&adapter->mesh_atlm_param_req_timer, adapter, rtw_mesh_atlm_param_req_timer, adapter);3095_init_workitem(&adapter->mesh_work, rtw_mesh_work_hdl, NULL);3096}30973098void rtw_mesh_deinit_mesh_info(_adapter *adapter)3099{3100struct rtw_mesh_info *minfo = &adapter->mesh_info;31013102tasklet_kill(&minfo->mpath_tx_tasklet);3103rtw_mpath_tx_queue_flush(adapter);3104_rtw_deinit_queue(&adapter->mesh_info.mpath_tx_queue);31053106rtw_mrc_free(adapter);31073108rtw_mesh_pathtbl_unregister(adapter);31093110rtw_mesh_plink_ctl_deinit(adapter);31113112_cancel_workitem_sync(&adapter->mesh_work);3113_cancel_timer_ex(&adapter->mesh_path_timer);3114_cancel_timer_ex(&adapter->mesh_path_root_timer);3115_cancel_timer_ex(&adapter->mesh_atlm_param_req_timer);3116}31173118/**3119* rtw_mesh_nexthop_resolve - lookup next hop; conditionally start path discovery3120*3121* @skb: 802.11 frame to be sent3122* @sdata: network subif the frame will be sent through3123*3124* Lookup next hop for given skb and start path discovery if no3125* forwarding information is found.3126*3127* Returns: 0 if the next hop was found and -ENOENT if the frame was queued.3128* skb is freeed here if no mpath could be allocated.3129*/3130int rtw_mesh_nexthop_resolve(_adapter *adapter,3131struct xmit_frame *xframe)3132{3133struct pkt_attrib *attrib = &xframe->attrib;3134struct rtw_mesh_path *mpath;3135struct xmit_frame *xframe_to_free = NULL;3136u8 *target_addr = attrib->mda;3137int err = 0;3138int ret = _SUCCESS;31393140rtw_rcu_read_lock();3141err = rtw_mesh_nexthop_lookup(adapter, target_addr, attrib->msa, attrib->ra);3142if (!err)3143goto endlookup;31443145/* no nexthop found, start resolving */3146mpath = rtw_mesh_path_lookup(adapter, target_addr);3147if (!mpath) {3148mpath = rtw_mesh_path_add(adapter, target_addr);3149if (IS_ERR(mpath)) {3150xframe->pkt = NULL; /* free pkt outside */3151rtw_mesh_path_discard_frame(adapter, xframe);3152err = PTR_ERR(mpath);3153ret = _FAIL;3154goto endlookup;3155}3156}31573158if (!(mpath->flags & RTW_MESH_PATH_RESOLVING))3159rtw_mesh_queue_preq(mpath, RTW_PREQ_Q_F_START);31603161enter_critical_bh(&mpath->frame_queue.lock);31623163if (mpath->frame_queue_len >= RTW_MESH_FRAME_QUEUE_LEN) {3164xframe_to_free = LIST_CONTAINOR(get_next(get_list_head(&mpath->frame_queue)), struct xmit_frame, list);3165rtw_list_delete(&(xframe_to_free->list));3166mpath->frame_queue_len--;3167}31683169rtw_list_insert_tail(&xframe->list, get_list_head(&mpath->frame_queue));3170mpath->frame_queue_len++;31713172exit_critical_bh(&mpath->frame_queue.lock);31733174ret = RTW_RA_RESOLVING;3175if (xframe_to_free)3176rtw_mesh_path_discard_frame(adapter, xframe_to_free);31773178endlookup:3179rtw_rcu_read_unlock();3180return ret;3181}31823183/**3184* rtw_mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling3185* this function is considered "using" the associated mpath, so preempt a path3186* refresh if this mpath expires soon.3187*3188* @skb: 802.11 frame to be sent3189* @sdata: network subif the frame will be sent through3190*3191* Returns: 0 if the next hop was found. Nonzero otherwise.3192*/3193int rtw_mesh_nexthop_lookup(_adapter *adapter,3194const u8 *mda, const u8 *msa, u8 *ra)3195{3196struct rtw_mesh_path *mpath;3197struct sta_info *next_hop;3198const u8 *target_addr = mda;3199int err = -ENOENT;3200struct registry_priv *registry_par = &adapter->registrypriv;3201u8 peer_alive_based_preq = registry_par->peer_alive_based_preq;3202BOOLEAN nexthop_alive = _TRUE;32033204rtw_rcu_read_lock();3205mpath = rtw_mesh_path_lookup(adapter, target_addr);32063207if (!mpath || !(mpath->flags & RTW_MESH_PATH_ACTIVE))3208goto endlookup;32093210next_hop = rtw_rcu_dereference(mpath->next_hop);3211if (next_hop) {3212_rtw_memcpy(ra, next_hop->cmn.mac_addr, ETH_ALEN);3213err = 0;3214}32153216if (peer_alive_based_preq && next_hop)3217nexthop_alive = next_hop->alive;32183219if (_rtw_memcmp(adapter_mac_addr(adapter), msa, ETH_ALEN) == _TRUE &&3220!(mpath->flags & RTW_MESH_PATH_RESOLVING) &&3221!(mpath->flags & RTW_MESH_PATH_FIXED)) {3222u8 flags = RTW_PREQ_Q_F_START | RTW_PREQ_Q_F_REFRESH;32233224if (peer_alive_based_preq && nexthop_alive == _FALSE) {3225flags |= RTW_PREQ_Q_F_BCAST_PREQ;3226rtw_mesh_queue_preq(mpath, flags);3227} else if (rtw_time_after(rtw_get_current_time(),3228mpath->exp_time -3229rtw_ms_to_systime(adapter->mesh_cfg.path_refresh_time))) {3230rtw_mesh_queue_preq(mpath, flags);3231}3232/* Avoid keeping trying unicast PREQ toward root,3233when next_hop leaves */3234} else if (peer_alive_based_preq &&3235_rtw_memcmp(adapter_mac_addr(adapter), msa, ETH_ALEN) == _TRUE &&3236(mpath->flags & RTW_MESH_PATH_RESOLVING) &&3237!(mpath->flags & RTW_MESH_PATH_FIXED) &&3238!(mpath->flags & RTW_MESH_PATH_BCAST_PREQ) &&3239mpath->is_root && nexthop_alive == _FALSE) {3240enter_critical_bh(&mpath->state_lock);3241mpath->flags |= RTW_MESH_PATH_BCAST_PREQ;3242exit_critical_bh(&mpath->state_lock);3243}32443245endlookup:3246rtw_rcu_read_unlock();3247return err;3248}32493250#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3251static bool rtw_mesh_data_bmc_to_uc(_adapter *adapter3252, const u8 *da, const u8 *sa, const u8 *mda, const u8 *msa3253, u8 ae_need, const u8 *ori_ta, u8 mfwd_ttl3254, _list *b2u_list, u8 *b2u_num, u32 *b2u_mseq)3255{3256struct sta_priv *stapriv = &adapter->stapriv;3257struct xmit_priv *xmitpriv = &adapter->xmitpriv;3258_irqL irqL;3259_list *head, *list;3260struct sta_info *sta;3261char b2u_sta_id[NUM_STA];3262u8 b2u_sta_num = 0;3263bool bmc_need = _FALSE;3264int i;32653266_enter_critical_bh(&stapriv->asoc_list_lock, &irqL);3267head = &stapriv->asoc_list;3268list = get_next(head);32693270while ((rtw_end_of_queue_search(head, list)) == _FALSE) {3271int stainfo_offset;32723273sta = LIST_CONTAINOR(list, struct sta_info, asoc_list);3274list = get_next(list);32753276stainfo_offset = rtw_stainfo_offset(stapriv, sta);3277if (stainfo_offset_valid(stainfo_offset))3278b2u_sta_id[b2u_sta_num++] = stainfo_offset;3279}3280_exit_critical_bh(&stapriv->asoc_list_lock, &irqL);32813282if (!b2u_sta_num)3283goto exit;32843285for (i = 0; i < b2u_sta_num; i++) {3286struct xmit_frame *b2uframe;3287struct pkt_attrib *attrib;32883289sta = rtw_get_stainfo_by_offset(stapriv, b2u_sta_id[i]);3290if (!(sta->state & _FW_LINKED)3291|| _rtw_memcmp(sta->cmn.mac_addr, msa, ETH_ALEN) == _TRUE3292|| (ori_ta && _rtw_memcmp(sta->cmn.mac_addr, ori_ta, ETH_ALEN) == _TRUE)3293|| is_broadcast_mac_addr(sta->cmn.mac_addr)3294|| is_zero_mac_addr(sta->cmn.mac_addr))3295continue;32963297b2uframe = rtw_alloc_xmitframe(xmitpriv);3298if (!b2uframe) {3299bmc_need = _TRUE;3300break;3301}33023303if ((*b2u_num)++ == 0 && !ori_ta) {3304*b2u_mseq = (cpu_to_le32(adapter->mesh_info.mesh_seqnum));3305adapter->mesh_info.mesh_seqnum++;3306}33073308attrib = &b2uframe->attrib;33093310attrib->mb2u = 1;3311attrib->mseq = *b2u_mseq;3312attrib->mfwd_ttl = ori_ta ? mfwd_ttl : 0;3313_rtw_memcpy(attrib->ra, sta->cmn.mac_addr, ETH_ALEN);3314_rtw_memcpy(attrib->ta, adapter_mac_addr(adapter), ETH_ALEN);3315_rtw_memcpy(attrib->mda, mda, ETH_ALEN);3316_rtw_memcpy(attrib->msa, msa, ETH_ALEN);3317_rtw_memcpy(attrib->dst, da, ETH_ALEN);3318_rtw_memcpy(attrib->src, sa, ETH_ALEN);3319attrib->mesh_frame_mode = ae_need ? MESH_UCAST_PX_DATA : MESH_UCAST_DATA;33203321rtw_list_insert_tail(&b2uframe->list, b2u_list);3322}33233324exit:3325return bmc_need;3326}33273328void dump_mesh_b2u_flags(void *sel, _adapter *adapter)3329{3330struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;33313332RTW_PRINT_SEL(sel, "%4s %4s\n", "msrc", "mfwd");3333RTW_PRINT_SEL(sel, "0x%02x 0x%02x\n", mcfg->b2u_flags_msrc, mcfg->b2u_flags_mfwd);3334}3335#endif /* CONFIG_RTW_MESH_DATA_BMC_TO_UC */33363337int rtw_mesh_addr_resolve(_adapter *adapter, struct xmit_frame *xframe, _pkt *pkt, _list *b2u_list)3338{3339struct pkt_file pktfile;3340struct ethhdr etherhdr;3341struct pkt_attrib *attrib;3342struct rtw_mesh_path *mpath = NULL, *mppath = NULL;3343u8 is_da_mcast;3344u8 ae_need;3345#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3346bool bmc_need = _TRUE;3347u8 b2u_num = 0;3348u32 b2u_mseq = 0;3349#endif3350int res = _SUCCESS;33513352_rtw_open_pktfile(pkt, &pktfile);3353if (_rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN) != ETH_HLEN) {3354res = _FAIL;3355goto exit;3356}33573358xframe->pkt = pkt;3359#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3360_rtw_init_listhead(b2u_list);3361#endif33623363is_da_mcast = IS_MCAST(etherhdr.h_dest);3364if (!is_da_mcast) {3365struct sta_info *next_hop;3366bool mpp_lookup = 1;33673368mpath = rtw_mesh_path_lookup(adapter, etherhdr.h_dest);3369if (mpath) {3370mpp_lookup = 0;3371next_hop = rtw_rcu_dereference(mpath->next_hop);3372if (!next_hop3373|| !(mpath->flags & (RTW_MESH_PATH_ACTIVE | RTW_MESH_PATH_RESOLVING))3374) {3375/* mpath is not valid, search mppath */3376mpp_lookup = 1;3377}3378}33793380if (mpp_lookup) {3381mppath = rtw_mpp_path_lookup(adapter, etherhdr.h_dest);3382if (mppath)3383mppath->exp_time = rtw_get_current_time();3384}33853386if (mppath && mpath)3387rtw_mesh_path_del(adapter, mpath->dst);33883389ae_need = _rtw_memcmp(adapter_mac_addr(adapter), etherhdr.h_source, ETH_ALEN) == _FALSE3390|| (mppath && _rtw_memcmp(mppath->mpp, etherhdr.h_dest, ETH_ALEN) == _FALSE);3391} else {3392ae_need = _rtw_memcmp(adapter_mac_addr(adapter), etherhdr.h_source, ETH_ALEN) == _FALSE;33933394#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3395if (rtw_msrc_b2u_policy_chk(adapter->mesh_cfg.b2u_flags_msrc, etherhdr.h_dest)) {3396bmc_need = rtw_mesh_data_bmc_to_uc(adapter3397, etherhdr.h_dest, etherhdr.h_source3398, etherhdr.h_dest, adapter_mac_addr(adapter), ae_need, NULL, 03399, b2u_list, &b2u_num, &b2u_mseq);3400if (bmc_need == _FALSE) {3401res = RTW_BMC_NO_NEED;3402goto exit;3403}3404}3405#endif3406}34073408attrib = &xframe->attrib;34093410#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3411if (b2u_num) {3412attrib->mb2u = 1;3413attrib->mseq = b2u_mseq;3414} else3415attrib->mb2u = 0;3416#endif34173418attrib->mfwd_ttl = 0;3419_rtw_memcpy(attrib->dst, etherhdr.h_dest, ETH_ALEN);3420_rtw_memcpy(attrib->src, etherhdr.h_source, ETH_ALEN);3421_rtw_memcpy(attrib->ta, adapter_mac_addr(adapter), ETH_ALEN);34223423if (is_da_mcast) {3424attrib->mesh_frame_mode = ae_need ? MESH_BMCAST_PX_DATA : MESH_BMCAST_DATA;3425_rtw_memcpy(attrib->ra, attrib->dst, ETH_ALEN);3426_rtw_memcpy(attrib->msa, adapter_mac_addr(adapter), ETH_ALEN);3427} else {3428attrib->mesh_frame_mode = ae_need ? MESH_UCAST_PX_DATA : MESH_UCAST_DATA;3429_rtw_memcpy(attrib->mda, (mppath && ae_need) ? mppath->mpp : attrib->dst, ETH_ALEN);3430_rtw_memcpy(attrib->msa, adapter_mac_addr(adapter), ETH_ALEN);3431/* RA needs to be resolved */3432res = rtw_mesh_nexthop_resolve(adapter, xframe);3433}34343435exit:3436return res;3437}34383439s8 rtw_mesh_tx_set_whdr_mctrl_len(u8 mesh_frame_mode, struct pkt_attrib *attrib)3440{3441u8 ret = 0;3442switch (mesh_frame_mode) {3443case MESH_UCAST_DATA:3444attrib->hdrlen = WLAN_HDR_A4_QOS_LEN;3445/* mesh flag + mesh TTL + Mesh SN. no ext addr. */3446attrib->meshctrl_len = 6;3447break;3448case MESH_BMCAST_DATA:3449attrib->hdrlen = WLAN_HDR_A3_QOS_LEN;3450/* mesh flag + mesh TTL + Mesh SN. no ext addr. */3451attrib->meshctrl_len = 6;3452break;3453case MESH_UCAST_PX_DATA:3454attrib->hdrlen = WLAN_HDR_A4_QOS_LEN;3455/* mesh flag + mesh TTL + Mesh SN + extaddr1 + extaddr2. */3456attrib->meshctrl_len = 18;3457break;3458case MESH_BMCAST_PX_DATA:3459attrib->hdrlen = WLAN_HDR_A3_QOS_LEN;3460/* mesh flag + mesh TTL + Mesh SN + extaddr1 */3461attrib->meshctrl_len = 12;3462break;3463default:3464RTW_WARN("Invalid mesh frame mode:%u\n", mesh_frame_mode);3465ret = -1;3466break;3467}34683469return ret;3470}34713472void rtw_mesh_tx_build_mctrl(_adapter *adapter, struct pkt_attrib *attrib, u8 *buf)3473{3474struct rtw_ieee80211s_hdr *mctrl = (struct rtw_ieee80211s_hdr *)buf;34753476_rtw_memset(mctrl, 0, XATTRIB_GET_MCTRL_LEN(attrib));34773478if (attrib->mfwd_ttl3479#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3480|| attrib->mb2u3481#endif3482) {3483#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3484if (!attrib->mfwd_ttl)3485mctrl->ttl = adapter->mesh_cfg.dot11MeshTTL;3486else3487#endif3488mctrl->ttl = attrib->mfwd_ttl;34893490mctrl->seqnum = (cpu_to_le32(attrib->mseq));3491} else {3492mctrl->ttl = adapter->mesh_cfg.dot11MeshTTL;3493mctrl->seqnum = (cpu_to_le32(adapter->mesh_info.mesh_seqnum));3494adapter->mesh_info.mesh_seqnum++;3495}34963497switch (attrib->mesh_frame_mode){3498case MESH_UCAST_DATA:3499case MESH_BMCAST_DATA:3500break;3501case MESH_UCAST_PX_DATA:3502mctrl->flags |= MESH_FLAGS_AE_A5_A6;3503_rtw_memcpy(mctrl->eaddr1, attrib->dst, ETH_ALEN);3504_rtw_memcpy(mctrl->eaddr2, attrib->src, ETH_ALEN);3505break;3506case MESH_BMCAST_PX_DATA:3507mctrl->flags |= MESH_FLAGS_AE_A4;3508_rtw_memcpy(mctrl->eaddr1, attrib->src, ETH_ALEN);3509break;3510case MESH_MHOP_UCAST_ACT:3511/* TBD */3512break;3513case MESH_MHOP_BMCAST_ACT:3514/* TBD */3515break;3516default:3517break;3518}3519}35203521u8 rtw_mesh_tx_build_whdr(_adapter *adapter, struct pkt_attrib *attrib3522, u16 *fctrl, struct rtw_ieee80211_hdr *whdr)3523{3524switch (attrib->mesh_frame_mode) {3525case MESH_UCAST_DATA: /* 1, 1, RA, TA, mDA(=DA), mSA(=SA) */3526case MESH_UCAST_PX_DATA: /* 1, 1, RA, TA, mDA, mSA, [DA, SA] */3527SetToDs(fctrl);3528SetFrDs(fctrl);3529_rtw_memcpy(whdr->addr1, attrib->ra, ETH_ALEN);3530_rtw_memcpy(whdr->addr2, attrib->ta, ETH_ALEN);3531_rtw_memcpy(whdr->addr3, attrib->mda, ETH_ALEN);3532_rtw_memcpy(whdr->addr4, attrib->msa, ETH_ALEN);3533break;3534case MESH_BMCAST_DATA: /* 0, 1, RA(DA), TA, mSA(SA) */3535case MESH_BMCAST_PX_DATA: /* 0, 1, RA(DA), TA, mSA, [SA] */3536SetFrDs(fctrl);3537_rtw_memcpy(whdr->addr1, attrib->ra, ETH_ALEN);3538_rtw_memcpy(whdr->addr2, attrib->ta, ETH_ALEN);3539_rtw_memcpy(whdr->addr3, attrib->msa, ETH_ALEN);3540break;3541case MESH_MHOP_UCAST_ACT:3542/* TBD */3543RTW_INFO("MESH_MHOP_UCAST_ACT\n");3544break;3545case MESH_MHOP_BMCAST_ACT:3546/* TBD */3547RTW_INFO("MESH_MHOP_BMCAST_ACT\n");3548break;3549default:3550RTW_WARN("Invalid mesh frame mode\n");3551break;3552}35533554return 0;3555}35563557int rtw_mesh_rx_data_validate_hdr(_adapter *adapter, union recv_frame *rframe, struct sta_info **sta)3558{3559struct sta_priv *stapriv = &adapter->stapriv;3560struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;3561u8 *whdr = get_recvframe_data(rframe);3562u8 is_ra_bmc = 0;3563u8 a4_shift = 0;3564u8 ps;3565u8 *qc;3566u8 mps_mode = RTW_MESH_PS_UNKNOWN;3567sint ret = _FAIL;35683569if (!(MLME_STATE(adapter) & WIFI_ASOC_STATE))3570goto exit;35713572if (!rattrib->qos)3573goto exit;35743575switch (rattrib->to_fr_ds) {3576case 1:3577if (!IS_MCAST(GetAddr1Ptr(whdr)))3578goto exit;3579*sta = rtw_get_stainfo(stapriv, get_addr2_ptr(whdr));3580if (*sta == NULL) {3581ret = _SUCCESS; /* return _SUCCESS to drop at sta checking */3582goto exit;3583}3584_rtw_memcpy(rattrib->ra, GetAddr1Ptr(whdr), ETH_ALEN);3585_rtw_memcpy(rattrib->ta, get_addr2_ptr(whdr), ETH_ALEN);3586_rtw_memcpy(rattrib->mda, GetAddr1Ptr(whdr), ETH_ALEN);3587_rtw_memcpy(rattrib->msa, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking AMSDU subframe header */3588_rtw_memcpy(rattrib->dst, GetAddr1Ptr(whdr), ETH_ALEN);3589_rtw_memcpy(rattrib->src, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking mesh ctrl field */3590_rtw_memcpy(rattrib->bssid, get_addr2_ptr(whdr), ETH_ALEN);3591is_ra_bmc = 1;3592break;3593case 3:3594if (IS_MCAST(GetAddr1Ptr(whdr)))3595goto exit;3596*sta = rtw_get_stainfo(stapriv, get_addr2_ptr(whdr));3597if (*sta == NULL) {3598ret = _SUCCESS; /* return _SUCCESS to drop at sta checking */3599goto exit;3600}3601_rtw_memcpy(rattrib->ra, GetAddr1Ptr(whdr), ETH_ALEN);3602_rtw_memcpy(rattrib->ta, get_addr2_ptr(whdr), ETH_ALEN);3603_rtw_memcpy(rattrib->mda, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking AMSDU subframe header */3604_rtw_memcpy(rattrib->msa, GetAddr4Ptr(whdr), ETH_ALEN); /* may change after checking AMSDU subframe header */3605_rtw_memcpy(rattrib->dst, GetAddr3Ptr(whdr), ETH_ALEN); /* may change after checking mesh ctrl field */3606_rtw_memcpy(rattrib->src, GetAddr4Ptr(whdr), ETH_ALEN); /* may change after checking mesh ctrl field */3607_rtw_memcpy(rattrib->bssid, get_addr2_ptr(whdr), ETH_ALEN);3608a4_shift = ETH_ALEN;3609break;3610default:3611goto exit;3612}36133614qc = whdr + WLAN_HDR_A3_LEN + a4_shift;3615ps = GetPwrMgt(whdr);3616mps_mode = ps ? (is_ra_bmc || (get_mps_lv(qc)) ? RTW_MESH_PS_DSLEEP : RTW_MESH_PS_LSLEEP) : RTW_MESH_PS_ACTIVE;36173618if (ps) {3619if (!((*sta)->state & WIFI_SLEEP_STATE))3620stop_sta_xmit(adapter, *sta);3621} else {3622if ((*sta)->state & WIFI_SLEEP_STATE)3623wakeup_sta_to_xmit(adapter, *sta);3624}36253626if (is_ra_bmc)3627(*sta)->nonpeer_mps = mps_mode;3628else {3629(*sta)->peer_mps = mps_mode;3630if (mps_mode != RTW_MESH_PS_ACTIVE && (*sta)->nonpeer_mps == RTW_MESH_PS_ACTIVE)3631(*sta)->nonpeer_mps = RTW_MESH_PS_DSLEEP;3632}36333634if (get_frame_sub_type(whdr) & BIT(6)) {3635/* No data, will not indicate to upper layer, temporily count it here */3636count_rx_stats(adapter, rframe, *sta);3637ret = RTW_RX_HANDLED;3638goto exit;3639}36403641rattrib->mesh_ctrl_present = get_mctrl_present(qc) ? 1 : 0;3642if (!rattrib->mesh_ctrl_present)3643goto exit;36443645ret = _SUCCESS;36463647exit:3648return ret;3649}36503651int rtw_mesh_rx_data_validate_mctrl(_adapter *adapter, union recv_frame *rframe3652, const struct rtw_ieee80211s_hdr *mctrl, const u8 *mda, const u8 *msa3653, u8 *mctrl_len3654, const u8 **da, const u8 **sa)3655{3656struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;3657u8 mlen;3658u8 ae;3659int ret = _SUCCESS;36603661ae = mctrl->flags & MESH_FLAGS_AE;3662mlen = ae_to_mesh_ctrl_len[ae];3663switch (rattrib->to_fr_ds) {3664case 1:3665*da = mda;3666if (ae == MESH_FLAGS_AE_A4)3667*sa = mctrl->eaddr1;3668else if (ae == 0)3669*sa = msa;3670else3671ret = _FAIL;3672break;3673case 3:3674if (ae == MESH_FLAGS_AE_A5_A6) {3675*da = mctrl->eaddr1;3676*sa = mctrl->eaddr2;3677} else if (ae == 0) {3678*da = mda;3679*sa = msa;3680} else3681ret = _FAIL;3682break;3683default:3684ret = _FAIL;3685}36863687if (ret == _FAIL) {3688#ifdef DBG_RX_DROP_FRAME3689RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" invalid tfDS:%u AE:%u combination ra="MAC_FMT" ta="MAC_FMT"\n"3690, FUNC_ADPT_ARG(adapter), rattrib->to_fr_ds, ae, MAC_ARG(rattrib->ra), MAC_ARG(rattrib->ta));3691#endif3692*mctrl_len = 0;3693} else3694*mctrl_len = mlen;36953696return ret;3697}36983699inline int rtw_mesh_rx_validate_mctrl_non_amsdu(_adapter *adapter, union recv_frame *rframe)3700{3701struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;3702const u8 *da, *sa;3703int ret;37043705ret = rtw_mesh_rx_data_validate_mctrl(adapter, rframe3706, (struct rtw_ieee80211s_hdr *)(get_recvframe_data(rframe) + rattrib->hdrlen + rattrib->iv_len)3707, rattrib->mda, rattrib->msa3708, &rattrib->mesh_ctrl_len3709, &da, &sa);37103711if (ret == _SUCCESS) {3712_rtw_memcpy(rattrib->dst, da, ETH_ALEN);3713_rtw_memcpy(rattrib->src, sa, ETH_ALEN);3714}37153716return ret;3717}37183719/**3720* rtw_mesh_rx_nexthop_resolve - lookup next hop; conditionally start path discovery3721*3722* @skb: 802.11 frame to be sent3723* @sdata: network subif the frame will be sent through3724*3725* Lookup next hop for given skb and start path discovery if no3726* forwarding information is found.3727*3728* Returns: 0 if the next hop was found and -ENOENT if the frame was queued.3729* skb is freeed here if no mpath could be allocated.3730*/3731static int rtw_mesh_rx_nexthop_resolve(_adapter *adapter,3732const u8 *mda, const u8 *msa, u8 *ra)3733{3734struct rtw_mesh_path *mpath;3735struct xmit_frame *xframe_to_free = NULL;3736int err = 0;3737int ret = _SUCCESS;37383739rtw_rcu_read_lock();3740err = rtw_mesh_nexthop_lookup(adapter, mda, msa, ra);3741if (!err)3742goto endlookup;37433744/* no nexthop found, start resolving */3745mpath = rtw_mesh_path_lookup(adapter, mda);3746if (!mpath) {3747mpath = rtw_mesh_path_add(adapter, mda);3748if (IS_ERR(mpath)) {3749err = PTR_ERR(mpath);3750ret = _FAIL;3751goto endlookup;3752}3753}37543755if (!(mpath->flags & RTW_MESH_PATH_RESOLVING))3756rtw_mesh_queue_preq(mpath, RTW_PREQ_Q_F_START);37573758ret = _FAIL;37593760endlookup:3761rtw_rcu_read_unlock();3762return ret;3763}37643765#define RTW_MESH_DECACHE_BMC 13766#define RTW_MESH_DECACHE_UC 037673768#define RTW_MESH_FORWARD_MDA_SELF_COND 03769#define DBG_RTW_MESH_FORWARD_MDA_SELF_COND 03770int rtw_mesh_rx_msdu_act_check(union recv_frame *rframe3771, const u8 *mda, const u8 *msa3772, const u8 *da, const u8 *sa3773, struct rtw_ieee80211s_hdr *mctrl3774, struct xmit_frame **fwd_frame, _list *b2u_list)3775{3776_adapter *adapter = rframe->u.hdr.adapter;3777struct rtw_mesh_cfg *mcfg = &adapter->mesh_cfg;3778struct rtw_mesh_info *minfo = &adapter->mesh_info;3779struct rx_pkt_attrib *rattrib = &rframe->u.hdr.attrib;3780struct rtw_mesh_path *mppath;3781u8 is_mda_bmc = IS_MCAST(mda);3782u8 is_mda_self = !is_mda_bmc && _rtw_memcmp(mda, adapter_mac_addr(adapter), ETH_ALEN);3783struct xmit_frame *xframe;3784struct pkt_attrib *xattrib;3785u8 fwd_ra[ETH_ALEN] = {0};3786u8 fwd_mpp[ETH_ALEN] = {0}; /* forward to other gate */3787u32 fwd_mseq;3788int act = 0;3789u8 ae_need;3790#if CONFIG_RTW_MESH_DATA_BMC_TO_UC3791bool bmc_need = _TRUE;3792u8 b2u_num = 0;3793#endif37943795/* fwd info lifetime update */3796#if 03797if (!is_mda_self)3798mDA(A3) fwinfo.lifetime3799mSA(A4) fwinfo.lifetime3800Precursor-to-mDA(A2) fwinfo.lifetime3801#endif38023803/* update/create pxoxy info for SA, mSA */3804if ((mctrl->flags & MESH_FLAGS_AE)3805&& sa != msa && _rtw_memcmp(sa, msa, ETH_ALEN) == _FALSE3806) {3807const u8 *proxied_addr = sa;3808const u8 *mpp_addr = msa;38093810rtw_rcu_read_lock();3811mppath = rtw_mpp_path_lookup(adapter, proxied_addr);3812if (!mppath)3813rtw_mpp_path_add(adapter, proxied_addr, mpp_addr);3814else {3815enter_critical_bh(&mppath->state_lock);3816if (_rtw_memcmp(mppath->mpp, mpp_addr, ETH_ALEN) == _FALSE)3817_rtw_memcpy(mppath->mpp, mpp_addr, ETH_ALEN);3818mppath->exp_time = rtw_get_current_time();3819exit_critical_bh(&mppath->state_lock);3820}3821rtw_rcu_read_unlock();3822}38233824/* mSA is self, need no further process */3825if (_rtw_memcmp(msa, adapter_mac_addr(adapter), ETH_ALEN) == _TRUE)3826goto exit;38273828fwd_mseq = le32_to_cpu(mctrl->seqnum);38293830/* check duplicate MSDU from mSA */3831if (((RTW_MESH_DECACHE_BMC && is_mda_bmc)3832|| (RTW_MESH_DECACHE_UC && !is_mda_bmc))3833&& rtw_mesh_decache(adapter, msa, fwd_mseq)3834) {3835minfo->mshstats.dropped_frames_duplicate++;3836goto exit;3837}38383839if (is_mda_bmc) {3840/* mDA is bmc addr */3841act |= RTW_RX_MSDU_ACT_INDICATE;3842if (!mcfg->dot11MeshForwarding)3843goto exit;3844goto fwd_chk;38453846} else if (!is_mda_self) {3847/* mDA is unicast but not self */3848if (!mcfg->dot11MeshForwarding) {3849rtw_mesh_path_error_tx(adapter3850, adapter->mesh_cfg.element_ttl3851, mda, 03852, WLAN_REASON_MESH_PATH_NOFORWARD3853, rattrib->ta3854);3855#ifdef DBG_RX_DROP_FRAME3856RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" mDA("MAC_FMT") not self, !dot11MeshForwarding\n"3857, FUNC_ADPT_ARG(adapter), MAC_ARG(mda));3858#endif3859goto exit;3860}38613862if (rtw_mesh_rx_nexthop_resolve(adapter, mda, msa, fwd_ra) != _SUCCESS) {3863/* mDA is unknown */3864rtw_mesh_path_error_tx(adapter3865, adapter->mesh_cfg.element_ttl3866, mda, 03867, WLAN_REASON_MESH_PATH_NOFORWARD3868, rattrib->ta3869);3870#ifdef DBG_RX_DROP_FRAME3871RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" mDA("MAC_FMT") unknown\n"3872, FUNC_ADPT_ARG(adapter), MAC_ARG(mda));3873#endif3874minfo->mshstats.dropped_frames_no_route++;3875goto exit;38763877} else {3878/* mDA is known in fwd info */3879#if 03880if (TA is not in precursors)3881goto exit;3882#endif3883goto fwd_chk;3884}38853886} else {3887/* mDA is self */3888#if RTW_MESH_FORWARD_MDA_SELF_COND3889if (da == mda3890|| _rtw_memcmp(da, adapter_mac_addr(adapter), ETH_ALEN)3891) {3892/* DA is self, indicate */3893act |= RTW_RX_MSDU_ACT_INDICATE;3894goto exit;3895}38963897if (rtw_get_iface_by_macddr(adapter, da)) {3898/* DA is buddy, indicate */3899act |= RTW_RX_MSDU_ACT_INDICATE;3900#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND3901RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") is buddy("ADPT_FMT")\n"3902, FUNC_ADPT_ARG(adapter), MAC_ARG(da), ADPT_ARG(rtw_get_iface_by_macddr(adapter, da)));3903#endif3904goto exit;3905}39063907/* DA is not self or buddy */3908if (rtw_mesh_nexthop_lookup(adapter, da, msa, fwd_ra) == 0) {3909/* DA is known in fwd info */3910if (!mcfg->dot11MeshForwarding) {3911/* path error to? */3912#if defined(DBG_RX_DROP_FRAME) || DBG_RTW_MESH_FORWARD_MDA_SELF_COND3913RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA("MAC_FMT") not self, !dot11MeshForwarding\n"3914, FUNC_ADPT_ARG(adapter), MAC_ARG(da));3915#endif3916goto exit;3917}3918mda = da;3919#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND3920RTW_INFO(FUNC_ADPT_FMT" fwd to DA("MAC_FMT"), fwd_RA("MAC_FMT")\n"3921, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(fwd_ra));3922#endif3923goto fwd_chk;3924}39253926rtw_rcu_read_lock();3927mppath = rtw_mpp_path_lookup(adapter, da);3928if (mppath) {3929if (_rtw_memcmp(mppath->mpp, adapter_mac_addr(adapter), ETH_ALEN) == _FALSE) {3930/* DA is proxied by others */3931if (!mcfg->dot11MeshForwarding) {3932/* path error to? */3933#if defined(DBG_RX_DROP_FRAME) || DBG_RTW_MESH_FORWARD_MDA_SELF_COND3934RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by ("MAC_FMT"), !dot11MeshForwarding\n"3935, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(mppath->mpp));3936#endif3937rtw_rcu_read_unlock();3938goto exit;3939}3940_rtw_memcpy(fwd_mpp, mppath->mpp, ETH_ALEN);3941mda = fwd_mpp;3942msa = adapter_mac_addr(adapter);3943rtw_rcu_read_unlock();39443945/* resolve RA */3946if (rtw_mesh_nexthop_lookup(adapter, mda, msa, fwd_ra) != 0) {3947minfo->mshstats.dropped_frames_no_route++;3948#if defined(DBG_RX_DROP_FRAME) || DBG_RTW_MESH_FORWARD_MDA_SELF_COND3949RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by ("MAC_FMT"), RA resolve fail\n"3950, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(mppath->mpp));3951#endif3952goto exit;3953}3954#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND3955RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by ("MAC_FMT"), fwd_RA("MAC_FMT")\n"3956, FUNC_ADPT_ARG(adapter), MAC_ARG(da), MAC_ARG(mppath->mpp), MAC_ARG(fwd_ra));3957#endif3958goto fwd_chk; /* forward to other gate */3959} else {3960#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND3961RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") is proxied by self\n"3962, FUNC_ADPT_ARG(adapter), MAC_ARG(da));3963#endif3964}3965}3966rtw_rcu_read_unlock();39673968if (!mppath) {3969#if DBG_RTW_MESH_FORWARD_MDA_SELF_COND3970RTW_INFO(FUNC_ADPT_FMT" DA("MAC_FMT") unknown\n"3971, FUNC_ADPT_ARG(adapter), MAC_ARG(da));3972#endif3973/* DA is unknown */3974#if 0 /* TODO: flags with AE bit */3975rtw_mesh_path_error_tx(adapter3976, adapter->mesh_cfg.element_ttl3977, mda, adapter->mesh_info.last_sn_update3978, WLAN_REASON_MESH_PATH_NOPROXY3979, msa3980);3981#endif3982}39833984/*3985* indicate to DS for both cases:3986* 1.) DA is proxied by self3987* 2.) DA is unknown3988*/3989#endif /* RTW_MESH_FORWARD_MDA_SELF_COND */3990act |= RTW_RX_MSDU_ACT_INDICATE;3991goto exit;3992}39933994fwd_chk:39953996if (adapter->stapriv.asoc_list_cnt <= 1)3997goto exit;39983999if (mctrl->ttl == 1) {4000minfo->mshstats.dropped_frames_ttl++;4001if (!act) {4002#ifdef DBG_RX_DROP_FRAME4003RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" ttl reaches 0, not forwarding\n"4004, FUNC_ADPT_ARG(adapter));4005#endif4006}4007goto exit;4008}40094010#if CONFIG_RTW_MESH_DATA_BMC_TO_UC4011_rtw_init_listhead(b2u_list);4012#endif40134014ae_need = _rtw_memcmp(da , mda, ETH_ALEN) == _FALSE4015|| _rtw_memcmp(sa , msa, ETH_ALEN) == _FALSE;40164017#if CONFIG_RTW_MESH_DATA_BMC_TO_UC4018if (is_mda_bmc4019&& rtw_mfwd_b2u_policy_chk(mcfg->b2u_flags_mfwd, mda, rattrib->to_fr_ds == 3)4020) {4021bmc_need = rtw_mesh_data_bmc_to_uc(adapter4022, da, sa, mda, msa, ae_need, rframe->u.hdr.psta->cmn.mac_addr, mctrl->ttl - 14023, b2u_list, &b2u_num, &fwd_mseq);4024}40254026if (bmc_need == _TRUE)4027#endif4028{4029xframe = rtw_alloc_xmitframe(&adapter->xmitpriv);4030if (!xframe) {4031#ifdef DBG_TX_DROP_FRAME4032RTW_INFO("DBG_TX_DROP_FRAME "FUNC_ADPT_FMT" rtw_alloc_xmitframe fail\n"4033, FUNC_ADPT_ARG(adapter));4034#endif4035goto exit;4036}40374038xattrib = &xframe->attrib;40394040#if CONFIG_RTW_MESH_DATA_BMC_TO_UC4041if (b2u_num)4042xattrib->mb2u = 1;4043else4044xattrib->mb2u = 0;4045#endif4046xattrib->mfwd_ttl = mctrl->ttl - 1;4047xattrib->mseq = fwd_mseq;4048_rtw_memcpy(xattrib->dst, da, ETH_ALEN);4049_rtw_memcpy(xattrib->src, sa, ETH_ALEN);4050_rtw_memcpy(xattrib->mda, mda, ETH_ALEN);4051_rtw_memcpy(xattrib->msa, msa, ETH_ALEN);4052_rtw_memcpy(xattrib->ta, adapter_mac_addr(adapter), ETH_ALEN);40534054if (is_mda_bmc) {4055xattrib->mesh_frame_mode = ae_need ? MESH_BMCAST_PX_DATA : MESH_BMCAST_DATA;4056_rtw_memcpy(xattrib->ra, mda, ETH_ALEN);4057} else {4058xattrib->mesh_frame_mode = ae_need ? MESH_UCAST_PX_DATA : MESH_UCAST_DATA;4059_rtw_memcpy(xattrib->ra, fwd_ra, ETH_ALEN);4060}40614062*fwd_frame = xframe;4063}40644065act |= RTW_RX_MSDU_ACT_FORWARD;4066if (is_mda_bmc)4067minfo->mshstats.fwded_mcast++;4068else4069minfo->mshstats.fwded_unicast++;4070minfo->mshstats.fwded_frames++;40714072exit:4073return act;4074}40754076void dump_mesh_stats(void *sel, _adapter *adapter)4077{4078struct rtw_mesh_info *minfo = &adapter->mesh_info;4079struct rtw_mesh_stats *stats = &minfo->mshstats;40804081RTW_PRINT_SEL(sel, "fwd_bmc:%u\n", stats->fwded_mcast);4082RTW_PRINT_SEL(sel, "fwd_uc:%u\n", stats->fwded_unicast);40834084RTW_PRINT_SEL(sel, "drop_ttl:%u\n", stats->dropped_frames_ttl);4085RTW_PRINT_SEL(sel, "drop_no_route:%u\n", stats->dropped_frames_no_route);4086RTW_PRINT_SEL(sel, "drop_congestion:%u\n", stats->dropped_frames_congestion);4087RTW_PRINT_SEL(sel, "drop_dup:%u\n", stats->dropped_frames_duplicate);40884089RTW_PRINT_SEL(sel, "mrc_del_qlen:%u\n", stats->mrc_del_qlen);4090}4091#endif /* CONFIG_RTW_MESH */4092409340944095