Larry Finger <[email protected]> writes:
> From: Tsang-Shian Lin <[email protected]>
>
> AP WiFi settings are changed(channel, bandwidth), but deauth may not
> received by STA. For these cases, we need to detect and handle beacon
> changes.
>
> Signed-off-by: Tsang-Shian Lin <[email protected]>
> Signed-off-by: Ping-Ke Shih <[email protected]>
> Signed-off-by: Larry Finger <[email protected]>
> Cc: Yan-Hsuan Chuang <[email protected]>
> Cc: Birming Chiu <[email protected]>
> Cc: Shaofu <[email protected]>
> Cc: Steven Ting <[email protected]>
[...]
> --- a/drivers/net/wireless/realtek/rtlwifi/base.c
> +++ b/drivers/net/wireless/realtek/rtlwifi/base.c
> @@ -2360,6 +2360,185 @@ struct sk_buff *rtl_make_del_ba(struct ieee80211_hw
> *hw,
> return skb;
> }
>
> +bool rtl_check_beacon_key(struct ieee80211_hw *hw, void *data, unsigned int
> len)
> +{
> + struct rtl_priv *rtlpriv = rtl_priv(hw);
> + struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
> + struct rtl_phy *rtlphy = &rtlpriv->phy;
> + struct ieee80211_hdr *hdr = data;
> + struct ieee80211_ht_cap *ht_cap_ie;
> + struct ieee80211_ht_operation *ht_oper_ie = NULL;
> + struct rtl_beacon_keys bcn_key = {0};
> + struct rtl_beacon_keys *cur_bcn_key;
> + u8 *ht_cap;
> + u8 ht_cap_len;
> + u8 *ht_oper;
> + u8 ht_oper_len;
> + u8 *ds_param;
> + u8 ds_param_len;
> +
> + if (mac->opmode != NL80211_IFTYPE_STATION)
> + return false;
> +
> + /* check if this really is a beacon*/
> + if (!ieee80211_is_beacon(hdr->frame_control))
> + return false;
> +
> + /* min. beacon length + FCS_LEN */
> + if (len <= 40 + FCS_LEN)
> + return false;
> +
> + cur_bcn_key = &mac->cur_beacon_keys;
> +
> + if (rtlpriv->mac80211.link_state == MAC80211_NOLINK) {
> + if (cur_bcn_key->valid) {
> + cur_bcn_key->valid = false;
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
> + "Reset cur_beacon_keys.valid to false!\n");
> + }
> + return false;
> + }
> +
> + /* and only beacons from the associated BSSID, please */
> + if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
> + return false;
> +
> + /***** Parsing DS Param IE ******/
> + ds_param = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_DS_PARAMS);
> +
> + if (ds_param && !(ds_param[1] < sizeof(*ds_param)))
> + ds_param_len = ds_param[1];
> + else
> + ds_param = NULL;
> +
> + /***** Parsing HT Cap. IE ******/
> + ht_cap = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_HT_CAPABILITY);
> +
> + if (ht_cap && !(ht_cap[1] < sizeof(*ht_cap))) {
> + ht_cap_len = ht_cap[1];
> + ht_cap_ie = (struct ieee80211_ht_cap *)&ht_cap[2];
> + } else {
> + ht_cap = NULL;
> + ht_cap_ie = NULL;
> + }
> +
> + /***** Parsing HT Info. IE ******/
> + ht_oper = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_HT_OPERATION);
> +
> + if (ht_oper && !(ht_oper[1] < sizeof(*ht_oper))) {
> + ht_oper_len = ht_oper[1];
> + ht_oper_ie = (struct ieee80211_ht_operation *)&ht_oper[2];
> + } else {
> + ht_oper = NULL;
> + }
> +
> + /* update bcn_key */
> + memset(&bcn_key, 0, sizeof(bcn_key));
> +
> + if (ds_param)
> + bcn_key.bcn_channel = ds_param[2];
> + else if (ht_oper && ht_oper_ie)
> + bcn_key.bcn_channel = ht_oper_ie->primary_chan;
> +
> + if (ht_cap_ie)
> + bcn_key.ht_cap_info = ht_cap_ie->cap_info;
> +
> + if (ht_oper && ht_oper_ie)
> + bcn_key.ht_info_infos_0_sco = ht_oper_ie->ht_param & 0x03;
> +
> + bcn_key.valid = true;
> +
> + /* update cur_beacon_keys or compare beacon key */
> + if (rtlpriv->mac80211.link_state != MAC80211_LINKED &&
> + rtlpriv->mac80211.link_state != MAC80211_LINKED_SCANNING)
> + return true;
> +
> + if (!cur_bcn_key->valid) {
> + /* update cur_beacon_keys */
> + memset(cur_bcn_key, 0, sizeof(bcn_key));
> + memcpy(cur_bcn_key, &bcn_key, sizeof(bcn_key));
> + cur_bcn_key->valid = true;
> +
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
> + "Beacon key update!ch=%d, ht_cap_info=0x%x,
> sco=0x%x\n",
> + cur_bcn_key->bcn_channel,
> + cur_bcn_key->ht_cap_info,
> + cur_bcn_key->ht_info_infos_0_sco);
> +
> + return true;
> + }
> +
> + /* compare beacon key */
> + if (!memcmp(cur_bcn_key, &bcn_key, sizeof(bcn_key))) {
> + /* same beacon key */
> + mac->new_beacon_cnt = 0;
> + goto chk_exit;
> + }
> +
> + if (cur_bcn_key->bcn_channel == bcn_key.bcn_channel &&
> + cur_bcn_key->ht_cap_info == bcn_key.ht_cap_info) {
> + /* Beacon HT info IE, secondary channel offset check */
> + /* 40M -> 20M */
> + if (cur_bcn_key->ht_info_infos_0_sco >
> + bcn_key.ht_info_infos_0_sco) {
> + /* Not a new beacon */
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "Beacon BW change! sco:0x%x -> 0x%x\n",
> + cur_bcn_key->ht_info_infos_0_sco,
> + bcn_key.ht_info_infos_0_sco);
> +
> + cur_bcn_key->ht_info_infos_0_sco =
> + bcn_key.ht_info_infos_0_sco;
> + } else {
> + /* 20M -> 40M */
> + if (rtlphy->max_ht_chan_bw >= HT_CHANNEL_WIDTH_20_40) {
> + /* Not a new beacon */
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "Beacon BW change! sco:0x%x -> 0x%x\n",
> + cur_bcn_key->ht_info_infos_0_sco,
> + bcn_key.ht_info_infos_0_sco);
> +
> + cur_bcn_key->ht_info_infos_0_sco =
> + bcn_key.ht_info_infos_0_sco;
> + } else {
> + mac->new_beacon_cnt++;
> + }
> + }
> + } else {
> + mac->new_beacon_cnt++;
> + }
> +
> + if (mac->new_beacon_cnt == 1) {
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "Get new beacon.\n");
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "Cur : ch=%d, ht_cap=0x%x, sco=0x%x\n",
> + cur_bcn_key->bcn_channel,
> + cur_bcn_key->ht_cap_info,
> + cur_bcn_key->ht_info_infos_0_sco);
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "New RX : ch=%d, ht_cap=0x%x, sco=0x%x\n",
> + bcn_key.bcn_channel,
> + bcn_key.ht_cap_info,
> + bcn_key.ht_info_infos_0_sco);
> +
> + } else if (mac->new_beacon_cnt > 1) {
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "new beacon cnt: %d\n",
> + mac->new_beacon_cnt);
> + }
> +
> + if (mac->new_beacon_cnt > 3) {
> + ieee80211_connection_loss(rtlpriv->mac80211.vif);
> + RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
> + "new beacon cnt >3, disconnect !\n");
> + }
> +
> +chk_exit:
> +
> + return true;
> +}
> +EXPORT_SYMBOL_GPL(rtl_check_beacon_key);
Why do all this in the driver? I would expect something like this to be
done in mac80211, not in the driver.
> +struct rtl_beacon_keys {
> + /*u8 ssid[32];*/
> + /*u32 ssid_len;*/
Commented out fields, please drop.
--
Kalle Valo