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.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 50ff82aa4890..491b0ba40c43 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 */
211static const struct nla_policy
212nl80211_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 */
210static int nl80211_get_ifidx(struct netlink_callback *cb) 219static int nl80211_get_ifidx(struct netlink_callback *cb)
211{ 220{
@@ -5408,6 +5417,57 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
5408 return err; 5417 return err;
5409} 5418}
5410 5419
5420static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
5421{
5422 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5423 struct net_device *dev = info->user_ptr[1];
5424 struct wireless_dev *wdev = dev->ieee80211_ptr;
5425 struct nlattr *tb[NUM_NL80211_REKEY_DATA];
5426 struct cfg80211_gtk_rekey_data rekey_data;
5427 int err;
5428
5429 if (!info->attrs[NL80211_ATTR_REKEY_DATA])
5430 return -EINVAL;
5431
5432 err = nla_parse(tb, MAX_NL80211_REKEY_DATA,
5433 nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]),
5434 nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]),
5435 nl80211_rekey_policy);
5436 if (err)
5437 return err;
5438
5439 if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
5440 return -ERANGE;
5441 if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
5442 return -ERANGE;
5443 if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
5444 return -ERANGE;
5445
5446 memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]),
5447 NL80211_KEK_LEN);
5448 memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]),
5449 NL80211_KCK_LEN);
5450 memcpy(rekey_data.replay_ctr,
5451 nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]),
5452 NL80211_REPLAY_CTR_LEN);
5453
5454 wdev_lock(wdev);
5455 if (!wdev->current_bss) {
5456 err = -ENOTCONN;
5457 goto out;
5458 }
5459
5460 if (!rdev->ops->set_rekey_data) {
5461 err = -EOPNOTSUPP;
5462 goto out;
5463 }
5464
5465 err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data);
5466 out:
5467 wdev_unlock(wdev);
5468 return err;
5469}
5470
5411#define NL80211_FLAG_NEED_WIPHY 0x01 5471#define NL80211_FLAG_NEED_WIPHY 0x01
5412#define NL80211_FLAG_NEED_NETDEV 0x02 5472#define NL80211_FLAG_NEED_NETDEV 0x02
5413#define NL80211_FLAG_NEED_RTNL 0x04 5473#define NL80211_FLAG_NEED_RTNL 0x04
@@ -5939,6 +5999,14 @@ static struct genl_ops nl80211_ops[] = {
5939 .internal_flags = NL80211_FLAG_NEED_WIPHY | 5999 .internal_flags = NL80211_FLAG_NEED_WIPHY |
5940 NL80211_FLAG_NEED_RTNL, 6000 NL80211_FLAG_NEED_RTNL,
5941 }, 6001 },
6002 {
6003 .cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
6004 .doit = nl80211_set_rekey_data,
6005 .policy = nl80211_policy,
6006 .flags = GENL_ADMIN_PERM,
6007 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
6008 NL80211_FLAG_NEED_RTNL,
6009 },
5942}; 6010};
5943 6011
5944static struct genl_multicast_group nl80211_mlme_mcgrp = { 6012static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6883,6 +6951,51 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
6883 nlmsg_free(msg); 6951 nlmsg_free(msg);
6884} 6952}
6885 6953
6954void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
6955 struct net_device *netdev, const u8 *bssid,
6956 const u8 *replay_ctr, gfp_t gfp)
6957{
6958 struct sk_buff *msg;
6959 struct nlattr *rekey_attr;
6960 void *hdr;
6961
6962 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
6963 if (!msg)
6964 return;
6965
6966 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
6967 if (!hdr) {
6968 nlmsg_free(msg);
6969 return;
6970 }
6971
6972 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
6973 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
6974 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
6975
6976 rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
6977 if (!rekey_attr)
6978 goto nla_put_failure;
6979
6980 NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR,
6981 NL80211_REPLAY_CTR_LEN, replay_ctr);
6982
6983 nla_nest_end(msg, rekey_attr);
6984
6985 if (genlmsg_end(msg, hdr) < 0) {
6986 nlmsg_free(msg);
6987 return;
6988 }
6989
6990 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
6991 nl80211_mlme_mcgrp.id, gfp);
6992 return;
6993
6994 nla_put_failure:
6995 genlmsg_cancel(msg, hdr);
6996 nlmsg_free(msg);
6997}
6998
6886void 6999void
6887nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, 7000nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
6888 struct net_device *netdev, const u8 *peer, 7001 struct net_device *netdev, const u8 *peer,