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 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 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 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
)
59 + sizeof(msg
->tx_mic_key
)
60 + sizeof(msg
->rx_mic_key
), "inconsistent data");
61 memcpy(msg
->tkip_key_data
, keybuf
, sizeof(msg
->tkip_key_data
));
62 keybuf
+= sizeof(msg
->tkip_key_data
);
63 memcpy(msg
->tx_mic_key
, keybuf
, sizeof(msg
->tx_mic_key
));
64 keybuf
+= sizeof(msg
->tx_mic_key
);
65 memcpy(msg
->rx_mic_key
, keybuf
, sizeof(msg
->rx_mic_key
));
66 ether_addr_copy(msg
->peer_address
, peer_addr
);
67 return HIF_KEY_TYPE_TKIP_PAIRWISE
;
70 static u8
fill_tkip_group(struct hif_tkip_group_key
*msg
,
71 struct ieee80211_key_conf
*key
,
72 struct ieee80211_key_seq
*seq
,
73 enum nl80211_iftype iftype
)
75 u8
*keybuf
= key
->key
;
77 WARN(key
->keylen
!= sizeof(msg
->tkip_key_data
)
78 + 2 * sizeof(msg
->rx_mic_key
), "inconsistent data");
79 msg
->key_id
= key
->keyidx
;
80 memcpy(msg
->rx_sequence_counter
,
81 &seq
->tkip
.iv16
, sizeof(seq
->tkip
.iv16
));
82 memcpy(msg
->rx_sequence_counter
+ sizeof(u16
),
83 &seq
->tkip
.iv32
, sizeof(seq
->tkip
.iv32
));
84 memcpy(msg
->tkip_key_data
, keybuf
, sizeof(msg
->tkip_key_data
));
85 keybuf
+= sizeof(msg
->tkip_key_data
);
86 if (iftype
== NL80211_IFTYPE_AP
)
88 memcpy(msg
->rx_mic_key
, keybuf
+ 0, sizeof(msg
->rx_mic_key
));
91 memcpy(msg
->rx_mic_key
, keybuf
+ 8, sizeof(msg
->rx_mic_key
));
92 return HIF_KEY_TYPE_TKIP_GROUP
;
95 static u8
fill_ccmp_pair(struct hif_aes_pairwise_key
*msg
,
96 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
98 WARN(key
->keylen
!= sizeof(msg
->aes_key_data
), "inconsistent data");
99 ether_addr_copy(msg
->peer_address
, peer_addr
);
100 memcpy(msg
->aes_key_data
, key
->key
, key
->keylen
);
101 return HIF_KEY_TYPE_AES_PAIRWISE
;
104 static u8
fill_ccmp_group(struct hif_aes_group_key
*msg
,
105 struct ieee80211_key_conf
*key
,
106 struct ieee80211_key_seq
*seq
)
108 WARN(key
->keylen
!= sizeof(msg
->aes_key_data
), "inconsistent data");
109 memcpy(msg
->aes_key_data
, key
->key
, key
->keylen
);
110 memcpy(msg
->rx_sequence_counter
, seq
->ccmp
.pn
, sizeof(seq
->ccmp
.pn
));
111 memreverse(msg
->rx_sequence_counter
, sizeof(seq
->ccmp
.pn
));
112 msg
->key_id
= key
->keyidx
;
113 return HIF_KEY_TYPE_AES_GROUP
;
116 static u8
fill_sms4_pair(struct hif_wapi_pairwise_key
*msg
,
117 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
119 u8
*keybuf
= key
->key
;
121 WARN(key
->keylen
!= sizeof(msg
->wapi_key_data
)
122 + sizeof(msg
->mic_key_data
), "inconsistent data");
123 ether_addr_copy(msg
->peer_address
, peer_addr
);
124 memcpy(msg
->wapi_key_data
, keybuf
, sizeof(msg
->wapi_key_data
));
125 keybuf
+= sizeof(msg
->wapi_key_data
);
126 memcpy(msg
->mic_key_data
, keybuf
, sizeof(msg
->mic_key_data
));
127 msg
->key_id
= key
->keyidx
;
128 return HIF_KEY_TYPE_WAPI_PAIRWISE
;
131 static u8
fill_sms4_group(struct hif_wapi_group_key
*msg
,
132 struct ieee80211_key_conf
*key
)
134 u8
*keybuf
= key
->key
;
136 WARN(key
->keylen
!= sizeof(msg
->wapi_key_data
)
137 + sizeof(msg
->mic_key_data
), "inconsistent data");
138 memcpy(msg
->wapi_key_data
, keybuf
, sizeof(msg
->wapi_key_data
));
139 keybuf
+= sizeof(msg
->wapi_key_data
);
140 memcpy(msg
->mic_key_data
, keybuf
, sizeof(msg
->mic_key_data
));
141 msg
->key_id
= key
->keyidx
;
142 return HIF_KEY_TYPE_WAPI_GROUP
;
145 static u8
fill_aes_cmac_group(struct hif_igtk_group_key
*msg
,
146 struct ieee80211_key_conf
*key
,
147 struct ieee80211_key_seq
*seq
)
149 WARN(key
->keylen
!= sizeof(msg
->igtk_key_data
), "inconsistent data");
150 memcpy(msg
->igtk_key_data
, key
->key
, key
->keylen
);
151 memcpy(msg
->ipn
, seq
->aes_cmac
.pn
, sizeof(seq
->aes_cmac
.pn
));
152 memreverse(msg
->ipn
, sizeof(seq
->aes_cmac
.pn
));
153 msg
->key_id
= key
->keyidx
;
154 return HIF_KEY_TYPE_IGTK_GROUP
;
157 static int wfx_add_key(struct wfx_vif
*wvif
, struct ieee80211_sta
*sta
,
158 struct ieee80211_key_conf
*key
)
161 struct hif_req_add_key k
= { };
162 struct ieee80211_key_seq seq
;
163 struct wfx_dev
*wdev
= wvif
->wdev
;
164 int idx
= wfx_alloc_key(wvif
->wdev
);
165 bool pairwise
= key
->flags
& IEEE80211_KEY_FLAG_PAIRWISE
;
167 WARN(key
->flags
& IEEE80211_KEY_FLAG_PAIRWISE
&& !sta
, "inconsistent data");
168 ieee80211_get_key_rx_seq(key
, 0, &seq
);
173 if (key
->cipher
== WLAN_CIPHER_SUITE_WEP40
||
174 key
->cipher
== WLAN_CIPHER_SUITE_WEP104
) {
176 k
.type
= fill_wep_pair(&k
.key
.wep_pairwise_key
, key
,
179 k
.type
= fill_wep_group(&k
.key
.wep_group_key
, key
);
180 } else if (key
->cipher
== WLAN_CIPHER_SUITE_TKIP
) {
182 k
.type
= fill_tkip_pair(&k
.key
.tkip_pairwise_key
, key
,
185 k
.type
= fill_tkip_group(&k
.key
.tkip_group_key
, key
,
186 &seq
, wvif
->vif
->type
);
187 } else if (key
->cipher
== WLAN_CIPHER_SUITE_CCMP
) {
189 k
.type
= fill_ccmp_pair(&k
.key
.aes_pairwise_key
, key
,
192 k
.type
= fill_ccmp_group(&k
.key
.aes_group_key
, key
,
194 } else if (key
->cipher
== WLAN_CIPHER_SUITE_SMS4
) {
196 k
.type
= fill_sms4_pair(&k
.key
.wapi_pairwise_key
, key
,
199 k
.type
= fill_sms4_group(&k
.key
.wapi_group_key
, key
);
200 } else if (key
->cipher
== WLAN_CIPHER_SUITE_AES_CMAC
) {
201 k
.type
= fill_aes_cmac_group(&k
.key
.igtk_group_key
, key
, &seq
);
202 key
->flags
|= IEEE80211_KEY_FLAG_GENERATE_MMIE
;
204 dev_warn(wdev
->dev
, "unsupported key type %d\n", key
->cipher
);
205 wfx_free_key(wdev
, idx
);
208 ret
= hif_add_key(wdev
, &k
);
210 wfx_free_key(wdev
, idx
);
213 key
->flags
|= IEEE80211_KEY_FLAG_PUT_IV_SPACE
|
214 IEEE80211_KEY_FLAG_RESERVE_TAILROOM
;
215 key
->hw_key_idx
= idx
;
219 static int wfx_remove_key(struct wfx_vif
*wvif
, struct ieee80211_key_conf
*key
)
221 WARN(key
->hw_key_idx
>= MAX_KEY_ENTRIES
, "corrupted hw_key_idx");
222 wfx_free_key(wvif
->wdev
, key
->hw_key_idx
);
223 return hif_remove_key(wvif
->wdev
, key
->hw_key_idx
);
226 int wfx_set_key(struct ieee80211_hw
*hw
, enum set_key_cmd cmd
,
227 struct ieee80211_vif
*vif
, struct ieee80211_sta
*sta
,
228 struct ieee80211_key_conf
*key
)
230 int ret
= -EOPNOTSUPP
;
231 struct wfx_vif
*wvif
= (struct wfx_vif
*)vif
->drv_priv
;
233 mutex_lock(&wvif
->wdev
->conf_mutex
);
235 ret
= wfx_add_key(wvif
, sta
, key
);
236 if (cmd
== DISABLE_KEY
)
237 ret
= wfx_remove_key(wvif
, key
);
238 mutex_unlock(&wvif
->wdev
->conf_mutex
);