1 // SPDX-License-Identifier: GPL-2.0-only
3 * Key management related functions.
5 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 #include <net/mac80211.h>
12 #include "hif_tx_mib.h"
14 static int wfx_alloc_key(struct wfx_dev
*wdev
)
18 idx
= ffs(~wdev
->key_map
) - 1;
19 if (idx
< 0 || idx
>= MAX_KEY_ENTRIES
)
22 wdev
->key_map
|= BIT(idx
);
23 wdev
->keys
[idx
].entry_index
= idx
;
27 static void wfx_free_key(struct wfx_dev
*wdev
, int idx
)
29 WARN(!(wdev
->key_map
& BIT(idx
)), "inconsistent key allocation");
30 memset(&wdev
->keys
[idx
], 0, sizeof(wdev
->keys
[idx
]));
31 wdev
->key_map
&= ~BIT(idx
);
34 static u8
fill_wep_pair(struct hif_wep_pairwise_key
*msg
,
35 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
37 WARN(key
->keylen
> sizeof(msg
->key_data
), "inconsistent data");
38 msg
->key_length
= key
->keylen
;
39 memcpy(msg
->key_data
, key
->key
, key
->keylen
);
40 ether_addr_copy(msg
->peer_address
, peer_addr
);
41 return HIF_KEY_TYPE_WEP_PAIRWISE
;
44 static u8
fill_wep_group(struct hif_wep_group_key
*msg
,
45 struct ieee80211_key_conf
*key
)
47 WARN(key
->keylen
> sizeof(msg
->key_data
), "inconsistent data");
48 msg
->key_id
= key
->keyidx
;
49 msg
->key_length
= key
->keylen
;
50 memcpy(msg
->key_data
, key
->key
, key
->keylen
);
51 return HIF_KEY_TYPE_WEP_DEFAULT
;
54 static u8
fill_tkip_pair(struct hif_tkip_pairwise_key
*msg
,
55 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
57 u8
*keybuf
= key
->key
;
59 WARN(key
->keylen
!= sizeof(msg
->tkip_key_data
)
60 + sizeof(msg
->tx_mic_key
)
61 + sizeof(msg
->rx_mic_key
), "inconsistent data");
62 memcpy(msg
->tkip_key_data
, keybuf
, sizeof(msg
->tkip_key_data
));
63 keybuf
+= sizeof(msg
->tkip_key_data
);
64 memcpy(msg
->tx_mic_key
, keybuf
, sizeof(msg
->tx_mic_key
));
65 keybuf
+= sizeof(msg
->tx_mic_key
);
66 memcpy(msg
->rx_mic_key
, keybuf
, sizeof(msg
->rx_mic_key
));
67 ether_addr_copy(msg
->peer_address
, peer_addr
);
68 return HIF_KEY_TYPE_TKIP_PAIRWISE
;
71 static u8
fill_tkip_group(struct hif_tkip_group_key
*msg
,
72 struct ieee80211_key_conf
*key
,
73 struct ieee80211_key_seq
*seq
,
74 enum nl80211_iftype iftype
)
76 u8
*keybuf
= key
->key
;
78 WARN(key
->keylen
!= sizeof(msg
->tkip_key_data
)
79 + 2 * sizeof(msg
->rx_mic_key
), "inconsistent data");
80 msg
->key_id
= key
->keyidx
;
81 memcpy(msg
->rx_sequence_counter
,
82 &seq
->tkip
.iv16
, sizeof(seq
->tkip
.iv16
));
83 memcpy(msg
->rx_sequence_counter
+ sizeof(u16
),
84 &seq
->tkip
.iv32
, sizeof(seq
->tkip
.iv32
));
85 memcpy(msg
->tkip_key_data
, keybuf
, sizeof(msg
->tkip_key_data
));
86 keybuf
+= sizeof(msg
->tkip_key_data
);
87 if (iftype
== NL80211_IFTYPE_AP
)
89 memcpy(msg
->rx_mic_key
, keybuf
+ 0, sizeof(msg
->rx_mic_key
));
92 memcpy(msg
->rx_mic_key
, keybuf
+ 8, sizeof(msg
->rx_mic_key
));
93 return HIF_KEY_TYPE_TKIP_GROUP
;
96 static u8
fill_ccmp_pair(struct hif_aes_pairwise_key
*msg
,
97 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
99 WARN(key
->keylen
!= sizeof(msg
->aes_key_data
), "inconsistent data");
100 ether_addr_copy(msg
->peer_address
, peer_addr
);
101 memcpy(msg
->aes_key_data
, key
->key
, key
->keylen
);
102 return HIF_KEY_TYPE_AES_PAIRWISE
;
105 static u8
fill_ccmp_group(struct hif_aes_group_key
*msg
,
106 struct ieee80211_key_conf
*key
,
107 struct ieee80211_key_seq
*seq
)
109 WARN(key
->keylen
!= sizeof(msg
->aes_key_data
), "inconsistent data");
110 memcpy(msg
->aes_key_data
, key
->key
, key
->keylen
);
111 memcpy(msg
->rx_sequence_counter
, seq
->ccmp
.pn
, sizeof(seq
->ccmp
.pn
));
112 memreverse(msg
->rx_sequence_counter
, sizeof(seq
->ccmp
.pn
));
113 msg
->key_id
= key
->keyidx
;
114 return HIF_KEY_TYPE_AES_GROUP
;
117 static u8
fill_sms4_pair(struct hif_wapi_pairwise_key
*msg
,
118 struct ieee80211_key_conf
*key
, u8
*peer_addr
)
120 u8
*keybuf
= key
->key
;
122 WARN(key
->keylen
!= sizeof(msg
->wapi_key_data
)
123 + sizeof(msg
->mic_key_data
), "inconsistent data");
124 ether_addr_copy(msg
->peer_address
, peer_addr
);
125 memcpy(msg
->wapi_key_data
, keybuf
, sizeof(msg
->wapi_key_data
));
126 keybuf
+= sizeof(msg
->wapi_key_data
);
127 memcpy(msg
->mic_key_data
, keybuf
, sizeof(msg
->mic_key_data
));
128 msg
->key_id
= key
->keyidx
;
129 return HIF_KEY_TYPE_WAPI_PAIRWISE
;
132 static u8
fill_sms4_group(struct hif_wapi_group_key
*msg
,
133 struct ieee80211_key_conf
*key
)
135 u8
*keybuf
= key
->key
;
137 WARN(key
->keylen
!= sizeof(msg
->wapi_key_data
)
138 + sizeof(msg
->mic_key_data
), "inconsistent data");
139 memcpy(msg
->wapi_key_data
, keybuf
, sizeof(msg
->wapi_key_data
));
140 keybuf
+= sizeof(msg
->wapi_key_data
);
141 memcpy(msg
->mic_key_data
, keybuf
, sizeof(msg
->mic_key_data
));
142 msg
->key_id
= key
->keyidx
;
143 return HIF_KEY_TYPE_WAPI_GROUP
;
146 static u8
fill_aes_cmac_group(struct hif_igtk_group_key
*msg
,
147 struct ieee80211_key_conf
*key
,
148 struct ieee80211_key_seq
*seq
)
150 WARN(key
->keylen
!= sizeof(msg
->igtk_key_data
), "inconsistent data");
151 memcpy(msg
->igtk_key_data
, key
->key
, key
->keylen
);
152 memcpy(msg
->ipn
, seq
->aes_cmac
.pn
, sizeof(seq
->aes_cmac
.pn
));
153 memreverse(msg
->ipn
, sizeof(seq
->aes_cmac
.pn
));
154 msg
->key_id
= key
->keyidx
;
155 return HIF_KEY_TYPE_IGTK_GROUP
;
158 static int wfx_add_key(struct wfx_vif
*wvif
, struct ieee80211_sta
*sta
,
159 struct ieee80211_key_conf
*key
)
162 struct hif_req_add_key
*k
;
163 struct ieee80211_key_seq seq
;
164 struct wfx_dev
*wdev
= wvif
->wdev
;
165 int idx
= wfx_alloc_key(wvif
->wdev
);
166 bool pairwise
= key
->flags
& IEEE80211_KEY_FLAG_PAIRWISE
;
168 WARN(key
->flags
& IEEE80211_KEY_FLAG_PAIRWISE
&& !sta
, "inconsistent data");
169 ieee80211_get_key_rx_seq(key
, 0, &seq
);
172 k
= &wdev
->keys
[idx
];
173 k
->int_id
= wvif
->id
;
174 if (key
->cipher
== WLAN_CIPHER_SUITE_WEP40
||
175 key
->cipher
== WLAN_CIPHER_SUITE_WEP104
) {
177 k
->type
= fill_wep_pair(&k
->key
.wep_pairwise_key
, key
,
180 k
->type
= fill_wep_group(&k
->key
.wep_group_key
, key
);
181 } else if (key
->cipher
== WLAN_CIPHER_SUITE_TKIP
) {
183 k
->type
= fill_tkip_pair(&k
->key
.tkip_pairwise_key
, key
,
186 k
->type
= fill_tkip_group(&k
->key
.tkip_group_key
, key
,
187 &seq
, wvif
->vif
->type
);
188 } else if (key
->cipher
== WLAN_CIPHER_SUITE_CCMP
) {
190 k
->type
= fill_ccmp_pair(&k
->key
.aes_pairwise_key
, key
,
193 k
->type
= fill_ccmp_group(&k
->key
.aes_group_key
, key
,
195 } else if (key
->cipher
== WLAN_CIPHER_SUITE_SMS4
) {
197 k
->type
= fill_sms4_pair(&k
->key
.wapi_pairwise_key
, key
,
200 k
->type
= fill_sms4_group(&k
->key
.wapi_group_key
, key
);
201 } else if (key
->cipher
== WLAN_CIPHER_SUITE_AES_CMAC
) {
202 k
->type
= fill_aes_cmac_group(&k
->key
.igtk_group_key
, key
,
205 dev_warn(wdev
->dev
, "unsupported key type %d\n", key
->cipher
);
206 wfx_free_key(wdev
, idx
);
209 ret
= hif_add_key(wdev
, k
);
211 wfx_free_key(wdev
, idx
);
214 key
->flags
|= IEEE80211_KEY_FLAG_PUT_IV_SPACE
|
215 IEEE80211_KEY_FLAG_RESERVE_TAILROOM
;
216 key
->hw_key_idx
= idx
;
220 static int wfx_remove_key(struct wfx_vif
*wvif
, struct ieee80211_key_conf
*key
)
222 WARN(key
->hw_key_idx
>= MAX_KEY_ENTRIES
, "corrupted hw_key_idx");
223 wfx_free_key(wvif
->wdev
, key
->hw_key_idx
);
224 return hif_remove_key(wvif
->wdev
, key
->hw_key_idx
);
227 int wfx_set_key(struct ieee80211_hw
*hw
, enum set_key_cmd cmd
,
228 struct ieee80211_vif
*vif
, struct ieee80211_sta
*sta
,
229 struct ieee80211_key_conf
*key
)
231 int ret
= -EOPNOTSUPP
;
232 struct wfx_vif
*wvif
= (struct wfx_vif
*) vif
->drv_priv
;
234 mutex_lock(&wvif
->wdev
->conf_mutex
);
236 ret
= wfx_add_key(wvif
, sta
, key
);
237 if (cmd
== DISABLE_KEY
)
238 ret
= wfx_remove_key(wvif
, key
);
239 mutex_unlock(&wvif
->wdev
->conf_mutex
);
243 int wfx_upload_keys(struct wfx_vif
*wvif
)
246 struct hif_req_add_key
*key
;
247 struct wfx_dev
*wdev
= wvif
->wdev
;
249 for (i
= 0; i
< ARRAY_SIZE(wdev
->keys
); i
++) {
250 if (wdev
->key_map
& BIT(i
)) {
251 key
= &wdev
->keys
[i
];
252 if (key
->int_id
== wvif
->id
)
253 hif_add_key(wdev
, key
);
259 void wfx_wep_key_work(struct work_struct
*work
)
261 struct wfx_vif
*wvif
= container_of(work
, struct wfx_vif
, wep_key_work
);
263 wfx_tx_flush(wvif
->wdev
);
264 hif_wep_default_key_id(wvif
, wvif
->wep_default_key_id
);
265 wfx_pending_requeue(wvif
->wdev
, wvif
->wep_pending_skb
);
266 wvif
->wep_pending_skb
= NULL
;
267 wfx_tx_unlock(wvif
->wdev
);