|
@@ -2751,7 +2751,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
struct vif_params params;
|
|
struct vif_params params;
|
|
struct wireless_dev *wdev;
|
|
struct wireless_dev *wdev;
|
|
- struct sk_buff *msg, *event;
|
|
|
|
|
|
+ struct sk_buff *msg;
|
|
int err;
|
|
int err;
|
|
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
|
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
|
u32 flags;
|
|
u32 flags;
|
|
@@ -2855,20 +2855,15 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|
return -ENOBUFS;
|
|
return -ENOBUFS;
|
|
}
|
|
}
|
|
|
|
|
|
- event = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
- if (event) {
|
|
|
|
- if (nl80211_send_iface(event, 0, 0, 0,
|
|
|
|
- rdev, wdev, false) < 0) {
|
|
|
|
- nlmsg_free(event);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
|
|
|
|
- event, 0, NL80211_MCGRP_CONFIG,
|
|
|
|
- GFP_KERNEL);
|
|
|
|
- }
|
|
|
|
|
|
+ /*
|
|
|
|
+ * For wdevs which have no associated netdev object (e.g. of type
|
|
|
|
+ * NL80211_IFTYPE_P2P_DEVICE), emit the NEW_INTERFACE event here.
|
|
|
|
+ * For all other types, the event will be generated from the
|
|
|
|
+ * netdev notifier
|
|
|
|
+ */
|
|
|
|
+ if (!wdev->netdev)
|
|
|
|
+ nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
|
|
|
|
|
|
-out:
|
|
|
|
return genlmsg_reply(msg, info);
|
|
return genlmsg_reply(msg, info);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2876,18 +2871,10 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
{
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
struct wireless_dev *wdev = info->user_ptr[1];
|
|
struct wireless_dev *wdev = info->user_ptr[1];
|
|
- struct sk_buff *msg;
|
|
|
|
- int status;
|
|
|
|
|
|
|
|
if (!rdev->ops->del_virtual_intf)
|
|
if (!rdev->ops->del_virtual_intf)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
- if (msg && nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, true) < 0) {
|
|
|
|
- nlmsg_free(msg);
|
|
|
|
- msg = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* If we remove a wireless device without a netdev then clear
|
|
* If we remove a wireless device without a netdev then clear
|
|
* user_ptr[1] so that nl80211_post_doit won't dereference it
|
|
* user_ptr[1] so that nl80211_post_doit won't dereference it
|
|
@@ -2898,15 +2885,7 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
|
|
if (!wdev->netdev)
|
|
if (!wdev->netdev)
|
|
info->user_ptr[1] = NULL;
|
|
info->user_ptr[1] = NULL;
|
|
|
|
|
|
- status = rdev_del_virtual_intf(rdev, wdev);
|
|
|
|
- if (status >= 0 && msg)
|
|
|
|
- genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
|
|
|
|
- msg, 0, NL80211_MCGRP_CONFIG,
|
|
|
|
- GFP_KERNEL);
|
|
|
|
- else
|
|
|
|
- nlmsg_free(msg);
|
|
|
|
-
|
|
|
|
- return status;
|
|
|
|
|
|
+ return rdev_del_virtual_intf(rdev, wdev);
|
|
}
|
|
}
|
|
|
|
|
|
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
|
|
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
|
|
@@ -5374,6 +5353,18 @@ static int nl80211_check_s32(const struct nlattr *nla, s32 min, s32 max, s32 *ou
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int nl80211_check_power_mode(const struct nlattr *nla,
|
|
|
|
+ enum nl80211_mesh_power_mode min,
|
|
|
|
+ enum nl80211_mesh_power_mode max,
|
|
|
|
+ enum nl80211_mesh_power_mode *out)
|
|
|
|
+{
|
|
|
|
+ u32 val = nla_get_u32(nla);
|
|
|
|
+ if (val < min || val > max)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ *out = val;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int nl80211_parse_mesh_config(struct genl_info *info,
|
|
static int nl80211_parse_mesh_config(struct genl_info *info,
|
|
struct mesh_config *cfg,
|
|
struct mesh_config *cfg,
|
|
u32 *mask_out)
|
|
u32 *mask_out)
|
|
@@ -5518,7 +5509,7 @@ do { \
|
|
NL80211_MESH_POWER_ACTIVE,
|
|
NL80211_MESH_POWER_ACTIVE,
|
|
NL80211_MESH_POWER_MAX,
|
|
NL80211_MESH_POWER_MAX,
|
|
mask, NL80211_MESHCONF_POWER_MODE,
|
|
mask, NL80211_MESHCONF_POWER_MODE,
|
|
- nl80211_check_u32);
|
|
|
|
|
|
+ nl80211_check_power_mode);
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
|
|
0, 65535, mask,
|
|
0, 65535, mask,
|
|
NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
|
|
NL80211_MESHCONF_AWAKE_WINDOW, nl80211_check_u16);
|
|
@@ -7773,12 +7764,13 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
|
|
ibss.beacon_interval = 100;
|
|
ibss.beacon_interval = 100;
|
|
|
|
|
|
- if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
|
|
|
|
|
|
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
|
|
ibss.beacon_interval =
|
|
ibss.beacon_interval =
|
|
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
|
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
|
- if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ err = cfg80211_validate_beacon_int(rdev, ibss.beacon_interval);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
|
|
if (!rdev->ops->join_ibss)
|
|
if (!rdev->ops->join_ibss)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
@@ -9252,9 +9244,10 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
|
|
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
|
|
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
|
|
setup.beacon_interval =
|
|
setup.beacon_interval =
|
|
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
|
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
|
|
- if (setup.beacon_interval < 10 ||
|
|
|
|
- setup.beacon_interval > 10000)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+
|
|
|
|
+ err = cfg80211_validate_beacon_int(rdev, setup.beacon_interval);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
|
|
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
|
|
@@ -11847,6 +11840,29 @@ void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev,
|
|
NL80211_MCGRP_CONFIG, GFP_KERNEL);
|
|
NL80211_MCGRP_CONFIG, GFP_KERNEL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
|
|
|
|
+ struct wireless_dev *wdev,
|
|
|
|
+ enum nl80211_commands cmd)
|
|
|
|
+{
|
|
|
|
+ struct sk_buff *msg;
|
|
|
|
+
|
|
|
|
+ WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
|
|
|
|
+ cmd != NL80211_CMD_DEL_INTERFACE);
|
|
|
|
+
|
|
|
|
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
|
|
|
+ if (!msg)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
|
|
|
|
+ cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
|
|
|
|
+ nlmsg_free(msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
|
|
|
+ NL80211_MCGRP_CONFIG, GFP_KERNEL);
|
|
|
|
+}
|
|
|
|
+
|
|
static int nl80211_add_scan_req(struct sk_buff *msg,
|
|
static int nl80211_add_scan_req(struct sk_buff *msg,
|
|
struct cfg80211_registered_device *rdev)
|
|
struct cfg80211_registered_device *rdev)
|
|
{
|
|
{
|