summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-02-13 15:17:18 +0100
committerVarun Colbert <vcolbert@nvidia.com>2012-09-07 16:08:51 -0700
commit91c8ef3843bf8ed24fbfb6396bba13b4a85f299d (patch)
treed821b6477df2b7e1d1cf14ecdd02bf3848e16993 /net
parent1a9346128adc2d4039cae2bc818302e4f7a509c1 (diff)
cfg80211: restructure AP/GO mode API
The AP/GO mode API isn't very clearly defined, it has "set beacon" and "new beacon" etc. Modify the API to the following: * start AP -- all settings * change beacon -- new beacon data * stop AP -- stop AP mode operation This also reflects in the nl80211 API, rename the commands there correspondingly (but keep the old names for compatibility.) Overall, this makes it much clearer what's going on in the API. Kalle developed the ath6kl changes, I created the rest of the patch. Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Change-Id: I93e94c16a38dd2662b2cde1269fa94f81327caaa Reviewed-on: http://git-master/r/130071 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Nitin Bindal <nbindal@nvidia.com> Tested-by: Nitin Bindal <nbindal@nvidia.com> Reviewed-by: Rakesh Kumar <krakesh@nvidia.com> Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c146
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/tx.c13
-rw-r--r--net/wireless/nl80211.c261
4 files changed, 213 insertions, 209 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 52c1edf36b75..677d65929780 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -496,27 +496,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
return ret;
}
-static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
- struct beacon_parameters *params)
-{
- struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-
- bss_conf->ssid_len = params->ssid_len;
-
- if (params->ssid_len)
- memcpy(bss_conf->ssid, params->ssid, params->ssid_len);
-
- bss_conf->hidden_ssid =
- (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
-}
-
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
- u8 *resp, size_t resp_len)
+ const u8 *resp, size_t resp_len)
{
struct sk_buff *new, *old;
if (!resp || !resp_len)
- return -EINVAL;
+ return 1;
old = rtnl_dereference(sdata->u.ap.probe_resp);
@@ -527,50 +513,28 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
memcpy(skb_put(new, resp_len), resp, resp_len);
rcu_assign_pointer(sdata->u.ap.probe_resp, new);
- synchronize_rcu();
-
- if (old)
+ if (old) {
+ /* TODO: use call_rcu() */
+ synchronize_rcu();
dev_kfree_skb(old);
+ }
return 0;
}
-/*
- * This handles both adding a beacon and setting new beacon info
- */
-static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
- struct beacon_parameters *params)
+static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_beacon_data *params)
{
struct beacon_data *new, *old;
int new_head_len, new_tail_len;
- int size;
- int err = -EINVAL;
- u32 changed = 0;
+ int size, err;
+ u32 changed = BSS_CHANGED_BEACON;
old = rtnl_dereference(sdata->u.ap.beacon);
- /* head must not be zero-length */
- if (params->head && !params->head_len)
- return -EINVAL;
-
- /*
- * This is a kludge. beacon interval should really be part
- * of the beacon information.
- */
- if (params->interval &&
- (sdata->vif.bss_conf.beacon_int != params->interval)) {
- sdata->vif.bss_conf.beacon_int = params->interval;
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_BEACON_INT);
- }
-
/* Need to have a beacon head if we don't have one yet */
if (!params->head && !old)
- return err;
-
- /* sorry, no way to start beaconing without dtim period */
- if (!params->dtim_period && !old)
- return err;
+ return -EINVAL;
/* new or old head? */
if (params->head)
@@ -593,12 +557,6 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
/* start filling the new info now */
- /* new or old dtim period? */
- if (params->dtim_period)
- new->dtim_period = params->dtim_period;
- else
- new->dtim_period = old->dtim_period;
-
/*
* pointers go into the block we allocated,
* memory is | beacon_data | head | tail |
@@ -621,46 +579,37 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
if (old)
memcpy(new->tail, old->tail, new_tail_len);
- sdata->vif.bss_conf.dtim_period = new->dtim_period;
-
- rcu_assign_pointer(sdata->u.ap.beacon, new);
-
- synchronize_rcu();
-
- kfree(old);
-
err = ieee80211_set_probe_resp(sdata, params->probe_resp,
params->probe_resp_len);
- if (!err)
+ if (err < 0)
+ return err;
+ if (err == 0)
changed |= BSS_CHANGED_AP_PROBE_RESP;
- ieee80211_config_ap_ssid(sdata, params);
- changed |= BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_BEACON |
- BSS_CHANGED_SSID;
+ rcu_assign_pointer(sdata->u.ap.beacon, new);
+
+ if (old)
+ kfree_rcu(old, rcu_head);
- ieee80211_bss_info_change_notify(sdata, changed);
- return 0;
+ return changed;
}
-static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *params)
+static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ap_settings *params)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct beacon_data *old;
struct ieee80211_sub_if_data *vlan;
- int ret;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ u32 changed = BSS_CHANGED_BEACON_INT |
+ BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON |
+ BSS_CHANGED_SSID;
+ int err;
old = rtnl_dereference(sdata->u.ap.beacon);
if (old)
return -EALREADY;
- ret = ieee80211_config_beacon(sdata, params);
- if (ret)
- return ret;
-
/*
* Apply control port protocol, this allows us to
* not encrypt dynamic WEP control frames.
@@ -674,14 +623,32 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
params->crypto.control_port_no_encrypt;
}
+ sdata->vif.bss_conf.beacon_int = params->beacon_interval;
+ sdata->vif.bss_conf.dtim_period = params->dtim_period;
+
+ sdata->vif.bss_conf.ssid_len = params->ssid_len;
+ if (params->ssid_len)
+ memcpy(sdata->vif.bss_conf.ssid, params->ssid,
+ params->ssid_len);
+ sdata->vif.bss_conf.hidden_ssid =
+ (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
+
+ err = ieee80211_assign_beacon(sdata, &params->beacon);
+ if (err < 0)
+ return err;
+ changed |= err;
+
+ ieee80211_bss_info_change_notify(sdata, changed);
+
return 0;
}
-static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *params)
+static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_beacon_data *params)
{
struct ieee80211_sub_if_data *sdata;
struct beacon_data *old;
+ int err;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -689,10 +656,14 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
if (!old)
return -ENOENT;
- return ieee80211_config_beacon(sdata, params);
+ err = ieee80211_assign_beacon(sdata, params);
+ if (err < 0)
+ return err;
+ ieee80211_bss_info_change_notify(sdata, err);
+ return 0;
}
-static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
+static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata;
struct beacon_data *old;
@@ -704,10 +675,11 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
return -ENOENT;
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
- synchronize_rcu();
- kfree(old);
+
+ kfree_rcu(old, rcu_head);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+
return 0;
}
@@ -2710,9 +2682,9 @@ struct cfg80211_ops mac80211_config_ops = {
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key,
.set_default_mgmt_key = ieee80211_config_default_mgmt_key,
- .add_beacon = ieee80211_add_beacon,
- .set_beacon = ieee80211_set_beacon,
- .del_beacon = ieee80211_del_beacon,
+ .start_ap = ieee80211_start_ap,
+ .change_beacon = ieee80211_change_beacon,
+ .stop_ap = ieee80211_stop_ap,
.add_station = ieee80211_add_station,
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5aec7bb2d9ff..db8fae51714c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -266,7 +266,7 @@ struct ieee80211_rx_data {
struct beacon_data {
u8 *head, *tail;
int head_len, tail_len;
- int dtim_period;
+ struct rcu_head rcu_head;
};
struct ieee80211_if_ap {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index f9104c37dba0..e76facc69e95 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2218,7 +2218,8 @@ void ieee80211_tx_pending(unsigned long data)
/* functions for drivers to get certain frames */
-static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
+static void ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_if_ap *bss,
struct sk_buff *skb,
struct beacon_data *beacon)
{
@@ -2235,7 +2236,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
IEEE80211_MAX_AID+1);
if (bss->dtim_count == 0)
- bss->dtim_count = beacon->dtim_period - 1;
+ bss->dtim_count = sdata->vif.bss_conf.dtim_period - 1;
else
bss->dtim_count--;
@@ -2243,7 +2244,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss,
*pos++ = WLAN_EID_TIM;
*pos++ = 4;
*pos++ = bss->dtim_count;
- *pos++ = beacon->dtim_period;
+ *pos++ = sdata->vif.bss_conf.dtim_period;
if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
aid0 = 1;
@@ -2336,12 +2337,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
* of the tim bitmap in mac80211 and the driver.
*/
if (local->tim_in_locked_section) {
- ieee80211_beacon_add_tim(ap, skb, beacon);
+ ieee80211_beacon_add_tim(sdata, ap, skb,
+ beacon);
} else {
unsigned long flags;
spin_lock_irqsave(&local->tim_lock, flags);
- ieee80211_beacon_add_tim(ap, skb, beacon);
+ ieee80211_beacon_add_tim(sdata, ap, skb,
+ beacon);
spin_unlock_irqrestore(&local->tim_lock, flags);
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c5b572cdb489..e0e655b4b80a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -873,7 +873,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
CMD(add_virtual_intf, NEW_INTERFACE);
CMD(change_virtual_intf, SET_INTERFACE);
CMD(add_key, NEW_KEY);
- CMD(add_beacon, NEW_BEACON);
+ CMD(start_ap, START_AP);
CMD(add_station, NEW_STATION);
CMD(add_mpath, NEW_MPATH);
CMD(update_mesh_config, SET_MESH_CONFIG);
@@ -2082,15 +2082,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
return err;
}
-static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_beacon(struct genl_info *info,
+ struct cfg80211_beacon_data *bcn)
{
- int (*call)(struct wiphy *wiphy, struct net_device *dev,
- struct beacon_parameters *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;
- struct beacon_parameters params;
- int haveinfo = 0, err;
+ bool haveinfo = false;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
@@ -2098,149 +2093,183 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
return -EINVAL;
- if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
- dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
- return -EOPNOTSUPP;
-
- memset(&params, 0, sizeof(params));
-
- switch (info->genlhdr->cmd) {
- case NL80211_CMD_NEW_BEACON:
- /* these are required for NEW_BEACON */
- if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
- !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
- !info->attrs[NL80211_ATTR_BEACON_HEAD])
- return -EINVAL;
-
- params.interval =
- nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- params.dtim_period =
- nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-
- err = cfg80211_validate_beacon_int(rdev, params.interval);
- if (err)
- return err;
-
- /*
- * In theory, some of these attributes could be required for
- * NEW_BEACON, but since they were not used when the command was
- * originally added, keep them optional for old user space
- * programs to work with drivers that do not need the additional
- * information.
- */
- if (info->attrs[NL80211_ATTR_SSID]) {
- params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- params.ssid_len =
- nla_len(info->attrs[NL80211_ATTR_SSID]);
- if (params.ssid_len == 0 ||
- params.ssid_len > IEEE80211_MAX_SSID_LEN)
- return -EINVAL;
- }
-
- if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
- params.hidden_ssid = nla_get_u32(
- info->attrs[NL80211_ATTR_HIDDEN_SSID]);
- if (params.hidden_ssid !=
- NL80211_HIDDEN_SSID_NOT_IN_USE &&
- params.hidden_ssid !=
- NL80211_HIDDEN_SSID_ZERO_LEN &&
- params.hidden_ssid !=
- NL80211_HIDDEN_SSID_ZERO_CONTENTS)
- return -EINVAL;
- }
-
- params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
-
- if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
- params.auth_type = nla_get_u32(
- info->attrs[NL80211_ATTR_AUTH_TYPE]);
- if (!nl80211_valid_auth_type(params.auth_type))
- return -EINVAL;
- } else
- params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-
- err = nl80211_crypto_settings(rdev, info, &params.crypto,
- NL80211_MAX_NR_CIPHER_SUITES);
- if (err)
- return err;
-
- call = rdev->ops->add_beacon;
- break;
- case NL80211_CMD_SET_BEACON:
- call = rdev->ops->set_beacon;
- break;
- default:
- WARN_ON(1);
- return -EOPNOTSUPP;
- }
-
- if (!call)
- return -EOPNOTSUPP;
+ memset(bcn, 0, sizeof(*bcn));
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
- params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
- params.head_len =
- nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
- haveinfo = 1;
+ bcn->head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ bcn->head_len = nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
+ if (!bcn->head_len)
+ return -EINVAL;
+ haveinfo = true;
}
if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
- params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
- params.tail_len =
+ bcn->tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
+ bcn->tail_len =
nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
- haveinfo = 1;
+ haveinfo = true;
}
if (!haveinfo)
return -EINVAL;
if (info->attrs[NL80211_ATTR_IE]) {
- params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
- params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ bcn->beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+ bcn->beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
- params.proberesp_ies =
+ bcn->proberesp_ies =
nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
- params.proberesp_ies_len =
+ bcn->proberesp_ies_len =
nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
}
if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
- params.assocresp_ies =
+ bcn->assocresp_ies =
nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
- params.assocresp_ies_len =
+ bcn->assocresp_ies_len =
nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
}
if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
- params.probe_resp =
+ bcn->probe_resp =
nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
- params.probe_resp_len =
+ bcn->probe_resp_len =
nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
}
- err = call(&rdev->wiphy, dev, &params);
- if (!err && params.interval)
- wdev->beacon_interval = params.interval;
+ return 0;
+}
+
+static int nl80211_start_ap(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;
+ struct cfg80211_ap_settings params;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->start_ap)
+ return -EOPNOTSUPP;
+
+ if (wdev->beacon_interval)
+ return -EALREADY;
+
+ memset(&params, 0, sizeof(params));
+
+ /* these are required for START_AP */
+ if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+ !info->attrs[NL80211_ATTR_BEACON_HEAD])
+ return -EINVAL;
+
+ err = nl80211_parse_beacon(info, &params.beacon);
+ if (err)
+ return err;
+
+ params.beacon_interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ params.dtim_period =
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+ err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
+ if (err)
+ return err;
+
+ /*
+ * In theory, some of these attributes should be required here
+ * but since they were not used when the command was originally
+ * added, keep them optional for old user space programs to let
+ * them continue to work with drivers that do not need the
+ * additional information -- drivers must check!
+ */
+ if (info->attrs[NL80211_ATTR_SSID]) {
+ params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ params.ssid_len =
+ nla_len(info->attrs[NL80211_ATTR_SSID]);
+ if (params.ssid_len == 0 ||
+ params.ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ }
+
+ if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+ params.hidden_ssid = nla_get_u32(
+ info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+ if (params.hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE &&
+ params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_LEN &&
+ params.hidden_ssid != NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+ return -EINVAL;
+ }
+
+ params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ params.auth_type = nla_get_u32(
+ info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ if (!nl80211_valid_auth_type(params.auth_type))
+ return -EINVAL;
+ } else
+ params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+ err = nl80211_crypto_settings(rdev, info, &params.crypto,
+ NL80211_MAX_NR_CIPHER_SUITES);
+ if (err)
+ return err;
+
+ err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
+ if (!err)
+ wdev->beacon_interval = params.beacon_interval;
return err;
}
-static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_beacon(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;
+ struct cfg80211_beacon_data params;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!rdev->ops->change_beacon)
+ return -EOPNOTSUPP;
+
+ if (!wdev->beacon_interval)
+ return -EINVAL;
+
+ err = nl80211_parse_beacon(info, &params);
+ if (err)
+ return err;
+
+ return rdev->ops->change_beacon(&rdev->wiphy, dev, &params);
+}
+
+static int nl80211_stop_ap(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;
int err;
- if (!rdev->ops->del_beacon)
+ if (!rdev->ops->stop_ap)
return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
- err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+ if (!wdev->beacon_interval)
+ return -ENOENT;
+
+ err = rdev->ops->stop_ap(&rdev->wiphy, dev);
if (!err)
wdev->beacon_interval = 0;
return err;
@@ -6384,24 +6413,24 @@ static struct genl_ops nl80211_ops[] = {
.cmd = NL80211_CMD_SET_BEACON,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_addset_beacon,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ .doit = nl80211_set_beacon,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_NEW_BEACON,
+ .cmd = NL80211_CMD_START_AP,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_addset_beacon,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ .doit = nl80211_start_ap,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{
- .cmd = NL80211_CMD_DEL_BEACON,
+ .cmd = NL80211_CMD_STOP_AP,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
- .doit = nl80211_del_beacon,
- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ .doit = nl80211_stop_ap,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
{