iwl-sta.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
  4. *
  5. * Portions of this file are derived from the ipw3945 project, as well
  6. * as portions of the ieee80211 subsystem header files.
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of version 2 of the GNU General Public License as
  10. * published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  20. *
  21. * The full GNU General Public License is included in this distribution in the
  22. * file called LICENSE.
  23. *
  24. * Contact Information:
  25. * James P. Ketrenos <ipw2100-admin@linux.intel.com>
  26. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  27. *
  28. *****************************************************************************/
  29. #include <net/mac80211.h>
  30. #include <linux/etherdevice.h>
  31. #include "iwl-eeprom.h"
  32. #include "iwl-dev.h"
  33. #include "iwl-core.h"
  34. #include "iwl-sta.h"
  35. #include "iwl-io.h"
  36. #include "iwl-helpers.h"
  37. u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
  38. {
  39. int i;
  40. int start = 0;
  41. int ret = IWL_INVALID_STATION;
  42. unsigned long flags;
  43. DECLARE_MAC_BUF(mac);
  44. if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
  45. (priv->iw_mode == IEEE80211_IF_TYPE_AP))
  46. start = IWL_STA_ID;
  47. if (is_broadcast_ether_addr(addr))
  48. return priv->hw_params.bcast_sta_id;
  49. spin_lock_irqsave(&priv->sta_lock, flags);
  50. for (i = start; i < priv->hw_params.max_stations; i++)
  51. if (priv->stations[i].used &&
  52. (!compare_ether_addr(priv->stations[i].sta.sta.addr,
  53. addr))) {
  54. ret = i;
  55. goto out;
  56. }
  57. IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
  58. print_mac(mac, addr), priv->num_stations);
  59. out:
  60. spin_unlock_irqrestore(&priv->sta_lock, flags);
  61. return ret;
  62. }
  63. EXPORT_SYMBOL(iwl_find_station);
  64. int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
  65. {
  66. int i;
  67. for (i = 0; i < STA_KEY_MAX_NUM; i++)
  68. if (!test_and_set_bit(i, &priv->ucode_key_table))
  69. return i;
  70. return -1;
  71. }
  72. int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
  73. {
  74. int i, not_empty = 0;
  75. u8 buff[sizeof(struct iwl_wep_cmd) +
  76. sizeof(struct iwl_wep_key) * WEP_KEYS_MAX];
  77. struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff;
  78. size_t cmd_size = sizeof(struct iwl_wep_cmd);
  79. struct iwl_host_cmd cmd = {
  80. .id = REPLY_WEPKEY,
  81. .data = wep_cmd,
  82. .meta.flags = CMD_ASYNC,
  83. };
  84. memset(wep_cmd, 0, cmd_size +
  85. (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
  86. for (i = 0; i < WEP_KEYS_MAX ; i++) {
  87. wep_cmd->key[i].key_index = i;
  88. if (priv->wep_keys[i].key_size) {
  89. wep_cmd->key[i].key_offset = i;
  90. not_empty = 1;
  91. } else {
  92. wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET;
  93. }
  94. wep_cmd->key[i].key_size = priv->wep_keys[i].key_size;
  95. memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key,
  96. priv->wep_keys[i].key_size);
  97. }
  98. wep_cmd->global_key_type = WEP_KEY_WEP_TYPE;
  99. wep_cmd->num_keys = WEP_KEYS_MAX;
  100. cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
  101. cmd.len = cmd_size;
  102. if (not_empty || send_if_empty)
  103. return iwl_send_cmd(priv, &cmd);
  104. else
  105. return 0;
  106. }
  107. int iwl_remove_default_wep_key(struct iwl_priv *priv,
  108. struct ieee80211_key_conf *keyconf)
  109. {
  110. int ret;
  111. unsigned long flags;
  112. spin_lock_irqsave(&priv->sta_lock, flags);
  113. if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
  114. IWL_ERROR("index %d not used in uCode key table.\n",
  115. keyconf->keyidx);
  116. priv->default_wep_key--;
  117. memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
  118. ret = iwl_send_static_wepkey_cmd(priv, 1);
  119. spin_unlock_irqrestore(&priv->sta_lock, flags);
  120. return ret;
  121. }
  122. int iwl_set_default_wep_key(struct iwl_priv *priv,
  123. struct ieee80211_key_conf *keyconf)
  124. {
  125. int ret;
  126. unsigned long flags;
  127. keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
  128. keyconf->hw_key_idx = keyconf->keyidx;
  129. priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
  130. spin_lock_irqsave(&priv->sta_lock, flags);
  131. priv->default_wep_key++;
  132. if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
  133. IWL_ERROR("index %d already used in uCode key table.\n",
  134. keyconf->keyidx);
  135. priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
  136. memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
  137. keyconf->keylen);
  138. ret = iwl_send_static_wepkey_cmd(priv, 0);
  139. spin_unlock_irqrestore(&priv->sta_lock, flags);
  140. return ret;
  141. }
  142. static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
  143. struct ieee80211_key_conf *keyconf,
  144. u8 sta_id)
  145. {
  146. unsigned long flags;
  147. __le16 key_flags = 0;
  148. int ret;
  149. keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
  150. keyconf->hw_key_idx = keyconf->keyidx;
  151. key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
  152. key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
  153. key_flags &= ~STA_KEY_FLG_INVALID;
  154. if (keyconf->keylen == WEP_KEY_LEN_128)
  155. key_flags |= STA_KEY_FLG_KEY_SIZE_MSK;
  156. if (sta_id == priv->hw_params.bcast_sta_id)
  157. key_flags |= STA_KEY_MULTICAST_MSK;
  158. spin_lock_irqsave(&priv->sta_lock, flags);
  159. priv->stations[sta_id].keyinfo.alg = keyconf->alg;
  160. priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
  161. priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx;
  162. memcpy(priv->stations[sta_id].keyinfo.key,
  163. keyconf->key, keyconf->keylen);
  164. memcpy(&priv->stations[sta_id].sta.key.key[3],
  165. keyconf->key, keyconf->keylen);
  166. if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
  167. == STA_KEY_FLG_NO_ENC)
  168. priv->stations[sta_id].sta.key.key_offset =
  169. iwl_get_free_ucode_key_index(priv);
  170. /* else, we are overriding an existing key => no need to allocated room
  171. * in uCode. */
  172. priv->stations[sta_id].sta.key.key_flags = key_flags;
  173. priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
  174. priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
  175. ret = iwl4965_send_add_station(priv,
  176. &priv->stations[sta_id].sta, CMD_ASYNC);
  177. spin_unlock_irqrestore(&priv->sta_lock, flags);
  178. return ret;
  179. }
  180. static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
  181. struct ieee80211_key_conf *keyconf,
  182. u8 sta_id)
  183. {
  184. unsigned long flags;
  185. __le16 key_flags = 0;
  186. key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
  187. key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
  188. key_flags &= ~STA_KEY_FLG_INVALID;
  189. if (sta_id == priv->hw_params.bcast_sta_id)
  190. key_flags |= STA_KEY_MULTICAST_MSK;
  191. keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
  192. keyconf->hw_key_idx = keyconf->keyidx;
  193. spin_lock_irqsave(&priv->sta_lock, flags);
  194. priv->stations[sta_id].keyinfo.alg = keyconf->alg;
  195. priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
  196. memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
  197. keyconf->keylen);
  198. memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
  199. keyconf->keylen);
  200. if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
  201. == STA_KEY_FLG_NO_ENC)
  202. priv->stations[sta_id].sta.key.key_offset =
  203. iwl_get_free_ucode_key_index(priv);
  204. /* else, we are overriding an existing key => no need to allocated room
  205. * in uCode. */
  206. priv->stations[sta_id].sta.key.key_flags = key_flags;
  207. priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
  208. priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
  209. spin_unlock_irqrestore(&priv->sta_lock, flags);
  210. IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
  211. return iwl4965_send_add_station(priv,
  212. &priv->stations[sta_id].sta, CMD_ASYNC);
  213. }
  214. static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
  215. struct ieee80211_key_conf *keyconf,
  216. u8 sta_id)
  217. {
  218. unsigned long flags;
  219. int ret = 0;
  220. keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
  221. keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
  222. keyconf->hw_key_idx = keyconf->keyidx;
  223. spin_lock_irqsave(&priv->sta_lock, flags);
  224. priv->stations[sta_id].keyinfo.alg = keyconf->alg;
  225. priv->stations[sta_id].keyinfo.conf = keyconf;
  226. priv->stations[sta_id].keyinfo.keylen = 16;
  227. if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
  228. == STA_KEY_FLG_NO_ENC)
  229. priv->stations[sta_id].sta.key.key_offset =
  230. iwl_get_free_ucode_key_index(priv);
  231. /* else, we are overriding an existing key => no need to allocated room
  232. * in uCode. */
  233. /* This copy is acutally not needed: we get the key with each TX */
  234. memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
  235. memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
  236. spin_unlock_irqrestore(&priv->sta_lock, flags);
  237. return ret;
  238. }
  239. int iwl_remove_dynamic_key(struct iwl_priv *priv,
  240. struct ieee80211_key_conf *keyconf,
  241. u8 sta_id)
  242. {
  243. unsigned long flags;
  244. int ret = 0;
  245. u16 key_flags;
  246. u8 keyidx;
  247. priv->key_mapping_key = 0;
  248. spin_lock_irqsave(&priv->sta_lock, flags);
  249. key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
  250. keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
  251. if (keyconf->keyidx != keyidx) {
  252. /* We need to remove a key with index different that the one
  253. * in the uCode. This means that the key we need to remove has
  254. * been replaced by another one with different index.
  255. * Don't do anything and return ok
  256. */
  257. spin_unlock_irqrestore(&priv->sta_lock, flags);
  258. return 0;
  259. }
  260. if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
  261. &priv->ucode_key_table))
  262. IWL_ERROR("index %d not used in uCode key table.\n",
  263. priv->stations[sta_id].sta.key.key_offset);
  264. memset(&priv->stations[sta_id].keyinfo, 0,
  265. sizeof(struct iwl4965_hw_key));
  266. memset(&priv->stations[sta_id].sta.key, 0,
  267. sizeof(struct iwl4965_keyinfo));
  268. priv->stations[sta_id].sta.key.key_flags =
  269. STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
  270. priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
  271. priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
  272. priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
  273. IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
  274. ret = iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
  275. spin_unlock_irqrestore(&priv->sta_lock, flags);
  276. return ret;
  277. }
  278. int iwl_set_dynamic_key(struct iwl_priv *priv,
  279. struct ieee80211_key_conf *key, u8 sta_id)
  280. {
  281. int ret;
  282. priv->key_mapping_key = 1;
  283. switch (key->alg) {
  284. case ALG_CCMP:
  285. ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
  286. break;
  287. case ALG_TKIP:
  288. ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
  289. break;
  290. case ALG_WEP:
  291. ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
  292. break;
  293. default:
  294. IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
  295. ret = -EINVAL;
  296. }
  297. return ret;
  298. }
  299. #ifdef CONFIG_IWLWIFI_DEBUG
  300. static void iwl_dump_lq_cmd(struct iwl_priv *priv,
  301. struct iwl_link_quality_cmd *lq)
  302. {
  303. int i;
  304. IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
  305. IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
  306. lq->general_params.single_stream_ant_msk,
  307. lq->general_params.dual_stream_ant_msk);
  308. for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
  309. IWL_DEBUG_RATE("lq index %d 0x%X\n",
  310. i, lq->rs_table[i].rate_n_flags);
  311. }
  312. #else
  313. static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
  314. struct iwl_link_quality_cmd *lq)
  315. {
  316. }
  317. #endif
  318. int iwl_send_lq_cmd(struct iwl_priv *priv,
  319. struct iwl_link_quality_cmd *lq, u8 flags)
  320. {
  321. struct iwl_host_cmd cmd = {
  322. .id = REPLY_TX_LINK_QUALITY_CMD,
  323. .len = sizeof(struct iwl_link_quality_cmd),
  324. .meta.flags = flags,
  325. .data = lq,
  326. };
  327. if ((lq->sta_id == 0xFF) &&
  328. (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
  329. return -EINVAL;
  330. if (lq->sta_id == 0xFF)
  331. lq->sta_id = IWL_AP_ID;
  332. iwl_dump_lq_cmd(priv,lq);
  333. if (iwl_is_associated(priv) && priv->assoc_station_added &&
  334. priv->lq_mngr.lq_ready)
  335. return iwl_send_cmd(priv, &cmd);
  336. return 0;
  337. }
  338. EXPORT_SYMBOL(iwl_send_lq_cmd);