aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-05 10:35:40 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-06 15:05:42 -0400
commite5497d766adb92bcbd1fa4a147e188f84f34b20a (patch)
treef5d41f4272b78b8c61a80c22389f6d4b24e65b34
parent830af02f24fbc087999b757b8eca51829c67fa6f (diff)
cfg80211/nl80211: support GTK rekey offload
In certain circumstances, like WoWLAN scenarios, devices may implement (partial) GTK rekeying on the device to avoid waking up the host for it. In order to successfully go through GTK rekeying, the KEK, KCK and the replay counter are required. Add API to let the supplicant hand the parameters to the driver which may store it for future GTK rekey operations. Note that, of course, if GTK rekeying is done by the device, the EAP frame must not be passed up to userspace, instead a rekey event needs to be sent to let userspace update its replay counter. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/nl80211.h39
-rw-r--r--include/net/cfg80211.h26
-rw-r--r--net/wireless/mlme.c11
-rw-r--r--net/wireless/nl80211.c113
-rw-r--r--net/wireless/nl80211.h4
5 files changed, 193 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index c7ccaae15af6..3ec2f949bf7a 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -483,6 +483,14 @@
483 * more background information, see 483 * more background information, see
484 * http://wireless.kernel.org/en/users/Documentation/WoWLAN. 484 * http://wireless.kernel.org/en/users/Documentation/WoWLAN.
485 * 485 *
486 * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
487 * the necessary information for supporting GTK rekey offload. This
488 * feature is typically used during WoWLAN. The configuration data
489 * is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
490 * contains the data in sub-attributes). After rekeying happened,
491 * this command may also be sent by the driver as an MLME event to
492 * inform userspace of the new replay counter.
493 *
486 * @NL80211_CMD_MAX: highest used command number 494 * @NL80211_CMD_MAX: highest used command number
487 * @__NL80211_CMD_AFTER_LAST: internal use 495 * @__NL80211_CMD_AFTER_LAST: internal use
488 */ 496 */
@@ -605,6 +613,8 @@ enum nl80211_commands {
605 NL80211_CMD_SCHED_SCAN_RESULTS, 613 NL80211_CMD_SCHED_SCAN_RESULTS,
606 NL80211_CMD_SCHED_SCAN_STOPPED, 614 NL80211_CMD_SCHED_SCAN_STOPPED,
607 615
616 NL80211_CMD_SET_REKEY_OFFLOAD,
617
608 /* add new commands above here */ 618 /* add new commands above here */
609 619
610 /* used to define NL80211_CMD_MAX below */ 620 /* used to define NL80211_CMD_MAX below */
@@ -996,6 +1006,9 @@ enum nl80211_commands {
996 * are managed in software: interfaces of these types aren't subject to 1006 * are managed in software: interfaces of these types aren't subject to
997 * any restrictions in their number or combinations. 1007 * any restrictions in their number or combinations.
998 * 1008 *
1009 * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
1010 * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
1011 *
999 * @NL80211_ATTR_MAX: highest attribute number currently defined 1012 * @NL80211_ATTR_MAX: highest attribute number currently defined
1000 * @__NL80211_ATTR_AFTER_LAST: internal use 1013 * @__NL80211_ATTR_AFTER_LAST: internal use
1001 */ 1014 */
@@ -1194,6 +1207,8 @@ enum nl80211_attrs {
1194 NL80211_ATTR_INTERFACE_COMBINATIONS, 1207 NL80211_ATTR_INTERFACE_COMBINATIONS,
1195 NL80211_ATTR_SOFTWARE_IFTYPES, 1208 NL80211_ATTR_SOFTWARE_IFTYPES,
1196 1209
1210 NL80211_ATTR_REKEY_DATA,
1211
1197 /* add attributes here, update the policy in nl80211.c */ 1212 /* add attributes here, update the policy in nl80211.c */
1198 1213
1199 __NL80211_ATTR_AFTER_LAST, 1214 __NL80211_ATTR_AFTER_LAST,
@@ -2361,4 +2376,28 @@ enum nl80211_plink_state {
2361 MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1 2376 MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
2362}; 2377};
2363 2378
2379#define NL80211_KCK_LEN 16
2380#define NL80211_KEK_LEN 16
2381#define NL80211_REPLAY_CTR_LEN 8
2382
2383/**
2384 * enum nl80211_rekey_data - attributes for GTK rekey offload
2385 * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
2386 * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
2387 * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
2388 * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
2389 * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
2390 * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
2391 */
2392enum nl80211_rekey_data {
2393 __NL80211_REKEY_DATA_INVALID,
2394 NL80211_REKEY_DATA_KEK,
2395 NL80211_REKEY_DATA_KCK,
2396 NL80211_REKEY_DATA_REPLAY_CTR,
2397
2398 /* keep last */
2399 NUM_NL80211_REKEY_DATA,
2400 MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
2401};
2402
2364#endif /* __LINUX_NL80211_H */ 2403#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7202bce7bfeb..4bf101bada4e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1154,6 +1154,18 @@ struct cfg80211_wowlan {
1154}; 1154};
1155 1155
1156/** 1156/**
1157 * struct cfg80211_gtk_rekey_data - rekey data
1158 * @kek: key encryption key
1159 * @kck: key confirmation key
1160 * @replay_ctr: replay counter
1161 */
1162struct cfg80211_gtk_rekey_data {
1163 u8 kek[NL80211_KEK_LEN];
1164 u8 kck[NL80211_KCK_LEN];
1165 u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
1166};
1167
1168/**
1157 * struct cfg80211_ops - backend description for wireless configuration 1169 * struct cfg80211_ops - backend description for wireless configuration
1158 * 1170 *
1159 * This struct is registered by fullmac card drivers and/or wireless stacks 1171 * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1197,6 +1209,8 @@ struct cfg80211_wowlan {
1197 * 1209 *
1198 * @set_default_mgmt_key: set the default management frame key on an interface 1210 * @set_default_mgmt_key: set the default management frame key on an interface
1199 * 1211 *
1212 * @set_rekey_data: give the data necessary for GTK rekeying to the driver
1213 *
1200 * @add_beacon: Add a beacon with given parameters, @head, @interval 1214 * @add_beacon: Add a beacon with given parameters, @head, @interval
1201 * and @dtim_period will be valid, @tail is optional. 1215 * and @dtim_period will be valid, @tail is optional.
1202 * @set_beacon: Change the beacon parameters for an access point mode 1216 * @set_beacon: Change the beacon parameters for an access point mode
@@ -1499,6 +1513,9 @@ struct cfg80211_ops {
1499 struct net_device *dev, 1513 struct net_device *dev,
1500 struct cfg80211_sched_scan_request *request); 1514 struct cfg80211_sched_scan_request *request);
1501 int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev); 1515 int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);
1516
1517 int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
1518 struct cfg80211_gtk_rekey_data *data);
1502}; 1519};
1503 1520
1504/* 1521/*
@@ -3033,6 +3050,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
3033void cfg80211_cqm_pktloss_notify(struct net_device *dev, 3050void cfg80211_cqm_pktloss_notify(struct net_device *dev,
3034 const u8 *peer, u32 num_packets, gfp_t gfp); 3051 const u8 *peer, u32 num_packets, gfp_t gfp);
3035 3052
3053/**
3054 * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
3055 * @dev: network device
3056 * @bssid: BSSID of AP (to avoid races)
3057 * @replay_ctr: new replay counter
3058 */
3059void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
3060 const u8 *replay_ctr, gfp_t gfp);
3061
3036/* Logging, debugging and troubleshooting/diagnostic helpers. */ 3062/* Logging, debugging and troubleshooting/diagnostic helpers. */
3037 3063
3038/* wiphy_printk helpers, similar to dev_printk */ 3064/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 3633ab6af184..832f6574e4ed 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -1084,3 +1084,14 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
1084 nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp); 1084 nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
1085} 1085}
1086EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); 1086EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
1087
1088void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
1089 const u8 *replay_ctr, gfp_t gfp)
1090{
1091 struct wireless_dev *wdev = dev->ieee80211_ptr;
1092 struct wiphy *wiphy = wdev->wiphy;
1093 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
1094
1095 nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
1096}
1097EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
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,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 2f1bfb87a651..5d69c56400ae 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -109,4 +109,8 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
109 struct net_device *netdev, const u8 *peer, 109 struct net_device *netdev, const u8 *peer,
110 u32 num_packets, gfp_t gfp); 110 u32 num_packets, gfp_t gfp);
111 111
112void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
113 struct net_device *netdev, const u8 *bssid,
114 const u8 *replay_ctr, gfp_t gfp);
115
112#endif /* __NET_WIRELESS_NL80211_H */ 116#endif /* __NET_WIRELESS_NL80211_H */