diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/chan.c | 6 | ||||
-rw-r--r-- | net/wireless/genregdb.awk | 2 | ||||
-rw-r--r-- | net/wireless/ibss.c | 7 | ||||
-rw-r--r-- | net/wireless/mesh.c | 6 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 33 | ||||
-rw-r--r-- | net/wireless/rdev-ops.h | 9 | ||||
-rw-r--r-- | net/wireless/reg.c | 83 | ||||
-rw-r--r-- | net/wireless/trace.h | 12 | ||||
-rw-r--r-- | net/wireless/util.c | 31 |
9 files changed, 96 insertions, 93 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 2d4268c..cd10c19 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -705,12 +705,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: - /* these interface types don't really have a channel */ - return; case NL80211_IFTYPE_P2P_DEVICE: - if (wdev->wiphy->features & - NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL) - *chanmode = CHAN_MODE_EXCLUSIVE; + /* these interface types don't really have a channel */ return; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 9a8217d..fdfd3f0 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -105,6 +105,8 @@ function parse_reg_rule() flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " } else if (flagarray[arg] == "NO-IR") { flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " + } else if (flagarray[arg] == "AUTO-BW") { + flags = flags "\n\t\t\tNL80211_RRF_AUTO_BW | " } } diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 1470b90..349db9d 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -128,12 +128,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, #endif check_chan = params->chandef.chan; if (params->userspace_handles_dfs) { - /* use channel NULL to check for radar even if the current - * channel is not a radar channel - it might decide to change - * to DFS channel later. + /* Check for radar even if the current channel is not + * a radar channel - it might decide to change to DFS + * channel later. */ radar_detect_width = BIT(params->chandef.width); - check_chan = NULL; } err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index d42a3fc..5af5cc6 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -236,6 +236,12 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, if (!netif_running(wdev->netdev)) return -ENETDOWN; + /* cfg80211_can_use_chan() calls + * cfg80211_can_use_iftype_chan() with no radar + * detection, so if we're trying to use a radar + * channel here, something is wrong. + */ + WARN_ON_ONCE(chandef->chan->flags & IEEE80211_CHAN_RADAR); err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, CHAN_MODE_SHARED); if (err) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8e6b6a2..2c38b28 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -384,6 +384,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { .len = IEEE80211_QOS_MAP_LEN_MAX }, [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, + [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -4627,6 +4628,8 @@ static int parse_reg_rule(struct nlattr *tb[], return -EINVAL; if (!tb[NL80211_ATTR_FREQ_RANGE_END]) return -EINVAL; + if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) + return -EINVAL; if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) return -EINVAL; @@ -4636,9 +4639,8 @@ static int parse_reg_rule(struct nlattr *tb[], nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); freq_range->end_freq_khz = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); - if (tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) - freq_range->max_bandwidth_khz = - nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + freq_range->max_bandwidth_khz = + nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); power_rule->max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); @@ -5710,8 +5712,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->min_rssi_thold = NL80211_SCAN_RSSI_THOLD_OFF; } - if (info->attrs[NL80211_ATTR_IE]) { - request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); + if (ie_len) { + request->ie_len = ie_len; memcpy((void *)request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), request->ie_len); @@ -5911,17 +5913,22 @@ skip_beacons: if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) return -EINVAL; - if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || - dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO || - dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) { + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); - if (err < 0) { + if (err < 0) return err; - } else if (err) { + if (err) { radar_detect_width = BIT(params.chandef.width); params.radar_required = true; } + break; + default: + break; } err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, @@ -7269,6 +7276,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; u8 action_code, dialog_token; + u32 peer_capability = 0; u16 status_code; u8 *peer; @@ -7287,9 +7295,12 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); + if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) + peer_capability = + nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); return rdev_tdls_mgmt(rdev, dev, peer, action_code, - dialog_token, status_code, + dialog_token, status_code, peer_capability, nla_data(info->attrs[NL80211_ATTR_IE]), nla_len(info->attrs[NL80211_ATTR_IE])); } diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index c8e2259..74d97d3 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -769,13 +769,16 @@ static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev, static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len) + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) { int ret; trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, buf, len); + dialog_token, status_code, peer_capability, + buf, len); ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, buf, len); + dialog_token, status_code, peer_capability, + buf, len); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 24c257c..90b82e0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -563,9 +563,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, if (freq_range_tmp->end_freq_khz < freq_range->start_freq_khz) break; - if (freq_range_tmp->max_bandwidth_khz) - break; - freq_range = freq_range_tmp; } @@ -582,9 +579,6 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, if (freq_range_tmp->start_freq_khz > freq_range->end_freq_khz) break; - if (freq_range_tmp->max_bandwidth_khz) - break; - freq_range = freq_range_tmp; } @@ -729,21 +723,29 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, max_bandwidth1 = freq_range1->max_bandwidth_khz; max_bandwidth2 = freq_range2->max_bandwidth_khz; - /* - * In case max_bandwidth1 == 0 and max_bandwith2 == 0 set - * output bandwidth as 0 (auto calculation). Next we will - * calculate this correctly in handle_channel function. - * In other case calculate output bandwidth here. - */ - if (max_bandwidth1 || max_bandwidth2) { - if (!max_bandwidth1) - max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); - if (!max_bandwidth2) - max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); - } + if (rule1->flags & NL80211_RRF_AUTO_BW) + max_bandwidth1 = reg_get_max_bandwidth(rd1, rule1); + if (rule2->flags & NL80211_RRF_AUTO_BW) + max_bandwidth2 = reg_get_max_bandwidth(rd2, rule2); freq_range->max_bandwidth_khz = min(max_bandwidth1, max_bandwidth2); + intersected_rule->flags = rule1->flags | rule2->flags; + + /* + * In case NL80211_RRF_AUTO_BW requested for both rules + * set AUTO_BW in intersected rule also. Next we will + * calculate BW correctly in handle_channel function. + * In other case remove AUTO_BW flag while we calculate + * maximum bandwidth correctly and auto calculation is + * not required. + */ + if ((rule1->flags & NL80211_RRF_AUTO_BW) && + (rule2->flags & NL80211_RRF_AUTO_BW)) + intersected_rule->flags |= NL80211_RRF_AUTO_BW; + else + intersected_rule->flags &= ~NL80211_RRF_AUTO_BW; + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; if (freq_range->max_bandwidth_khz > freq_diff) freq_range->max_bandwidth_khz = freq_diff; @@ -753,8 +755,6 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, power_rule2->max_antenna_gain); - intersected_rule->flags = rule1->flags | rule2->flags; - if (!is_valid_reg_rule(intersected_rule)) return -EINVAL; @@ -938,31 +938,42 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator) EXPORT_SYMBOL(reg_initiator_name); #ifdef CONFIG_CFG80211_REG_DEBUG -static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, +static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, + struct ieee80211_channel *chan, const struct ieee80211_reg_rule *reg_rule) { const struct ieee80211_power_rule *power_rule; const struct ieee80211_freq_range *freq_range; - char max_antenna_gain[32]; + char max_antenna_gain[32], bw[32]; power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; if (!power_rule->max_antenna_gain) - snprintf(max_antenna_gain, 32, "N/A"); + snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A"); else - snprintf(max_antenna_gain, 32, "%d", power_rule->max_antenna_gain); + snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d", + power_rule->max_antenna_gain); + + if (reg_rule->flags & NL80211_RRF_AUTO_BW) + snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", + freq_range->max_bandwidth_khz, + reg_get_max_bandwidth(regd, reg_rule)); + else + snprintf(bw, sizeof(bw), "%d KHz", + freq_range->max_bandwidth_khz); REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n", chan->center_freq); - REG_DBG_PRINT("%d KHz - %d KHz @ %d KHz), (%s mBi, %d mBm)\n", + REG_DBG_PRINT("%d KHz - %d KHz @ %s), (%s mBi, %d mBm)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, - freq_range->max_bandwidth_khz, max_antenna_gain, + bw, max_antenna_gain, power_rule->max_eirp); } #else -static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, +static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd, + struct ieee80211_channel *chan, const struct ieee80211_reg_rule *reg_rule) { return; @@ -1022,17 +1033,16 @@ static void handle_channel(struct wiphy *wiphy, return; } - chan_reg_rule_print_dbg(chan, reg_rule); + regd = reg_get_regdomain(wiphy); + chan_reg_rule_print_dbg(regd, chan, reg_rule); power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; max_bandwidth_khz = freq_range->max_bandwidth_khz; /* Check if auto calculation requested */ - if (!max_bandwidth_khz) { - regd = reg_get_regdomain(wiphy); + if (reg_rule->flags & NL80211_RRF_AUTO_BW) max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); - } if (max_bandwidth_khz < MHZ_TO_KHZ(40)) bw_flags = IEEE80211_CHAN_NO_HT40; @@ -1437,14 +1447,14 @@ static void handle_channel_custom(struct wiphy *wiphy, return; } - chan_reg_rule_print_dbg(chan, reg_rule); + chan_reg_rule_print_dbg(regd, chan, reg_rule); power_rule = ®_rule->power_rule; freq_range = ®_rule->freq_range; max_bandwidth_khz = freq_range->max_bandwidth_khz; /* Check if auto calculation requested */ - if (!max_bandwidth_khz) + if (reg_rule->flags & NL80211_RRF_AUTO_BW) max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule); if (max_bandwidth_khz < MHZ_TO_KHZ(40)) @@ -2254,11 +2264,12 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) freq_range = ®_rule->freq_range; power_rule = ®_rule->power_rule; - if (!freq_range->max_bandwidth_khz) - snprintf(bw, 32, "%d KHz, AUTO", + if (reg_rule->flags & NL80211_RRF_AUTO_BW) + snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO", + freq_range->max_bandwidth_khz, reg_get_max_bandwidth(rd, reg_rule)); else - snprintf(bw, 32, "%d KHz", + snprintf(bw, sizeof(bw), "%d KHz", freq_range->max_bandwidth_khz); /* diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 5eaeed5..aabccf1 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1468,9 +1468,10 @@ TRACE_EVENT(rdev_sched_scan_start, TRACE_EVENT(rdev_tdls_mgmt, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len), + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len), TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, - buf, len), + peer_capability, buf, len), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY @@ -1478,6 +1479,7 @@ TRACE_EVENT(rdev_tdls_mgmt, __field(u8, action_code) __field(u8, dialog_token) __field(u16, status_code) + __field(u32, peer_capability) __dynamic_array(u8, buf, len) ), TP_fast_assign( @@ -1487,13 +1489,15 @@ TRACE_EVENT(rdev_tdls_mgmt, __entry->action_code = action_code; __entry->dialog_token = dialog_token; __entry->status_code = status_code; + __entry->peer_capability = peer_capability; memcpy(__get_dynamic_array(buf), buf, len); ), TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, " - "dialog_token: %u, status_code: %u, buf: %#.2x ", + "dialog_token: %u, status_code: %u, peer_capability: %u buf: %#.2x ", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->action_code, __entry->dialog_token, - __entry->status_code, ((u8 *)__get_dynamic_array(buf))[0]) + __entry->status_code, __entry->peer_capability, + ((u8 *)__get_dynamic_array(buf))[0]) ); TRACE_EVENT(rdev_dump_survey, diff --git a/net/wireless/util.c b/net/wireless/util.c index ad03af3..2bb685f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1285,7 +1285,6 @@ 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 = false; int i, j; ASSERT_RTNL(); @@ -1293,35 +1292,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, 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: - /* if the interface could potentially choose a DFS channel, - * then mark DFS as required. - */ - if (!chan) { - if (chanmode != CHAN_MODE_UNDEFINED && radar_detect) - radar_required = true; - break; - } - radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); - break; - case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_DEVICE: - case NL80211_IFTYPE_MONITOR: - break; - case NUM_NL80211_IFTYPES: - case NL80211_IFTYPE_UNSPECIFIED: - default: - return -EINVAL; - } - - if (radar_required && !radar_detect) + if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) return -EINVAL; /* Always allow software iftypes */ |