|
@@ -343,7 +343,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|
|
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
|
|
|
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
|
|
|
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
|
|
|
- [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
|
|
|
+ [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
|
|
|
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
|
|
|
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
|
|
|
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
|
|
@@ -400,6 +400,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|
|
[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
|
|
|
[NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
|
|
|
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
|
|
|
+ [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
|
|
|
+ .len = FILS_MAX_KEK_LEN },
|
|
|
+ [NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
|
|
|
+ [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
|
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
@@ -421,6 +425,7 @@ nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
|
|
|
[NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
|
|
|
};
|
|
|
|
|
|
+#ifdef CONFIG_PM
|
|
|
/* policy for WoWLAN attributes */
|
|
|
static const struct nla_policy
|
|
|
nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
|
|
@@ -454,6 +459,7 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
|
|
|
[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
|
|
|
[NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
|
|
|
};
|
|
|
+#endif /* CONFIG_PM */
|
|
|
|
|
|
/* policy for coalesce rule attributes */
|
|
|
static const struct nla_policy
|
|
@@ -1062,6 +1068,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
|
|
|
nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
|
|
|
c->radar_detect_regions)))
|
|
|
goto nla_put_failure;
|
|
|
+ if (c->beacon_int_min_gcd &&
|
|
|
+ nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
|
|
|
+ c->beacon_int_min_gcd))
|
|
|
+ goto nla_put_failure;
|
|
|
|
|
|
nla_nest_end(msg, nl_combi);
|
|
|
}
|
|
@@ -1309,6 +1319,95 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#define CMD(op, n) \
|
|
|
+ do { \
|
|
|
+ if (rdev->ops->op) { \
|
|
|
+ i++; \
|
|
|
+ if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
|
|
|
+ goto nla_put_failure; \
|
|
|
+ } \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
+static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
|
|
|
+ struct sk_buff *msg)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * do *NOT* add anything into this function, new things need to be
|
|
|
+ * advertised only to new versions of userspace that can deal with
|
|
|
+ * the split (and they can't possibly care about new features...
|
|
|
+ */
|
|
|
+ CMD(add_virtual_intf, NEW_INTERFACE);
|
|
|
+ CMD(change_virtual_intf, SET_INTERFACE);
|
|
|
+ CMD(add_key, NEW_KEY);
|
|
|
+ CMD(start_ap, START_AP);
|
|
|
+ CMD(add_station, NEW_STATION);
|
|
|
+ CMD(add_mpath, NEW_MPATH);
|
|
|
+ CMD(update_mesh_config, SET_MESH_CONFIG);
|
|
|
+ CMD(change_bss, SET_BSS);
|
|
|
+ CMD(auth, AUTHENTICATE);
|
|
|
+ CMD(assoc, ASSOCIATE);
|
|
|
+ CMD(deauth, DEAUTHENTICATE);
|
|
|
+ CMD(disassoc, DISASSOCIATE);
|
|
|
+ CMD(join_ibss, JOIN_IBSS);
|
|
|
+ CMD(join_mesh, JOIN_MESH);
|
|
|
+ CMD(set_pmksa, SET_PMKSA);
|
|
|
+ CMD(del_pmksa, DEL_PMKSA);
|
|
|
+ CMD(flush_pmksa, FLUSH_PMKSA);
|
|
|
+ if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
|
|
|
+ CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
|
|
+ CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
|
|
|
+ CMD(mgmt_tx, FRAME);
|
|
|
+ CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
|
|
|
+ if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
|
|
|
+ i++;
|
|
|
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
|
|
|
+ rdev->ops->join_mesh) {
|
|
|
+ i++;
|
|
|
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ CMD(set_wds_peer, SET_WDS_PEER);
|
|
|
+ if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
|
|
|
+ CMD(tdls_mgmt, TDLS_MGMT);
|
|
|
+ CMD(tdls_oper, TDLS_OPER);
|
|
|
+ }
|
|
|
+ if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
|
|
|
+ CMD(sched_scan_start, START_SCHED_SCAN);
|
|
|
+ CMD(probe_client, PROBE_CLIENT);
|
|
|
+ CMD(set_noack_map, SET_NOACK_MAP);
|
|
|
+ if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
|
|
|
+ i++;
|
|
|
+ if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+ CMD(start_p2p_device, START_P2P_DEVICE);
|
|
|
+ CMD(set_mcast_rate, SET_MCAST_RATE);
|
|
|
+#ifdef CONFIG_NL80211_TESTMODE
|
|
|
+ CMD(testmode_cmd, TESTMODE);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (rdev->ops->connect || rdev->ops->auth) {
|
|
|
+ i++;
|
|
|
+ if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rdev->ops->disconnect || rdev->ops->deauth) {
|
|
|
+ i++;
|
|
|
+ if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
|
|
|
+ goto nla_put_failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ return i;
|
|
|
+ nla_put_failure:
|
|
|
+ return -ENOBUFS;
|
|
|
+}
|
|
|
+
|
|
|
struct nl80211_dump_wiphy_state {
|
|
|
s64 filter_wiphy;
|
|
|
long start;
|
|
@@ -1536,68 +1635,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|
|
if (!nl_cmds)
|
|
|
goto nla_put_failure;
|
|
|
|
|
|
- i = 0;
|
|
|
-#define CMD(op, n) \
|
|
|
- do { \
|
|
|
- if (rdev->ops->op) { \
|
|
|
- i++; \
|
|
|
- if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
|
|
|
- goto nla_put_failure; \
|
|
|
- } \
|
|
|
- } while (0)
|
|
|
-
|
|
|
- CMD(add_virtual_intf, NEW_INTERFACE);
|
|
|
- CMD(change_virtual_intf, SET_INTERFACE);
|
|
|
- CMD(add_key, NEW_KEY);
|
|
|
- CMD(start_ap, START_AP);
|
|
|
- CMD(add_station, NEW_STATION);
|
|
|
- CMD(add_mpath, NEW_MPATH);
|
|
|
- CMD(update_mesh_config, SET_MESH_CONFIG);
|
|
|
- CMD(change_bss, SET_BSS);
|
|
|
- CMD(auth, AUTHENTICATE);
|
|
|
- CMD(assoc, ASSOCIATE);
|
|
|
- CMD(deauth, DEAUTHENTICATE);
|
|
|
- CMD(disassoc, DISASSOCIATE);
|
|
|
- CMD(join_ibss, JOIN_IBSS);
|
|
|
- CMD(join_mesh, JOIN_MESH);
|
|
|
- CMD(set_pmksa, SET_PMKSA);
|
|
|
- CMD(del_pmksa, DEL_PMKSA);
|
|
|
- CMD(flush_pmksa, FLUSH_PMKSA);
|
|
|
- if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
|
|
|
- CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
|
|
- CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
|
|
|
- CMD(mgmt_tx, FRAME);
|
|
|
- CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
|
|
|
- if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
|
|
|
- i++;
|
|
|
- if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
|
|
|
- goto nla_put_failure;
|
|
|
- }
|
|
|
- if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
|
|
|
- rdev->ops->join_mesh) {
|
|
|
- i++;
|
|
|
- if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
|
|
|
- goto nla_put_failure;
|
|
|
- }
|
|
|
- CMD(set_wds_peer, SET_WDS_PEER);
|
|
|
- if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
|
|
|
- CMD(tdls_mgmt, TDLS_MGMT);
|
|
|
- CMD(tdls_oper, TDLS_OPER);
|
|
|
- }
|
|
|
- if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
|
|
|
- CMD(sched_scan_start, START_SCHED_SCAN);
|
|
|
- CMD(probe_client, PROBE_CLIENT);
|
|
|
- CMD(set_noack_map, SET_NOACK_MAP);
|
|
|
- if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
|
|
|
- i++;
|
|
|
- if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
|
|
|
- goto nla_put_failure;
|
|
|
- }
|
|
|
- CMD(start_p2p_device, START_P2P_DEVICE);
|
|
|
- CMD(set_mcast_rate, SET_MCAST_RATE);
|
|
|
-#ifdef CONFIG_NL80211_TESTMODE
|
|
|
- CMD(testmode_cmd, TESTMODE);
|
|
|
-#endif
|
|
|
+ i = nl80211_add_commands_unsplit(rdev, msg);
|
|
|
+ if (i < 0)
|
|
|
+ goto nla_put_failure;
|
|
|
if (state->split) {
|
|
|
CMD(crit_proto_start, CRIT_PROTOCOL_START);
|
|
|
CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
|
|
@@ -1607,22 +1647,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
|
|
if (rdev->wiphy.features &
|
|
|
NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
|
|
|
CMD(add_tx_ts, ADD_TX_TS);
|
|
|
+ CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
|
|
|
+ CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
|
|
|
}
|
|
|
- /* add into the if now */
|
|
|
#undef CMD
|
|
|
|
|
|
- if (rdev->ops->connect || rdev->ops->auth) {
|
|
|
- i++;
|
|
|
- if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
|
|
|
- goto nla_put_failure;
|
|
|
- }
|
|
|
-
|
|
|
- if (rdev->ops->disconnect || rdev->ops->deauth) {
|
|
|
- i++;
|
|
|
- if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
|
|
|
- goto nla_put_failure;
|
|
|
- }
|
|
|
-
|
|
|
nla_nest_end(msg, nl_cmds);
|
|
|
state->split_start++;
|
|
|
if (state->split)
|
|
@@ -2283,10 +2312,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|
|
nla_for_each_nested(nl_txq_params,
|
|
|
info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
|
|
|
rem_txq_params) {
|
|
|
- result = nla_parse(tb, NL80211_TXQ_ATTR_MAX,
|
|
|
- nla_data(nl_txq_params),
|
|
|
- nla_len(nl_txq_params),
|
|
|
- txq_params_policy);
|
|
|
+ result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
|
|
|
+ nl_txq_params,
|
|
|
+ txq_params_policy);
|
|
|
if (result)
|
|
|
return result;
|
|
|
result = parse_txq_params(tb, &txq_params);
|
|
@@ -3536,8 +3564,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
|
|
|
sband = rdev->wiphy.bands[band];
|
|
|
if (sband == NULL)
|
|
|
return -EINVAL;
|
|
|
- err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
|
|
|
- nla_len(tx_rates), nl80211_txattr_policy);
|
|
|
+ err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
|
|
|
+ nl80211_txattr_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
if (tb[NL80211_TXRATE_LEGACY]) {
|
|
@@ -3743,12 +3771,23 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
|
|
|
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
|
|
|
auth_type == NL80211_AUTHTYPE_SAE)
|
|
|
return false;
|
|
|
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
|
|
+ NL80211_EXT_FEATURE_FILS_STA) &&
|
|
|
+ (auth_type == NL80211_AUTHTYPE_FILS_SK ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_PK))
|
|
|
+ return false;
|
|
|
return true;
|
|
|
case NL80211_CMD_CONNECT:
|
|
|
case NL80211_CMD_START_AP:
|
|
|
/* SAE not supported yet */
|
|
|
if (auth_type == NL80211_AUTHTYPE_SAE)
|
|
|
return false;
|
|
|
+ /* FILS not supported yet */
|
|
|
+ if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_PK)
|
|
|
+ return false;
|
|
|
return true;
|
|
|
default:
|
|
|
return false;
|
|
@@ -3790,7 +3829,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|
|
params.dtim_period =
|
|
|
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
|
|
|
|
|
|
- err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
|
|
|
+ err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
|
|
|
+ params.beacon_interval);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -6292,9 +6332,8 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
|
|
nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
|
|
|
rem_reg_rules) {
|
|
|
- r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
|
|
|
- nla_data(nl_reg_rule), nla_len(nl_reg_rule),
|
|
|
- reg_rule_policy);
|
|
|
+ r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
|
|
|
+ nl_reg_rule, reg_rule_policy);
|
|
|
if (r)
|
|
|
goto bad_reg;
|
|
|
r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
|
|
@@ -6361,8 +6400,8 @@ static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
|
|
|
if (!nla_ok(nest, nla_len(nest)))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest),
|
|
|
- nla_len(nest), nl80211_bss_select_policy);
|
|
|
+ err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
|
|
|
+ nl80211_bss_select_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -6752,9 +6791,8 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
|
|
|
if (WARN_ON(i >= n_plans))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- err = nla_parse(plan, NL80211_SCHED_SCAN_PLAN_MAX,
|
|
|
- nla_data(attr), nla_len(attr),
|
|
|
- nl80211_plan_policy);
|
|
|
+ err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
|
|
|
+ attr, nl80211_plan_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -6843,9 +6881,9 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|
|
tmp) {
|
|
|
struct nlattr *rssi;
|
|
|
|
|
|
- err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
|
|
|
- nla_data(attr), nla_len(attr),
|
|
|
- nl80211_match_policy);
|
|
|
+ err = nla_parse_nested(tb,
|
|
|
+ NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
|
|
|
+ attr, nl80211_match_policy);
|
|
|
if (err)
|
|
|
return ERR_PTR(err);
|
|
|
/* add other standalone attributes here */
|
|
@@ -7016,9 +7054,9 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
|
|
|
tmp) {
|
|
|
struct nlattr *ssid, *rssi;
|
|
|
|
|
|
- err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
|
|
|
- nla_data(attr), nla_len(attr),
|
|
|
- nl80211_match_policy);
|
|
|
+ err = nla_parse_nested(tb,
|
|
|
+ NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
|
|
|
+ attr, nl80211_match_policy);
|
|
|
if (err)
|
|
|
goto out_free;
|
|
|
ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
|
|
@@ -7696,8 +7734,8 @@ static int nl80211_authenticate(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];
|
|
|
struct ieee80211_channel *chan;
|
|
|
- const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
|
|
|
- int err, ssid_len, ie_len = 0, sae_data_len = 0;
|
|
|
+ const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
|
|
|
+ int err, ssid_len, ie_len = 0, auth_data_len = 0;
|
|
|
enum nl80211_auth_type auth_type;
|
|
|
struct key_parse key;
|
|
|
bool local_state_change;
|
|
@@ -7777,17 +7815,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (auth_type == NL80211_AUTHTYPE_SAE &&
|
|
|
- !info->attrs[NL80211_ATTR_SAE_DATA])
|
|
|
+ if ((auth_type == NL80211_AUTHTYPE_SAE ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_SK ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
|
|
|
+ auth_type == NL80211_AUTHTYPE_FILS_PK) &&
|
|
|
+ !info->attrs[NL80211_ATTR_AUTH_DATA])
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (info->attrs[NL80211_ATTR_SAE_DATA]) {
|
|
|
- if (auth_type != NL80211_AUTHTYPE_SAE)
|
|
|
+ if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
|
|
|
+ if (auth_type != NL80211_AUTHTYPE_SAE &&
|
|
|
+ auth_type != NL80211_AUTHTYPE_FILS_SK &&
|
|
|
+ auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
|
|
|
+ auth_type != NL80211_AUTHTYPE_FILS_PK)
|
|
|
return -EINVAL;
|
|
|
- sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
|
|
|
- sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
|
|
|
+ auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
|
|
|
+ auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
|
|
|
/* need to include at least Auth Transaction and Status Code */
|
|
|
- if (sae_data_len < 4)
|
|
|
+ if (auth_data_len < 4)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -7804,7 +7848,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
|
|
|
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
|
|
|
ssid, ssid_len, ie, ie_len,
|
|
|
key.p.key, key.p.key_len, key.idx,
|
|
|
- sae_data, sae_data_len);
|
|
|
+ auth_data, auth_data_len);
|
|
|
wdev_unlock(dev->ieee80211_ptr);
|
|
|
return err;
|
|
|
}
|
|
@@ -7983,6 +8027,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
|
|
req.flags |= ASSOC_REQ_USE_RRM;
|
|
|
}
|
|
|
|
|
|
+ if (info->attrs[NL80211_ATTR_FILS_KEK]) {
|
|
|
+ req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
|
|
|
+ req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
|
|
|
+ if (!info->attrs[NL80211_ATTR_FILS_NONCES])
|
|
|
+ return -EINVAL;
|
|
|
+ req.fils_nonces =
|
|
|
+ nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
|
|
|
+ }
|
|
|
+
|
|
|
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
|
|
|
if (!err) {
|
|
|
wdev_lock(dev->ieee80211_ptr);
|
|
@@ -8140,7 +8193,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
|
|
ibss.beacon_interval =
|
|
|
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
|
|
|
|
|
- err = cfg80211_validate_beacon_int(rdev, ibss.beacon_interval);
|
|
|
+ err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
|
|
|
+ ibss.beacon_interval);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -8713,6 +8767,37 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int nl80211_update_connect_params(struct sk_buff *skb,
|
|
|
+ struct genl_info *info)
|
|
|
+{
|
|
|
+ struct cfg80211_connect_params connect = {};
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+ struct net_device *dev = info->user_ptr[1];
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
+ u32 changed = 0;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!rdev->ops->update_connect_params)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (info->attrs[NL80211_ATTR_IE]) {
|
|
|
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
|
|
|
+ return -EINVAL;
|
|
|
+ connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
|
|
|
+ connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
|
|
|
+ changed |= UPDATE_ASSOC_IES;
|
|
|
+ }
|
|
|
+
|
|
|
+ wdev_lock(dev->ieee80211_ptr);
|
|
|
+ if (!wdev->current_bss)
|
|
|
+ ret = -ENOLINK;
|
|
|
+ else
|
|
|
+ ret = rdev_update_connect_params(rdev, dev, &connect, changed);
|
|
|
+ wdev_unlock(dev->ieee80211_ptr);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
|
|
|
{
|
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
@@ -9404,7 +9489,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
|
|
|
setup.beacon_interval =
|
|
|
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
|
|
|
|
|
- err = cfg80211_validate_beacon_int(rdev, setup.beacon_interval);
|
|
|
+ err = cfg80211_validate_beacon_int(rdev,
|
|
|
+ NL80211_IFTYPE_MESH_POINT,
|
|
|
+ setup.beacon_interval);
|
|
|
if (err)
|
|
|
return err;
|
|
|
}
|
|
@@ -9715,9 +9802,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
|
|
|
if (!rdev->wiphy.wowlan->tcp)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP,
|
|
|
- nla_data(attr), nla_len(attr),
|
|
|
- nl80211_wowlan_tcp_policy);
|
|
|
+ err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
|
|
|
+ nl80211_wowlan_tcp_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -9862,9 +9948,7 @@ static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- err = nla_parse(tb, NL80211_ATTR_MAX,
|
|
|
- nla_data(attr), nla_len(attr),
|
|
|
- nl80211_policy);
|
|
|
+ err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy);
|
|
|
if (err)
|
|
|
goto out;
|
|
|
|
|
@@ -9898,10 +9982,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|
|
goto set_wakeup;
|
|
|
}
|
|
|
|
|
|
- err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
|
|
|
- nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
|
|
|
- nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
|
|
|
- nl80211_wowlan_policy);
|
|
|
+ err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
|
|
|
+ info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
|
|
|
+ nl80211_wowlan_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -9983,8 +10066,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
|
|
rem) {
|
|
|
u8 *mask_pat;
|
|
|
|
|
|
- nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
|
|
|
- nla_len(pat), NULL);
|
|
|
+ nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
|
|
|
+ NULL);
|
|
|
err = -EINVAL;
|
|
|
if (!pat_tb[NL80211_PKTPAT_MASK] ||
|
|
|
!pat_tb[NL80211_PKTPAT_PATTERN])
|
|
@@ -10194,8 +10277,8 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
|
|
|
int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
|
|
|
struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
|
|
|
|
|
|
- err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule),
|
|
|
- nla_len(rule), nl80211_coalesce_policy);
|
|
|
+ err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
|
|
|
+ nl80211_coalesce_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -10233,8 +10316,7 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
|
|
|
rem) {
|
|
|
u8 *mask_pat;
|
|
|
|
|
|
- nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat),
|
|
|
- nla_len(pat), NULL);
|
|
|
+ nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat, NULL);
|
|
|
if (!pat_tb[NL80211_PKTPAT_MASK] ||
|
|
|
!pat_tb[NL80211_PKTPAT_PATTERN])
|
|
|
return -EINVAL;
|
|
@@ -10353,10 +10435,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (!info->attrs[NL80211_ATTR_REKEY_DATA])
|
|
|
return -EINVAL;
|
|
|
|
|
|
- err = nla_parse(tb, MAX_NL80211_REKEY_DATA,
|
|
|
- nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]),
|
|
|
- nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]),
|
|
|
- nl80211_rekey_policy);
|
|
|
+ err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
|
|
|
+ info->attrs[NL80211_ATTR_REKEY_DATA],
|
|
|
+ nl80211_rekey_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -10505,7 +10586,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (wdev->p2p_started)
|
|
|
+ if (wdev_running(wdev))
|
|
|
return 0;
|
|
|
|
|
|
if (rfkill_blocked(rdev->rfkill))
|
|
@@ -10515,7 +10596,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
- wdev->p2p_started = true;
|
|
|
+ wdev->is_running = true;
|
|
|
rdev->opencount++;
|
|
|
|
|
|
return 0;
|
|
@@ -10547,7 +10628,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (wdev->iftype != NL80211_IFTYPE_NAN)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (wdev->nan_started)
|
|
|
+ if (!wdev_running(wdev))
|
|
|
return -EEXIST;
|
|
|
|
|
|
if (rfkill_blocked(rdev->rfkill))
|
|
@@ -10570,7 +10651,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
- wdev->nan_started = true;
|
|
|
+ wdev->is_running = true;
|
|
|
rdev->opencount++;
|
|
|
|
|
|
return 0;
|
|
@@ -10654,7 +10735,7 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
|
|
|
if (wdev->iftype != NL80211_IFTYPE_NAN)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (!wdev->nan_started)
|
|
|
+ if (!wdev_running(wdev))
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
if (!info->attrs[NL80211_ATTR_NAN_FUNC])
|
|
@@ -10664,10 +10745,9 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
|
|
|
wdev->owner_nlportid != info->snd_portid)
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
- err = nla_parse(tb, NL80211_NAN_FUNC_ATTR_MAX,
|
|
|
- nla_data(info->attrs[NL80211_ATTR_NAN_FUNC]),
|
|
|
- nla_len(info->attrs[NL80211_ATTR_NAN_FUNC]),
|
|
|
- nl80211_nan_func_policy);
|
|
|
+ err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
|
|
|
+ info->attrs[NL80211_ATTR_NAN_FUNC],
|
|
|
+ nl80211_nan_func_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -10762,9 +10842,9 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
|
|
|
if (tb[NL80211_NAN_FUNC_SRF]) {
|
|
|
struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
|
|
|
|
|
|
- err = nla_parse(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
|
|
|
- nla_data(tb[NL80211_NAN_FUNC_SRF]),
|
|
|
- nla_len(tb[NL80211_NAN_FUNC_SRF]), NULL);
|
|
|
+ err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
|
|
|
+ tb[NL80211_NAN_FUNC_SRF],
|
|
|
+ nl80211_nan_srf_policy);
|
|
|
if (err)
|
|
|
goto out;
|
|
|
|
|
@@ -10890,7 +10970,7 @@ static int nl80211_nan_del_func(struct sk_buff *skb,
|
|
|
if (wdev->iftype != NL80211_IFTYPE_NAN)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (!wdev->nan_started)
|
|
|
+ if (!wdev_running(wdev))
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
if (!info->attrs[NL80211_ATTR_COOKIE])
|
|
@@ -10918,7 +10998,7 @@ static int nl80211_nan_change_config(struct sk_buff *skb,
|
|
|
if (wdev->iftype != NL80211_IFTYPE_NAN)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if (!wdev->nan_started)
|
|
|
+ if (!wdev_running(wdev))
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
|
|
@@ -11230,10 +11310,7 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
|
|
|
- if (wdev->netdev &&
|
|
|
- !netif_running(wdev->netdev))
|
|
|
- return -ENETDOWN;
|
|
|
- if (!wdev->netdev && !wdev->p2p_started)
|
|
|
+ if (!wdev_running(wdev))
|
|
|
return -ENETDOWN;
|
|
|
}
|
|
|
|
|
@@ -11394,10 +11471,7 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
|
|
|
- if (wdev->netdev &&
|
|
|
- !netif_running(wdev->netdev))
|
|
|
- return -ENETDOWN;
|
|
|
- if (!wdev->netdev && !wdev->p2p_started)
|
|
|
+ if (!wdev_running(wdev))
|
|
|
return -ENETDOWN;
|
|
|
}
|
|
|
}
|
|
@@ -11710,6 +11784,31 @@ static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int nl80211_set_multicast_to_unicast(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];
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
+ const struct nlattr *nla;
|
|
|
+ bool enabled;
|
|
|
+
|
|
|
+ if (netif_running(dev))
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ if (!rdev->ops->set_multicast_to_unicast)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
|
|
|
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
|
|
|
+ enabled = nla_get_flag(nla);
|
|
|
+
|
|
|
+ return rdev_set_multicast_to_unicast(rdev, dev, enabled);
|
|
|
+}
|
|
|
+
|
|
|
#define NL80211_FLAG_NEED_WIPHY 0x01
|
|
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
|
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
|
@@ -11768,29 +11867,15 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
|
|
|
info->user_ptr[1] = wdev;
|
|
|
}
|
|
|
|
|
|
- if (dev) {
|
|
|
- if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
|
|
|
- !netif_running(dev)) {
|
|
|
- if (rtnl)
|
|
|
- rtnl_unlock();
|
|
|
- return -ENETDOWN;
|
|
|
- }
|
|
|
+ if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
|
|
|
+ !wdev_running(wdev)) {
|
|
|
+ if (rtnl)
|
|
|
+ rtnl_unlock();
|
|
|
+ return -ENETDOWN;
|
|
|
+ }
|
|
|
|
|
|
+ if (dev)
|
|
|
dev_hold(dev);
|
|
|
- } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
|
|
|
- if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
|
|
|
- !wdev->p2p_started) {
|
|
|
- if (rtnl)
|
|
|
- rtnl_unlock();
|
|
|
- return -ENETDOWN;
|
|
|
- }
|
|
|
- if (wdev->iftype == NL80211_IFTYPE_NAN &&
|
|
|
- !wdev->nan_started) {
|
|
|
- if (rtnl)
|
|
|
- rtnl_unlock();
|
|
|
- return -ENETDOWN;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
info->user_ptr[0] = rdev;
|
|
|
}
|
|
@@ -12162,6 +12247,14 @@ static const struct genl_ops nl80211_ops[] = {
|
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
NL80211_FLAG_NEED_RTNL,
|
|
|
},
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
|
|
|
+ .doit = nl80211_update_connect_params,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
{
|
|
|
.cmd = NL80211_CMD_DISCONNECT,
|
|
|
.doit = nl80211_disconnect,
|
|
@@ -12583,6 +12676,14 @@ static const struct genl_ops nl80211_ops[] = {
|
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
NL80211_FLAG_NEED_RTNL,
|
|
|
},
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
|
|
|
+ .doit = nl80211_set_multicast_to_unicast,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_UNS_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct genl_family nl80211_fam __ro_after_init = {
|