linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/3] cfg80211/mac80211 wowlan crypto offload
@ 2011-07-01 22:13 Johannes Berg
  2011-07-01 22:13 ` [RFC 1/3] mac80211: allow driver to iterate keys Johannes Berg
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Johannes Berg @ 2011-07-01 22:13 UTC (permalink / raw)
  To: linux-wireless

This is my current code for wowlan crypto offload.

It's still incomplete, but I figured I could use some
feedback.

Missing is access for the driver to IV/PN/RSC/TSC
so it can correctly check frames and use the right
one when sending frames. Will do that soon.

johannes


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC 1/3] mac80211: allow driver to iterate keys
  2011-07-01 22:13 [RFC 0/3] cfg80211/mac80211 wowlan crypto offload Johannes Berg
@ 2011-07-01 22:13 ` Johannes Berg
  2011-07-01 22:13 ` [RFC 2/3] cfg80211/nl80211: support GTK rekey offload Johannes Berg
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2011-07-01 22:13 UTC (permalink / raw)
  To: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

When in suspend/wowlan, devices might implement crypto
offload differently (more features), and might require
reprogramming keys for the WoWLAN (as it is the case
for Intel devices that use another uCode image). Thus
allow the driver to iterate all keys in this context.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h |   23 +++++++++++++++++++++++
 net/mac80211/key.c     |   33 +++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)

--- a/include/net/mac80211.h	2011-07-02 00:08:12.000000000 +0200
+++ b/include/net/mac80211.h	2011-07-02 00:08:13.000000000 +0200
@@ -2850,6 +2850,29 @@ void ieee80211_sta_block_awake(struct ie
 			       struct ieee80211_sta *pubsta, bool block);
 
 /**
+ * ieee80211_iter_keys - iterate keys programmed into the device
+ * @hw: pointer obtained from ieee80211_alloc_hw()
+ * @vif: virtual interface to iterate, may be %NULL for all
+ * @iter: iterator function that will be called for each key
+ * @iter_data: custom data to pass to the iterator function
+ *
+ * This function can be used to iterate all the keys known to
+ * mac80211, even those that weren't previously programmed into
+ * the device. This is intended for use in WoWLAN if the device
+ * needs reprogramming of the keys during suspend. Note that due
+ * to locking reasons, it is also only safe to call this at few
+ * spots since it must hold the RTNL and be able to sleep.
+ */
+void ieee80211_iter_keys(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif,
+			 void (*iter)(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      struct ieee80211_sta *sta,
+				      struct ieee80211_key_conf *key,
+				      void *data),
+			 void *iter_data);
+
+/**
  * ieee80211_ap_probereq_get - retrieve a Probe Request template
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
--- a/net/mac80211/key.c	2011-07-02 00:07:58.000000000 +0200
+++ b/net/mac80211/key.c	2011-07-02 00:08:13.000000000 +0200
@@ -504,6 +504,39 @@ void ieee80211_enable_keys(struct ieee80
 	mutex_unlock(&sdata->local->key_mtx);
 }
 
+void ieee80211_iter_keys(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif,
+			 void (*iter)(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif,
+				      struct ieee80211_sta *sta,
+				      struct ieee80211_key_conf *key,
+				      void *data),
+			 void *iter_data)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_key *key;
+	struct ieee80211_sub_if_data *sdata;
+
+	ASSERT_RTNL();
+
+	mutex_lock(&local->key_mtx);
+	if (vif) {
+		sdata = vif_to_sdata(vif);
+		list_for_each_entry(key, &sdata->key_list, list)
+			iter(hw, &sdata->vif,
+			     key->sta ? &key->sta->sta : NULL,
+			     &key->conf, iter_data);
+	} else {
+		list_for_each_entry(sdata, &local->interfaces, list)
+			list_for_each_entry(key, &sdata->key_list, list)
+				iter(hw, &sdata->vif,
+				     key->sta ? &key->sta->sta : NULL,
+				     &key->conf, iter_data);
+	}
+	mutex_unlock(&local->key_mtx);
+}
+EXPORT_SYMBOL(ieee80211_iter_keys);
+
 void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_key *key;



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC 2/3] cfg80211/nl80211: support GTK rekey offload
  2011-07-01 22:13 [RFC 0/3] cfg80211/mac80211 wowlan crypto offload Johannes Berg
  2011-07-01 22:13 ` [RFC 1/3] mac80211: allow driver to iterate keys Johannes Berg
@ 2011-07-01 22:13 ` Johannes Berg
  2011-07-01 22:13 ` [RFC 3/3] mac80211: " Johannes Berg
  2011-07-01 22:19 ` [RFC] wpa_supplicant/nl80211: " Johannes Berg
  3 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2011-07-01 22:13 UTC (permalink / raw)
  To: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

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>
---
 include/linux/nl80211.h |   39 ++++++++++++++++
 include/net/cfg80211.h  |   26 +++++++++++
 net/wireless/mlme.c     |   11 ++++
 net/wireless/nl80211.c  |  113 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.h  |    4 +
 5 files changed, 193 insertions(+)

--- a/include/linux/nl80211.h	2011-07-02 00:00:35.000000000 +0200
+++ b/include/linux/nl80211.h	2011-07-02 00:00:44.000000000 +0200
@@ -483,6 +483,14 @@
  *	more background information, see
  *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
  *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ *	the necessary information for supporting GTK rekey offload. This
+ *	feature is typically used during WoWLAN. The configuration data
+ *	is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ *	contains the data in sub-attributes). After rekeying happened,
+ *	this command may also be sent by the driver as an MLME event to
+ *	inform userspace of the new replay counter.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -605,6 +613,8 @@ enum nl80211_commands {
 	NL80211_CMD_SCHED_SCAN_RESULTS,
 	NL80211_CMD_SCHED_SCAN_STOPPED,
 
+	NL80211_CMD_SET_REKEY_OFFLOAD,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -996,6 +1006,9 @@ enum nl80211_commands {
  *	are managed in software: interfaces of these types aren't subject to
  *	any restrictions in their number or combinations.
  *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1194,6 +1207,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_INTERFACE_COMBINATIONS,
 	NL80211_ATTR_SOFTWARE_IFTYPES,
 
+	NL80211_ATTR_REKEY_DATA,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2361,4 +2376,28 @@ enum nl80211_plink_state {
 	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
 };
 
+#define NL80211_KCK_LEN			16
+#define NL80211_KEK_LEN			16
+#define NL80211_REPLAY_CTR_LEN		8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+	__NL80211_REKEY_DATA_INVALID,
+	NL80211_REKEY_DATA_KEK,
+	NL80211_REKEY_DATA_KCK,
+	NL80211_REKEY_DATA_REPLAY_CTR,
+
+	/* keep last */
+	NUM_NL80211_REKEY_DATA,
+	MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
 #endif /* __LINUX_NL80211_H */
--- a/include/net/cfg80211.h	2011-07-02 00:00:35.000000000 +0200
+++ b/include/net/cfg80211.h	2011-07-02 00:00:44.000000000 +0200
@@ -1154,6 +1154,18 @@ struct cfg80211_wowlan {
 };
 
 /**
+ * struct cfg80211_gtk_rekey_data - rekey data
+ * @kek: key encryption key
+ * @kck: key confirmation key
+ * @replay_ctr: replay counter
+ */
+struct cfg80211_gtk_rekey_data {
+	u8 kek[NL80211_KEK_LEN];
+	u8 kck[NL80211_KCK_LEN];
+	u8 replay_ctr[NL80211_REPLAY_CTR_LEN];
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1197,6 +1209,8 @@ struct cfg80211_wowlan {
  *
  * @set_default_mgmt_key: set the default management frame key on an interface
  *
+ * @set_rekey_data: give the data necessary for GTK rekeying to the driver
+ *
  * @add_beacon: Add a beacon with given parameters, @head, @interval
  *	and @dtim_period will be valid, @tail is optional.
  * @set_beacon: Change the beacon parameters for an access point mode
@@ -1499,6 +1513,9 @@ struct cfg80211_ops {
 				struct net_device *dev,
 				struct cfg80211_sched_scan_request *request);
 	int	(*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);
+
+	int	(*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
+				  struct cfg80211_gtk_rekey_data *data);
 };
 
 /*
@@ -3033,6 +3050,15 @@ void cfg80211_cqm_rssi_notify(struct net
 void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 				 const u8 *peer, u32 num_packets, gfp_t gfp);
 
+/**
+ * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
+ * @dev: network device
+ * @bssid: BSSID of AP (to avoid races)
+ * @replay_ctr: new replay counter
+ */
+void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
+			       const u8 *replay_ctr, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
--- a/net/wireless/nl80211.c	2011-07-02 00:00:35.000000000 +0200
+++ b/net/wireless/nl80211.c	2011-07-02 00:00:44.000000000 +0200
@@ -176,6 +176,7 @@ static const struct nla_policy nl80211_p
 	[NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
 	[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
 	[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
+	[NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
 };
 
 /* policy for the key attributes */
@@ -206,6 +207,14 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN
 	[NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
 };
 
+/* policy for GTK rekey offload attributes */
+static const struct nla_policy
+nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
+	[NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN },
+	[NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN },
+	[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
+};
+
 /* ifidx get helper */
 static int nl80211_get_ifidx(struct netlink_callback *cb)
 {
@@ -5408,6 +5417,57 @@ static int nl80211_set_wowlan(struct sk_
 	return err;
 }
 
+static int nl80211_set_rekey_data(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 nlattr *tb[NUM_NL80211_REKEY_DATA];
+	struct cfg80211_gtk_rekey_data rekey_data;
+	int err;
+
+	if (!info->attrs[NL80211_ATTR_REKEY_DATA])
+		return -EINVAL;
+
+	err = nla_parse(tb, MAX_NL80211_REKEY_DATA,
+			nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]),
+			nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]),
+			nl80211_rekey_policy);
+	if (err)
+		return err;
+
+	if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
+		return -ERANGE;
+	if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
+		return -ERANGE;
+	if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN)
+		return -ERANGE;
+
+	memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]),
+	       NL80211_KEK_LEN);
+	memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]),
+	       NL80211_KCK_LEN);
+	memcpy(rekey_data.replay_ctr,
+	       nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]),
+	       NL80211_REPLAY_CTR_LEN);
+
+	wdev_lock(wdev);
+	if (!wdev->current_bss) {
+		err = -ENOTCONN;
+		goto out;
+	}
+
+	if (!rdev->ops->set_rekey_data) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data);
+ out:
+	wdev_unlock(wdev);
+	return err;
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -5939,6 +5999,14 @@ static struct genl_ops nl80211_ops[] = {
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
+		.doit = nl80211_set_rekey_data,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6871,6 +6939,51 @@ nl80211_send_cqm_rssi_notify(struct cfg8
 
 	if (genlmsg_end(msg, hdr) < 0) {
 		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_mlme_mcgrp.id, gfp);
+	return;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
+			      struct net_device *netdev, const u8 *bssid,
+			      const u8 *replay_ctr, gfp_t gfp)
+{
+	struct sk_buff *msg;
+	struct nlattr *rekey_attr;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+	rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+	if (!rekey_attr)
+		goto nla_put_failure;
+
+	NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR,
+		NL80211_REPLAY_CTR_LEN, replay_ctr);
+
+	nla_nest_end(msg, rekey_attr);
+
+	if (genlmsg_end(msg, hdr) < 0) {
+		nlmsg_free(msg);
 		return;
 	}
 
--- a/net/wireless/mlme.c	2011-07-02 00:00:35.000000000 +0200
+++ b/net/wireless/mlme.c	2011-07-02 00:00:44.000000000 +0200
@@ -1084,3 +1084,14 @@ void cfg80211_cqm_pktloss_notify(struct
 	nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
 }
 EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
+
+void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
+			       const u8 *replay_ctr, gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+	nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
--- a/net/wireless/nl80211.h	2011-07-02 00:00:35.000000000 +0200
+++ b/net/wireless/nl80211.h	2011-07-02 00:00:44.000000000 +0200
@@ -109,4 +109,8 @@ nl80211_send_cqm_pktloss_notify(struct c
 				struct net_device *netdev, const u8 *peer,
 				u32 num_packets, gfp_t gfp);
 
+void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
+			      struct net_device *netdev, const u8 *bssid,
+			      const u8 *replay_ctr, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC 3/3] mac80211: support GTK rekey offload
  2011-07-01 22:13 [RFC 0/3] cfg80211/mac80211 wowlan crypto offload Johannes Berg
  2011-07-01 22:13 ` [RFC 1/3] mac80211: allow driver to iterate keys Johannes Berg
  2011-07-01 22:13 ` [RFC 2/3] cfg80211/nl80211: support GTK rekey offload Johannes Berg
@ 2011-07-01 22:13 ` Johannes Berg
  2011-07-01 22:19 ` [RFC] wpa_supplicant/nl80211: " Johannes Berg
  3 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2011-07-01 22:13 UTC (permalink / raw)
  To: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

This adds the necessary mac80211 APIs to support
GTK rekey offload, mirroring the functionality
from cfg80211.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/mac80211.h      |   20 +++++++++++++++++
 net/mac80211/cfg.c          |   16 ++++++++++++++
 net/mac80211/driver-ops.h   |   10 ++++++++
 net/mac80211/driver-trace.h |   49 ++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/key.c          |   12 ++++++++++
 5 files changed, 107 insertions(+)

--- a/include/net/mac80211.h	2011-07-02 00:08:13.000000000 +0200
+++ b/include/net/mac80211.h	2011-07-02 00:12:31.000000000 +0200
@@ -1700,6 +1700,12 @@ enum ieee80211_ampdu_mlme_action {
  * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
  *	The callback must be atomic.
  *
+ * @set_rekey_data: If the device supports GTK rekeying, for example while the
+ *	host is suspended, it can assign this callback to retrieve the data
+ *	necessary to do GTK rekeying, this is the KEK, KCK and replay counter.
+ *	After rekeying was done it should (for example during resume) notify
+ *	userspace of the new replay counter using ieee80211_gtk_rekey_notify().
+ *
  * @hw_scan: Ask the hardware to service the scan request, no need to start
  *	the scan state machine in stack. The scan must honour the channel
  *	configuration done by the regulatory agent in the wiphy's
@@ -1912,6 +1918,9 @@ struct ieee80211_ops {
 				struct ieee80211_key_conf *conf,
 				struct ieee80211_sta *sta,
 				u32 iv32, u16 *phase1key);
+	void (*set_rekey_data)(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct cfg80211_gtk_rekey_data *data);
 	int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		       struct cfg80211_scan_request *req);
 	void (*cancel_hw_scan)(struct ieee80211_hw *hw,
@@ -2585,6 +2594,17 @@ ieee80211_get_buffered_bc(struct ieee802
 void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
 				struct sk_buff *skb,
 				enum ieee80211_tkip_key_type type, u8 *key);
+
+/**
+ * ieee80211_gtk_rekey_notify - notify userspace supplicant of rekeying
+ * @vif: virtual interface the rekeying was done on
+ * @bssid: The BSSID of the AP, for checking association
+ * @replay_ctr: the new replay counter after GTK rekeying
+ * @gfp: allocation flags
+ */
+void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
+				const u8 *replay_ctr, gfp_t gfp);
+
 /**
  * ieee80211_wake_queue - wake specific queue
  * @hw: pointer as obtained from ieee80211_alloc_hw().
--- a/net/mac80211/cfg.c	2011-07-02 00:00:35.000000000 +0200
+++ b/net/mac80211/cfg.c	2011-07-02 00:12:31.000000000 +0200
@@ -2101,6 +2101,21 @@ static void ieee80211_get_ringparam(stru
 	drv_get_ringparam(local, tx, tx_max, rx, rx_max);
 }
 
+static int ieee80211_set_rekey_data(struct wiphy *wiphy,
+				    struct net_device *dev,
+				    struct cfg80211_gtk_rekey_data *data)
+{
+	struct ieee80211_local *local = wiphy_priv(wiphy);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (!local->ops->set_rekey_data)
+		return -EOPNOTSUPP;
+
+	drv_set_rekey_data(local, sdata, data);
+
+	return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -2163,4 +2178,5 @@ struct cfg80211_ops mac80211_config_ops
 	.get_antenna = ieee80211_get_antenna,
 	.set_ringparam = ieee80211_set_ringparam,
 	.get_ringparam = ieee80211_get_ringparam,
+	.set_rekey_data = ieee80211_set_rekey_data,
 };
--- a/net/mac80211/driver-trace.h	2011-07-02 00:00:35.000000000 +0200
+++ b/net/mac80211/driver-trace.h	2011-07-02 00:12:31.000000000 +0200
@@ -1024,6 +1024,34 @@ TRACE_EVENT(drv_set_bitrate_mask,
 	)
 );
 
+TRACE_EVENT(drv_set_rekey_data,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct cfg80211_gtk_rekey_data *data),
+
+	TP_ARGS(local, sdata, data),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__array(u8, kek, NL80211_KEK_LEN)
+		__array(u8, kck, NL80211_KCK_LEN)
+		__array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		memcpy(__entry->kek, data->kek, NL80211_KEK_LEN);
+		memcpy(__entry->kck, data->kck, NL80211_KCK_LEN);
+		memcpy(__entry->replay_ctr, data->replay_ctr,
+		       NL80211_REPLAY_CTR_LEN);
+	),
+
+	TP_printk(LOCAL_PR_FMT VIF_PR_FMT,
+		  LOCAL_PR_ARG, VIF_PR_ARG)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
@@ -1293,6 +1321,27 @@ DEFINE_EVENT(local_only_evt, api_remain_
 	TP_ARGS(local)
 );
 
+TRACE_EVENT(api_gtk_rekey_notify,
+	TP_PROTO(struct ieee80211_sub_if_data *sdata,
+		 const u8 *bssid, const u8 *replay_ctr),
+
+	TP_ARGS(sdata, bssid, replay_ctr),
+
+	TP_STRUCT__entry(
+		VIF_ENTRY
+		__array(u8, bssid, ETH_ALEN)
+		__array(u8, replay_ctr, NL80211_REPLAY_CTR_LEN)
+	),
+
+	TP_fast_assign(
+		VIF_ASSIGN;
+		memcpy(__entry->bssid, bssid, ETH_ALEN);
+		memcpy(__entry->replay_ctr, replay_ctr, NL80211_REPLAY_CTR_LEN);
+	),
+
+	TP_printk(VIF_PR_FMT, VIF_PR_ARG)
+);
+
 /*
  * Tracing for internal functions
  * (which may also be called in response to driver calls)
--- a/net/mac80211/key.c	2011-07-02 00:08:13.000000000 +0200
+++ b/net/mac80211/key.c	2011-07-02 00:12:31.000000000 +0200
@@ -566,3 +566,15 @@ void ieee80211_free_keys(struct ieee8021
 
 	mutex_unlock(&sdata->local->key_mtx);
 }
+
+
+void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
+				const u8 *replay_ctr, gfp_t gfp)
+{
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+	trace_api_gtk_rekey_notify(sdata, bssid, replay_ctr);
+
+	cfg80211_gtk_rekey_notify(sdata->dev, bssid, replay_ctr, gfp);
+}
+EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
--- a/net/mac80211/driver-ops.h	2011-07-02 00:07:54.000000000 +0200
+++ b/net/mac80211/driver-ops.h	2011-07-02 00:12:48.000000000 +0200
@@ -647,4 +647,14 @@ static inline int drv_set_bitrate_mask(s
 	return ret;
 }
 
+static inline void drv_set_rekey_data(struct ieee80211_local *local,
+				      struct ieee80211_sub_if_data *sdata,
+				      struct cfg80211_gtk_rekey_data *data)
+{
+	trace_drv_set_rekey_data(local, sdata, data);
+	if (local->ops->set_rekey_data)
+		local->ops->set_rekey_data(&local->hw, &sdata->vif, data);
+	trace_drv_return_void(local);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC] wpa_supplicant/nl80211: support GTK rekey offload
  2011-07-01 22:13 [RFC 0/3] cfg80211/mac80211 wowlan crypto offload Johannes Berg
                   ` (2 preceding siblings ...)
  2011-07-01 22:13 ` [RFC 3/3] mac80211: " Johannes Berg
@ 2011-07-01 22:19 ` Johannes Berg
  3 siblings, 0 replies; 5+ messages in thread
From: Johannes Berg @ 2011-07-01 22:19 UTC (permalink / raw)
  To: linux-wireless

From: Johannes Berg <johannes.berg@intel.com>

Add support to wpa_supplicant for device-based
GTK rekeying. In order to support that, pass the
KEK, KCK and replay counter to the driver, and
handle rekey events that update the latter.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
Not included is a massive nl80211_copy.h update, that'd just pollute the
patch as you can see in the diffstat...

 src/drivers/driver.h         |   23 +
 src/drivers/driver_nl80211.c |   76 ++++++
 src/drivers/nl80211_copy.h   |  504 +++++++++++++++++++++++++++++++++++++++++--
 src/rsn_supp/wpa.c           |    7 
 src/rsn_supp/wpa.h           |    9 
 src/rsn_supp/wpa_i.h         |    8 
 wpa_supplicant/driver_i.h    |    9 
 wpa_supplicant/events.c      |    9 
 wpa_supplicant/wpas_glue.c   |   10 
 9 files changed, 634 insertions(+), 21 deletions(-)

--- a/src/drivers/driver.h	2011-07-01 19:18:00.000000000 +0200
+++ b/src/drivers/driver.h	2011-07-01 23:40:06.000000000 +0200
@@ -2253,6 +2253,12 @@ struct wpa_driver_ops {
 	 * implementation, there is no need to implement this function.
 	 */
 	int (*set_authmode)(void *priv, int authmode);
+
+	/**
+	 * set_rekey_info - set rekey information
+	 */
+	void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+			       const u8 *replay_ctr);
 };
 
 
@@ -2655,7 +2661,14 @@ enum wpa_event_type {
 	/**
 	 * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
 	 */
-	EVENT_IBSS_PEER_LOST
+	EVENT_IBSS_PEER_LOST,
+
+	/**
+	 * EVENT_DRIVER_GTK_REKEY - device/driver did rekey
+	 *
+	 * This event carries the new replay counter.
+	 */
+	EVENT_DRIVER_GTK_REKEY
 };
 
 
@@ -3187,6 +3200,14 @@ union wpa_event_data {
 	struct ibss_peer_lost {
 		u8 peer[ETH_ALEN];
 	} ibss_peer_lost;
+
+	/**
+	 * struct driver_gtk_rekey
+	 */
+	struct driver_gtk_rekey {
+		const u8 *bssid;
+		const u8 *replay_ctr;
+	} driver_gtk_rekey;
 };
 
 /**
--- a/wpa_supplicant/driver_i.h	2011-07-01 19:18:01.000000000 +0200
+++ b/wpa_supplicant/driver_i.h	2011-07-01 19:23:37.000000000 +0200
@@ -704,4 +704,13 @@ static inline int wpa_drv_tdls_oper(stru
 	return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
 }
 
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+					  const u8 *kek, const u8 *kck,
+					  const u8 *replay_ctr)
+{
+	if (!wpa_s->driver->set_rekey_info)
+		return;
+	wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+}
+
 #endif /* DRIVER_I_H */
--- a/src/rsn_supp/wpa.c	2011-07-01 19:18:00.000000000 +0200
+++ b/src/rsn_supp/wpa.c	2011-07-01 19:23:37.000000000 +0200
@@ -1172,6 +1172,8 @@ static void wpa_supplicant_process_3_of_
 		goto failed;
 	}
 
+	wpa_sm_set_rekey_offload(sm);
+
 	return;
 
 failed:
@@ -2642,3 +2644,8 @@ int wpa_sm_has_ptk(struct wpa_sm *sm)
 		return 0;
 	return sm->ptk_set;
 }
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
--- a/src/rsn_supp/wpa_i.h	2011-07-01 19:18:00.000000000 +0200
+++ b/src/rsn_supp/wpa_i.h	2011-07-01 19:23:37.000000000 +0200
@@ -244,6 +244,14 @@ static inline int wpa_sm_mark_authentica
 	return -1;
 }
 
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+	if (!sm->ctx->set_rekey_offload)
+		return;
+	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+				   sm->ptk.kck, sm->rx_replay_counter);
+}
+
 #ifdef CONFIG_TDLS
 static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
 					u8 action_code, u8 dialog_token,
--- a/src/rsn_supp/wpa.h	2011-07-01 19:18:00.000000000 +0200
+++ b/src/rsn_supp/wpa.h	2011-07-01 19:23:37.000000000 +0200
@@ -61,6 +61,8 @@ struct wpa_sm_ctx {
 			      u16 status_code, const u8 *buf, size_t len);
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
 #endif /* CONFIG_TDLS */
+	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+				  const u8 *replay_ctr);
 };
 
 
@@ -132,6 +134,8 @@ int wpa_sm_pmksa_cache_list(struct wpa_s
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
 
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -277,6 +281,11 @@ static inline int wpa_sm_has_ptk(struct
 	return 0;
 }
 
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+					    const u8 *replay_ctr)
+{
+}
+
 #endif /* CONFIG_NO_WPA */
 
 #ifdef CONFIG_PEERKEY
--- a/wpa_supplicant/events.c	2011-07-01 19:23:31.000000000 +0200
+++ b/wpa_supplicant/events.c	2011-07-01 19:23:37.000000000 +0200
@@ -2203,6 +2203,15 @@ void wpa_supplicant_event(void *ctx, enu
 		ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer);
 #endif /* CONFIG_IBSS_RSN */
 		break;
+	case EVENT_DRIVER_GTK_REKEY:
+		if (os_memcmp(data->driver_gtk_rekey.bssid,
+			      wpa_s->bssid, ETH_ALEN))
+			break;
+		if (!wpa_s->wpa)
+			break;
+		wpa_sm_update_replay_ctr(wpa_s->wpa,
+					 data->driver_gtk_rekey.replay_ctr);
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
--- a/wpa_supplicant/wpas_glue.c	2011-07-01 19:18:00.000000000 +0200
+++ b/wpa_supplicant/wpas_glue.c	2011-07-01 19:23:37.000000000 +0200
@@ -655,6 +655,15 @@ int wpa_supplicant_init_eapol(struct wpa
 }
 
 
+static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
+					     const u8 *kck, const u8 *replay_ctr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+}
+
+
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_WPA
@@ -694,6 +703,7 @@ int wpa_supplicant_init_wpa(struct wpa_s
 	ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
 	ctx->tdls_oper = wpa_supplicant_tdls_oper;
 #endif /* CONFIG_TDLS */
+	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
 
 	wpa_s->wpa = wpa_sm_init(ctx);
 	if (wpa_s->wpa == NULL) {
--- a/src/drivers/driver_nl80211.c	2011-07-01 19:23:31.000000000 +0200
+++ b/src/drivers/driver_nl80211.c	2011-07-01 23:39:16.000000000 +0200
@@ -1376,6 +1376,44 @@ static void nl80211_del_station_event(st
 }
 
 
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+					struct nlattr **tb)
+{
+	struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+	static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+		[NL80211_REKEY_DATA_KEK] = {
+			.minlen = NL80211_KEK_LEN,
+			.maxlen = NL80211_KEK_LEN,
+		},
+		[NL80211_REKEY_DATA_KCK] = {
+			.minlen = NL80211_KCK_LEN,
+			.maxlen = NL80211_KCK_LEN,
+		},
+		[NL80211_REKEY_DATA_REPLAY_CTR] = {
+			.minlen = NL80211_REPLAY_CTR_LEN,
+			.maxlen = NL80211_REPLAY_CTR_LEN,
+		},
+	};
+	union wpa_event_data data;
+
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+	if (!tb[NL80211_ATTR_REKEY_DATA])
+		return;
+	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+		return;
+	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+	data.driver_gtk_rekey.replay_ctr =
+		nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
 static int process_event(struct nl_msg *msg, void *arg)
 {
 	struct wpa_driver_nl80211_data *drv = arg;
@@ -1494,6 +1532,8 @@ static int process_event(struct nl_msg *
 	case NL80211_CMD_DEL_STATION:
 		nl80211_del_station_event(drv, tb);
 		break;
+	case NL80211_CMD_SET_REKEY_OFFLOAD:
+		nl80211_rekey_offload_event(drv, tb);
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
 			   "(cmd=%d)", gnlh->cmd);
@@ -6639,6 +6679,41 @@ static int nl80211_flush_pmkid(void *pri
 }
 
 
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+				   const u8 *replay_ctr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nlattr *replay_nested;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+		    NL80211_CMD_SET_REKEY_OFFLOAD, 0);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
+	if (!replay_nested)
+		goto nla_put_failure;
+
+	NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
+	NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
+	NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+		replay_ctr);
+
+	nla_nest_end(msg, replay_nested);
+
+	send_and_recv_msgs(drv, msg, NULL, NULL);
+	return;
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -6711,4 +6786,5 @@ const struct wpa_driver_ops wpa_driver_n
 	.add_pmkid = nl80211_add_pmkid,
 	.remove_pmkid = nl80211_remove_pmkid,
 	.flush_pmkid = nl80211_flush_pmkid,
+	.set_rekey_info = nl80211_set_rekey_info,
 };



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-07-01 22:19 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-01 22:13 [RFC 0/3] cfg80211/mac80211 wowlan crypto offload Johannes Berg
2011-07-01 22:13 ` [RFC 1/3] mac80211: allow driver to iterate keys Johannes Berg
2011-07-01 22:13 ` [RFC 2/3] cfg80211/nl80211: support GTK rekey offload Johannes Berg
2011-07-01 22:13 ` [RFC 3/3] mac80211: " Johannes Berg
2011-07-01 22:19 ` [RFC] wpa_supplicant/nl80211: " Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).