aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c218
1 files changed, 217 insertions, 1 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 60f854377f90..ff857f10cb85 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -141,6 +141,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
141 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, 141 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
142 [NL80211_ATTR_PMKID] = { .type = NLA_BINARY, 142 [NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
143 .len = WLAN_PMKID_LEN }, 143 .len = WLAN_PMKID_LEN },
144 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
145 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
144}; 146};
145 147
146/* policy for the attributes */ 148/* policy for the attributes */
@@ -569,6 +571,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
569 CMD(set_pmksa, SET_PMKSA); 571 CMD(set_pmksa, SET_PMKSA);
570 CMD(del_pmksa, DEL_PMKSA); 572 CMD(del_pmksa, DEL_PMKSA);
571 CMD(flush_pmksa, FLUSH_PMKSA); 573 CMD(flush_pmksa, FLUSH_PMKSA);
574 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
572 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 575 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
573 i++; 576 i++;
574 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 577 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -4283,6 +4286,143 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
4283 4286
4284} 4287}
4285 4288
4289static int nl80211_remain_on_channel(struct sk_buff *skb,
4290 struct genl_info *info)
4291{
4292 struct cfg80211_registered_device *rdev;
4293 struct net_device *dev;
4294 struct ieee80211_channel *chan;
4295 struct sk_buff *msg;
4296 void *hdr;
4297 u64 cookie;
4298 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
4299 u32 freq, duration;
4300 int err;
4301
4302 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
4303 !info->attrs[NL80211_ATTR_DURATION])
4304 return -EINVAL;
4305
4306 duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
4307
4308 /*
4309 * We should be on that channel for at least one jiffie,
4310 * and more than 5 seconds seems excessive.
4311 */
4312 if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
4313 return -EINVAL;
4314
4315 rtnl_lock();
4316
4317 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4318 if (err)
4319 goto unlock_rtnl;
4320
4321 if (!rdev->ops->remain_on_channel) {
4322 err = -EOPNOTSUPP;
4323 goto out;
4324 }
4325
4326 if (!netif_running(dev)) {
4327 err = -ENETDOWN;
4328 goto out;
4329 }
4330
4331 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
4332 channel_type = nla_get_u32(
4333 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
4334 if (channel_type != NL80211_CHAN_NO_HT &&
4335 channel_type != NL80211_CHAN_HT20 &&
4336 channel_type != NL80211_CHAN_HT40PLUS &&
4337 channel_type != NL80211_CHAN_HT40MINUS)
4338 err = -EINVAL;
4339 goto out;
4340 }
4341
4342 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
4343 chan = rdev_freq_to_chan(rdev, freq, channel_type);
4344 if (chan == NULL) {
4345 err = -EINVAL;
4346 goto out;
4347 }
4348
4349 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4350 if (!msg) {
4351 err = -ENOMEM;
4352 goto out;
4353 }
4354
4355 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4356 NL80211_CMD_REMAIN_ON_CHANNEL);
4357
4358 if (IS_ERR(hdr)) {
4359 err = PTR_ERR(hdr);
4360 goto free_msg;
4361 }
4362
4363 err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan,
4364 channel_type, duration, &cookie);
4365
4366 if (err)
4367 goto free_msg;
4368
4369 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
4370
4371 genlmsg_end(msg, hdr);
4372 err = genlmsg_reply(msg, info);
4373 goto out;
4374
4375 nla_put_failure:
4376 err = -ENOBUFS;
4377 free_msg:
4378 nlmsg_free(msg);
4379 out:
4380 cfg80211_unlock_rdev(rdev);
4381 dev_put(dev);
4382 unlock_rtnl:
4383 rtnl_unlock();
4384 return err;
4385}
4386
4387static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
4388 struct genl_info *info)
4389{
4390 struct cfg80211_registered_device *rdev;
4391 struct net_device *dev;
4392 u64 cookie;
4393 int err;
4394
4395 if (!info->attrs[NL80211_ATTR_COOKIE])
4396 return -EINVAL;
4397
4398 rtnl_lock();
4399
4400 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4401 if (err)
4402 goto unlock_rtnl;
4403
4404 if (!rdev->ops->cancel_remain_on_channel) {
4405 err = -EOPNOTSUPP;
4406 goto out;
4407 }
4408
4409 if (!netif_running(dev)) {
4410 err = -ENETDOWN;
4411 goto out;
4412 }
4413
4414 cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
4415
4416 err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
4417
4418 out:
4419 cfg80211_unlock_rdev(rdev);
4420 dev_put(dev);
4421 unlock_rtnl:
4422 rtnl_unlock();
4423 return err;
4424}
4425
4286static struct genl_ops nl80211_ops[] = { 4426static struct genl_ops nl80211_ops[] = {
4287 { 4427 {
4288 .cmd = NL80211_CMD_GET_WIPHY, 4428 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4545,8 +4685,20 @@ static struct genl_ops nl80211_ops[] = {
4545 .policy = nl80211_policy, 4685 .policy = nl80211_policy,
4546 .flags = GENL_ADMIN_PERM, 4686 .flags = GENL_ADMIN_PERM,
4547 }, 4687 },
4548 4688 {
4689 .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
4690 .doit = nl80211_remain_on_channel,
4691 .policy = nl80211_policy,
4692 .flags = GENL_ADMIN_PERM,
4693 },
4694 {
4695 .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
4696 .doit = nl80211_cancel_remain_on_channel,
4697 .policy = nl80211_policy,
4698 .flags = GENL_ADMIN_PERM,
4699 },
4549}; 4700};
4701
4550static struct genl_multicast_group nl80211_mlme_mcgrp = { 4702static struct genl_multicast_group nl80211_mlme_mcgrp = {
4551 .name = "mlme", 4703 .name = "mlme",
4552}; 4704};
@@ -5134,6 +5286,70 @@ nla_put_failure:
5134 nlmsg_free(msg); 5286 nlmsg_free(msg);
5135} 5287}
5136 5288
5289static void nl80211_send_remain_on_chan_event(
5290 int cmd, struct cfg80211_registered_device *rdev,
5291 struct net_device *netdev, u64 cookie,
5292 struct ieee80211_channel *chan,
5293 enum nl80211_channel_type channel_type,
5294 unsigned int duration, gfp_t gfp)
5295{
5296 struct sk_buff *msg;
5297 void *hdr;
5298
5299 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5300 if (!msg)
5301 return;
5302
5303 hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
5304 if (!hdr) {
5305 nlmsg_free(msg);
5306 return;
5307 }
5308
5309 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5310 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5311 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq);
5312 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type);
5313 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
5314
5315 if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
5316 NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
5317
5318 if (genlmsg_end(msg, hdr) < 0) {
5319 nlmsg_free(msg);
5320 return;
5321 }
5322
5323 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
5324 nl80211_mlme_mcgrp.id, gfp);
5325 return;
5326
5327 nla_put_failure:
5328 genlmsg_cancel(msg, hdr);
5329 nlmsg_free(msg);
5330}
5331
5332void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
5333 struct net_device *netdev, u64 cookie,
5334 struct ieee80211_channel *chan,
5335 enum nl80211_channel_type channel_type,
5336 unsigned int duration, gfp_t gfp)
5337{
5338 nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
5339 rdev, netdev, cookie, chan,
5340 channel_type, duration, gfp);
5341}
5342
5343void nl80211_send_remain_on_channel_cancel(
5344 struct cfg80211_registered_device *rdev, struct net_device *netdev,
5345 u64 cookie, struct ieee80211_channel *chan,
5346 enum nl80211_channel_type channel_type, gfp_t gfp)
5347{
5348 nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
5349 rdev, netdev, cookie, chan,
5350 channel_type, 0, gfp);
5351}
5352
5137/* initialisation/exit functions */ 5353/* initialisation/exit functions */
5138 5354
5139int nl80211_init(void) 5355int nl80211_init(void)