diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 259 |
1 files changed, 244 insertions, 15 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 98fa8eb6cc4..6a82c898f83 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -176,6 +176,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
176 | [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, | 176 | [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, |
177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, | 177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, |
178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, | 178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, |
179 | [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, | ||
179 | }; | 180 | }; |
180 | 181 | ||
181 | /* policy for the key attributes */ | 182 | /* policy for the key attributes */ |
@@ -206,6 +207,14 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
206 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, | 207 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, |
207 | }; | 208 | }; |
208 | 209 | ||
210 | /* policy for GTK rekey offload attributes */ | ||
211 | static const struct nla_policy | ||
212 | nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | ||
213 | [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN }, | ||
214 | [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN }, | ||
215 | [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN }, | ||
216 | }; | ||
217 | |||
209 | /* ifidx get helper */ | 218 | /* ifidx get helper */ |
210 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 219 | static int nl80211_get_ifidx(struct netlink_callback *cb) |
211 | { | 220 | { |
@@ -3461,9 +3470,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3461 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3470 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
3462 | return -EINVAL; | 3471 | return -EINVAL; |
3463 | 3472 | ||
3464 | if (rdev->sched_scan_req) | ||
3465 | return -EINPROGRESS; | ||
3466 | |||
3467 | if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) | 3473 | if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) |
3468 | return -EINVAL; | 3474 | return -EINVAL; |
3469 | 3475 | ||
@@ -3502,12 +3508,21 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3502 | if (ie_len > wiphy->max_scan_ie_len) | 3508 | if (ie_len > wiphy->max_scan_ie_len) |
3503 | return -EINVAL; | 3509 | return -EINVAL; |
3504 | 3510 | ||
3511 | mutex_lock(&rdev->sched_scan_mtx); | ||
3512 | |||
3513 | if (rdev->sched_scan_req) { | ||
3514 | err = -EINPROGRESS; | ||
3515 | goto out; | ||
3516 | } | ||
3517 | |||
3505 | request = kzalloc(sizeof(*request) | 3518 | request = kzalloc(sizeof(*request) |
3506 | + sizeof(*request->ssids) * n_ssids | 3519 | + sizeof(*request->ssids) * n_ssids |
3507 | + sizeof(*request->channels) * n_channels | 3520 | + sizeof(*request->channels) * n_channels |
3508 | + ie_len, GFP_KERNEL); | 3521 | + ie_len, GFP_KERNEL); |
3509 | if (!request) | 3522 | if (!request) { |
3510 | return -ENOMEM; | 3523 | err = -ENOMEM; |
3524 | goto out; | ||
3525 | } | ||
3511 | 3526 | ||
3512 | if (n_ssids) | 3527 | if (n_ssids) |
3513 | request->ssids = (void *)&request->channels[n_channels]; | 3528 | request->ssids = (void *)&request->channels[n_channels]; |
@@ -3605,6 +3620,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3605 | out_free: | 3620 | out_free: |
3606 | kfree(request); | 3621 | kfree(request); |
3607 | out: | 3622 | out: |
3623 | mutex_unlock(&rdev->sched_scan_mtx); | ||
3608 | return err; | 3624 | return err; |
3609 | } | 3625 | } |
3610 | 3626 | ||
@@ -3612,15 +3628,21 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
3612 | struct genl_info *info) | 3628 | struct genl_info *info) |
3613 | { | 3629 | { |
3614 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3630 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3631 | int err; | ||
3615 | 3632 | ||
3616 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 3633 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
3617 | !rdev->ops->sched_scan_stop) | 3634 | !rdev->ops->sched_scan_stop) |
3618 | return -EOPNOTSUPP; | 3635 | return -EOPNOTSUPP; |
3619 | 3636 | ||
3620 | return __cfg80211_stop_sched_scan(rdev, false); | 3637 | mutex_lock(&rdev->sched_scan_mtx); |
3638 | err = __cfg80211_stop_sched_scan(rdev, false); | ||
3639 | mutex_unlock(&rdev->sched_scan_mtx); | ||
3640 | |||
3641 | return err; | ||
3621 | } | 3642 | } |
3622 | 3643 | ||
3623 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 3644 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
3645 | u32 seq, int flags, | ||
3624 | struct cfg80211_registered_device *rdev, | 3646 | struct cfg80211_registered_device *rdev, |
3625 | struct wireless_dev *wdev, | 3647 | struct wireless_dev *wdev, |
3626 | struct cfg80211_internal_bss *intbss) | 3648 | struct cfg80211_internal_bss *intbss) |
@@ -3632,11 +3654,13 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3632 | 3654 | ||
3633 | ASSERT_WDEV_LOCK(wdev); | 3655 | ASSERT_WDEV_LOCK(wdev); |
3634 | 3656 | ||
3635 | hdr = nl80211hdr_put(msg, pid, seq, flags, | 3657 | hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).pid, seq, flags, |
3636 | NL80211_CMD_NEW_SCAN_RESULTS); | 3658 | NL80211_CMD_NEW_SCAN_RESULTS); |
3637 | if (!hdr) | 3659 | if (!hdr) |
3638 | return -1; | 3660 | return -1; |
3639 | 3661 | ||
3662 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | ||
3663 | |||
3640 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); | 3664 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3641 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3665 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3642 | 3666 | ||
@@ -3725,11 +3749,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3725 | spin_lock_bh(&rdev->bss_lock); | 3749 | spin_lock_bh(&rdev->bss_lock); |
3726 | cfg80211_bss_expire(rdev); | 3750 | cfg80211_bss_expire(rdev); |
3727 | 3751 | ||
3752 | cb->seq = rdev->bss_generation; | ||
3753 | |||
3728 | list_for_each_entry(scan, &rdev->bss_list, list) { | 3754 | list_for_each_entry(scan, &rdev->bss_list, list) { |
3729 | if (++idx <= start) | 3755 | if (++idx <= start) |
3730 | continue; | 3756 | continue; |
3731 | if (nl80211_send_bss(skb, | 3757 | if (nl80211_send_bss(skb, cb, |
3732 | NETLINK_CB(cb->skb).pid, | ||
3733 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3758 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3734 | rdev, wdev, scan) < 0) { | 3759 | rdev, wdev, scan) < 0) { |
3735 | idx--; | 3760 | idx--; |
@@ -3753,10 +3778,6 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | |||
3753 | void *hdr; | 3778 | void *hdr; |
3754 | struct nlattr *infoattr; | 3779 | struct nlattr *infoattr; |
3755 | 3780 | ||
3756 | /* Survey without a channel doesn't make sense */ | ||
3757 | if (!survey->channel) | ||
3758 | return -EINVAL; | ||
3759 | |||
3760 | hdr = nl80211hdr_put(msg, pid, seq, flags, | 3781 | hdr = nl80211hdr_put(msg, pid, seq, flags, |
3761 | NL80211_CMD_NEW_SURVEY_RESULTS); | 3782 | NL80211_CMD_NEW_SURVEY_RESULTS); |
3762 | if (!hdr) | 3783 | if (!hdr) |
@@ -3819,6 +3840,8 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3819 | } | 3840 | } |
3820 | 3841 | ||
3821 | while (1) { | 3842 | while (1) { |
3843 | struct ieee80211_channel *chan; | ||
3844 | |||
3822 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, | 3845 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, |
3823 | &survey); | 3846 | &survey); |
3824 | if (res == -ENOENT) | 3847 | if (res == -ENOENT) |
@@ -3826,6 +3849,19 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3826 | if (res) | 3849 | if (res) |
3827 | goto out_err; | 3850 | goto out_err; |
3828 | 3851 | ||
3852 | /* Survey without a channel doesn't make sense */ | ||
3853 | if (!survey.channel) { | ||
3854 | res = -EINVAL; | ||
3855 | goto out; | ||
3856 | } | ||
3857 | |||
3858 | chan = ieee80211_get_channel(&dev->wiphy, | ||
3859 | survey.channel->center_freq); | ||
3860 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | ||
3861 | survey_idx++; | ||
3862 | continue; | ||
3863 | } | ||
3864 | |||
3829 | if (nl80211_send_survey(skb, | 3865 | if (nl80211_send_survey(skb, |
3830 | NETLINK_CB(cb->skb).pid, | 3866 | NETLINK_CB(cb->skb).pid, |
3831 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3867 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
@@ -4360,6 +4396,93 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4360 | return err; | 4396 | return err; |
4361 | } | 4397 | } |
4362 | 4398 | ||
4399 | static int nl80211_testmode_dump(struct sk_buff *skb, | ||
4400 | struct netlink_callback *cb) | ||
4401 | { | ||
4402 | struct cfg80211_registered_device *dev; | ||
4403 | int err; | ||
4404 | long phy_idx; | ||
4405 | void *data = NULL; | ||
4406 | int data_len = 0; | ||
4407 | |||
4408 | if (cb->args[0]) { | ||
4409 | /* | ||
4410 | * 0 is a valid index, but not valid for args[0], | ||
4411 | * so we need to offset by 1. | ||
4412 | */ | ||
4413 | phy_idx = cb->args[0] - 1; | ||
4414 | } else { | ||
4415 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
4416 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
4417 | nl80211_policy); | ||
4418 | if (err) | ||
4419 | return err; | ||
4420 | if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) | ||
4421 | return -EINVAL; | ||
4422 | phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); | ||
4423 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | ||
4424 | cb->args[1] = | ||
4425 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; | ||
4426 | } | ||
4427 | |||
4428 | if (cb->args[1]) { | ||
4429 | data = nla_data((void *)cb->args[1]); | ||
4430 | data_len = nla_len((void *)cb->args[1]); | ||
4431 | } | ||
4432 | |||
4433 | mutex_lock(&cfg80211_mutex); | ||
4434 | dev = cfg80211_rdev_by_wiphy_idx(phy_idx); | ||
4435 | if (!dev) { | ||
4436 | mutex_unlock(&cfg80211_mutex); | ||
4437 | return -ENOENT; | ||
4438 | } | ||
4439 | cfg80211_lock_rdev(dev); | ||
4440 | mutex_unlock(&cfg80211_mutex); | ||
4441 | |||
4442 | if (!dev->ops->testmode_dump) { | ||
4443 | err = -EOPNOTSUPP; | ||
4444 | goto out_err; | ||
4445 | } | ||
4446 | |||
4447 | while (1) { | ||
4448 | void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid, | ||
4449 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
4450 | NL80211_CMD_TESTMODE); | ||
4451 | struct nlattr *tmdata; | ||
4452 | |||
4453 | if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) { | ||
4454 | genlmsg_cancel(skb, hdr); | ||
4455 | break; | ||
4456 | } | ||
4457 | |||
4458 | tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA); | ||
4459 | if (!tmdata) { | ||
4460 | genlmsg_cancel(skb, hdr); | ||
4461 | break; | ||
4462 | } | ||
4463 | err = dev->ops->testmode_dump(&dev->wiphy, skb, cb, | ||
4464 | data, data_len); | ||
4465 | nla_nest_end(skb, tmdata); | ||
4466 | |||
4467 | if (err == -ENOBUFS || err == -ENOENT) { | ||
4468 | genlmsg_cancel(skb, hdr); | ||
4469 | break; | ||
4470 | } else if (err) { | ||
4471 | genlmsg_cancel(skb, hdr); | ||
4472 | goto out_err; | ||
4473 | } | ||
4474 | |||
4475 | genlmsg_end(skb, hdr); | ||
4476 | } | ||
4477 | |||
4478 | err = skb->len; | ||
4479 | /* see above */ | ||
4480 | cb->args[0] = phy_idx + 1; | ||
4481 | out_err: | ||
4482 | cfg80211_unlock_rdev(dev); | ||
4483 | return err; | ||
4484 | } | ||
4485 | |||
4363 | static struct sk_buff * | 4486 | static struct sk_buff * |
4364 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, | 4487 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, |
4365 | int approxlen, u32 pid, u32 seq, gfp_t gfp) | 4488 | int approxlen, u32 pid, u32 seq, gfp_t gfp) |
@@ -5306,6 +5429,57 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5306 | return err; | 5429 | return err; |
5307 | } | 5430 | } |
5308 | 5431 | ||
5432 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | ||
5433 | { | ||
5434 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5435 | struct net_device *dev = info->user_ptr[1]; | ||
5436 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5437 | struct nlattr *tb[NUM_NL80211_REKEY_DATA]; | ||
5438 | struct cfg80211_gtk_rekey_data rekey_data; | ||
5439 | int err; | ||
5440 | |||
5441 | if (!info->attrs[NL80211_ATTR_REKEY_DATA]) | ||
5442 | return -EINVAL; | ||
5443 | |||
5444 | err = nla_parse(tb, MAX_NL80211_REKEY_DATA, | ||
5445 | nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]), | ||
5446 | nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]), | ||
5447 | nl80211_rekey_policy); | ||
5448 | if (err) | ||
5449 | return err; | ||
5450 | |||
5451 | if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN) | ||
5452 | return -ERANGE; | ||
5453 | if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN) | ||
5454 | return -ERANGE; | ||
5455 | if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN) | ||
5456 | return -ERANGE; | ||
5457 | |||
5458 | memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]), | ||
5459 | NL80211_KEK_LEN); | ||
5460 | memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]), | ||
5461 | NL80211_KCK_LEN); | ||
5462 | memcpy(rekey_data.replay_ctr, | ||
5463 | nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]), | ||
5464 | NL80211_REPLAY_CTR_LEN); | ||
5465 | |||
5466 | wdev_lock(wdev); | ||
5467 | if (!wdev->current_bss) { | ||
5468 | err = -ENOTCONN; | ||
5469 | goto out; | ||
5470 | } | ||
5471 | |||
5472 | if (!rdev->ops->set_rekey_data) { | ||
5473 | err = -EOPNOTSUPP; | ||
5474 | goto out; | ||
5475 | } | ||
5476 | |||
5477 | err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data); | ||
5478 | out: | ||
5479 | wdev_unlock(wdev); | ||
5480 | return err; | ||
5481 | } | ||
5482 | |||
5309 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 5483 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
5310 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 5484 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
5311 | #define NL80211_FLAG_NEED_RTNL 0x04 | 5485 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -5657,6 +5831,7 @@ static struct genl_ops nl80211_ops[] = { | |||
5657 | { | 5831 | { |
5658 | .cmd = NL80211_CMD_TESTMODE, | 5832 | .cmd = NL80211_CMD_TESTMODE, |
5659 | .doit = nl80211_testmode_do, | 5833 | .doit = nl80211_testmode_do, |
5834 | .dumpit = nl80211_testmode_dump, | ||
5660 | .policy = nl80211_policy, | 5835 | .policy = nl80211_policy, |
5661 | .flags = GENL_ADMIN_PERM, | 5836 | .flags = GENL_ADMIN_PERM, |
5662 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 5837 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
@@ -5836,6 +6011,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5836 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 6011 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
5837 | NL80211_FLAG_NEED_RTNL, | 6012 | NL80211_FLAG_NEED_RTNL, |
5838 | }, | 6013 | }, |
6014 | { | ||
6015 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | ||
6016 | .doit = nl80211_set_rekey_data, | ||
6017 | .policy = nl80211_policy, | ||
6018 | .flags = GENL_ADMIN_PERM, | ||
6019 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6020 | NL80211_FLAG_NEED_RTNL, | ||
6021 | }, | ||
5839 | }; | 6022 | }; |
5840 | 6023 | ||
5841 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6024 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -6463,7 +6646,8 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | |||
6463 | if (addr) | 6646 | if (addr) |
6464 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | 6647 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); |
6465 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); | 6648 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); |
6466 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); | 6649 | if (key_id != -1) |
6650 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); | ||
6467 | if (tsc) | 6651 | if (tsc) |
6468 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); | 6652 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); |
6469 | 6653 | ||
@@ -6779,6 +6963,51 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
6779 | nlmsg_free(msg); | 6963 | nlmsg_free(msg); |
6780 | } | 6964 | } |
6781 | 6965 | ||
6966 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | ||
6967 | struct net_device *netdev, const u8 *bssid, | ||
6968 | const u8 *replay_ctr, gfp_t gfp) | ||
6969 | { | ||
6970 | struct sk_buff *msg; | ||
6971 | struct nlattr *rekey_attr; | ||
6972 | void *hdr; | ||
6973 | |||
6974 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
6975 | if (!msg) | ||
6976 | return; | ||
6977 | |||
6978 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD); | ||
6979 | if (!hdr) { | ||
6980 | nlmsg_free(msg); | ||
6981 | return; | ||
6982 | } | ||
6983 | |||
6984 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
6985 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
6986 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
6987 | |||
6988 | rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); | ||
6989 | if (!rekey_attr) | ||
6990 | goto nla_put_failure; | ||
6991 | |||
6992 | NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, | ||
6993 | NL80211_REPLAY_CTR_LEN, replay_ctr); | ||
6994 | |||
6995 | nla_nest_end(msg, rekey_attr); | ||
6996 | |||
6997 | if (genlmsg_end(msg, hdr) < 0) { | ||
6998 | nlmsg_free(msg); | ||
6999 | return; | ||
7000 | } | ||
7001 | |||
7002 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
7003 | nl80211_mlme_mcgrp.id, gfp); | ||
7004 | return; | ||
7005 | |||
7006 | nla_put_failure: | ||
7007 | genlmsg_cancel(msg, hdr); | ||
7008 | nlmsg_free(msg); | ||
7009 | } | ||
7010 | |||
6782 | void | 7011 | void |
6783 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 7012 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
6784 | struct net_device *netdev, const u8 *peer, | 7013 | struct net_device *netdev, const u8 *peer, |