key.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Key management related functions.
  4. *
  5. * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  6. * Copyright (c) 2010, ST-Ericsson
  7. */
  8. #include <linux/etherdevice.h>
  9. #include <net/mac80211.h>
  10. #include "key.h"
  11. #include "wfx.h"
  12. #include "hif_tx_mib.h"
  13. static int wfx_alloc_key(struct wfx_dev *wdev)
  14. {
  15. int idx;
  16. idx = ffs(~wdev->key_map) - 1;
  17. if (idx < 0 || idx >= MAX_KEY_ENTRIES)
  18. return -1;
  19. wdev->key_map |= BIT(idx);
  20. return idx;
  21. }
  22. static void wfx_free_key(struct wfx_dev *wdev, int idx)
  23. {
  24. WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation");
  25. wdev->key_map &= ~BIT(idx);
  26. }
  27. static u8 fill_wep_pair(struct wfx_hif_wep_pairwise_key *msg,
  28. struct ieee80211_key_conf *key, u8 *peer_addr)
  29. {
  30. WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
  31. msg->key_length = key->keylen;
  32. memcpy(msg->key_data, key->key, key->keylen);
  33. ether_addr_copy(msg->peer_address, peer_addr);
  34. return HIF_KEY_TYPE_WEP_PAIRWISE;
  35. }
  36. static u8 fill_wep_group(struct wfx_hif_wep_group_key *msg,
  37. struct ieee80211_key_conf *key)
  38. {
  39. WARN(key->keylen > sizeof(msg->key_data), "inconsistent data");
  40. msg->key_id = key->keyidx;
  41. msg->key_length = key->keylen;
  42. memcpy(msg->key_data, key->key, key->keylen);
  43. return HIF_KEY_TYPE_WEP_DEFAULT;
  44. }
  45. static u8 fill_tkip_pair(struct wfx_hif_tkip_pairwise_key *msg,
  46. struct ieee80211_key_conf *key, u8 *peer_addr)
  47. {
  48. u8 *keybuf = key->key;
  49. WARN(key->keylen != sizeof(msg->tkip_key_data) + sizeof(msg->tx_mic_key) +
  50. sizeof(msg->rx_mic_key), "inconsistent data");
  51. memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
  52. keybuf += sizeof(msg->tkip_key_data);
  53. memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key));
  54. keybuf += sizeof(msg->tx_mic_key);
  55. memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key));
  56. ether_addr_copy(msg->peer_address, peer_addr);
  57. return HIF_KEY_TYPE_TKIP_PAIRWISE;
  58. }
  59. static u8 fill_tkip_group(struct wfx_hif_tkip_group_key *msg, struct ieee80211_key_conf *key,
  60. struct ieee80211_key_seq *seq, enum nl80211_iftype iftype)
  61. {
  62. u8 *keybuf = key->key;
  63. WARN(key->keylen != sizeof(msg->tkip_key_data) + 2 * sizeof(msg->rx_mic_key),
  64. "inconsistent data");
  65. msg->key_id = key->keyidx;
  66. memcpy(msg->rx_sequence_counter, &seq->tkip.iv16, sizeof(seq->tkip.iv16));
  67. memcpy(msg->rx_sequence_counter + sizeof(u16), &seq->tkip.iv32, sizeof(seq->tkip.iv32));
  68. memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data));
  69. keybuf += sizeof(msg->tkip_key_data);
  70. if (iftype == NL80211_IFTYPE_AP)
  71. /* Use Tx MIC Key */
  72. memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key));
  73. else
  74. /* Use Rx MIC Key */
  75. memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key));
  76. return HIF_KEY_TYPE_TKIP_GROUP;
  77. }
  78. static u8 fill_ccmp_pair(struct wfx_hif_aes_pairwise_key *msg,
  79. struct ieee80211_key_conf *key, u8 *peer_addr)
  80. {
  81. WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
  82. ether_addr_copy(msg->peer_address, peer_addr);
  83. memcpy(msg->aes_key_data, key->key, key->keylen);
  84. return HIF_KEY_TYPE_AES_PAIRWISE;
  85. }
  86. static u8 fill_ccmp_group(struct wfx_hif_aes_group_key *msg,
  87. struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq)
  88. {
  89. WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data");
  90. memcpy(msg->aes_key_data, key->key, key->keylen);
  91. memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn));
  92. memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn));
  93. msg->key_id = key->keyidx;
  94. return HIF_KEY_TYPE_AES_GROUP;
  95. }
  96. static u8 fill_sms4_pair(struct wfx_hif_wapi_pairwise_key *msg,
  97. struct ieee80211_key_conf *key, u8 *peer_addr)
  98. {
  99. u8 *keybuf = key->key;
  100. WARN(key->keylen != sizeof(msg->wapi_key_data) + sizeof(msg->mic_key_data),
  101. "inconsistent data");
  102. ether_addr_copy(msg->peer_address, peer_addr);
  103. memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
  104. keybuf += sizeof(msg->wapi_key_data);
  105. memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
  106. msg->key_id = key->keyidx;
  107. return HIF_KEY_TYPE_WAPI_PAIRWISE;
  108. }
  109. static u8 fill_sms4_group(struct wfx_hif_wapi_group_key *msg,
  110. struct ieee80211_key_conf *key)
  111. {
  112. u8 *keybuf = key->key;
  113. WARN(key->keylen != sizeof(msg->wapi_key_data) + sizeof(msg->mic_key_data),
  114. "inconsistent data");
  115. memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data));
  116. keybuf += sizeof(msg->wapi_key_data);
  117. memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data));
  118. msg->key_id = key->keyidx;
  119. return HIF_KEY_TYPE_WAPI_GROUP;
  120. }
  121. static u8 fill_aes_cmac_group(struct wfx_hif_igtk_group_key *msg,
  122. struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq)
  123. {
  124. WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data");
  125. memcpy(msg->igtk_key_data, key->key, key->keylen);
  126. memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn));
  127. memreverse(msg->ipn, sizeof(seq->aes_cmac.pn));
  128. msg->key_id = key->keyidx;
  129. return HIF_KEY_TYPE_IGTK_GROUP;
  130. }
  131. static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta,
  132. struct ieee80211_key_conf *key)
  133. {
  134. int ret;
  135. struct wfx_hif_req_add_key k = { };
  136. struct ieee80211_key_seq seq;
  137. struct wfx_dev *wdev = wvif->wdev;
  138. int idx = wfx_alloc_key(wvif->wdev);
  139. bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
  140. struct ieee80211_vif *vif = wvif_to_vif(wvif);
  141. WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data");
  142. ieee80211_get_key_rx_seq(key, 0, &seq);
  143. if (idx < 0)
  144. return -EINVAL;
  145. k.int_id = wvif->id;
  146. k.entry_index = idx;
  147. if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
  148. key->cipher == WLAN_CIPHER_SUITE_WEP104) {
  149. if (pairwise)
  150. k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, sta->addr);
  151. else
  152. k.type = fill_wep_group(&k.key.wep_group_key, key);
  153. } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
  154. if (pairwise)
  155. k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, sta->addr);
  156. else
  157. k.type = fill_tkip_group(&k.key.tkip_group_key, key, &seq,
  158. vif->type);
  159. } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) {
  160. if (pairwise)
  161. k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, sta->addr);
  162. else
  163. k.type = fill_ccmp_group(&k.key.aes_group_key, key, &seq);
  164. } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) {
  165. if (pairwise)
  166. k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, sta->addr);
  167. else
  168. k.type = fill_sms4_group(&k.key.wapi_group_key, key);
  169. } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
  170. k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq);
  171. key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
  172. } else {
  173. dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher);
  174. wfx_free_key(wdev, idx);
  175. return -EOPNOTSUPP;
  176. }
  177. ret = wfx_hif_add_key(wdev, &k);
  178. if (ret) {
  179. wfx_free_key(wdev, idx);
  180. return -EOPNOTSUPP;
  181. }
  182. key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
  183. key->hw_key_idx = idx;
  184. return 0;
  185. }
  186. static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key)
  187. {
  188. WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx");
  189. wfx_free_key(wvif->wdev, key->hw_key_idx);
  190. return wfx_hif_remove_key(wvif->wdev, key->hw_key_idx);
  191. }
  192. int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif,
  193. struct ieee80211_sta *sta, struct ieee80211_key_conf *key)
  194. {
  195. int ret = -EOPNOTSUPP;
  196. struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
  197. mutex_lock(&wvif->wdev->conf_mutex);
  198. if (cmd == SET_KEY)
  199. ret = wfx_add_key(wvif, sta, key);
  200. if (cmd == DISABLE_KEY)
  201. ret = wfx_remove_key(wvif, key);
  202. mutex_unlock(&wvif->wdev->conf_mutex);
  203. return ret;
  204. }