diff mbox series

[v8,01/15] Introduce and add key_type

Message ID 20191031091901.2889-2-alexander@wetzel-home.de
State Changes Requested
Headers show
Series Support seamless PTK rekeys with Extended Key ID | expand

Commit Message

Alexander Wetzel Oct. 31, 2019, 9:18 a.m. UTC
Add the new attribute key_type which will in the following patches
replace the "boolean" set_tx with something also able to handle
Extended Key ID.

The new key types are:

  KEY_TYPE_BROADCAST
    To be set when installing a broadcast key which is not also a default
    key. (Replaces set_tx=0)

  KEY_TYPE_DEFAULT
    To be set when installing a WEP or a group key running without a
    pairwise key. Must not be used when pairwise keys are used. Never
    set when deleting a key. (Replaces set_tx=1)

  KEY_TYPE_PAIRWISE:
    Used to distinguish pairwise from broadcast keys. This is needed
    since Extended Key ID can use keyidx=1 both as a pairwise and a group
    key and we sometimes need an additional hint to distinguish them.

  KEY_TYPE_NO_AUTO_TX
    To be set when installing a pairwise key which must not be used for
    Tx, yet. (New requirement for Extended Key ID support.)

  KEY_TYPE_SET_TX
    To be set when activating Tx for a key already installed with
    KEY_TYPE_NO_AUTO_TX. (New requirement for Extended Key ID support.)

This patch is not changing any functionality and just adds the new
argument key_type to all hostapd/wpa_supplicant set_key() functions.

The new argument key_type is always set to zero within this patch and
only hostapd_ctrl_set_key() has some additional lines to read and store
the new value in the matching variable.

Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---

I started out using key_flags instead an enum here. But after getting it
working it turned out that there simply is no useful case where we would
have to set more than one bit.  (In the RFC version I morphed
- incompletely - set_tx to key_flags but that was just a half-step. See
https://patchwork.ozlabs.org/project/hostap/list/?series=75270)

 hostapd/ctrl_iface.c            | 37 +++++++++++++++++++++------------
 src/ap/ap_drv_ops.c             |  4 ++--
 src/ap/ap_drv_ops.h             |  2 +-
 src/ap/hostapd.c                |  8 +++----
 src/ap/ieee802_11.c             |  3 ++-
 src/ap/ieee802_1x.c             |  7 ++++---
 src/ap/wpa_auth.c               | 16 +++++++-------
 src/ap/wpa_auth.h               |  3 ++-
 src/ap/wpa_auth_ft.c            |  7 ++++---
 src/ap/wpa_auth_glue.c          |  4 ++--
 src/common/defs.h               |  8 +++++++
 src/drivers/driver.h            | 19 ++++++++++++++++-
 src/drivers/driver_atheros.c    |  3 ++-
 src/drivers/driver_bsd.c        |  3 ++-
 src/drivers/driver_hostap.c     |  3 ++-
 src/drivers/driver_ndis.c       | 12 ++++++-----
 src/drivers/driver_nl80211.c    | 11 ++++++----
 src/drivers/driver_openbsd.c    |  3 ++-
 src/drivers/driver_privsep.c    |  3 ++-
 src/drivers/driver_wext.c       |  8 ++++---
 src/drivers/driver_wext.h       |  3 ++-
 src/rsn_supp/tdls.c             |  6 +++---
 src/rsn_supp/wpa.c              | 15 ++++++-------
 src/rsn_supp/wpa.h              |  2 +-
 src/rsn_supp/wpa_ft.c           |  7 ++++---
 src/rsn_supp/wpa_i.h            |  5 +++--
 tests/hwsim/test_ap_ciphers.py  |  2 +-
 wpa_supplicant/ctrl_iface.c     | 18 ++++++++--------
 wpa_supplicant/driver_i.h       |  6 ++++--
 wpa_supplicant/ibss_rsn.c       | 11 +++++-----
 wpa_supplicant/mesh_mpm.c       |  6 +++---
 wpa_supplicant/mesh_rsn.c       |  9 ++++----
 wpa_supplicant/wpa_supplicant.c |  8 +++----
 wpa_supplicant/wpas_glue.c      | 11 +++++-----
 34 files changed, 168 insertions(+), 105 deletions(-)

Comments

Jouni Malinen Dec. 28, 2019, 8:58 a.m. UTC | #1
On Thu, Oct 31, 2019 at 10:18:47AM +0100, Alexander Wetzel wrote:
> Add the new attribute key_type which will in the following patches
> replace the "boolean" set_tx with something also able to handle
> Extended Key ID.
> 
> The new key types are:
> 
>   KEY_TYPE_BROADCAST
>     To be set when installing a broadcast key which is not also a default
>     key. (Replaces set_tx=0)

This is quite confusing. KEY_TYPE_BROADCAST is used on the station side
to configure an RX-only group key (GTK) which is set_tx=0. On the AP
side, though, this is setting TX-only group key (GTK) which is set_tx=1.
In other words, on the AP side, this needs to change the default TX key
index while on the station side there is no such need. At minimum, the
documentation needs to be clear on how this is used on AP/STA and how
the difference may be different. And that "Replace set_tx=0" part seems
more misleading than helpful in understanding this.

In addition, this KEY_TYPE_BROADCAST has value 0 and the PMK
configuration cases for 4-way handshake offload are using magic value 0
in set_key() calls. That should be fixed by defining a new KEY_TYPE_
value for that special case of set_key() being used for other keys than
the ones going to be used in WEP/TKIP/CCMP/GCMP/BIP.

I'm not sure I understand wpa_driver_nl80211_set_key() changes for this
either since there would now be a block there that has key_type ==
KEY_TYPE_BROADCAST comparison within an if block that uses condition
"addr && !is_broadcast_ether_addr(addr)". How can KEY_TYPE_BROADCAST be
used with a non-broadcast address?

>   KEY_TYPE_DEFAULT
>     To be set when installing a WEP or a group key running without a
>     pairwise key. Must not be used when pairwise keys are used. Never
>     set when deleting a key. (Replaces set_tx=1)

That "Replaces set_tx=1" does not help here either or at least for me,
that makes it very difficult to see how the other changes would actually
be correct.

How would one change TX key index of default WEP keys? For example, if
one were to first configure three default WEP keys with key indexes 0,
1, and 2 and then want to set key index 1 as the default TX key and then
change that to key index 2. How those operations use set_key()? Same
actually applies for CCMP group keys as well (KEY_TYPE_BROADCAST),
i.e., the AP could configure two group keys and then alternate between
them without changing the particular key itself. Does this interface
work for that?

>   KEY_TYPE_PAIRWISE:
>     Used to distinguish pairwise from broadcast keys. This is needed
>     since Extended Key ID can use keyidx=1 both as a pairwise and a group
>     key and we sometimes need an additional hint to distinguish them.

This should be clearly documented to immediately set the new key as the
TX key (i.e., change TX key index) which is what set_tx=1 would imply.

>   KEY_TYPE_NO_AUTO_TX
>     To be set when installing a pairwise key which must not be used for
>     Tx, yet. (New requirement for Extended Key ID support.)

The name without _PAIRWISE here is somewhat confusing if this is indeed
only used with pairwise keys. This would sound like set_tx=0 case.

>   KEY_TYPE_SET_TX
>     To be set when activating Tx for a key already installed with
>     KEY_TYPE_NO_AUTO_TX. (New requirement for Extended Key ID support.)

So this might be the operation I was looking for KEY_TYPE_BROADCAST and
KEY_TYPE_DEFAULT above, but this seems to be documented to be used only
with KEY_TYPE_NO_AUTO_TX..

I'm not completely convinced that this set of values is going to cover
all needs. There are three different kinds of keys (ignoring the PMK
type special case): pairwise keys, group keys, default keys (when
separate pairwise keys are not used). Keys can be set as RX-only,
TX-only, or RX+TX; and there is possibility to move from RX-only to
RX+TX and from TX-only to RX+TX. Any previously configured key that
includes TX (i.e., TX-only or RX+TX) can be selected as the key to use
for transmission and this can be swapped at will on the transmitter side
(e.g., switching between group keys with keyidx 1 and 2 or switching
between pairwise keys with keyidx 0 and 1).

It would be nice to get a description on how all these possible
configuration cases can be covered by the proposed interface and if some
of the combinations cannot be covered, there would need to be a good
justification for that. If we are going to go through this extensive
redesign of the interface, we'd should be confident that it will cover
future needs as well and does not leave out something that might not be
used in the current implementation but is defined or allowed in the
standard.

> diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
> @@ -2219,13 +2221,22 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
>  	if (*pos != ' ')
>  		return -1;
>  	pos++;
> -	key_len = os_strlen(pos) / 2;
> +	key_len = (os_strchr(pos, ' ') - pos) / 2;

Couldn't os_strchr(pos, ' ') be NULL here? If so, that NULL - pos would
not be a defined operation.
Alexander Wetzel Dec. 29, 2019, 11:42 a.m. UTC | #2
> On Thu, Oct 31, 2019 at 10:18:47AM +0100, Alexander Wetzel wrote:
>> Add the new attribute key_type which will in the following patches
>> replace the "boolean" set_tx with something also able to handle
>> Extended Key ID.
>>
>> The new key types are:
>>
>>    KEY_TYPE_BROADCAST
>>      To be set when installing a broadcast key which is not also a default
>>      key. (Replaces set_tx=0)
> 
> This is quite confusing. KEY_TYPE_BROADCAST is used on the station side
> to configure an RX-only group key (GTK) which is set_tx=0. On the AP
> side, though, this is setting TX-only group key (GTK) which is set_tx=1.
> In other words, on the AP side, this needs to change the default TX key
> index while on the station side there is no such need. At minimum, the
> documentation needs to be clear on how this is used on AP/STA and how
> the difference may be different. And that "Replace set_tx=0" part seems
> more misleading than helpful in understanding this.

The short version is: you are of course right, the logic is suboptimal - 
with one real regression and some pointless limitations for the future.

> 
> In addition, this KEY_TYPE_BROADCAST has value 0 and the PMK
> configuration cases for 4-way handshake offload are using magic value 0
> in set_key() calls. That should be fixed by defining a new KEY_TYPE_
> value for that special case of set_key() being used for other keys than
> the ones going to be used in WEP/TKIP/CCMP/GCMP/BIP.
> 

I at least planned to mention that option somewhere but looks I forgot.
It's technically not needed but should make that a bit simpler to 
understand. I'll add that in the next version.

> I'm not sure I understand wpa_driver_nl80211_set_key() changes for this
> either since there would now be a block there that has key_type ==
> KEY_TYPE_BROADCAST comparison within an if block that uses condition
> "addr && !is_broadcast_ether_addr(addr)". How can KEY_TYPE_BROADCAST be
> used with a non-broadcast address?
> 

I'm on thin ice with the explanation, but it looks like we need that for 
ibss:
supp_set_key() is actively replacing the "broadcast" with the "unicast" 
address prior to installing the key for all broadcast keys installed in 
an ibss.
I believe this is linked to the fact that there is only one sta using 
the ibss group key for TX but each sta in the ibss will have an own 
broadcast key. (Guess there can only be one "real" broadcast key and 
ibss therefore is a special case using unicast broadcast keys...)
So I would keep the case in the reworked patch.

>>    KEY_TYPE_DEFAULT
>>      To be set when installing a WEP or a group key running without a
>>      pairwise key. Must not be used when pairwise keys are used. Never
>>      set when deleting a key. (Replaces set_tx=1)
> 
> That "Replaces set_tx=1" does not help here either or at least for me,
> that makes it very difficult to see how the other changes would actually
> be correct.
> 
> How would one change TX key index of default WEP keys? For example, if
> one were to first configure three default WEP keys with key indexes 0,
> 1, and 2 and then want to set key index 1 as the default TX key and then
> change that to key index 2. How those operations use set_key()? Same
> actually applies for CCMP group keys as well (KEY_TYPE_BROADCAST),
> i.e., the AP could configure two group keys and then alternate between
> them without changing the particular key itself. Does this interface
> work for that?
> 

The interface - or at least the implementation here - is not handling 
that (well). The roots of the patch are comparable old and it looks like 
I was too fixated on that to catch it later when I understood it better.
Probably due to the fact that it still able to cover the needs of the 
current code with one (for usability harmless) regression: group keys 
are always installed as TX. (So the patches stop installing PTK keys as 
default ones but "replace" that bug with installing group keys always 
for TX...) I'll make sure the new series address that and let you decide 
if that really fixes it:-)

Changing a WEP Key index is for my understanding already requiring a 
"normal" set_key call, basically reinstalling the key. The same is true 
for CCMP group keys. I don't plan to change that (yet) but will make 
sure that API is able to handle it when we want to do that later.


>>    KEY_TYPE_PAIRWISE:
>>      Used to distinguish pairwise from broadcast keys. This is needed
>>      since Extended Key ID can use keyidx=1 both as a pairwise and a group
>>      key and we sometimes need an additional hint to distinguish them.
> 
> This should be clearly documented to immediately set the new key as the
> TX key (i.e., change TX key index) which is what set_tx=1 would imply.
> 
>>    KEY_TYPE_NO_AUTO_TX
>>      To be set when installing a pairwise key which must not be used for
>>      Tx, yet. (New requirement for Extended Key ID support.)
> 
> The name without _PAIRWISE here is somewhat confusing if this is indeed
> only used with pairwise keys. This would sound like set_tx=0 case.
> 
>>    KEY_TYPE_SET_TX
>>      To be set when activating Tx for a key already installed with
>>      KEY_TYPE_NO_AUTO_TX. (New requirement for Extended Key ID support.)
> 
> So this might be the operation I was looking for KEY_TYPE_BROADCAST and
> KEY_TYPE_DEFAULT above, but this seems to be documented to be used only
> with KEY_TYPE_NO_AUTO_TX..

I'll move to bit flags, so we'll have a bit for RX,TX, DEFAULT, 
BROADCAST and so on. I'll probably also add some defines for common 
combinations.

> 
> I'm not completely convinced that this set of values is going to cover
> all needs. There are three different kinds of keys (ignoring the PMK
> type special case): pairwise keys, group keys, default keys (when
> separate pairwise keys are not used). Keys can be set as RX-only,
> TX-only, or RX+TX; and there is possibility to move from RX-only to
> RX+TX and from TX-only to RX+TX. Any previously configured key that
> includes TX (i.e., TX-only or RX+TX) can be selected as the key to use
> for transmission and this can be swapped at will on the transmitter side
> (e.g., switching between group keys with keyidx 1 and 2 or switching
> between pairwise keys with keyidx 0 and 1). >

You are right. It outright miss the the RX only group key we use in the 
current code. (It's handling the rest but only because the current code 
is already always installing a key again when it has to switch.)

> It would be nice to get a description on how all these possible
> configuration cases can be covered by the proposed interface and if some
> of the combinations cannot be covered, there would need to be a good
> justification for that. If we are going to go through this extensive
> redesign of the interface, we'd should be confident that it will cover
> future needs as well and does not leave out something that might not be
> used in the current implementation but is defined or allowed in the
> standard.
> 

When you see a better - and/or less invasive - way to handle the 
Extended Key ID requirements I'm sure I can implement that instead.

>> diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
>> @@ -2219,13 +2221,22 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
>>   	if (*pos != ' ')
>>   		return -1;
>>   	pos++;
>> -	key_len = os_strlen(pos) / 2;
>> +	key_len = (os_strchr(pos, ' ') - pos) / 2;
> 
> Couldn't os_strchr(pos, ' ') be NULL here? If so, that NULL - pos would
> not be a defined operation.
> 

Thanks, missed that.
I'll change it to:
         key_len = os_strchr(pos, ' ');
         if (!key_len)
                 return -1;
         key_len = (key_len - pos) / 2;

Alexander
diff mbox series

Patch

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 2c44d1e4e..961a35f2d 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2122,7 +2122,7 @@  static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					hapd->last_igtk_alg,
 					broadcast_ether_addr,
 					hapd->last_igtk_key_idx, 1, NULL, 0,
-					zero, hapd->last_igtk_len) < 0)
+					zero, hapd->last_igtk_len, 0) < 0)
 			return -1;
 
 		/* Set the previously configured key to reset its TSC */
@@ -2131,7 +2131,7 @@  static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					   broadcast_ether_addr,
 					   hapd->last_igtk_key_idx, 1, NULL, 0,
 					   hapd->last_igtk,
-					   hapd->last_igtk_len);
+					   hapd->last_igtk_len, 0);
 	}
 
 	if (is_broadcast_ether_addr(addr)) {
@@ -2146,7 +2146,7 @@  static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					hapd->last_gtk_alg,
 					broadcast_ether_addr,
 					hapd->last_gtk_key_idx, 1, NULL, 0,
-					zero, hapd->last_gtk_len) < 0)
+					zero, hapd->last_gtk_len, 0) < 0)
 			return -1;
 
 		/* Set the previously configured key to reset its TSC */
@@ -2154,7 +2154,8 @@  static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					   hapd->last_gtk_alg,
 					   broadcast_ether_addr,
 					   hapd->last_gtk_key_idx, 1, NULL, 0,
-					   hapd->last_gtk, hapd->last_gtk_len);
+					   hapd->last_gtk, hapd->last_gtk_len,
+					   0);
 	}
 
 	sta = ap_get_sta(hapd, addr);
@@ -2171,13 +2172,13 @@  static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 	 * in the driver. */
 	if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
 				sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-				zero, sta->last_tk_len) < 0)
+				zero, sta->last_tk_len, 0) < 0)
 		return -1;
 
 	/* Set the previously configured key to reset its TSC/RSC */
 	return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
 				   sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-				   sta->last_tk, sta->last_tk_len);
+				   sta->last_tk, sta->last_tk_len, 0);
 }
 
 
@@ -2186,11 +2187,12 @@  static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
 	u8 addr[ETH_ALEN];
 	const char *pos = cmd;
 	enum wpa_alg alg;
+	enum key_type key_type;
 	int idx, set_tx;
 	u8 seq[6], key[WPA_TK_MAX_LEN];
 	size_t key_len;
 
-	/* parameters: alg addr idx set_tx seq key */
+	/* parameters: alg addr idx set_tx seq key key_type */
 
 	alg = atoi(pos);
 	pos = os_strchr(pos, ' ');
@@ -2219,13 +2221,22 @@  static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
 	if (*pos != ' ')
 		return -1;
 	pos++;
-	key_len = os_strlen(pos) / 2;
+	key_len = (os_strchr(pos, ' ') - pos) / 2;
 	if (hexstr2bin(pos, key, key_len) < 0)
 		return -1;
+	pos += 2 * key_len;
+	if (*pos != ' ')
+		return -1;
+
+	pos++;
+	key_type = atoi(pos);
+	pos = os_strchr(pos, ' ');
+	if (pos)
+		return -1;
 
 	wpa_printf(MSG_INFO, "TESTING: Set key");
 	return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
-				   set_tx, seq, 6, key, key_len);
+				   set_tx, seq, 6, key, key_len, key_type);
 }
 
 
@@ -2241,7 +2252,7 @@  static void restore_tk(void *ctx1, void *ctx2)
 	 * preventing encryption of a single EAPOL frame. */
 	hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
 			    sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-			    sta->last_tk, sta->last_tk_len);
+			    sta->last_tk, sta->last_tk_len, 0);
 }
 
 
@@ -2265,7 +2276,7 @@  static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
 				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    NULL, 0, 0);
 	}
 
 	wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
@@ -2295,7 +2306,7 @@  static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
 				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    NULL, 0, 0);
 	}
 
 	wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
@@ -2325,7 +2336,7 @@  static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
 				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    NULL, 0, 0);
 	}
 
 	wpa_printf(MSG_INFO,
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 204274f0d..59db5b827 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -681,13 +681,13 @@  int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
 			enum wpa_alg alg, const u8 *addr,
 			int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
+			const u8 *key, size_t key_len, enum key_type key_type)
 {
 	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
 		return 0;
 	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
 				     key_idx, set_tx, seq, seq_len, key,
-				     key_len);
+				     key_len, key_type);
 }
 
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 79b1302ac..e772642b7 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -91,7 +91,7 @@  int hostapd_drv_set_key(const char *ifname,
 			enum wpa_alg alg, const u8 *addr,
 			int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len);
+			const u8 *key, size_t key_len, enum key_type key_type);
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
 			  const void *msg, size_t len, int noack);
 int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 368643867..316d1e833 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -292,7 +292,7 @@  static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
 		return;
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
 		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
-					0, NULL, 0, NULL, 0)) {
+					0, NULL, 0, NULL, 0, 0)) {
 			wpa_printf(MSG_DEBUG, "Failed to clear default "
 				   "encryption keys (ifname=%s keyidx=%d)",
 				   ifname, i);
@@ -302,7 +302,7 @@  static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
 		for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
 			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
 						NULL, i, 0, NULL,
-						0, NULL, 0)) {
+						0, NULL, 0, 0)) {
 				wpa_printf(MSG_DEBUG, "Failed to clear "
 					   "default mgmt encryption keys "
 					   "(ifname=%s keyidx=%d)", ifname, i);
@@ -329,7 +329,7 @@  static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
 	    hostapd_drv_set_key(hapd->conf->iface,
 				hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
 				1, NULL, 0, ssid->wep.key[idx],
-				ssid->wep.len[idx])) {
+				ssid->wep.len[idx], 0)) {
 		wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
 		errors++;
 	}
@@ -555,7 +555,7 @@  static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
 		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
 					i == hapd->conf->ssid.wep.idx, NULL, 0,
 					hapd->conf->ssid.wep.key[i],
-					hapd->conf->ssid.wep.len[i])) {
+					hapd->conf->ssid.wep.len[i], 0)) {
 			wpa_printf(MSG_WARNING, "Could not set WEP "
 				   "encryption.");
 			return -1;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 92ae026e5..a4f3aa72f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4900,7 +4900,8 @@  static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
 		if (ssid->wep.key[i] &&
 		    hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
 					i == ssid->wep.idx, NULL, 0,
-					ssid->wep.key[i], ssid->wep.len[i])) {
+					ssid->wep.key[i], ssid->wep.len[i],
+					0)) {
 			wpa_printf(MSG_WARNING,
 				   "Could not set WEP keys for WDS interface; %s",
 				   ifname_wds);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d0810310c..1a94b0c44 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -285,7 +285,8 @@  static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 		 * has ACKed EAPOL-Key frame */
 		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
 					sta->addr, 0, 1, NULL, 0, ikey,
-					hapd->conf->individual_wep_key_len)) {
+					hapd->conf->individual_wep_key_len,
+					0)) {
 			wpa_printf(MSG_ERROR,
 				   "Could not set individual WEP encryption");
 		}
@@ -2179,7 +2180,7 @@  static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
 				broadcast_ether_addr,
 				eapol->default_wep_key_idx, 1, NULL, 0,
 				eapol->default_wep_key,
-				hapd->conf->default_wep_key_len)) {
+				hapd->conf->default_wep_key_len, 0)) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_WARNING,
 			       "failed to configure a new broadcast key");
@@ -2471,7 +2472,7 @@  int ieee802_1x_init(struct hostapd_data *hapd)
 		for (i = 0; i < 4; i++)
 			hostapd_drv_set_key(hapd->conf->iface, hapd,
 					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-					    NULL, 0);
+					    NULL, 0, 0);
 
 		ieee802_1x_rekey(hapd, NULL);
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7b690d730..30c575880 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -136,12 +136,13 @@  static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
+				   u8 *key, size_t key_len,
+				   enum key_type key_type)
 {
 	if (wpa_auth->cb->set_key == NULL)
 		return -1;
 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-				     key, key_len);
+				     key, key_len, key_type);
 }
 
 
@@ -1714,7 +1715,7 @@  void wpa_remove_ptk(struct wpa_state_machine *sm)
 	sm->PTK_valid = FALSE;
 	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
 	if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
-			     0))
+			     0, 0))
 		wpa_printf(MSG_DEBUG,
 			   "RSN: PTK removal from the driver failed");
 	sm->pairwise_set = FALSE;
@@ -2746,7 +2747,7 @@  int fils_set_tk(struct wpa_state_machine *sm)
 
 	wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk, klen)) {
+			     sm->PTK.tk, klen, 0)) {
 		wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
 		return -1;
 	}
@@ -3343,7 +3344,7 @@  SM_STATE(WPA_PTK, PTKINITDONE)
 		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
 		int klen = wpa_cipher_key_len(sm->pairwise);
 		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-				     sm->PTK.tk, klen)) {
+				     sm->PTK.tk, klen, 0)) {
 			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 			return;
@@ -3935,7 +3936,7 @@  static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 	if (wpa_auth_set_key(wpa_auth, group->vlan_id,
 			     wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
 			     broadcast_ether_addr, group->GN,
-			     group->GTK[group->GN - 1], group->GTK_len) < 0)
+			     group->GTK[group->GN - 1], group->GTK_len, 0) < 0)
 		ret = -1;
 
 	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
@@ -3948,7 +3949,8 @@  static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 		if (ret == 0 &&
 		    wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
 				     broadcast_ether_addr, group->GN_igtk,
-				     group->IGTK[group->GN_igtk - 4], len) < 0)
+				     group->IGTK[group->GN_igtk - 4],
+				     len, 0) < 0)
 			ret = -1;
 	}
 
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index f62783812..e714176a6 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -257,7 +257,8 @@  struct wpa_auth_callbacks {
 			      int *vlan_id);
 	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
 	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
-		       const u8 *addr, int idx, u8 *key, size_t key_len);
+		       const u8 *addr, int idx, u8 *key, size_t key_len,
+		       enum key_type key_type);
 	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
 	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
 			  size_t data_len, int encrypt);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index a599be225..0898ddae2 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2620,12 +2620,13 @@  u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
+				   u8 *key, size_t key_len,
+				   enum key_type key_type)
 {
 	if (wpa_auth->cb->set_key == NULL)
 		return -1;
 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-				     key, key_len);
+				     key, key_len, key_type);
 }
 
 
@@ -2658,7 +2659,7 @@  void wpa_ft_install_ptk(struct wpa_state_machine *sm)
 	 * optimized by adding the STA entry earlier.
 	 */
 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk, klen))
+			     sm->PTK.tk, klen, 0))
 		return;
 
 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index ddab95040..c50eb9d77 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -354,7 +354,7 @@  static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
 
 static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 				    const u8 *addr, int idx, u8 *key,
-				    size_t key_len)
+				    size_t key_len, enum key_type key_type)
 {
 	struct hostapd_data *hapd = ctx;
 	const char *ifname = hapd->conf->iface;
@@ -395,7 +395,7 @@  static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 	return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
-				   key, key_len);
+				   key, key_len, key_type);
 }
 
 
diff --git a/src/common/defs.h b/src/common/defs.h
index 4faf1c860..dc33ff18d 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -419,4 +419,12 @@  enum chan_width {
 	CHAN_WIDTH_UNKNOWN
 };
 
+enum key_type {
+	KEY_TYPE_BROADCAST,
+	KEY_TYPE_DEFAULT,
+	KEY_TYPE_PAIRWISE,
+	KEY_TYPE_NO_AUTO_TX,
+	KEY_TYPE_SET_TX,
+};
+
 #endif /* DEFS_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index ad68a0765..142d2fd60 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2335,6 +2335,23 @@  struct wpa_driver_ops {
 	 *	8-byte Rx Mic Key
 	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
 	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
+	 * @key_type: Additional instructions for key install:
+	 *	%KEY_TYPE_BROADCAST:
+	 *	  Key is a broadcast but no default key.
+	 *	%KEY_TYPE_DEFAULT:
+	 *	  Key is the default key (not using pairwise keys, WEP or
+	 *	  group key only.) Must not be used when pairwise keys are
+	 *	  also in use.
+	 *	%KEY_TYPE_PAIRWISE:
+	 *	  Normal pairwise key not requiring Extended Key ID actions.
+	 *	%KEY_TYPE_NO_AUTO_TX:
+	 *	  Pairwise Key, but it must not be used for Tx, yet.
+	 *	  Can only be used when the driver supports Extended Key ID.
+	 *	%KEY_TYPE_SET_TX:
+	 *	  Key already installed with %KEY_TYPE_NO_AUTO_TX is selected as
+	 *	  the pairwise Tx key for the STA. Only @ifname, @priv, @addr
+	 *	  and @key_idx must be set and all other arguments have to be
+	 *	  zero or NULL.
 	 *
 	 * Returns: 0 on success, -1 on failure
 	 *
@@ -2359,7 +2376,7 @@  struct wpa_driver_ops {
 	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
 		       const u8 *addr, int key_idx, int set_tx,
 		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
+		       const u8 *key, size_t key_len, enum key_type key_type);
 
 	/**
 	 * init - Initialize driver interface
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index eac3ae8af..e95652de5 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -494,7 +494,8 @@  atheros_del_key(void *priv, const u8 *addr, int key_idx)
 static int
 atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 		const u8 *addr, int key_idx, int set_tx, const u8 *seq,
-		size_t seq_len, const u8 *key, size_t key_len)
+		size_t seq_len, const u8 *key, size_t key_len,
+		enum key_type key_type)
 {
 	struct atheros_driver_data *drv = priv;
 	struct ieee80211req_key wk;
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 8667ee519..de9fa6b02 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -333,7 +333,8 @@  bsd_ctrl_iface(void *priv, int enable)
 static int
 bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
+	    size_t seq_len, const u8 *key, size_t key_len,
+	    enum key_type key_type)
 {
 	struct ieee80211req_key wk;
 #ifdef IEEE80211_KEY_NOREPLAY
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 186eccbf2..bf22858fb 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -399,7 +399,8 @@  static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
 				     enum wpa_alg alg, const u8 *addr,
 				     int key_idx, int set_tx,
 				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
+				     const u8 *key, size_t key_len,
+				     enum key_type key_type)
 {
 	struct hostap_driver_data *drv = priv;
 	struct prism2_hostapd_param *param;
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 5b4b9247e..649bc01ea 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -932,7 +932,8 @@  static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
 
 static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
 				   int pairwise, int key_idx, int set_tx,
-				   const u8 *key, size_t key_len)
+				   const u8 *key, size_t key_len,
+				   enum key_type key_type)
 {
 	NDIS_802_11_WEP *wep;
 	size_t len;
@@ -967,7 +968,8 @@  static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
 				   enum wpa_alg alg, const u8 *addr,
 				   int key_idx, int set_tx,
 				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
+				   const u8 *key, size_t key_len,
+				   enum key_type key_type)
 {
 	struct wpa_driver_ndis_data *drv = priv;
 	size_t len, i;
@@ -993,7 +995,7 @@  static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
 
 	if (alg == WPA_ALG_WEP) {
 		return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
-					       key, key_len);
+					       key, key_len, key_type);
 	}
 
 	len = 12 + 6 + 6 + 8 + key_len;
@@ -1075,7 +1077,7 @@  wpa_driver_ndis_associate(void *priv,
 						bcast, i,
 						i == params->wep_tx_keyidx,
 						NULL, 0, params->wep_key[i],
-						params->wep_key_len[i]);
+						params->wep_key_len[i], 0);
 		}
 	}
 
@@ -1112,7 +1114,7 @@  wpa_driver_ndis_associate(void *priv,
 			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
 						bcast, 0, 1,
 						NULL, 0, dummy_key,
-						sizeof(dummy_key));
+						sizeof(dummy_key), 0);
 		}
 #endif /* CONFIG_WPS */
 	} else {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4c8dcad8d..830e37a54 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3007,7 +3007,8 @@  static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
 				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
+				      const u8 *key, size_t key_len,
+				      enum key_type key_type)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex;
@@ -3485,7 +3486,7 @@  retry:
 					   NULL, i,
 					   i == params->wep_tx_keyidx, NULL, 0,
 					   params->wep_key[i],
-					   params->wep_key_len[i]);
+					   params->wep_key_len[i], 0);
 		if (params->wep_tx_keyidx != i)
 			continue;
 		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
@@ -8675,11 +8676,13 @@  static int driver_nl80211_set_key(const char *ifname, void *priv,
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_type key_type)
 {
 	struct i802_bss *bss = priv;
 	return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
-					  set_tx, seq, seq_len, key, key_len);
+					  set_tx, seq, seq_len, key, key_len,
+					  key_type);
 }
 
 
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index c06e75c0f..0d975c4c5 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -71,7 +71,8 @@  wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
 static int
 wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
+	    size_t seq_len, const u8 *key, size_t key_len,
+	    enum key_type key_type)
 {
 	struct openbsd_driver_data *drv = priv;
 	struct ieee80211_keyavail keyavail;
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 55cf61885..e3375cd90 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -209,7 +209,8 @@  static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
 				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
+				      const u8 *key, size_t key_len,
+				      enum key_type key_type)
 {
 	struct wpa_driver_privsep_data *drv = priv;
 	struct privsep_cmd_set_key cmd;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 32c297138..5008bdc99 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1712,7 +1712,8 @@  static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
 				       const u8 *addr, int key_idx,
 				       int set_tx, const u8 *seq,
 				       size_t seq_len,
-				       const u8 *key, size_t key_len)
+				       const u8 *key, size_t key_len,
+				       enum key_type key_type)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
@@ -1829,7 +1830,8 @@  static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
 int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 			    const u8 *addr, int key_idx,
 			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len)
+			    const u8 *key, size_t key_len,
+			    enum key_type key_type)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
@@ -1841,7 +1843,7 @@  int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 		   (unsigned long) seq_len, (unsigned long) key_len);
 
 	ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
-					  seq, seq_len, key, key_len);
+					  seq, seq_len, key, key_len, key_type);
 	if (ret == 0)
 		return 0;
 
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index b4b5960a7..7e2009079 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -55,7 +55,8 @@  int wpa_driver_wext_set_mode(void *priv, int mode);
 int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 			    const u8 *addr, int key_idx,
 			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len);
+			    const u8 *key, size_t key_len,
+			    enum key_type key_type);
 int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
 
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 704c95e68..28048d9fc 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -178,7 +178,7 @@  static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
 static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 {
 	if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
-			   0, 0, NULL, 0, NULL, 0) < 0) {
+			   0, 0, NULL, 0, NULL, 0, 0) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
 			   "the driver");
 		return -1;
@@ -227,8 +227,8 @@  static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 
 	wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
 		   MAC2STR(peer->addr));
-	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
-			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, rsc, sizeof(rsc),
+			   peer->tpk.tk, key_len, 0) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
 			   "driver");
 		return -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 504feaf2a..60e5dd833 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -781,7 +781,8 @@  static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
 
 
 static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
-				      const struct wpa_eapol_key *key)
+				      const struct wpa_eapol_key *key,
+				      enum key_type key_type)
 {
 	int keylen, rsclen;
 	enum wpa_alg alg;
@@ -826,7 +827,7 @@  static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 	}
 
 	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+			   sm->ptk.tk, keylen, key_type) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set PTK to the "
 			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -919,7 +920,7 @@  static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
 	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
 		if (wpa_sm_set_key(sm, gd->alg, NULL,
 				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
-				   _gtk, gd->gtk_len) < 0) {
+				   _gtk, gd->gtk_len, 0) < 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Failed to set GTK to the driver "
 				"(Group only)");
@@ -928,7 +929,7 @@  static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
 		}
 	} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
 				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
-				  _gtk, gd->gtk_len) < 0) {
+				  _gtk, gd->gtk_len, 0) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set GTK to "
 			"the driver (alg=%d keylen=%d keyidx=%d)",
@@ -1082,7 +1083,7 @@  static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
 	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
 			   broadcast_ether_addr,
 			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
-			   igtk->igtk, len) < 0) {
+			   igtk->igtk, len, 0) < 0) {
 		if (keyidx == 0x0400 || keyidx == 0x0500) {
 			/* Assume the AP has broken PMF implementation since it
 			 * seems to have swapped the KeyID bytes. The AP cannot
@@ -1534,7 +1535,7 @@  static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 	sm->renew_snonce = 1;
 
 	if (key_info & WPA_KEY_INFO_INSTALL) {
-		if (wpa_supplicant_install_ptk(sm, key))
+		if (wpa_supplicant_install_ptk(sm, key, 0))
 			goto failed;
 	}
 
@@ -4558,7 +4559,7 @@  int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
 	wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
 			sm->ptk.tk, keylen);
 	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+			   sm->ptk.tk, keylen, 0) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
 			MACSTR ")",
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f1fbb1bb5..4d3fc1e29 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -30,7 +30,7 @@  struct wpa_sm_ctx {
 	int (*set_key)(void *ctx, enum wpa_alg alg,
 		       const u8 *addr, int key_idx, int set_tx,
 		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
+		       const u8 *key, size_t key_len, enum key_type key_type);
 	void * (*get_network_ctx)(void *ctx);
 	int (*get_bssid)(void *ctx, u8 *bssid);
 	int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 2b8b41fa5..59a187425 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -423,7 +423,8 @@  static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
 
 	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
-			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
+			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen,
+			   0) < 0) {
 		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
 		return -1;
 	}
@@ -773,7 +774,7 @@  static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
 		os_memcpy(gtk + 24, tmp, 8);
 	}
 	if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
-			   gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+			   gtk_elem + 3, rsc_len, gtk, keylen, 0) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
 			   "driver.");
 		return -1;
@@ -840,7 +841,7 @@  static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
 			igtk_len);
 	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
 			   broadcast_ether_addr, keyidx, 0,
-			   igtk_elem + 2, 6, igtk, igtk_len) < 0) {
+			   igtk_elem + 2, 6, igtk, igtk_len, 0) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
 			   "driver.");
 		forced_memzero(igtk, sizeof(igtk));
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 2a433425c..2d56cb36e 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -198,11 +198,12 @@  static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code)
 static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
 				 const u8 *addr, int key_idx, int set_tx,
 				 const u8 *seq, size_t seq_len,
-				 const u8 *key, size_t key_len)
+				 const u8 *key, size_t key_len,
+				 enum key_type key_type)
 {
 	WPA_ASSERT(sm->ctx->set_key);
 	return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
-				seq, seq_len, key, key_len);
+				seq, seq_len, key, key_len, key_type);
 }
 
 static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
diff --git a/tests/hwsim/test_ap_ciphers.py b/tests/hwsim/test_ap_ciphers.py
index e10927a9c..cd45c6fd9 100644
--- a/tests/hwsim/test_ap_ciphers.py
+++ b/tests/hwsim/test_ap_ciphers.py
@@ -862,7 +862,7 @@  def test_ap_wpa2_delayed_m1_m3_zero_tk(dev, apdev):
     if "OK" not in hapd.request("RESEND_M3 " + addr):
         raise Exception("RESEND_M3 failed")
 
-    if "OK" not in hapd.request("SET_KEY 3 %s %d %d %s %s" % (addr, 0, 1, 6*"00", 16*"00")):
+    if "OK" not in hapd.request("SET_KEY 3 %s %d %d %s %s 0" % (addr, 0, 1, 6*"00", 16*"00")):
         raise Exception("SET_KEY failed")
     time.sleep(0.1)
     hwsim_utils.test_connectivity(dev[0], hapd, timeout=1, broadcast=False,
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 7f8ec4a6a..552901185 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5249,15 +5249,15 @@  static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
 {
 	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
 	/* MLME-DELETEKEYS.request */
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0, 0);
 
 	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
-			0);
+			0, 0);
 	/* MLME-SETPROTECTION.request(None) */
 	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
 				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -9237,13 +9237,13 @@  static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
 	 * in the driver. */
 	if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
 			    wpa_s->last_tk_key_idx, 1, zero, 6,
-			    zero, wpa_s->last_tk_len) < 0)
+			    zero, wpa_s->last_tk_len, 0) < 0)
 		return -1;
 
 	/* Set the previously configured key to reset its TSC/RSC */
 	return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
 			       wpa_s->last_tk_key_idx, 1, zero, 6,
-			       wpa_s->last_tk, wpa_s->last_tk_len);
+			       wpa_s->last_tk, wpa_s->last_tk_len, 0);
 }
 
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index cf9972a6b..efb17c471 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -152,7 +152,8 @@  static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_type key_type)
 {
 	if (alg != WPA_ALG_NONE) {
 		if (key_idx >= 0 && key_idx <= 6)
@@ -163,7 +164,8 @@  static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
 	if (wpa_s->driver->set_key) {
 		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
 					      alg, addr, key_idx, set_tx,
-					      seq, seq_len, key, key_len);
+					      seq, seq_len, key, key_len,
+					      key_type);
 	}
 	return -1;
 }
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 36c0aff17..86837d62b 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -140,7 +140,7 @@  static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
 static int supp_set_key(void *ctx, enum wpa_alg alg,
 			const u8 *addr, int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
+			const u8 *key, size_t key_len, enum key_type key_type)
 {
 	struct ibss_rsn_peer *peer = ctx;
 
@@ -167,7 +167,7 @@  static int supp_set_key(void *ctx, enum wpa_alg alg,
 	if (is_broadcast_ether_addr(addr))
 		addr = peer->addr;
 	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
-			       set_tx, seq, seq_len, key, key_len);
+			       set_tx, seq, seq_len, key, key_len, key_type);
 }
 
 
@@ -296,7 +296,8 @@  static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			enum key_type key_type)
 {
 	struct ibss_rsn *ibss_rsn = ctx;
 	u8 seq[6];
@@ -335,7 +336,7 @@  static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	}
 
 	return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
+			       1, seq, 6, key, key_len, key_type);
 }
 
 
@@ -852,7 +853,7 @@  static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
 		wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
 			   MACSTR, MAC2STR(addr));
 		wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
-				NULL, 0, NULL, 0);
+				NULL, 0, NULL, 0, 0);
 	}
 
 	if (peer &&
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 4a163b6eb..041c158e4 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -876,7 +876,7 @@  static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
 		wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
 		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
 				sta->addr, 0, 0, seq, sizeof(seq),
-				sta->mtk, sta->mtk_len);
+				sta->mtk, sta->mtk_len, 0);
 
 		wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
 				sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
@@ -885,7 +885,7 @@  static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
 		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
 				sta->addr, sta->mgtk_key_id, 0,
 				sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
-				sta->mgtk, sta->mgtk_len);
+				sta->mgtk, sta->mgtk_len, 0);
 
 		if (sta->igtk_len) {
 			wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
@@ -897,7 +897,7 @@  static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
 				wpa_cipher_to_alg(conf->mgmt_group_cipher),
 				sta->addr, sta->igtk_key_id, 0,
 				sta->igtk_rsc, sizeof(sta->igtk_rsc),
-				sta->igtk, sta->igtk_len);
+				sta->igtk, sta->igtk_len, 0);
 		}
 	}
 
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e730b6336..4df4dcc73 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -100,7 +100,8 @@  static const u8 *auth_get_psk(void *ctx, const u8 *addr,
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			enum key_type key_type)
 {
 	struct mesh_rsn *mesh_rsn = ctx;
 	u8 seq[6];
@@ -118,7 +119,7 @@  static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
 
 	return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
+			       1, seq, 6, key, key_len, key_type);
 }
 
 
@@ -196,7 +197,7 @@  static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
 		wpa_drv_set_key(rsn->wpa_s,
 				wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
 				rsn->igtk_key_id, 1,
-				seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+				seq, sizeof(seq), rsn->igtk, rsn->igtk_len, 0);
 	}
 
 	/* group privacy / data frames */
@@ -204,7 +205,7 @@  static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
 			rsn->mgtk, rsn->mgtk_len);
 	wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
 			rsn->mgtk_key_id, 1, seq, sizeof(seq),
-			rsn->mgtk, rsn->mgtk_len);
+			rsn->mgtk, rsn->mgtk_len, 0);
 
 	return 0;
 }
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6688d71af..919f99244 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -142,7 +142,7 @@  int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 		set = 1;
 		wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
 				i, i == ssid->wep_tx_keyidx, NULL, 0,
-				ssid->wep_key[i], ssid->wep_key_len[i]);
+				ssid->wep_key[i], ssid->wep_key_len[i], 0);
 	}
 
 	return set;
@@ -200,7 +200,7 @@  int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
 	/* TODO: should actually remember the previously used seq#, both for TX
 	 * and RX from each STA.. */
 
-	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen, 0);
 	os_memset(key, 0, sizeof(key));
 	return ret;
 }
@@ -701,12 +701,12 @@  void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 		if (wpa_s->keys_cleared & BIT(i))
 			continue;
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-				NULL, 0);
+				NULL, 0, 0);
 	}
 	if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
 	    !is_zero_ether_addr(addr)) {
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
-				0);
+				0, 0);
 		/* MLME-SETPROTECTION.request(None) */
 		wpa_drv_mlme_setprotection(
 			wpa_s, addr,
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index d80b8f28d..39b6001c0 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -242,7 +242,7 @@  static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
 	}
 	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
 			       unicast ? wpa_s->bssid : NULL,
-			       keyidx, unicast, NULL, 0, key, keylen);
+			       keyidx, unicast, NULL, 0, key, keylen, 0);
 }
 
 
@@ -341,7 +341,7 @@  static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
 			"handshake", pmk, pmk_len);
 
 	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
-			    pmk_len)) {
+			    pmk_len, 0)) {
 		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
 	}
 
@@ -492,7 +492,8 @@  static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
 static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
 				  const u8 *addr, int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_type key_type)
 {
 	struct wpa_supplicant *wpa_s = _wpa_s;
 	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
@@ -517,7 +518,7 @@  static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
-			       key, key_len);
+			       key, key_len, key_type);
 }
 
 
@@ -1161,7 +1162,7 @@  static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
 	if (wpa_s->conf->key_mgmt_offload &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
 		return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
-				       NULL, 0, pmk, pmk_len);
+				       NULL, 0, pmk, pmk_len, 0);
 	else
 		return 0;
 }