···437437 u32 prohibited_flags);438438439439/**440440+ * cfg80211_chandef_dfs_required - checks if radar detection is required441441+ * @wiphy: the wiphy to validate against442442+ * @chandef: the channel definition to check443443+ * Return: 1 if radar detection is required, 0 if it is not, < 0 on error444444+ */445445+int cfg80211_chandef_dfs_required(struct wiphy *wiphy,446446+ const struct cfg80211_chan_def *chandef);447447+448448+/**440449 * ieee80211_chandef_rate_flags - returns rate flags for a channel441450 *442451 * In some channel types, not all rates may be used - for example CCK
+42
include/net/mac80211.h
···829829 * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3830830 * @RX_FLAG_10MHZ: 10 MHz (half channel) was used831831 * @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used832832+ * @RX_FLAG_AMSDU_MORE: Some drivers may prefer to report separate A-MSDU833833+ * subframes instead of a one huge frame for performance reasons.834834+ * All, but the last MSDU from an A-MSDU should have this flag set. E.g.835835+ * if an A-MSDU has 3 frames, the first 2 must have the flag set, while836836+ * the 3rd (last) one must not have this flag set. The flag is used to837837+ * deal with retransmission/duplication recovery properly since A-MSDU838838+ * subframes share the same sequence number. Reported subframes can be839839+ * either regular MSDU or singly A-MSDUs. Subframes must not be840840+ * interleaved with other frames.832841 */833842enum mac80211_rx_flags {834843 RX_FLAG_MMIC_ERROR = BIT(0),···868859 RX_FLAG_STBC_MASK = BIT(26) | BIT(27),869860 RX_FLAG_10MHZ = BIT(28),870861 RX_FLAG_5MHZ = BIT(29),862862+ RX_FLAG_AMSDU_MORE = BIT(30),871863};872864873865#define RX_FLAG_STBC_SHIFT 26···15021492 *15031493 * @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames15041494 * only, to allow getting TBTT of a DTIM beacon.14951495+ *14961496+ * @IEEE80211_HW_CHANCTX_STA_CSA: Support 802.11h based channel-switch (CSA)14971497+ * for a single active channel while using channel contexts. When support14981498+ * is not enabled the default action is to disconnect when getting the14991499+ * CSA frame.15051500 */15061501enum ieee80211_hw_flags {15071502 IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,···15371522 IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25,15381523 IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26,15391524 IEEE80211_HW_SUPPORTS_HT_CCK_RATES = 1<<27,15251525+ IEEE80211_HW_CHANCTX_STA_CSA = 1<<28,15401526};1541152715421528/**···26822666 * zero using ieee80211_csa_is_complete() after the beacon has been26832667 * transmitted and then call ieee80211_csa_finish().26842668 *26692669+ * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all26702670+ * information in bss_conf is set up and the beacon can be retrieved. A26712671+ * channel context is bound before this is called.26722672+ * @leave_ibss: Leave the IBSS again.26852673 */26862674struct ieee80211_ops {26872675 void (*tx)(struct ieee80211_hw *hw,···28772857 void (*channel_switch_beacon)(struct ieee80211_hw *hw,28782858 struct ieee80211_vif *vif,28792859 struct cfg80211_chan_def *chandef);28602860+28612861+ int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);28622862+ void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);28802863};2881286428822865/**···39413918 u8 *mac,39423919 struct ieee80211_vif *vif),39433920 void *data);39213921+39223922+/**39233923+ * ieee80211_iterate_active_interfaces_rtnl - iterate active interfaces39243924+ *39253925+ * This function iterates over the interfaces associated with a given39263926+ * hardware that are currently active and calls the callback for them.39273927+ * This version can only be used while holding the RTNL.39283928+ *39293929+ * @hw: the hardware struct of which the interfaces should be iterated over39303930+ * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags39313931+ * @iterator: the iterator function to call, cannot sleep39323932+ * @data: first argument of the iterator function39333933+ */39343934+void ieee80211_iterate_active_interfaces_rtnl(struct ieee80211_hw *hw,39353935+ u32 iter_flags,39363936+ void (*iterator)(void *data,39373937+ u8 *mac,39383938+ struct ieee80211_vif *vif),39393939+ void *data);3944394039453941/**39463942 * ieee80211_queue_work - add work onto the mac80211 workqueue
+69-23
net/mac80211/cfg.c
···28652865 if (!ieee80211_sdata_running(sdata))28662866 return;2867286728682868- if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))28692869- return;28702870-28712868 sdata->radar_required = sdata->csa_radar_required;28722869 err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,28732870 &changed);28742871 if (WARN_ON(err < 0))28752872 return;2876287328772877- err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);28782878- if (err < 0)28792879- return;28742874+ if (!local->use_chanctx) {28752875+ local->_oper_chandef = local->csa_chandef;28762876+ ieee80211_hw_config(local, 0);28772877+ }2880287828812881- changed |= err;28822882- kfree(sdata->u.ap.next_beacon);28832883- sdata->u.ap.next_beacon = NULL;28792879+ ieee80211_bss_info_change_notify(sdata, changed);28802880+28812881+ switch (sdata->vif.type) {28822882+ case NL80211_IFTYPE_AP:28832883+ err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);28842884+ if (err < 0)28852885+ return;28862886+ changed |= err;28872887+ kfree(sdata->u.ap.next_beacon);28882888+ sdata->u.ap.next_beacon = NULL;28892889+28902890+ ieee80211_bss_info_change_notify(sdata, err);28912891+ break;28922892+ case NL80211_IFTYPE_ADHOC:28932893+ ieee80211_ibss_finish_csa(sdata);28942894+ break;28952895+ default:28962896+ WARN_ON(1);28972897+ return;28982898+ }28842899 sdata->vif.csa_active = false;2885290028862901 ieee80211_wake_queues_by_reason(&sdata->local->hw,28872902 IEEE80211_MAX_QUEUE_MAP,28882903 IEEE80211_QUEUE_STOP_REASON_CSA);28892889-28902890- ieee80211_bss_info_change_notify(sdata, changed);2891290428922905 cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);28932906}···29492936 if (sdata->vif.csa_active)29502937 return -EBUSY;2951293829522952- /* only handle AP for now. */29532939 switch (sdata->vif.type) {29542940 case NL80211_IFTYPE_AP:29412941+ sdata->csa_counter_offset_beacon =29422942+ params->counter_offset_beacon;29432943+ sdata->csa_counter_offset_presp = params->counter_offset_presp;29442944+ sdata->u.ap.next_beacon =29452945+ cfg80211_beacon_dup(¶ms->beacon_after);29462946+ if (!sdata->u.ap.next_beacon)29472947+ return -ENOMEM;29482948+29492949+ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);29502950+ if (err < 0) {29512951+ kfree(sdata->u.ap.next_beacon);29522952+ return err;29532953+ }29542954+ break;29552955+ case NL80211_IFTYPE_ADHOC:29562956+ if (!sdata->vif.bss_conf.ibss_joined)29572957+ return -EINVAL;29582958+29592959+ if (params->chandef.width != sdata->u.ibss.chandef.width)29602960+ return -EINVAL;29612961+29622962+ switch (params->chandef.width) {29632963+ case NL80211_CHAN_WIDTH_40:29642964+ if (cfg80211_get_chandef_type(¶ms->chandef) !=29652965+ cfg80211_get_chandef_type(&sdata->u.ibss.chandef))29662966+ return -EINVAL;29672967+ case NL80211_CHAN_WIDTH_5:29682968+ case NL80211_CHAN_WIDTH_10:29692969+ case NL80211_CHAN_WIDTH_20_NOHT:29702970+ case NL80211_CHAN_WIDTH_20:29712971+ break;29722972+ default:29732973+ return -EINVAL;29742974+ }29752975+29762976+ /* changes into another band are not supported */29772977+ if (sdata->u.ibss.chandef.chan->band !=29782978+ params->chandef.chan->band)29792979+ return -EINVAL;29802980+29812981+ err = ieee80211_ibss_csa_beacon(sdata, params);29822982+ if (err < 0)29832983+ return err;29552984 break;29562985 default:29572986 return -EOPNOTSUPP;29582987 }2959298829602960- sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after);29612961- if (!sdata->u.ap.next_beacon)29622962- return -ENOMEM;29632963-29642964- sdata->csa_counter_offset_beacon = params->counter_offset_beacon;29652965- sdata->csa_counter_offset_presp = params->counter_offset_presp;29662989 sdata->csa_radar_required = params->radar_required;2967299029682991 if (params->block_tx)29692992 ieee80211_stop_queues_by_reason(&local->hw,29702993 IEEE80211_MAX_QUEUE_MAP,29712994 IEEE80211_QUEUE_STOP_REASON_CSA);29722972-29732973- err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);29742974- if (err < 0)29752975- return err;2976299529772996 local->csa_chandef = params->chandef;29782997 sdata->vif.csa_active = true;···30593014 need_offchan = true;30603015 if (!ieee80211_is_action(mgmt->frame_control) ||30613016 mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||30623062- mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED)30173017+ mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||30183018+ mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)30633019 break;30643020 rcu_read_lock();30653021 sta = sta_info_get(sdata, mgmt->da);
···103103 if (!buf)104104 return 0;105105106106- sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);106106+ sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);107107 if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)108108- sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");108108+ sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");109109 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)110110- sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");110110+ sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");111111 if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)112112- sf += snprintf(buf + sf, mxln - sf,113113- "HOST_BCAST_PS_BUFFERING\n");112112+ sf += scnprintf(buf + sf, mxln - sf,113113+ "HOST_BCAST_PS_BUFFERING\n");114114 if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)115115- sf += snprintf(buf + sf, mxln - sf,116116- "2GHZ_SHORT_SLOT_INCAPABLE\n");115115+ sf += scnprintf(buf + sf, mxln - sf,116116+ "2GHZ_SHORT_SLOT_INCAPABLE\n");117117 if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)118118- sf += snprintf(buf + sf, mxln - sf,119119- "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");118118+ sf += scnprintf(buf + sf, mxln - sf,119119+ "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");120120 if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)121121- sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");121121+ sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");122122 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)123123- sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");123123+ sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");124124 if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC)125125- sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n");125125+ sf += scnprintf(buf + sf, mxln - sf,126126+ "NEED_DTIM_BEFORE_ASSOC\n");126127 if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)127127- sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");128128+ sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");128129 if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)129129- sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");130130+ sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");130131 if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)131131- sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");132132+ sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");132133 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)133133- sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");134134+ sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");134135 if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)135135- sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");136136+ sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");136137 if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)137137- sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");138138+ sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");138139 if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS)139139- sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");140140+ sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");140141 if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)141141- sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n");142142+ sf += scnprintf(buf + sf, mxln - sf,143143+ "SUPPORTS_DYNAMIC_SMPS\n");142144 if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)143143- sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");145145+ sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");144146 if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)145145- sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n");147147+ sf += scnprintf(buf + sf, mxln - sf,148148+ "REPORTS_TX_ACK_STATUS\n");146149 if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)147147- sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");150150+ sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");148151 if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)149149- sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");152152+ sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");150153 if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)151151- sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");154154+ sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");152155 if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)153153- sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");156156+ sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");154157155158 rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));156159 kfree(buf);
+27
net/mac80211/driver-ops.h
···10851085 }10861086}1087108710881088+static inline int drv_join_ibss(struct ieee80211_local *local,10891089+ struct ieee80211_sub_if_data *sdata)10901090+{10911091+ int ret = 0;10921092+10931093+ might_sleep();10941094+ check_sdata_in_driver(sdata);10951095+10961096+ trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf);10971097+ if (local->ops->join_ibss)10981098+ ret = local->ops->join_ibss(&local->hw, &sdata->vif);10991099+ trace_drv_return_int(local, ret);11001100+ return ret;11011101+}11021102+11031103+static inline void drv_leave_ibss(struct ieee80211_local *local,11041104+ struct ieee80211_sub_if_data *sdata)11051105+{11061106+ might_sleep();11071107+ check_sdata_in_driver(sdata);11081108+11091109+ trace_drv_leave_ibss(local, sdata);11101110+ if (local->ops->leave_ibss)11111111+ local->ops->leave_ibss(&local->hw, &sdata->vif);11121112+ trace_drv_return_void(local);11131113+}11141114+10881115#endif /* __MAC80211_DRIVER_OPS */
+520-88
net/mac80211/ibss.c
···3939 const int beacon_int, const u32 basic_rates,4040 const u16 capability, u64 tsf,4141 struct cfg80211_chan_def *chandef,4242- bool *have_higher_than_11mbit)4242+ bool *have_higher_than_11mbit,4343+ struct cfg80211_csa_settings *csa_settings)4344{4445 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;4546 struct ieee80211_local *local = sdata->local;···6059 2 + 8 /* max Supported Rates */ +6160 3 /* max DS params */ +6261 4 /* IBSS params */ +6262+ 5 /* Channel Switch Announcement */ +6363 2 + (IEEE80211_MAX_SUPP_RATES - 8) +6464 2 + sizeof(struct ieee80211_ht_cap) +6565 2 + sizeof(struct ieee80211_ht_operation) +···136134 /* FIX: set ATIM window based on scan results */137135 *pos++ = 0;138136 *pos++ = 0;137137+138138+ if (csa_settings) {139139+ *pos++ = WLAN_EID_CHANNEL_SWITCH;140140+ *pos++ = 3;141141+ *pos++ = csa_settings->block_tx ? 1 : 0;142142+ *pos++ = ieee80211_frequency_to_channel(143143+ csa_settings->chandef.chan->center_freq);144144+ sdata->csa_counter_offset_beacon = (pos - presp->head);145145+ *pos++ = csa_settings->count;146146+ }139147140148 /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */141149 if (rates_n > 8) {···229217 struct beacon_data *presp;230218 enum nl80211_bss_scan_width scan_width;231219 bool have_higher_than_11mbit;220220+ int err;232221233222 sdata_assert_lock(sdata);234223···248235 ieee80211_bss_info_change_notify(sdata,249236 BSS_CHANGED_IBSS |250237 BSS_CHANGED_BEACON_ENABLED);238238+ drv_leave_ibss(local, sdata);251239 }252240253241 presp = rcu_dereference_protected(ifibss->presp,···290276291277 presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,292278 capability, tsf, &chandef,293293- &have_higher_than_11mbit);279279+ &have_higher_than_11mbit, NULL);294280 if (!presp)295281 return;296282···331317 else332318 sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;333319320320+ ieee80211_set_wmm_default(sdata, true);321321+334322 sdata->vif.bss_conf.ibss_joined = true;335323 sdata->vif.bss_conf.ibss_creator = creator;336336- ieee80211_bss_info_change_notify(sdata, bss_change);337324338338- ieee80211_set_wmm_default(sdata, true);325325+ err = drv_join_ibss(local, sdata);326326+ if (err) {327327+ sdata->vif.bss_conf.ibss_joined = false;328328+ sdata->vif.bss_conf.ibss_creator = false;329329+ sdata->vif.bss_conf.enable_beacon = false;330330+ sdata->vif.bss_conf.ssid_len = 0;331331+ RCU_INIT_POINTER(ifibss->presp, NULL);332332+ kfree_rcu(presp, rcu_head);333333+ ieee80211_vif_release_channel(sdata);334334+ sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",335335+ err);336336+ return;337337+ }338338+339339+ ieee80211_bss_info_change_notify(sdata, bss_change);339340340341 ifibss->state = IEEE80211_IBSS_MLME_JOINED;341342 mod_timer(&ifibss->timer,···445416 tsf, false);446417}447418419419+static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,420420+ struct cfg80211_csa_settings *csa_settings)421421+{422422+ struct sk_buff *skb;423423+ struct ieee80211_mgmt *mgmt;424424+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;425425+ struct ieee80211_local *local = sdata->local;426426+ int freq;427427+ int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +428428+ sizeof(mgmt->u.action.u.chan_switch);429429+ u8 *pos;430430+431431+ skb = dev_alloc_skb(local->tx_headroom + hdr_len +432432+ 5 + /* channel switch announcement element */433433+ 3); /* secondary channel offset element */434434+ if (!skb)435435+ return -1;436436+437437+ skb_reserve(skb, local->tx_headroom);438438+ mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);439439+ memset(mgmt, 0, hdr_len);440440+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |441441+ IEEE80211_STYPE_ACTION);442442+443443+ eth_broadcast_addr(mgmt->da);444444+ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);445445+ memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);446446+ mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;447447+ mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;448448+ pos = skb_put(skb, 5);449449+ *pos++ = WLAN_EID_CHANNEL_SWITCH; /* EID */450450+ *pos++ = 3; /* IE length */451451+ *pos++ = csa_settings->block_tx ? 1 : 0; /* CSA mode */452452+ freq = csa_settings->chandef.chan->center_freq;453453+ *pos++ = ieee80211_frequency_to_channel(freq); /* channel */454454+ *pos++ = csa_settings->count; /* count */455455+456456+ if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {457457+ enum nl80211_channel_type ch_type;458458+459459+ skb_put(skb, 3);460460+ *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */461461+ *pos++ = 1; /* IE length */462462+ ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);463463+ if (ch_type == NL80211_CHAN_HT40PLUS)464464+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;465465+ else466466+ *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;467467+ }468468+469469+ ieee80211_tx_skb(sdata, skb);470470+ return 0;471471+}472472+473473+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,474474+ struct cfg80211_csa_settings *csa_settings)475475+{476476+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;477477+ struct beacon_data *presp, *old_presp;478478+ struct cfg80211_bss *cbss;479479+ const struct cfg80211_bss_ies *ies;480480+ u16 capability;481481+ u64 tsf;482482+ int ret = 0;483483+484484+ sdata_assert_lock(sdata);485485+486486+ capability = WLAN_CAPABILITY_IBSS;487487+488488+ if (ifibss->privacy)489489+ capability |= WLAN_CAPABILITY_PRIVACY;490490+491491+ cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,492492+ ifibss->bssid, ifibss->ssid,493493+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |494494+ WLAN_CAPABILITY_PRIVACY,495495+ capability);496496+497497+ if (WARN_ON(!cbss)) {498498+ ret = -EINVAL;499499+ goto out;500500+ }501501+502502+ rcu_read_lock();503503+ ies = rcu_dereference(cbss->ies);504504+ tsf = ies->tsf;505505+ rcu_read_unlock();506506+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);507507+508508+ old_presp = rcu_dereference_protected(ifibss->presp,509509+ lockdep_is_held(&sdata->wdev.mtx));510510+511511+ presp = ieee80211_ibss_build_presp(sdata,512512+ sdata->vif.bss_conf.beacon_int,513513+ sdata->vif.bss_conf.basic_rates,514514+ capability, tsf, &ifibss->chandef,515515+ NULL, csa_settings);516516+ if (!presp) {517517+ ret = -ENOMEM;518518+ goto out;519519+ }520520+521521+ rcu_assign_pointer(ifibss->presp, presp);522522+ if (old_presp)523523+ kfree_rcu(old_presp, rcu_head);524524+525525+ /* it might not send the beacon for a while. send an action frame526526+ * immediately to announce the channel switch.527527+ */528528+ if (csa_settings)529529+ ieee80211_send_action_csa(sdata, csa_settings);530530+531531+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);532532+ out:533533+ return ret;534534+}535535+536536+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)537537+{538538+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;539539+ struct cfg80211_bss *cbss;540540+ int err;541541+ u16 capability;542542+543543+ sdata_lock(sdata);544544+ /* update cfg80211 bss information with the new channel */545545+ if (!is_zero_ether_addr(ifibss->bssid)) {546546+ capability = WLAN_CAPABILITY_IBSS;547547+548548+ if (ifibss->privacy)549549+ capability |= WLAN_CAPABILITY_PRIVACY;550550+551551+ cbss = cfg80211_get_bss(sdata->local->hw.wiphy,552552+ ifibss->chandef.chan,553553+ ifibss->bssid, ifibss->ssid,554554+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |555555+ WLAN_CAPABILITY_PRIVACY,556556+ capability);557557+ /* XXX: should not really modify cfg80211 data */558558+ if (cbss) {559559+ cbss->channel = sdata->local->csa_chandef.chan;560560+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);561561+ }562562+ }563563+564564+ ifibss->chandef = sdata->local->csa_chandef;565565+566566+ /* generate the beacon */567567+ err = ieee80211_ibss_csa_beacon(sdata, NULL);568568+ sdata_unlock(sdata);569569+ if (err < 0)570570+ return err;571571+572572+ return 0;573573+}574574+575575+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)576576+{577577+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;578578+579579+ cancel_work_sync(&ifibss->csa_connection_drop_work);580580+}581581+448582static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)449583 __acquires(RCU)450584{···689497 ieee80211_mandatory_rates(sband, scan_width);690498691499 return ieee80211_ibss_finish_sta(sta);500500+}501501+502502+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)503503+{504504+ struct ieee80211_local *local = sdata->local;505505+ int active = 0;506506+ struct sta_info *sta;507507+508508+ sdata_assert_lock(sdata);509509+510510+ rcu_read_lock();511511+512512+ list_for_each_entry_rcu(sta, &local->sta_list, list) {513513+ if (sta->sdata == sdata &&514514+ time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,515515+ jiffies)) {516516+ active++;517517+ break;518518+ }519519+ }520520+521521+ rcu_read_unlock();522522+523523+ return active;524524+}525525+526526+static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)527527+{528528+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;529529+ struct ieee80211_local *local = sdata->local;530530+ struct cfg80211_bss *cbss;531531+ struct beacon_data *presp;532532+ struct sta_info *sta;533533+ int active_ibss;534534+ u16 capability;535535+536536+ active_ibss = ieee80211_sta_active_ibss(sdata);537537+538538+ if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {539539+ capability = WLAN_CAPABILITY_IBSS;540540+541541+ if (ifibss->privacy)542542+ capability |= WLAN_CAPABILITY_PRIVACY;543543+544544+ cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,545545+ ifibss->bssid, ifibss->ssid,546546+ ifibss->ssid_len, WLAN_CAPABILITY_IBSS |547547+ WLAN_CAPABILITY_PRIVACY,548548+ capability);549549+550550+ if (cbss) {551551+ cfg80211_unlink_bss(local->hw.wiphy, cbss);552552+ cfg80211_put_bss(sdata->local->hw.wiphy, cbss);553553+ }554554+ }555555+556556+ ifibss->state = IEEE80211_IBSS_MLME_SEARCH;557557+558558+ sta_info_flush(sdata);559559+560560+ spin_lock_bh(&ifibss->incomplete_lock);561561+ while (!list_empty(&ifibss->incomplete_stations)) {562562+ sta = list_first_entry(&ifibss->incomplete_stations,563563+ struct sta_info, list);564564+ list_del(&sta->list);565565+ spin_unlock_bh(&ifibss->incomplete_lock);566566+567567+ sta_info_free(local, sta);568568+ spin_lock_bh(&ifibss->incomplete_lock);569569+ }570570+ spin_unlock_bh(&ifibss->incomplete_lock);571571+572572+ netif_carrier_off(sdata->dev);573573+574574+ sdata->vif.bss_conf.ibss_joined = false;575575+ sdata->vif.bss_conf.ibss_creator = false;576576+ sdata->vif.bss_conf.enable_beacon = false;577577+ sdata->vif.bss_conf.ssid_len = 0;578578+579579+ /* remove beacon */580580+ presp = rcu_dereference_protected(ifibss->presp,581581+ lockdep_is_held(&sdata->wdev.mtx));582582+ RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);583583+ if (presp)584584+ kfree_rcu(presp, rcu_head);585585+586586+ clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);587587+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |588588+ BSS_CHANGED_IBSS);589589+ drv_leave_ibss(local, sdata);590590+ ieee80211_vif_release_channel(sdata);591591+}592592+593593+static void ieee80211_csa_connection_drop_work(struct work_struct *work)594594+{595595+ struct ieee80211_sub_if_data *sdata =596596+ container_of(work, struct ieee80211_sub_if_data,597597+ u.ibss.csa_connection_drop_work);598598+599599+ ieee80211_ibss_disconnect(sdata);600600+ synchronize_rcu();601601+ skb_queue_purge(&sdata->skb_queue);602602+603603+ /* trigger a scan to find another IBSS network to join */604604+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);605605+}606606+607607+static bool608608+ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,609609+ struct ieee802_11_elems *elems,610610+ bool beacon)611611+{612612+ struct cfg80211_csa_settings params;613613+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;614614+ struct ieee80211_chanctx_conf *chanctx_conf;615615+ struct ieee80211_chanctx *chanctx;616616+ enum nl80211_channel_type ch_type;617617+ int err, num_chanctx;618618+ u32 sta_flags;619619+ u8 mode;620620+621621+ if (sdata->vif.csa_active)622622+ return true;623623+624624+ if (!sdata->vif.bss_conf.ibss_joined)625625+ return false;626626+627627+ sta_flags = IEEE80211_STA_DISABLE_VHT;628628+ switch (ifibss->chandef.width) {629629+ case NL80211_CHAN_WIDTH_5:630630+ case NL80211_CHAN_WIDTH_10:631631+ case NL80211_CHAN_WIDTH_20_NOHT:632632+ sta_flags |= IEEE80211_STA_DISABLE_HT;633633+ /* fall through */634634+ case NL80211_CHAN_WIDTH_20:635635+ sta_flags |= IEEE80211_STA_DISABLE_40MHZ;636636+ break;637637+ default:638638+ break;639639+ }640640+641641+ memset(¶ms, 0, sizeof(params));642642+ err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,643643+ ifibss->chandef.chan->band,644644+ sta_flags, ifibss->bssid,645645+ ¶ms.count, &mode,646646+ ¶ms.chandef);647647+648648+ /* can't switch to destination channel, fail */649649+ if (err < 0)650650+ goto disconnect;651651+652652+ /* did not contain a CSA */653653+ if (err)654654+ return false;655655+656656+ if (ifibss->chandef.chan->band != params.chandef.chan->band)657657+ goto disconnect;658658+659659+ switch (ifibss->chandef.width) {660660+ case NL80211_CHAN_WIDTH_20_NOHT:661661+ case NL80211_CHAN_WIDTH_20:662662+ case NL80211_CHAN_WIDTH_40:663663+ /* keep our current HT mode (HT20/HT40+/HT40-), even if664664+ * another mode has been announced. The mode is not adopted665665+ * within the beacon while doing CSA and we should therefore666666+ * keep the mode which we announce.667667+ */668668+ ch_type = cfg80211_get_chandef_type(&ifibss->chandef);669669+ cfg80211_chandef_create(¶ms.chandef, params.chandef.chan,670670+ ch_type);671671+ break;672672+ case NL80211_CHAN_WIDTH_5:673673+ case NL80211_CHAN_WIDTH_10:674674+ if (params.chandef.width != ifibss->chandef.width) {675675+ sdata_info(sdata,676676+ "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",677677+ ifibss->bssid,678678+ params.chandef.chan->center_freq,679679+ params.chandef.width,680680+ params.chandef.center_freq1,681681+ params.chandef.center_freq2);682682+ goto disconnect;683683+ }684684+ break;685685+ default:686686+ /* should not happen, sta_flags should prevent VHT modes. */687687+ WARN_ON(1);688688+ goto disconnect;689689+ }690690+691691+ if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef,692692+ IEEE80211_CHAN_DISABLED)) {693693+ sdata_info(sdata,694694+ "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",695695+ ifibss->bssid,696696+ params.chandef.chan->center_freq,697697+ params.chandef.width,698698+ params.chandef.center_freq1,699699+ params.chandef.center_freq2);700700+ goto disconnect;701701+ }702702+703703+ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,704704+ ¶ms.chandef);705705+ if (err < 0)706706+ goto disconnect;707707+ if (err) {708708+ params.radar_required = true;709709+710710+ /* TODO: IBSS-DFS not (yet) supported, disconnect. */711711+ goto disconnect;712712+ }713713+714714+ rcu_read_lock();715715+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);716716+ if (!chanctx_conf) {717717+ rcu_read_unlock();718718+ goto disconnect;719719+ }720720+721721+ /* don't handle for multi-VIF cases */722722+ chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);723723+ if (chanctx->refcount > 1) {724724+ rcu_read_unlock();725725+ goto disconnect;726726+ }727727+ num_chanctx = 0;728728+ list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)729729+ num_chanctx++;730730+731731+ if (num_chanctx > 1) {732732+ rcu_read_unlock();733733+ goto disconnect;734734+ }735735+ rcu_read_unlock();736736+737737+ /* all checks done, now perform the channel switch. */738738+ ibss_dbg(sdata,739739+ "received channel switch announcement to go to channel %d MHz\n",740740+ params.chandef.chan->center_freq);741741+742742+ params.block_tx = !!mode;743743+744744+ ieee80211_ibss_csa_beacon(sdata, ¶ms);745745+ sdata->csa_radar_required = params.radar_required;746746+747747+ if (params.block_tx)748748+ ieee80211_stop_queues_by_reason(&sdata->local->hw,749749+ IEEE80211_MAX_QUEUE_MAP,750750+ IEEE80211_QUEUE_STOP_REASON_CSA);751751+752752+ sdata->local->csa_chandef = params.chandef;753753+ sdata->vif.csa_active = true;754754+755755+ ieee80211_bss_info_change_notify(sdata, err);756756+ drv_channel_switch_beacon(sdata, ¶ms.chandef);757757+758758+ return true;759759+disconnect:760760+ ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");761761+ ieee80211_queue_work(&sdata->local->hw,762762+ &ifibss->csa_connection_drop_work);763763+764764+ return true;765765+}766766+767767+static void768768+ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,769769+ struct ieee80211_mgmt *mgmt, size_t len,770770+ struct ieee80211_rx_status *rx_status,771771+ struct ieee802_11_elems *elems)772772+{773773+ int required_len;774774+775775+ if (len < IEEE80211_MIN_ACTION_SIZE + 1)776776+ return;777777+778778+ /* CSA is the only action we handle for now */779779+ if (mgmt->u.action.u.measurement.action_code !=780780+ WLAN_ACTION_SPCT_CHL_SWITCH)781781+ return;782782+783783+ required_len = IEEE80211_MIN_ACTION_SIZE +784784+ sizeof(mgmt->u.action.u.chan_switch);785785+ if (len < required_len)786786+ return;787787+788788+ ieee80211_ibss_process_chanswitch(sdata, elems, false);692789}693790694791static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,···11426611143662 /* check if we need to merge IBSS */114466311451145- /* we use a fixed BSSID */11461146- if (sdata->u.ibss.fixed_bssid)11471147- goto put_bss;11481148-1149664 /* not an IBSS */1150665 if (!(cbss->capability & WLAN_CAPABILITY_IBSS))1151666 goto put_bss;···1157680 sdata->u.ibss.ssid_len))1158681 goto put_bss;1159682683683+ /* process channel switch */684684+ if (ieee80211_ibss_process_chanswitch(sdata, elems, true))685685+ goto put_bss;686686+1160687 /* same BSSID */1161688 if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))689689+ goto put_bss;690690+691691+ /* we use a fixed BSSID */692692+ if (sdata->u.ibss.fixed_bssid)1162693 goto put_bss;11636941164695 if (ieee80211_have_rx_timestamp(rx_status)) {···1258773 list_add(&sta->list, &ifibss->incomplete_stations);1259774 spin_unlock(&ifibss->incomplete_lock);1260775 ieee80211_queue_work(&local->hw, &sdata->work);12611261-}12621262-12631263-static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)12641264-{12651265- struct ieee80211_local *local = sdata->local;12661266- int active = 0;12671267- struct sta_info *sta;12681268-12691269- sdata_assert_lock(sdata);12701270-12711271- rcu_read_lock();12721272-12731273- list_for_each_entry_rcu(sta, &local->sta_list, list) {12741274- if (sta->sdata == sdata &&12751275- time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,12761276- jiffies)) {12771277- active++;12781278- break;12791279- }12801280- }12811281-12821282- rcu_read_unlock();12831283-12841284- return active;1285776}12867771287778static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)···15371076 struct ieee80211_rx_status *rx_status;15381077 struct ieee80211_mgmt *mgmt;15391078 u16 fc;10791079+ struct ieee802_11_elems elems;10801080+ int ies_len;1540108115411082 rx_status = IEEE80211_SKB_RXCB(skb);15421083 mgmt = (struct ieee80211_mgmt *) skb->data;···15641101 case IEEE80211_STYPE_DEAUTH:15651102 ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len);15661103 break;11041104+ case IEEE80211_STYPE_ACTION:11051105+ switch (mgmt->u.action.category) {11061106+ case WLAN_CATEGORY_SPECTRUM_MGMT:11071107+ ies_len = skb->len -11081108+ offsetof(struct ieee80211_mgmt,11091109+ u.action.u.chan_switch.variable);11101110+11111111+ if (ies_len < 0)11121112+ break;11131113+11141114+ ieee802_11_parse_elems(11151115+ mgmt->u.action.u.chan_switch.variable,11161116+ ies_len, true, &elems);11171117+11181118+ if (elems.parse_error)11191119+ break;11201120+11211121+ ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,11221122+ rx_status, &elems);11231123+ break;11241124+ }15671125 }1568112615691127 mgmt_out:···16511167 (unsigned long) sdata);16521168 INIT_LIST_HEAD(&ifibss->incomplete_stations);16531169 spin_lock_init(&ifibss->incomplete_lock);11701170+ INIT_WORK(&ifibss->csa_connection_drop_work,11711171+ ieee80211_csa_connection_drop_work);16541172}1655117316561174/* scan finished notification */···17511265int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)17521266{17531267 struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;17541754- struct ieee80211_local *local = sdata->local;17551755- struct cfg80211_bss *cbss;17561756- u16 capability;17571757- int active_ibss;17581758- struct sta_info *sta;17591759- struct beacon_data *presp;1760126817611761- active_ibss = ieee80211_sta_active_ibss(sdata);17621762-17631763- if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {17641764- capability = WLAN_CAPABILITY_IBSS;17651765-17661766- if (ifibss->privacy)17671767- capability |= WLAN_CAPABILITY_PRIVACY;17681768-17691769- cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,17701770- ifibss->bssid, ifibss->ssid,17711771- ifibss->ssid_len, WLAN_CAPABILITY_IBSS |17721772- WLAN_CAPABILITY_PRIVACY,17731773- capability);17741774-17751775- if (cbss) {17761776- cfg80211_unlink_bss(local->hw.wiphy, cbss);17771777- cfg80211_put_bss(local->hw.wiphy, cbss);17781778- }17791779- }17801780-17811781- ifibss->state = IEEE80211_IBSS_MLME_SEARCH;17821782- memset(ifibss->bssid, 0, ETH_ALEN);12691269+ ieee80211_ibss_disconnect(sdata);17831270 ifibss->ssid_len = 0;17841784-17851785- sta_info_flush(sdata);17861786-17871787- spin_lock_bh(&ifibss->incomplete_lock);17881788- while (!list_empty(&ifibss->incomplete_stations)) {17891789- sta = list_first_entry(&ifibss->incomplete_stations,17901790- struct sta_info, list);17911791- list_del(&sta->list);17921792- spin_unlock_bh(&ifibss->incomplete_lock);17931793-17941794- sta_info_free(local, sta);17951795- spin_lock_bh(&ifibss->incomplete_lock);17961796- }17971797- spin_unlock_bh(&ifibss->incomplete_lock);17981798-17991799- netif_carrier_off(sdata->dev);12711271+ memset(ifibss->bssid, 0, ETH_ALEN);1800127218011273 /* remove beacon */18021274 kfree(sdata->u.ibss.ie);18031803- presp = rcu_dereference_protected(ifibss->presp,18041804- lockdep_is_held(&sdata->wdev.mtx));18051805- RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);1806127518071276 /* on the next join, re-program HT parameters */18081277 memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));18091278 memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));1810127918111811- sdata->vif.bss_conf.ibss_joined = false;18121812- sdata->vif.bss_conf.ibss_creator = false;18131813- sdata->vif.bss_conf.enable_beacon = false;18141814- sdata->vif.bss_conf.ssid_len = 0;18151815- clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);18161816- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |18171817- BSS_CHANGED_IBSS);18181818- ieee80211_vif_release_channel(sdata);18191280 synchronize_rcu();18201820- kfree(presp);1821128118221282 skb_queue_purge(&sdata->skb_queue);18231283
+29-1
net/mac80211/ieee80211_i.h
···322322323323/* flags used in struct ieee80211_if_managed.flags */324324enum ieee80211_sta_flags {325325- IEEE80211_STA_BEACON_POLL = BIT(0),326325 IEEE80211_STA_CONNECTION_POLL = BIT(1),327326 IEEE80211_STA_CONTROL_PORT = BIT(2),328327 IEEE80211_STA_DISABLE_HT = BIT(4),···486487487488struct ieee80211_if_ibss {488489 struct timer_list timer;490490+ struct work_struct csa_connection_drop_work;489491490492 unsigned long last_scan_completed;491493···13301330void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);13311331void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,13321332 struct sk_buff *skb);13331333+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,13341334+ struct cfg80211_csa_settings *csa_settings);13351335+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);13361336+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);1333133713341338/* mesh code */13351339void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);···14851481void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,14861482 struct ieee80211_mgmt *mgmt,14871483 size_t len);14841484+/**14851485+ * ieee80211_parse_ch_switch_ie - parses channel switch IEs14861486+ * @sdata: the sdata of the interface which has received the frame14871487+ * @elems: parsed 802.11 elements received with the frame14881488+ * @beacon: indicates if the frame was a beacon or probe response14891489+ * @current_band: indicates the current band14901490+ * @sta_flags: contains information about own capabilities and restrictions14911491+ * to decide which channel switch announcements can be accepted. Only the14921492+ * following subset of &enum ieee80211_sta_flags are evaluated:14931493+ * %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,14941494+ * %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,14951495+ * %IEEE80211_STA_DISABLE_160MHZ.14961496+ * @count: to be filled with the counter until the switch (on success only)14971497+ * @bssid: the currently connected bssid (for reporting)14981498+ * @mode: to be filled with CSA mode (on success only)14991499+ * @new_chandef: to be filled with destination chandef (on success only)15001500+ * Return: 0 on success, <0 on error and >0 if there is nothing to parse.15011501+ */15021502+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,15031503+ struct ieee802_11_elems *elems, bool beacon,15041504+ enum ieee80211_band current_band,15051505+ u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,15061506+ struct cfg80211_chan_def *new_chandef);1488150714891508/* Suspend/resume and hw reconfiguration */14901509int ieee80211_reconfig(struct ieee80211_local *local);···16811654void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,16821655 const struct ieee80211_ht_operation *ht_oper,16831656 struct cfg80211_chan_def *chandef);16571657+u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);1684165816851659int __must_check16861660ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+4
net/mac80211/iface.c
···766766 if (sdata->vif.type == NL80211_IFTYPE_STATION)767767 ieee80211_mgd_stop(sdata);768768769769+ if (sdata->vif.type == NL80211_IFTYPE_ADHOC)770770+ ieee80211_ibss_stop(sdata);771771+772772+769773 /*770774 * Remove all stations associated with this interface.771775 *
+1-1
net/mac80211/key.c
···879879 keyconf->keylen, keyconf->key,880880 0, NULL);881881 if (IS_ERR(key))882882- return ERR_PTR(PTR_ERR(key));882882+ return ERR_CAST(key);883883884884 if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)885885 key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
+70-268
net/mac80211/mlme.c
···145145 return (1 << ecw) - 1;146146}147147148148-static u32 chandef_downgrade(struct cfg80211_chan_def *c)149149-{150150- u32 ret;151151- int tmp;152152-153153- switch (c->width) {154154- case NL80211_CHAN_WIDTH_20:155155- c->width = NL80211_CHAN_WIDTH_20_NOHT;156156- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;157157- break;158158- case NL80211_CHAN_WIDTH_40:159159- c->width = NL80211_CHAN_WIDTH_20;160160- c->center_freq1 = c->chan->center_freq;161161- ret = IEEE80211_STA_DISABLE_40MHZ |162162- IEEE80211_STA_DISABLE_VHT;163163- break;164164- case NL80211_CHAN_WIDTH_80:165165- tmp = (30 + c->chan->center_freq - c->center_freq1)/20;166166- /* n_P40 */167167- tmp /= 2;168168- /* freq_P40 */169169- c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;170170- c->width = NL80211_CHAN_WIDTH_40;171171- ret = IEEE80211_STA_DISABLE_VHT;172172- break;173173- case NL80211_CHAN_WIDTH_80P80:174174- c->center_freq2 = 0;175175- c->width = NL80211_CHAN_WIDTH_80;176176- ret = IEEE80211_STA_DISABLE_80P80MHZ |177177- IEEE80211_STA_DISABLE_160MHZ;178178- break;179179- case NL80211_CHAN_WIDTH_160:180180- /* n_P20 */181181- tmp = (70 + c->chan->center_freq - c->center_freq1)/20;182182- /* n_P80 */183183- tmp /= 4;184184- c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;185185- c->width = NL80211_CHAN_WIDTH_80;186186- ret = IEEE80211_STA_DISABLE_80P80MHZ |187187- IEEE80211_STA_DISABLE_160MHZ;188188- break;189189- default:190190- case NL80211_CHAN_WIDTH_20_NOHT:191191- WARN_ON_ONCE(1);192192- c->width = NL80211_CHAN_WIDTH_20_NOHT;193193- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;194194- break;195195- case NL80211_CHAN_WIDTH_5:196196- case NL80211_CHAN_WIDTH_10:197197- WARN_ON_ONCE(1);198198- /* keep c->width */199199- ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;200200- break;201201- }202202-203203- WARN_ON_ONCE(!cfg80211_chandef_valid(c));204204-205205- return ret;206206-}207207-208148static u32209149ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,210150 struct ieee80211_supported_band *sband,···292352 break;293353 }294354295295- ret |= chandef_downgrade(chandef);355355+ ret |= ieee80211_chandef_downgrade(chandef);296356 }297357298358 if (chandef->width != vht_chandef.width && !tracking)···346406 */347407 if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&348408 chandef.width == NL80211_CHAN_WIDTH_80P80)349349- flags |= chandef_downgrade(&chandef);409409+ flags |= ieee80211_chandef_downgrade(&chandef);350410 if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&351411 chandef.width == NL80211_CHAN_WIDTH_160)352352- flags |= chandef_downgrade(&chandef);412412+ flags |= ieee80211_chandef_downgrade(&chandef);353413 if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&354414 chandef.width > NL80211_CHAN_WIDTH_20)355355- flags |= chandef_downgrade(&chandef);415415+ flags |= ieee80211_chandef_downgrade(&chandef);356416357417 if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef))358418 return 0;···833893 if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)834894 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;835895836836- if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |837837- IEEE80211_STA_CONNECTION_POLL))896896+ if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)838897 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;839898840899 ieee80211_tx_skb(sdata, skb);···876937 container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);877938 struct ieee80211_local *local = sdata->local;878939 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;940940+ u32 changed = 0;941941+ int ret;879942880943 if (!ieee80211_sdata_running(sdata))881944 return;···886945 if (!ifmgd->associated)887946 goto out;888947889889- local->_oper_chandef = local->csa_chandef;948948+ ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,949949+ &changed);950950+ if (ret) {951951+ sdata_info(sdata,952952+ "vif channel switch failed, disconnecting\n");953953+ ieee80211_queue_work(&sdata->local->hw,954954+ &ifmgd->csa_connection_drop_work);955955+ goto out;956956+ }890957891891- if (!local->ops->channel_switch) {892892- /* call "hw_config" only if doing sw channel switch */893893- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);894894- } else {895895- /* update the device channel directly */896896- local->hw.conf.chandef = local->_oper_chandef;958958+ if (!local->use_chanctx) {959959+ local->_oper_chandef = local->csa_chandef;960960+ /* Call "hw_config" only if doing sw channel switch.961961+ * Otherwise update the channel directly962962+ */963963+ if (!local->ops->channel_switch)964964+ ieee80211_hw_config(local, 0);965965+ else966966+ local->hw.conf.chandef = local->_oper_chandef;897967 }898968899969 /* XXX: shouldn't really modify cfg80211-owned data! */900900- ifmgd->associated->channel = local->_oper_chandef.chan;970970+ ifmgd->associated->channel = local->csa_chandef.chan;901971902972 /* XXX: wait for a beacon first? */903973 ieee80211_wake_queues_by_reason(&local->hw,904974 IEEE80211_MAX_QUEUE_MAP,905975 IEEE80211_QUEUE_STOP_REASON_CSA);976976+977977+ ieee80211_bss_info_change_notify(sdata, changed);978978+906979 out:980980+ sdata->vif.csa_active = false;907981 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;908982 sdata_unlock(sdata);909983}···9561000 struct ieee80211_local *local = sdata->local;9571001 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;9581002 struct cfg80211_bss *cbss = ifmgd->associated;959959- struct ieee80211_bss *bss;9601003 struct ieee80211_chanctx *chanctx;961961- enum ieee80211_band new_band;962962- int new_freq;963963- u8 new_chan_no;10041004+ enum ieee80211_band current_band;9641005 u8 count;9651006 u8 mode;966966- struct ieee80211_channel *new_chan;9671007 struct cfg80211_chan_def new_chandef = {};968968- struct cfg80211_chan_def new_vht_chandef = {};969969- const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;970970- const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;971971- const struct ieee80211_ht_operation *ht_oper;972972- int secondary_channel_offset = -1;10081008+ int res;97310099741010 sdata_assert_lock(sdata);9751011···9751027 if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)9761028 return;9771029978978- sec_chan_offs = elems->sec_chan_offs;979979- wide_bw_chansw_ie = elems->wide_bw_chansw_ie;980980- ht_oper = elems->ht_operation;981981-982982- if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |983983- IEEE80211_STA_DISABLE_40MHZ)) {984984- sec_chan_offs = NULL;985985- wide_bw_chansw_ie = NULL;986986- /* only used for bandwidth here */987987- ht_oper = NULL;988988- }989989-990990- if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)991991- wide_bw_chansw_ie = NULL;992992-993993- if (elems->ext_chansw_ie) {994994- if (!ieee80211_operating_class_to_band(995995- elems->ext_chansw_ie->new_operating_class,996996- &new_band)) {997997- sdata_info(sdata,998998- "cannot understand ECSA IE operating class %d, disconnecting\n",999999- elems->ext_chansw_ie->new_operating_class);10001000- ieee80211_queue_work(&local->hw,10011001- &ifmgd->csa_connection_drop_work);10021002- }10031003- new_chan_no = elems->ext_chansw_ie->new_ch_num;10041004- count = elems->ext_chansw_ie->count;10051005- mode = elems->ext_chansw_ie->mode;10061006- } else if (elems->ch_switch_ie) {10071007- new_band = cbss->channel->band;10081008- new_chan_no = elems->ch_switch_ie->new_ch_num;10091009- count = elems->ch_switch_ie->count;10101010- mode = elems->ch_switch_ie->mode;10111011- } else {10121012- /* nothing here we understand */10131013- return;10141014- }10151015-10161016- bss = (void *)cbss->priv;10171017-10181018- new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);10191019- new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);10201020- if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {10211021- sdata_info(sdata,10221022- "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",10231023- ifmgd->associated->bssid, new_freq);10301030+ current_band = cbss->channel->band;10311031+ res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,10321032+ ifmgd->flags,10331033+ ifmgd->associated->bssid, &count,10341034+ &mode, &new_chandef);10351035+ if (res < 0)10241036 ieee80211_queue_work(&local->hw,10251037 &ifmgd->csa_connection_drop_work);10381038+ if (res)10261039 return;10271027- }10281028-10291029- if (!beacon && sec_chan_offs) {10301030- secondary_channel_offset = sec_chan_offs->sec_chan_offs;10311031- } else if (beacon && ht_oper) {10321032- secondary_channel_offset =10331033- ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;10341034- } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {10351035- /*10361036- * If it's not a beacon, HT is enabled and the IE not present,10371037- * it's 20 MHz, 802.11-2012 8.5.2.6:10381038- * This element [the Secondary Channel Offset Element] is10391039- * present when switching to a 40 MHz channel. It may be10401040- * present when switching to a 20 MHz channel (in which10411041- * case the secondary channel offset is set to SCN).10421042- */10431043- secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;10441044- }10451045-10461046- switch (secondary_channel_offset) {10471047- default:10481048- /* secondary_channel_offset was present but is invalid */10491049- case IEEE80211_HT_PARAM_CHA_SEC_NONE:10501050- cfg80211_chandef_create(&new_chandef, new_chan,10511051- NL80211_CHAN_HT20);10521052- break;10531053- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:10541054- cfg80211_chandef_create(&new_chandef, new_chan,10551055- NL80211_CHAN_HT40PLUS);10561056- break;10571057- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:10581058- cfg80211_chandef_create(&new_chandef, new_chan,10591059- NL80211_CHAN_HT40MINUS);10601060- break;10611061- case -1:10621062- cfg80211_chandef_create(&new_chandef, new_chan,10631063- NL80211_CHAN_NO_HT);10641064- /* keep width for 5/10 MHz channels */10651065- switch (sdata->vif.bss_conf.chandef.width) {10661066- case NL80211_CHAN_WIDTH_5:10671067- case NL80211_CHAN_WIDTH_10:10681068- new_chandef.width = sdata->vif.bss_conf.chandef.width;10691069- break;10701070- default:10711071- break;10721072- }10731073- break;10741074- }10751075-10761076- if (wide_bw_chansw_ie) {10771077- new_vht_chandef.chan = new_chan;10781078- new_vht_chandef.center_freq1 =10791079- ieee80211_channel_to_frequency(10801080- wide_bw_chansw_ie->new_center_freq_seg0,10811081- new_band);10821082-10831083- switch (wide_bw_chansw_ie->new_channel_width) {10841084- default:10851085- /* hmmm, ignore VHT and use HT if present */10861086- case IEEE80211_VHT_CHANWIDTH_USE_HT:10871087- new_vht_chandef.chan = NULL;10881088- break;10891089- case IEEE80211_VHT_CHANWIDTH_80MHZ:10901090- new_vht_chandef.width = NL80211_CHAN_WIDTH_80;10911091- break;10921092- case IEEE80211_VHT_CHANWIDTH_160MHZ:10931093- new_vht_chandef.width = NL80211_CHAN_WIDTH_160;10941094- break;10951095- case IEEE80211_VHT_CHANWIDTH_80P80MHZ:10961096- /* field is otherwise reserved */10971097- new_vht_chandef.center_freq2 =10981098- ieee80211_channel_to_frequency(10991099- wide_bw_chansw_ie->new_center_freq_seg1,11001100- new_band);11011101- new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;11021102- break;11031103- }11041104- if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&11051105- new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)11061106- chandef_downgrade(&new_vht_chandef);11071107- if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&11081108- new_vht_chandef.width == NL80211_CHAN_WIDTH_160)11091109- chandef_downgrade(&new_vht_chandef);11101110- if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&11111111- new_vht_chandef.width > NL80211_CHAN_WIDTH_20)11121112- chandef_downgrade(&new_vht_chandef);11131113- }11141114-11151115- /* if VHT data is there validate & use it */11161116- if (new_vht_chandef.chan) {11171117- if (!cfg80211_chandef_compatible(&new_vht_chandef,11181118- &new_chandef)) {11191119- sdata_info(sdata,11201120- "AP %pM CSA has inconsistent channel data, disconnecting\n",11211121- ifmgd->associated->bssid);11221122- ieee80211_queue_work(&local->hw,11231123- &ifmgd->csa_connection_drop_work);11241124- return;11251125- }11261126- new_chandef = new_vht_chandef;11271127- }1128104011291041 if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,11301042 IEEE80211_CHAN_DISABLED)) {11311043 sdata_info(sdata,11321044 "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",11331133- ifmgd->associated->bssid, new_freq,10451045+ ifmgd->associated->bssid,10461046+ new_chandef.chan->center_freq,11341047 new_chandef.width, new_chandef.center_freq1,11351048 new_chandef.center_freq2);11361049 ieee80211_queue_work(&local->hw,···10001191 }1001119210021193 ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;10031003-10041004- if (local->use_chanctx) {10051005- sdata_info(sdata,10061006- "not handling channel switch with channel contexts\n");10071007- ieee80211_queue_work(&local->hw,10081008- &ifmgd->csa_connection_drop_work);10091009- return;10101010- }11941194+ sdata->vif.csa_active = true;1011119510121196 mutex_lock(&local->chanctx_mtx);11971197+ if (local->use_chanctx) {11981198+ u32 num_chanctx = 0;11991199+ list_for_each_entry(chanctx, &local->chanctx_list, list)12001200+ num_chanctx++;12011201+12021202+ if (num_chanctx > 1 ||12031203+ !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {12041204+ sdata_info(sdata,12051205+ "not handling chan-switch with channel contexts\n");12061206+ ieee80211_queue_work(&local->hw,12071207+ &ifmgd->csa_connection_drop_work);12081208+ mutex_unlock(&local->chanctx_mtx);12091209+ return;12101210+ }12111211+ }12121212+10131213 if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {12141214+ ieee80211_queue_work(&local->hw,12151215+ &ifmgd->csa_connection_drop_work);10141216 mutex_unlock(&local->chanctx_mtx);10151217 return;10161218 }···11941374 if (!mgd->associated)11951375 return false;1196137611971197- if (mgd->flags & (IEEE80211_STA_BEACON_POLL |11981198- IEEE80211_STA_CONNECTION_POLL))13771377+ if (mgd->flags & IEEE80211_STA_CONNECTION_POLL)11991378 return false;1200137912011380 if (!mgd->have_beacon)···15101691{15111692 lockdep_assert_held(&sdata->local->mtx);1512169315131513- sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |15141514- IEEE80211_STA_BEACON_POLL);16941694+ sdata->u.mgd.flags &= ~IEEE80211_STA_CONNECTION_POLL;15151695 ieee80211_run_deferred_scan(sdata->local);15161696}15171697···17721954 struct ieee80211_local *local = sdata->local;1773195517741956 mutex_lock(&local->mtx);17751775- if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |17761776- IEEE80211_STA_CONNECTION_POLL))) {17771777- mutex_unlock(&local->mtx);17781778- return;17791779- }19571957+ if (!(ifmgd->flags & IEEE80211_STA_CONNECTION_POLL))19581958+ goto out;1780195917811960 __ieee80211_stop_poll(sdata);17821961···19092094 * because otherwise we would reset the timer every time and19102095 * never check whether we received a probe response!19112096 */19121912- if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |19131913- IEEE80211_STA_CONNECTION_POLL))20972097+ if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)19142098 already = true;19151915-19161916- if (beacon)19171917- ifmgd->flags |= IEEE80211_STA_BEACON_POLL;19181918- else19191919- ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;1920209919212100 mutex_unlock(&sdata->local->mtx);19222101···19832174 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,19842175 true, frame_buf);19852176 ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;21772177+ sdata->vif.csa_active = false;19862178 ieee80211_wake_queues_by_reason(&sdata->local->hw,19872179 IEEE80211_MAX_QUEUE_MAP,19882180 IEEE80211_QUEUE_STOP_REASON_CSA);···28713061 }28723062 }2873306328742874- if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {30643064+ if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {28753065 mlme_dbg_ratelimited(sdata,28763066 "cancelling AP probe due to a received beacon\n");28772877- mutex_lock(&local->mtx);28782878- ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;28792879- ieee80211_run_deferred_scan(local);28802880- mutex_unlock(&local->mtx);28812881-28822882- mutex_lock(&local->iflist_mtx);28832883- ieee80211_recalc_ps(local, -1);28842884- mutex_unlock(&local->iflist_mtx);30673067+ ieee80211_reset_ap_probe(sdata);28853068 }2886306928873070 /*···33463543 } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)33473544 run_again(sdata, ifmgd->assoc_data->timeout);3348354533493349- if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |33503350- IEEE80211_STA_CONNECTION_POLL) &&35463546+ if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL &&33513547 ifmgd->associated) {33523548 u8 bssid[ETH_ALEN];33533549 int max_tries;···36783876 return ret;3679387736803878 while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {36813681- ifmgd->flags |= chandef_downgrade(&chandef);38793879+ ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);36823880 ret = ieee80211_vif_use_channel(sdata, &chandef,36833881 IEEE80211_CHANCTX_SHARED);36843882 }
+14
net/mac80211/rc80211_minstrel.c
···203203 memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));204204 mi->max_prob_rate = tmp_prob_rate;205205206206+#ifdef CONFIG_MAC80211_DEBUGFS207207+ /* use fixed index if set */208208+ if (mp->fixed_rate_idx != -1) {209209+ mi->max_tp_rate[0] = mp->fixed_rate_idx;210210+ mi->max_tp_rate[1] = mp->fixed_rate_idx;211211+ mi->max_prob_rate = mp->fixed_rate_idx;212212+ }213213+#endif214214+206215 /* Reset update timer */207216 mi->stats_update = jiffies;208217···318309319310 /* increase sum packet counter */320311 mi->packet_count++;312312+313313+#ifdef CONFIG_MAC80211_DEBUGFS314314+ if (mp->fixed_rate_idx != -1)315315+ return;316316+#endif321317322318 delta = (mi->packet_count * sampling_ratio / 100) -323319 (mi->sample_count + mi->sample_deferred / 2);
+13-10
net/mac80211/rc80211_minstrel_ht.c
···365365 }366366 }367367368368+#ifdef CONFIG_MAC80211_DEBUGFS369369+ /* use fixed index if set */370370+ if (mp->fixed_rate_idx != -1) {371371+ mi->max_tp_rate = mp->fixed_rate_idx;372372+ mi->max_tp_rate2 = mp->fixed_rate_idx;373373+ mi->max_prob_rate = mp->fixed_rate_idx;374374+ }375375+#endif368376369377 mi->stats_update = jiffies;370378}···782774 info->flags |= mi->tx_flags;783775 minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);784776777777+#ifdef CONFIG_MAC80211_DEBUGFS778778+ if (mp->fixed_rate_idx != -1)779779+ return;780780+#endif781781+785782 /* Don't use EAPOL frames for sampling on non-mrr hw */786783 if (mp->hw->max_rates == 1 &&787784 (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))788785 sample_idx = -1;789786 else790787 sample_idx = minstrel_get_sample_rate(mp, mi);791791-792792-#ifdef CONFIG_MAC80211_DEBUGFS793793- /* use fixed index if set */794794- if (mp->fixed_rate_idx != -1) {795795- mi->max_tp_rate = mp->fixed_rate_idx;796796- mi->max_tp_rate2 = mp->fixed_rate_idx;797797- mi->max_prob_rate = mp->fixed_rate_idx;798798- sample_idx = -1;799799- }800800-#endif801788802789 mi->total_packets++;803790