[PATCH v2] wpa_supplicant/nl80211: support GTK rekey offload

Johannes Berg johannes
Wed Jul 6 05:56:57 PDT 2011


From: Johannes Berg <johannes.berg at 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 at intel.com>
---
v2: update rekey data after group rekeying


This patch requires a separate update of nl80211_copy.h
to the version including the NL80211_CMD_SET_REKEY_OFFLOAD
command.

 src/drivers/driver.h         |   23 ++++++++++++
 src/drivers/driver_nl80211.c |   77 +++++++++++++++++++++++++++++++++++++++++++
 src/rsn_supp/wpa.c           |    9 +++++
 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 +++++
 8 files changed, 153 insertions(+), 1 deletion(-)

--- a/src/drivers/driver.h	2011-07-05 16:39:12.000000000 +0200
+++ b/src/drivers/driver.h	2011-07-05 16:39:13.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-05 16:39:12.000000000 +0200
+++ b/wpa_supplicant/driver_i.h	2011-07-05 16:39:13.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-05 16:39:12.000000000 +0200
+++ b/src/rsn_supp/wpa.c	2011-07-06 14:51:53.000000000 +0200
@@ -1172,6 +1172,8 @@ static void wpa_supplicant_process_3_of_
 		goto failed;
 	}
 
+	wpa_sm_set_rekey_offload(sm);
+
 	return;
 
 failed:
@@ -1390,6 +1392,8 @@ static void wpa_supplicant_process_1_of_
 			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
 		wpa_sm_cancel_auth_timeout(sm);
 		wpa_sm_set_state(sm, WPA_COMPLETED);
+
+		wpa_sm_set_rekey_offload(sm);
 	} else {
 		wpa_supplicant_key_neg_complete(sm, sm->bssid,
 						key_info &
@@ -2642,3 +2646,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-05 16:39:12.000000000 +0200
+++ b/src/rsn_supp/wpa_i.h	2011-07-05 16:39:13.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-05 16:39:12.000000000 +0200
+++ b/src/rsn_supp/wpa.h	2011-07-05 16:39:13.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-05 16:39:12.000000000 +0200
+++ b/wpa_supplicant/events.c	2011-07-05 16:39:13.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-05 16:39:12.000000000 +0200
+++ b/wpa_supplicant/wpas_glue.c	2011-07-05 16:39:13.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-05 16:39:12.000000000 +0200
+++ b/src/drivers/driver_nl80211.c	2011-07-05 16:40:25.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,9 @@ 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);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
 			   "(cmd=%d)", gnlh->cmd);
@@ -6639,6 +6680,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 +6787,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,
 };





More information about the Hostap mailing list