提交 066433a6 编写于 作者: J John W. Linville
......@@ -240,13 +240,14 @@ static const struct ath_ops ath5k_common_ops = {
* Driver Initialization *
\***********************/
static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
static void ath5k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath5k_hw *ah = hw->priv;
struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
return ath_reg_notifier_apply(wiphy, request, regulatory);
ath_reg_notifier_apply(wiphy, request, regulatory);
}
/********************\
......
......@@ -3492,8 +3492,8 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ath6kl_cfg80211_stop(vif);
}
static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
static void ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ath6kl *ar = wiphy_priv(wiphy);
u32 rates[IEEE80211_NUM_BANDS];
......@@ -3506,17 +3506,13 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
request->processed ? " processed" : "",
request->initiator, request->user_reg_hint_type);
/*
* As firmware is not able intersect regdoms, we can only listen to
* cellular hints.
*/
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
return -EOPNOTSUPP;
return;
ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
if (ret) {
ath6kl_err("failed to set regdomain: %d\n", ret);
return ret;
return;
}
/*
......@@ -3536,10 +3532,8 @@ static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
if (ret) {
ath6kl_err("failed to start scan for a regdomain change: %d\n",
ret);
return ret;
return;
}
return 0;
}
static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
......
......@@ -280,14 +280,14 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
return ret;
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath9k_htc_priv *priv = hw->priv;
return ath_reg_notifier_apply(wiphy, request,
ath9k_hw_regulatory(priv->ah));
ath_reg_notifier_apply(wiphy, request,
ath9k_hw_regulatory(priv->ah));
}
static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
......
......@@ -303,16 +303,15 @@ static void setup_ht_cap(struct ath_softc *sc,
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void ath9k_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
int ret;
ret = ath_reg_notifier_apply(wiphy, request, reg);
ath_reg_notifier_apply(wiphy, request, reg);
/* Set tx power */
if (ah->curchan) {
......@@ -322,8 +321,6 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
ath9k_ps_restore(sc);
}
return ret;
}
/*
......
......@@ -1981,13 +1981,13 @@ static int carl9170_parse_eeprom(struct ar9170 *ar)
return 0;
}
static int carl9170_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void carl9170_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct ar9170 *ar = hw->priv;
return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
}
int carl9170_register(struct ar9170 *ar)
......
......@@ -356,9 +356,9 @@ static u16 ath_regd_find_country_by_name(char *alpha2)
return -1;
}
int ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg)
void ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg)
{
struct ath_common *common = container_of(reg, struct ath_common,
regulatory);
......@@ -373,7 +373,7 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
* any pending requests in the queue.
*/
if (!request)
return 0;
return;
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_CORE:
......@@ -409,8 +409,6 @@ int ath_reg_notifier_apply(struct wiphy *wiphy,
break;
}
return 0;
}
EXPORT_SYMBOL(ath_reg_notifier_apply);
......@@ -500,8 +498,8 @@ ath_get_regpair(int regdmn)
static int
ath_regd_init_wiphy(struct ath_regulatory *reg,
struct wiphy *wiphy,
int (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
{
const struct ieee80211_regdomain *regd;
......@@ -621,8 +619,8 @@ static int __ath_regd_init(struct ath_regulatory *reg)
int
ath_regd_init(struct ath_regulatory *reg,
struct wiphy *wiphy,
int (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
{
struct ath_common *common = container_of(reg, struct ath_common,
regulatory);
......
......@@ -252,12 +252,12 @@ enum CountryCode {
bool ath_is_world_regd(struct ath_regulatory *reg);
bool ath_is_49ghz_allowed(u16 redomain);
int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
int (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request));
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request));
u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
enum ieee80211_band band);
int ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg);
void ath_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct ath_regulatory *reg);
#endif
......@@ -702,8 +702,8 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
}
}
static int brcms_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void brcms_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct brcms_info *wl = hw->priv;
......@@ -744,8 +744,6 @@ static int brcms_reg_notifier(struct wiphy *wiphy,
if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
brcms_c_japan_ccode(request->alpha2));
return 0;
}
void brcms_c_regd_init(struct brcms_c_info *wlc)
......
......@@ -2132,6 +2132,21 @@ static void lbs_cfg_set_regulatory_hint(struct lbs_private *priv)
lbs_deb_leave(LBS_DEB_CFG80211);
}
static void lbs_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct lbs_private *priv = wiphy_priv(wiphy);
lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
"callback for domain %c%c\n", request->alpha2[0],
request->alpha2[1]);
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
if (lbs_iface_active(priv))
lbs_set_11d_domain_info(priv);
lbs_deb_leave(LBS_DEB_CFG80211);
}
/*
* This function get's called after lbs_setup_firmware() determined the
......@@ -2184,24 +2199,6 @@ int lbs_cfg_register(struct lbs_private *priv)
return ret;
}
int lbs_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = 0;
lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
"callback for domain %c%c\n", request->alpha2[0],
request->alpha2[1]);
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
if (lbs_iface_active(priv))
ret = lbs_set_11d_domain_info(priv);
lbs_deb_leave(LBS_DEB_CFG80211);
return ret;
}
void lbs_scan_deinit(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_CFG80211);
......
......@@ -10,9 +10,6 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
int lbs_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request);
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
......
......@@ -519,8 +519,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
* - Set by user
* - Set bt Country IE
*/
static int mwifiex_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
static void mwifiex_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
......@@ -540,8 +540,6 @@ static int mwifiex_reg_notifier(struct wiphy *wiphy,
break;
}
mwifiex_send_domain_info_cmd_fw(wiphy);
return 0;
}
/*
......
......@@ -298,9 +298,9 @@ static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
return;
}
static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct rtl_regulatory *reg)
static void _rtl_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct rtl_regulatory *reg)
{
/* We always apply this */
_rtl_reg_apply_radar_flags(wiphy);
......@@ -314,8 +314,6 @@ static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
_rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
break;
}
return 0;
}
static const struct ieee80211_regdomain *_rtl_regdomain_select(
......@@ -348,9 +346,9 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
struct wiphy *wiphy,
int (*reg_notifier) (struct wiphy *wiphy,
struct regulatory_request *
request))
void (*reg_notifier) (struct wiphy *wiphy,
struct regulatory_request *
request))
{
const struct ieee80211_regdomain *regd;
......@@ -379,7 +377,7 @@ static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
}
int rtl_regd_init(struct ieee80211_hw *hw,
int (*reg_notifier) (struct wiphy *wiphy,
void (*reg_notifier) (struct wiphy *wiphy,
struct regulatory_request *request))
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
......@@ -421,12 +419,12 @@ int rtl_regd_init(struct ieee80211_hw *hw,
return 0;
}
int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct rtl_priv *rtlpriv = rtl_priv(hw);
RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, "\n");
return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
_rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
}
......@@ -55,7 +55,7 @@ enum country_code_type_t {
};
int rtl_regd_init(struct ieee80211_hw *hw,
int (*reg_notifier) (struct wiphy *wiphy,
struct regulatory_request *request));
int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
void (*reg_notifier) (struct wiphy *wiphy,
struct regulatory_request *request));
void rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
#endif
......@@ -89,8 +89,8 @@ static int wl12xx_set_authorized(struct wl1271 *wl,
return 0;
}
static int wl1271_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
static void wl1271_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_supported_band *band;
struct ieee80211_channel *ch;
......@@ -107,8 +107,6 @@ static int wl1271_reg_notify(struct wiphy *wiphy,
IEEE80211_CHAN_PASSIVE_SCAN;
}
return 0;
}
static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
......
此差异已折叠。
......@@ -1522,6 +1522,8 @@ struct ieee80211_hw {
* structure can then access it via hw->priv. Note that mac802111 drivers should
* not use wiphy_priv() to try to get their private driver structure as this
* is already used internally by mac80211.
*
* Return: The mac80211 driver hw struct of @wiphy.
*/
struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy);
......@@ -2486,7 +2488,10 @@ enum ieee80211_rate_control_changed {
*
* @restart_complete: Called after a call to ieee80211_restart_hw(), when the
* reconfiguration has completed. This can help the driver implement the
* reconfiguration step. This callback may sleep.
* reconfiguration step. Also called when reconfiguring because the
* driver's resume function returned 1, as this is just like an "inline"
* hardware restart. This callback may sleep.
*
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
......@@ -2673,6 +2678,8 @@ struct ieee80211_ops {
*
* @priv_data_len: length of private data
* @ops: callbacks for this device
*
* Return: A pointer to the new hardware device, or %NULL on error.
*/
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops);
......@@ -2685,6 +2692,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
* need to fill the contained wiphy's information.
*
* @hw: the device to register as returned by ieee80211_alloc_hw()
*
* Return: 0 on success. An error code otherwise.
*/
int ieee80211_register_hw(struct ieee80211_hw *hw);
......@@ -2731,6 +2740,8 @@ extern char *__ieee80211_create_tpt_led_trigger(
* of the trigger so you can automatically link the LED device.
*
* @hw: the hardware to get the LED trigger name for
*
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
*/
static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
{
......@@ -2750,6 +2761,8 @@ static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
* of the trigger so you can automatically link the LED device.
*
* @hw: the hardware to get the LED trigger name for
*
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
*/
static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
{
......@@ -2769,6 +2782,8 @@ static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
* of the trigger so you can automatically link the LED device.
*
* @hw: the hardware to get the LED trigger name for
*
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
*/
static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
{
......@@ -2788,6 +2803,8 @@ static inline char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
* of the trigger so you can automatically link the LED device.
*
* @hw: the hardware to get the LED trigger name for
*
* Return: The name of the LED trigger. %NULL if not configured for LEDs.
*/
static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
{
......@@ -2805,9 +2822,10 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
* @blink_table: the blink table -- needs to be ordered by throughput
* @blink_table_len: size of the blink table
*
* This function returns %NULL (in case of error, or if no LED
* triggers are configured) or the name of the new trigger.
* This function must be called before ieee80211_register_hw().
* Return: %NULL (in case of error, or if no LED triggers are
* configured) or the name of the new trigger.
*
* Note: This function must be called before ieee80211_register_hw().
*/
static inline char *
ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags,
......@@ -2940,10 +2958,10 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw,
* Calls to this function for a single hardware must be synchronized against
* each other.
*
* The function returns -EINVAL when the requested PS mode is already set.
*
* @sta: currently connected sta
* @start: start or stop PS
*
* Return: 0 on success. -EINVAL when the requested PS mode is already set.
*/
int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
......@@ -2957,6 +2975,8 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start);
*
* @sta: currently connected sta
* @start: start or stop PS
*
* Return: Like ieee80211_sta_ps_transition().
*/
static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta,
bool start)
......@@ -3094,6 +3114,8 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets);
* according to the current DTIM parameters/TIM bitmap.
*
* The driver is responsible for freeing the returned skb.
*
* Return: The beacon template. %NULL on error.
*/
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
......@@ -3105,6 +3127,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* See ieee80211_beacon_get_tim().
*
* Return: See ieee80211_beacon_get_tim().
*/
static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
......@@ -3121,6 +3145,8 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
* hardware. The destination address should be set by the caller.
*
* Can only be called in AP mode.
*
* Return: The Probe Response template. %NULL on error.
*/
struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
......@@ -3136,6 +3162,8 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
*
* Note: Caller (or hardware) is responsible for setting the
* &IEEE80211_FCTL_PM bit.
*
* Return: The PS Poll template. %NULL on error.
*/
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
......@@ -3151,6 +3179,8 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
*
* Note: Caller (or hardware) is responsible for setting the
* &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields.
*
* Return: The nullfunc template. %NULL on error.
*/
struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
......@@ -3165,6 +3195,8 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
*
* Creates a Probe Request template which can, for example, be uploaded to
* hardware.
*
* Return: The Probe Request template. %NULL on error.
*/
struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
......@@ -3200,6 +3232,8 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
* If the RTS is generated in firmware, but the host system must provide
* the duration field, the low-level driver uses this function to receive
* the duration field value in little-endian byteorder.
*
* Return: The duration.
*/
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, size_t frame_len,
......@@ -3235,6 +3269,8 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
* If the CTS-to-self is generated in firmware, but the host system must provide
* the duration field, the low-level driver uses this function to receive
* the duration field value in little-endian byteorder.
*
* Return: The duration.
*/
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
......@@ -3251,6 +3287,8 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
*
* Calculate the duration field of some generic frame, given its
* length and transmission rate (in 100kbps).
*
* Return: The duration.
*/
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
......@@ -3267,9 +3305,10 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
* hardware/firmware does not implement buffering of broadcast/multicast
* frames when power saving is used, 802.11 code buffers them in the host
* memory. The low-level driver uses this function to fetch next buffered
* frame. In most cases, this is used when generating beacon frame. This
* function returns a pointer to the next buffered skb or NULL if no more
* buffered frames are available.
* frame. In most cases, this is used when generating beacon frame.
*
* Return: A pointer to the next buffered skb or NULL if no more buffered
* frames are available.
*
* Note: buffered frames are returned only after DTIM beacon frame was
* generated with ieee80211_beacon_get() and the low-level driver must thus
......@@ -3449,6 +3488,8 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
* @queue: queue number (counted from zero).
*
* Drivers should use this function instead of netif_stop_queue.
*
* Return: %true if the queue is stopped. %false otherwise.
*/
int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue);
......@@ -3646,7 +3687,9 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
* @vif: virtual interface to look for station on
* @addr: station's address
*
* This function must be called under RCU lock and the
* Return: The station, if found. %NULL otherwise.
*
* Note: This function must be called under RCU lock and the
* resulting pointer is only valid under RCU lock as well.
*/
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
......@@ -3659,7 +3702,9 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
* @addr: remote station's address
* @localaddr: local address (vif->sdata->vif.addr). Use NULL for 'any'.
*
* This function must be called under RCU lock and the
* Return: The station, if found. %NULL otherwise.
*
* Note: This function must be called under RCU lock and the
* resulting pointer is only valid under RCU lock as well.
*
* NOTE: You may pass NULL for localaddr, but then you will just get
......@@ -3789,7 +3834,9 @@ void ieee80211_iter_chan_contexts_atomic(
* information. This function must only be called from within the
* .bss_info_changed callback function and only in managed mode. The function
* is only useful when the interface is associated, otherwise it will return
* NULL.
* %NULL.
*
* Return: The Probe Request template. %NULL on error.
*/
struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
......@@ -4136,12 +4183,14 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif);
/**
* ieee80211_ave_rssi - report the average rssi for the specified interface
* ieee80211_ave_rssi - report the average RSSI for the specified interface
*
* @vif: the specified virtual interface
*
* This function return the average rssi value for the requested interface.
* It assumes that the given vif is valid.
* Note: This function assumes that the given vif is valid.
*
* Return: The average RSSI value for the requested interface, or 0 if not
* applicable.
*/
int ieee80211_ave_rssi(struct ieee80211_vif *vif);
......
......@@ -374,8 +374,8 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
* %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
* %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
* Background scan period can optionally be
......@@ -958,7 +958,7 @@ enum nl80211_commands {
* @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
* used for the association (&enum nl80211_mfp, represented as a u32);
* this attribute can be used
* with %NL80211_CMD_ASSOCIATE request
* with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
*
* @NL80211_ATTR_STA_FLAGS2: Attribute containing a
* &struct nl80211_sta_flag_update.
......@@ -1310,6 +1310,9 @@ enum nl80211_commands {
* if not given in START_AP 0 is assumed, if not given in SET_BSS
* no change is made.
*
* @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
* defined in &enum nl80211_mesh_power_mode.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
......@@ -1580,6 +1583,8 @@ enum nl80211_attrs {
NL80211_ATTR_P2P_CTWINDOW,
NL80211_ATTR_P2P_OPPPS,
NL80211_ATTR_LOCAL_MESH_POWER_MODE,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
......@@ -1838,6 +1843,10 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
* @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
* @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
* @NL80211_STA_INFO_LOCAL_PM: local mesh STA link-specific power mode
* @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
* @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
* non-peer STA
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
......@@ -1862,6 +1871,9 @@ enum nl80211_sta_info {
NL80211_STA_INFO_STA_FLAGS,
NL80211_STA_INFO_BEACON_LOSS,
NL80211_STA_INFO_T_OFFSET,
NL80211_STA_INFO_LOCAL_PM,
NL80211_STA_INFO_PEER_PM,
NL80211_STA_INFO_NONPEER_PM,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
......@@ -2252,6 +2264,34 @@ enum nl80211_mntr_flags {
NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
};
/**
* enum nl80211_mesh_power_mode - mesh power save modes
*
* @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is
* not known or has not been set yet.
* @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is
* in Awake state all the time.
* @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will
* alternate between Active and Doze states, but will wake up for
* neighbor's beacons.
* @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will
* alternate between Active and Doze states, but may not wake up
* for neighbor's beacons.
*
* @__NL80211_MESH_POWER_AFTER_LAST - internal use
* @NL80211_MESH_POWER_MAX - highest possible power save level
*/
enum nl80211_mesh_power_mode {
NL80211_MESH_POWER_UNKNOWN,
NL80211_MESH_POWER_ACTIVE,
NL80211_MESH_POWER_LIGHT_SLEEP,
NL80211_MESH_POWER_DEEP_SLEEP,
__NL80211_MESH_POWER_AFTER_LAST,
NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
};
/**
* enum nl80211_meshconf_params - mesh configuration parameters
*
......@@ -2346,6 +2386,11 @@ enum nl80211_mntr_flags {
* (in TUs) during which a mesh STA can send only one Action frame
* containing a PREQ element for root path confirmation.
*
* @NL80211_MESHCONF_POWER_MODE: Default mesh power mode for new peer links.
* type &enum nl80211_mesh_power_mode (u32)
*
* @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
......@@ -2375,6 +2420,8 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
NL80211_MESHCONF_POWER_MODE,
NL80211_MESHCONF_AWAKE_WINDOW,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
......@@ -2937,6 +2984,8 @@ enum nl80211_iface_limit_attrs {
* the infrastructure network's beacon interval.
* @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
* different channels may be used within this group.
* @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
* of supported channel widths for radar detection.
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
......@@ -2969,6 +3018,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_MAXNUM,
NL80211_IFACE_COMB_STA_AP_BI_MATCH,
NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
/* keep last */
NUM_NL80211_IFACE_COMB,
......
......@@ -1243,18 +1243,33 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
u32 changed = 0;
switch (params->plink_state) {
case NL80211_PLINK_LISTEN:
case NL80211_PLINK_ESTAB:
if (sta->plink_state != NL80211_PLINK_ESTAB)
changed = mesh_plink_inc_estab_count(
sdata);
sta->plink_state = params->plink_state;
break;
case NL80211_PLINK_LISTEN:
case NL80211_PLINK_BLOCKED:
case NL80211_PLINK_OPN_SNT:
case NL80211_PLINK_OPN_RCVD:
case NL80211_PLINK_CNF_RCVD:
case NL80211_PLINK_HOLDING:
if (sta->plink_state == NL80211_PLINK_ESTAB)
changed = mesh_plink_dec_estab_count(
sdata);
sta->plink_state = params->plink_state;
break;
default:
/* nothing */
break;
}
else
ieee80211_bss_info_change_notify(sdata, changed);
} else {
switch (params->plink_action) {
case PLINK_ACTION_OPEN:
mesh_plink_open(sta);
......@@ -1263,6 +1278,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
mesh_plink_block(sta);
break;
}
}
#endif
}
......@@ -1650,6 +1666,9 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
sizeof(setup->mcast_rate));
sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
sdata->vif.bss_conf.dtim_period = setup->dtim_period;
return 0;
}
......@@ -2232,7 +2251,8 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
if (sdata->vif.type != NL80211_IFTYPE_STATION)
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
......
......@@ -625,7 +625,6 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
ieee80211_queue_work(&local->hw, &sdata->work);
sdata->vif.bss_conf.ht_operation_mode =
ifmsh->mshcfg.ht_opmode;
sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.basic_rates =
ieee80211_mandatory_rates(local, band);
......
......@@ -191,8 +191,6 @@ struct mesh_rmc {
#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */
#define MESH_PATH_EXPIRE (600 * HZ)
/* Default maximum number of plinks per interface */
......@@ -307,6 +305,20 @@ extern int mesh_paths_generation;
#ifdef CONFIG_MAC80211_MESH
extern int mesh_allocated;
static inline
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.mesh.estab_plinks);
return mesh_accept_plinks_update(sdata);
}
static inline
u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.mesh.estab_plinks);
return mesh_accept_plinks_update(sdata);
}
static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
{
return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks -
......
......@@ -41,20 +41,6 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode action,
u8 *da, __le16 llid, __le16 plid, __le16 reason);
static inline
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.mesh.estab_plinks);
return mesh_accept_plinks_update(sdata);
}
static inline
u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.mesh.estab_plinks);
return mesh_accept_plinks_update(sdata);
}
/**
* mesh_plink_fsm_restart - restart a mesh peer link finite state machine
*
......
......@@ -199,11 +199,11 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
case NL80211_CHAN_WIDTH_40:
if (sdata->vif.bss_conf.chandef.chan->center_freq >
sdata->vif.bss_conf.chandef.center_freq1 &&
chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
disable_40 = true;
if (sdata->vif.bss_conf.chandef.chan->center_freq <
sdata->vif.bss_conf.chandef.center_freq1 &&
chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
disable_40 = true;
break;
default:
......
......@@ -28,21 +28,27 @@
#define VIF_PR_FMT " vif:%s(%d%s)"
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
#define CHANCTX_ENTRY __field(u32, control_freq) \
#define CHANDEF_ENTRY __field(u32, control_freq) \
__field(u32, chan_width) \
__field(u32, center_freq1) \
__field(u32, center_freq2) \
__field(u32, center_freq2)
#define CHANDEF_ASSIGN(c) \
__entry->control_freq = (c)->chan->center_freq; \
__entry->chan_width = (c)->width; \
__entry->center_freq1 = (c)->center_freq1; \
__entry->center_freq1 = (c)->center_freq2;
#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
__entry->center_freq1, __entry->center_freq2
#define CHANCTX_ENTRY CHANDEF_ENTRY \
__field(u8, rx_chains_static) \
__field(u8, rx_chains_dynamic)
#define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\
__entry->chan_width = ctx->conf.def.width; \
__entry->center_freq1 = ctx->conf.def.center_freq1; \
__entry->center_freq2 = ctx->conf.def.center_freq2; \
#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \
__entry->rx_chains_static = ctx->conf.rx_chains_static; \
__entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
#define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d"
#define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width, \
__entry->center_freq1, __entry->center_freq2, \
#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d"
#define CHANCTX_PR_ARG CHANDEF_PR_ARG, \
__entry->rx_chains_static, __entry->rx_chains_dynamic
......
......@@ -2261,9 +2261,8 @@ void ieee80211_tx_pending(unsigned long data)
/* functions for drivers to get certain frames */
static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ps_data *ps,
struct sk_buff *skb)
static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ps_data *ps, struct sk_buff *skb)
{
u8 *pos, *tim;
int aid0 = 0;
......@@ -2325,6 +2324,31 @@ static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
}
}
static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
struct ps_data *ps, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
/*
* Not very nice, but we want to allow the driver to call
* ieee80211_beacon_get() as a response to the set_tim()
* callback. That, however, is already invoked under the
* sta_lock to guarantee consistent and race-free update
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
__ieee80211_beacon_add_tim(sdata, ps, skb);
} else {
unsigned long flags;
spin_lock_irqsave(&local->tim_lock, flags);
__ieee80211_beacon_add_tim(sdata, ps, skb);
spin_unlock_irqrestore(&local->tim_lock, flags);
}
return 0;
}
struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u16 *tim_offset, u16 *tim_length)
......@@ -2369,22 +2393,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
memcpy(skb_put(skb, beacon->head_len), beacon->head,
beacon->head_len);
/*
* Not very nice, but we want to allow the driver to call
* ieee80211_beacon_get() as a response to the set_tim()
* callback. That, however, is already invoked under the
* sta_lock to guarantee consistent and race-free update
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
} else {
unsigned long flags;
spin_lock_irqsave(&local->tim_lock, flags);
ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
spin_unlock_irqrestore(&local->tim_lock, flags);
}
ieee80211_beacon_add_tim(sdata, &ap->ps, skb);
if (tim_offset)
*tim_offset = beacon->head_len;
......
......@@ -1358,6 +1358,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
struct ieee80211_chanctx *ctx;
struct sta_info *sta;
int res, i;
bool reconfig_due_to_wowlan = false;
#ifdef CONFIG_PM
if (local->suspended)
......@@ -1377,6 +1378,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* res is 1, which means the driver requested
* to go through a regular reset on wakeup.
*/
reconfig_due_to_wowlan = true;
}
#endif
/* everything else happens only if HW was up & running */
......@@ -1527,7 +1529,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
BSS_CHANGED_TXPOWER;
#ifdef CONFIG_PM
if (local->resuming)
if (local->resuming && !reconfig_due_to_wowlan)
sdata->vif.bss_conf = sdata->suspend_bss_conf;
#endif
......@@ -1654,10 +1656,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* If this is for hw restart things are still running.
* We may want to change that later, however.
*/
if (!local->suspended) {
if (!local->suspended || reconfig_due_to_wowlan)
drv_restart_complete(local);
if (!local->suspended)
return 0;
}
#ifdef CONFIG_PM
/* first set suspended false, then resuming */
......
......@@ -382,8 +382,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
c = &wiphy->iface_combinations[i];
/* Combinations with just one interface aren't real */
if (WARN_ON(c->max_interfaces < 2))
/*
* Combinations with just one interface aren't real,
* however we make an exception for DFS.
*/
if (WARN_ON((c->max_interfaces < 2) && !c->radar_detect_widths))
return -EINVAL;
/* Need at least one channel */
......@@ -398,6 +401,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
return -EINVAL;
/* DFS only works on one channel. */
if (WARN_ON(c->radar_detect_widths &&
(c->num_different_channels > 1)))
return -EINVAL;
if (WARN_ON(!c->n_limits))
return -EINVAL;
......
......@@ -425,7 +425,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_iftype iftype,
struct ieee80211_channel *chan,
enum cfg80211_chan_mode chanmode);
enum cfg80211_chan_mode chanmode,
u8 radar_detect);
static inline int
cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
......@@ -433,7 +434,7 @@ cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype)
{
return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
CHAN_MODE_UNDEFINED);
CHAN_MODE_UNDEFINED, 0);
}
static inline int
......@@ -450,7 +451,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
enum cfg80211_chan_mode chanmode)
{
return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
chan, chanmode);
chan, chanmode, 0);
}
void
......
......@@ -44,6 +44,10 @@
#define MESH_SYNC_NEIGHBOR_OFFSET_MAX 50
#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units (=TUs) */
#define MESH_DEFAULT_DTIM_PERIOD 2
#define MESH_DEFAULT_AWAKE_WINDOW 10 /* in 1024 us units (=TUs) */
const struct mesh_config default_mesh_config = {
.dot11MeshRetryTimeout = MESH_RET_T,
.dot11MeshConfirmTimeout = MESH_CONF_T,
......@@ -69,6 +73,8 @@ const struct mesh_config default_mesh_config = {
.dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT,
.dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL,
.dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
.power_mode = NL80211_MESH_POWER_ACTIVE,
.dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW,
};
const struct mesh_setup default_mesh_setup = {
......@@ -79,6 +85,8 @@ const struct mesh_setup default_mesh_setup = {
.ie = NULL,
.ie_len = 0,
.is_secure = false,
.beacon_interval = MESH_DEFAULT_BEACON_INTERVAL,
.dtim_period = MESH_DEFAULT_DTIM_PERIOD,
};
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
......
......@@ -856,6 +856,9 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
c->max_interfaces))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
c->radar_detect_widths))
goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
......@@ -2079,6 +2082,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
!(rdev->wiphy.interface_modes & (1 << type)))
return -EOPNOTSUPP;
if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) {
nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
ETH_ALEN);
if (!is_valid_ether_addr(params.macaddr))
return -EADDRNOTAVAIL;
}
if (info->attrs[NL80211_ATTR_4ADDR]) {
params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
......@@ -3001,6 +3011,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
sinfo->beacon_loss_count))
goto nla_put_failure;
if ((sinfo->filled & STATION_INFO_LOCAL_PM) &&
nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM,
sinfo->local_pm))
goto nla_put_failure;
if ((sinfo->filled & STATION_INFO_PEER_PM) &&
nla_put_u32(msg, NL80211_STA_INFO_PEER_PM,
sinfo->peer_pm))
goto nla_put_failure;
if ((sinfo->filled & STATION_INFO_NONPEER_PM) &&
nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM,
sinfo->nonpeer_pm))
goto nla_put_failure;
if (sinfo->filled & STATION_INFO_BSS_PARAM) {
bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
if (!bss_param)
......@@ -3206,6 +3228,17 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.plink_state =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
enum nl80211_mesh_power_mode pm = nla_get_u32(
info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
if (pm <= NL80211_MESH_POWER_UNKNOWN ||
pm > NL80211_MESH_POWER_MAX)
return -EINVAL;
params.local_pm = pm;
}
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
......@@ -3213,6 +3246,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
/* disallow mesh-specific things */
if (params.plink_action)
return -EINVAL;
if (params.local_pm)
return -EINVAL;
/* TDLS can't be set, ... */
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
......@@ -3265,6 +3300,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
/* disallow things sta doesn't support */
if (params.plink_action)
return -EINVAL;
if (params.local_pm)
return -EINVAL;
/* reject any changes other than AUTHORIZED */
if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
return -EINVAL;
......@@ -3922,7 +3959,11 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
cur_params.dot11MeshHWMProotInterval) ||
nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
cur_params.dot11MeshHWMPconfirmationInterval))
cur_params.dot11MeshHWMPconfirmationInterval) ||
nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
cur_params.power_mode) ||
nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
cur_params.dot11MeshAwakeWindowDuration))
goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
......@@ -3961,6 +4002,8 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
[NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
[NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
};
static const struct nla_policy
......@@ -3981,13 +4024,15 @@ static int nl80211_parse_mesh_config(struct genl_info *info,
struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
u32 mask = 0;
#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
do {\
if (table[attr_num]) {\
cfg->param = nla_fn(table[attr_num]); \
mask |= (1 << (attr_num - 1)); \
} \
} while (0);\
#define FILL_IN_MESH_PARAM_IF_SET(tb, cfg, param, min, max, mask, attr, fn) \
do { \
if (tb[attr]) { \
if (fn(tb[attr]) < min || fn(tb[attr]) > max) \
return -EINVAL; \
cfg->param = fn(tb[attr]); \
mask |= (1 << (attr - 1)); \
} \
} while (0)
if (!info->attrs[NL80211_ATTR_MESH_CONFIG])
......@@ -4002,83 +4047,98 @@ do {\
BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
/* Fill in the params struct */
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, 1, 255,
mask, NL80211_MESHCONF_RETRY_TIMEOUT,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, 1, 255,
mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, 1, 255,
mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, 0, 255,
mask, NL80211_MESHCONF_MAX_PEER_LINKS,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, 0, 16,
mask, NL80211_MESHCONF_MAX_RETRIES,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, 1, 255,
mask, NL80211_MESHCONF_TTL, nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, 1, 255,
mask, NL80211_MESHCONF_ELEMENT_TTL,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, 0, 1,
mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
1, 255, mask,
NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, 0, 255,
mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, 1, 65535,
mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, 1, 65535,
mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
1, 65535, mask,
NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
1, 65535, mask,
NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
1, 65535, mask,
NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
dot11MeshHWMPnetDiameterTraversalTime, mask,
dot11MeshHWMPnetDiameterTraversalTime,
1, 65535, mask,
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
NL80211_MESHCONF_HWMP_RANN_INTERVAL,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, 0, 4,
mask, NL80211_MESHCONF_HWMP_ROOTMODE,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, 1, 65535,
mask, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
dot11MeshGateAnnouncementProtocol, mask,
NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
dot11MeshGateAnnouncementProtocol, 0, 1,
mask, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
mask, NL80211_MESHCONF_FORWARDING,
nla_get_u8);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255,
mask, NL80211_MESHCONF_RSSI_THRESHOLD,
nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
mask, NL80211_MESHCONF_HT_OPMODE,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
mask,
1, 65535, mask,
NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval,
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, 1, 65535,
mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
dot11MeshHWMPconfirmationInterval, mask,
dot11MeshHWMPconfirmationInterval,
1, 65535, mask,
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
nla_get_u16);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, power_mode,
NL80211_MESH_POWER_ACTIVE,
NL80211_MESH_POWER_MAX,
mask, NL80211_MESHCONF_POWER_MODE,
nla_get_u32);
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
0, 65535, mask,
NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
if (mask_out)
*mask_out = mask;
......@@ -5875,6 +5935,15 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
if (info->attrs[NL80211_ATTR_USE_MFP]) {
connect.mfp = nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
if (connect.mfp != NL80211_MFP_REQUIRED &&
connect.mfp != NL80211_MFP_NO)
return -EINVAL;
} else {
connect.mfp = NL80211_MFP_NO;
}
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
connect.channel =
ieee80211_get_channel(wiphy,
......@@ -6660,6 +6729,21 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
return -EINVAL;
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
if (setup.beacon_interval < 10 ||
setup.beacon_interval > 10000)
return -EINVAL;
}
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
setup.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
if (setup.dtim_period < 1 || setup.dtim_period > 100)
return -EINVAL;
}
if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
/* parse additional setup parameters if given */
err = nl80211_parse_mesh_setup(info, &setup);
......
......@@ -1123,7 +1123,9 @@ static bool is_ht40_allowed(struct ieee80211_channel *chan)
if (chan->flags & IEEE80211_CHAN_DISABLED)
return false;
/* This would happen when regulatory rules disallow HT40 completely */
return !(chan->flags & IEEE80211_CHAN_NO_HT40);
if ((chan->flags & IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40)
return false;
return true;
}
static void reg_process_ht_flags_channel(struct wiphy *wiphy,
......
......@@ -192,7 +192,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
prev_bssid,
params->ssid, params->ssid_len,
params->ie, params->ie_len,
false, &params->crypto,
params->mfp != NL80211_MFP_NO,
&params->crypto,
params->flags, &params->ht_capa,
&params->ht_capa_mask);
if (err)
......
......@@ -1184,7 +1184,8 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
enum nl80211_iftype iftype,
struct ieee80211_channel *chan,
enum cfg80211_chan_mode chanmode)
enum cfg80211_chan_mode chanmode,
u8 radar_detect)
{
struct wireless_dev *wdev_iter;
u32 used_iftypes = BIT(iftype);
......@@ -1195,14 +1196,45 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
enum cfg80211_chan_mode chmode;
int num_different_channels = 0;
int total = 1;
bool radar_required;
int i, j;
ASSERT_RTNL();
lockdep_assert_held(&rdev->devlist_mtx);
if (WARN_ON(hweight32(radar_detect) > 1))
return -EINVAL;
switch (iftype) {
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_WDS:
radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR);
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_MONITOR:
radar_required = false;
break;
case NL80211_IFTYPE_P2P_DEVICE:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_UNSPECIFIED:
default:
return -EINVAL;
}
if (radar_required && !radar_detect)
return -EINVAL;
/* Always allow software iftypes */
if (rdev->wiphy.software_iftypes & BIT(iftype))
if (rdev->wiphy.software_iftypes & BIT(iftype)) {
if (radar_detect)
return -EINVAL;
return 0;
}
memset(num, 0, sizeof(num));
memset(used_channels, 0, sizeof(used_channels));
......@@ -1275,7 +1307,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
used_iftypes |= BIT(wdev_iter->iftype);
}
if (total == 1)
if (total == 1 && !radar_detect)
return 0;
for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
......@@ -1308,6 +1340,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
}
}
if (radar_detect && !(c->radar_detect_widths & radar_detect))
goto cont;
/*
* Finally check that all iftypes that we're currently
* using are actually part of this combination. If they
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册