1 // SPDX-License-Identifier: GPL-2.0-only
3 * Key management related functions.
5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 #include <linux/etherdevice.h>
9 #include <net/mac80211.h>
13 #include "hif_tx_mib.h"
15 static int wfx_alloc_key(struct wfx_dev
*wdev
)
19 idx
= ffs(~wdev
->key_map
) - 1;
20 if (idx
< 0 || idx
>= MAX_KEY_ENTRIES
)
23 wdev
->key_map
|= BIT(idx
);
27 static void wfx_free_key(struct wfx_dev
*wdev
, int idx
)
29 WARN(!(wdev
->key_map
& BIT(idx
)), "inconsistent key allocation");
30 wdev
->key_map
&= ~BIT(idx
);
33 static u8
fill_wep_pair(struct wfx_hif_wep_pairwise_key
*msg
,
34 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
36 WARN(key
->keylen
> sizeof(msg
->key_data
), "inconsistent data");
37 msg
->key_length
= key
->keylen
;
38 memcpy(msg
->key_data
, key
->key
, key
->keylen
);
39 ether_addr_copy(msg
->peer_address
, peer_addr
);
40 return HIF_KEY_TYPE_WEP_PAIRWISE
;
43 static u8
fill_wep_group(struct wfx_hif_wep_group_key
*msg
,
44 struct ieee80211_key_conf
*key
)
46 WARN(key
->keylen
> sizeof(msg
->key_data
), "inconsistent data");
47 msg
->key_id
= key
->keyidx
;
48 msg
->key_length
= key
->keylen
;
49 memcpy(msg
->key_data
, key
->key
, key
->keylen
);
50 return HIF_KEY_TYPE_WEP_DEFAULT
;
53 static u8
fill_tkip_pair(struct wfx_hif_tkip_pairwise_key
*msg
,
54 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
56 u8
*keybuf
= key
->key
;
58 WARN(key
->keylen
!= sizeof(msg
->tkip_key_data
) + sizeof(msg
->tx_mic_key
) +
59 sizeof(msg
->rx_mic_key
), "inconsistent data");
60 memcpy(msg
->tkip_key_data
, keybuf
, sizeof(msg
->tkip_key_data
));
61 keybuf
+= sizeof(msg
->tkip_key_data
);
62 memcpy(msg
->tx_mic_key
, keybuf
, sizeof(msg
->tx_mic_key
));
63 keybuf
+= sizeof(msg
->tx_mic_key
);
64 memcpy(msg
->rx_mic_key
, keybuf
, sizeof(msg
->rx_mic_key
));
65 ether_addr_copy(msg
->peer_address
, peer_addr
);
66 return HIF_KEY_TYPE_TKIP_PAIRWISE
;
69 static u8
fill_tkip_group(struct wfx_hif_tkip_group_key
*msg
, struct ieee80211_key_conf
*key
,
70 struct ieee80211_key_seq
*seq
, enum nl80211_iftype iftype
)
72 u8
*keybuf
= key
->key
;
74 WARN(key
->keylen
!= sizeof(msg
->tkip_key_data
) + 2 * sizeof(msg
->rx_mic_key
),
76 msg
->key_id
= key
->keyidx
;
77 memcpy(msg
->rx_sequence_counter
, &seq
->tkip
.iv16
, sizeof(seq
->tkip
.iv16
));
78 memcpy(msg
->rx_sequence_counter
+ sizeof(u16
), &seq
->tkip
.iv32
, sizeof(seq
->tkip
.iv32
));
79 memcpy(msg
->tkip_key_data
, keybuf
, sizeof(msg
->tkip_key_data
));
80 keybuf
+= sizeof(msg
->tkip_key_data
);
81 if (iftype
== NL80211_IFTYPE_AP
)
83 memcpy(msg
->rx_mic_key
, keybuf
+ 0, sizeof(msg
->rx_mic_key
));
86 memcpy(msg
->rx_mic_key
, keybuf
+ 8, sizeof(msg
->rx_mic_key
));
87 return HIF_KEY_TYPE_TKIP_GROUP
;
90 static u8
fill_ccmp_pair(struct wfx_hif_aes_pairwise_key
*msg
,
91 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
93 WARN(key
->keylen
!= sizeof(msg
->aes_key_data
), "inconsistent data");
94 ether_addr_copy(msg
->peer_address
, peer_addr
);
95 memcpy(msg
->aes_key_data
, key
->key
, key
->keylen
);
96 return HIF_KEY_TYPE_AES_PAIRWISE
;
99 static u8
fill_ccmp_group(struct wfx_hif_aes_group_key
*msg
,
100 struct ieee80211_key_conf
*key
, struct ieee80211_key_seq
*seq
)
102 WARN(key
->keylen
!= sizeof(msg
->aes_key_data
), "inconsistent data");
103 memcpy(msg
->aes_key_data
, key
->key
, key
->keylen
);
104 memcpy(msg
->rx_sequence_counter
, seq
->ccmp
.pn
, sizeof(seq
->ccmp
.pn
));
105 memreverse(msg
->rx_sequence_counter
, sizeof(seq
->ccmp
.pn
));
106 msg
->key_id
= key
->keyidx
;
107 return HIF_KEY_TYPE_AES_GROUP
;
110 static u8
fill_sms4_pair(struct wfx_hif_wapi_pairwise_key
*msg
,
111 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
113 u8
*keybuf
= key
->key
;
115 WARN(key
->keylen
!= sizeof(msg
->wapi_key_data
) + sizeof(msg
->mic_key_data
),
116 "inconsistent data");
117 ether_addr_copy(msg
->peer_address
, peer_addr
);
118 memcpy(msg
->wapi_key_data
, keybuf
, sizeof(msg
->wapi_key_data
));
119 keybuf
+= sizeof(msg
->wapi_key_data
);
120 memcpy(msg
->mic_key_data
, keybuf
, sizeof(msg
->mic_key_data
));
121 msg
->key_id
= key
->keyidx
;
122 return HIF_KEY_TYPE_WAPI_PAIRWISE
;
125 static u8
fill_sms4_group(struct wfx_hif_wapi_group_key
*msg
,
126 struct ieee80211_key_conf
*key
)
128 u8
*keybuf
= key
->key
;
130 WARN(key
->keylen
!= sizeof(msg
->wapi_key_data
) + sizeof(msg
->mic_key_data
),
131 "inconsistent data");
132 memcpy(msg
->wapi_key_data
, keybuf
, sizeof(msg
->wapi_key_data
));
133 keybuf
+= sizeof(msg
->wapi_key_data
);
134 memcpy(msg
->mic_key_data
, keybuf
, sizeof(msg
->mic_key_data
));
135 msg
->key_id
= key
->keyidx
;
136 return HIF_KEY_TYPE_WAPI_GROUP
;
139 static u8
fill_aes_cmac_group(struct wfx_hif_igtk_group_key
*msg
,
140 struct ieee80211_key_conf
*key
, struct ieee80211_key_seq
*seq
)
142 WARN(key
->keylen
!= sizeof(msg
->igtk_key_data
), "inconsistent data");
143 memcpy(msg
->igtk_key_data
, key
->key
, key
->keylen
);
144 memcpy(msg
->ipn
, seq
->aes_cmac
.pn
, sizeof(seq
->aes_cmac
.pn
));
145 memreverse(msg
->ipn
, sizeof(seq
->aes_cmac
.pn
));
146 msg
->key_id
= key
->keyidx
;
147 return HIF_KEY_TYPE_IGTK_GROUP
;
150 static int wfx_add_key(struct wfx_vif
*wvif
, struct ieee80211_sta
*sta
,
151 struct ieee80211_key_conf
*key
)
154 struct wfx_hif_req_add_key k
= { };
155 struct ieee80211_key_seq seq
;
156 struct wfx_dev
*wdev
= wvif
->wdev
;
157 int idx
= wfx_alloc_key(wvif
->wdev
);
158 bool pairwise
= key
->flags
& IEEE80211_KEY_FLAG_PAIRWISE
;
159 struct ieee80211_vif
*vif
= wvif_to_vif(wvif
);
161 WARN(key
->flags
& IEEE80211_KEY_FLAG_PAIRWISE
&& !sta
, "inconsistent data");
162 ieee80211_get_key_rx_seq(key
, 0, &seq
);
167 if (key
->cipher
== WLAN_CIPHER_SUITE_WEP40
||
168 key
->cipher
== WLAN_CIPHER_SUITE_WEP104
) {
170 k
.type
= fill_wep_pair(&k
.key
.wep_pairwise_key
, key
, sta
->addr
);
172 k
.type
= fill_wep_group(&k
.key
.wep_group_key
, key
);
173 } else if (key
->cipher
== WLAN_CIPHER_SUITE_TKIP
) {
175 k
.type
= fill_tkip_pair(&k
.key
.tkip_pairwise_key
, key
, sta
->addr
);
177 k
.type
= fill_tkip_group(&k
.key
.tkip_group_key
, key
, &seq
,
179 } else if (key
->cipher
== WLAN_CIPHER_SUITE_CCMP
) {
181 k
.type
= fill_ccmp_pair(&k
.key
.aes_pairwise_key
, key
, sta
->addr
);
183 k
.type
= fill_ccmp_group(&k
.key
.aes_group_key
, key
, &seq
);
184 } else if (key
->cipher
== WLAN_CIPHER_SUITE_SMS4
) {
186 k
.type
= fill_sms4_pair(&k
.key
.wapi_pairwise_key
, key
, sta
->addr
);
188 k
.type
= fill_sms4_group(&k
.key
.wapi_group_key
, key
);
189 } else if (key
->cipher
== WLAN_CIPHER_SUITE_AES_CMAC
) {
190 k
.type
= fill_aes_cmac_group(&k
.key
.igtk_group_key
, key
, &seq
);
191 key
->flags
|= IEEE80211_KEY_FLAG_GENERATE_MMIE
;
193 dev_warn(wdev
->dev
, "unsupported key type %d\n", key
->cipher
);
194 wfx_free_key(wdev
, idx
);
197 ret
= wfx_hif_add_key(wdev
, &k
);
199 wfx_free_key(wdev
, idx
);
202 key
->flags
|= IEEE80211_KEY_FLAG_PUT_IV_SPACE
| IEEE80211_KEY_FLAG_RESERVE_TAILROOM
;
203 key
->hw_key_idx
= idx
;
207 static int wfx_remove_key(struct wfx_vif
*wvif
, struct ieee80211_key_conf
*key
)
209 WARN(key
->hw_key_idx
>= MAX_KEY_ENTRIES
, "corrupted hw_key_idx");
210 wfx_free_key(wvif
->wdev
, key
->hw_key_idx
);
211 return wfx_hif_remove_key(wvif
->wdev
, key
->hw_key_idx
);
214 int wfx_set_key(struct ieee80211_hw
*hw
, enum set_key_cmd cmd
, struct ieee80211_vif
*vif
,
215 struct ieee80211_sta
*sta
, struct ieee80211_key_conf
*key
)
217 int ret
= -EOPNOTSUPP
;
218 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
220 mutex_lock(&wvif
->wdev
->conf_mutex
);
222 ret
= wfx_add_key(wvif
, sta
, key
);
223 if (cmd
== DISABLE_KEY
)
224 ret
= wfx_remove_key(wvif
, key
);
225 mutex_unlock(&wvif
->wdev
->conf_mutex
);