wext.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. /*
  2. * Intel Wireless Multicomm 3200 WiFi driver
  3. *
  4. * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
  5. * Samuel Ortiz <samuel.ortiz@intel.com>
  6. * Zhu Yi <yi.zhu@intel.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License version
  10. * 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20. * 02110-1301, USA.
  21. *
  22. */
  23. #include <linux/kernel.h>
  24. #include <linux/netdevice.h>
  25. #include <linux/wireless.h>
  26. #include <linux/if_arp.h>
  27. #include <linux/etherdevice.h>
  28. #include <net/cfg80211.h>
  29. #include <net/iw_handler.h>
  30. #include "iwm.h"
  31. #include "umac.h"
  32. #include "commands.h"
  33. #include "debug.h"
  34. static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
  35. {
  36. struct iwm_priv *iwm = ndev_to_iwm(dev);
  37. struct iw_statistics *wstats = &iwm->wstats;
  38. if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
  39. memset(wstats, 0, sizeof(struct iw_statistics));
  40. wstats->qual.updated = IW_QUAL_ALL_INVALID;
  41. }
  42. return wstats;
  43. }
  44. static int iwm_wext_siwfreq(struct net_device *dev,
  45. struct iw_request_info *info,
  46. struct iw_freq *freq, char *extra)
  47. {
  48. struct iwm_priv *iwm = ndev_to_iwm(dev);
  49. if (freq->flags == IW_FREQ_AUTO)
  50. return 0;
  51. /* frequency/channel can only be set in IBSS mode */
  52. if (iwm->conf.mode != UMAC_MODE_IBSS)
  53. return -EOPNOTSUPP;
  54. return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
  55. }
  56. static int iwm_wext_giwfreq(struct net_device *dev,
  57. struct iw_request_info *info,
  58. struct iw_freq *freq, char *extra)
  59. {
  60. struct iwm_priv *iwm = ndev_to_iwm(dev);
  61. if (iwm->conf.mode == UMAC_MODE_IBSS)
  62. return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
  63. freq->e = 0;
  64. freq->m = iwm->channel;
  65. return 0;
  66. }
  67. static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
  68. struct sockaddr *ap_addr, char *extra)
  69. {
  70. struct iwm_priv *iwm = ndev_to_iwm(dev);
  71. if (iwm->conf.mode == UMAC_MODE_IBSS)
  72. return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
  73. if (!test_bit(IWM_STATUS_READY, &iwm->status))
  74. return -EIO;
  75. if (is_zero_ether_addr(ap_addr->sa_data) ||
  76. is_broadcast_ether_addr(ap_addr->sa_data)) {
  77. IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
  78. iwm->umac_profile->bssid[0]);
  79. memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
  80. iwm->umac_profile->bss_num = 0;
  81. } else {
  82. IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
  83. ap_addr->sa_data);
  84. memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
  85. ETH_ALEN);
  86. iwm->umac_profile->bss_num = 1;
  87. }
  88. if (iwm->umac_profile_active) {
  89. if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
  90. return 0;
  91. iwm_invalidate_mlme_profile(iwm);
  92. }
  93. if (iwm->umac_profile->ssid.ssid_len)
  94. return iwm_send_mlme_profile(iwm);
  95. return 0;
  96. }
  97. static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
  98. struct sockaddr *ap_addr, char *extra)
  99. {
  100. struct iwm_priv *iwm = ndev_to_iwm(dev);
  101. switch (iwm->conf.mode) {
  102. case UMAC_MODE_IBSS:
  103. return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
  104. case UMAC_MODE_BSS:
  105. if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
  106. ap_addr->sa_family = ARPHRD_ETHER;
  107. memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
  108. } else
  109. memset(&ap_addr->sa_data, 0, ETH_ALEN);
  110. break;
  111. default:
  112. return -EOPNOTSUPP;
  113. }
  114. return 0;
  115. }
  116. static int iwm_wext_siwessid(struct net_device *dev,
  117. struct iw_request_info *info,
  118. struct iw_point *data, char *ssid)
  119. {
  120. struct iwm_priv *iwm = ndev_to_iwm(dev);
  121. size_t len = data->length;
  122. int ret;
  123. if (iwm->conf.mode == UMAC_MODE_IBSS)
  124. return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
  125. if (!test_bit(IWM_STATUS_READY, &iwm->status))
  126. return -EIO;
  127. if (len > 0 && ssid[len - 1] == '\0')
  128. len--;
  129. if (iwm->umac_profile_active) {
  130. if (iwm->umac_profile->ssid.ssid_len == len &&
  131. !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
  132. return 0;
  133. ret = iwm_invalidate_mlme_profile(iwm);
  134. if (ret < 0) {
  135. IWM_ERR(iwm, "Couldn't invalidate profile\n");
  136. return ret;
  137. }
  138. }
  139. iwm->umac_profile->ssid.ssid_len = len;
  140. memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
  141. return iwm_send_mlme_profile(iwm);
  142. }
  143. static int iwm_wext_giwessid(struct net_device *dev,
  144. struct iw_request_info *info,
  145. struct iw_point *data, char *ssid)
  146. {
  147. struct iwm_priv *iwm = ndev_to_iwm(dev);
  148. if (iwm->conf.mode == UMAC_MODE_IBSS)
  149. return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
  150. if (!test_bit(IWM_STATUS_READY, &iwm->status))
  151. return -EIO;
  152. data->length = iwm->umac_profile->ssid.ssid_len;
  153. if (data->length) {
  154. memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
  155. data->flags = 1;
  156. } else
  157. data->flags = 0;
  158. return 0;
  159. }
  160. static struct iwm_key *
  161. iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
  162. struct iw_encode_ext *ext, u8 alg)
  163. {
  164. struct iwm_key *key = &iwm->keys[key_idx];
  165. memset(key, 0, sizeof(struct iwm_key));
  166. memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
  167. key->hdr.key_idx = key_idx;
  168. if (is_broadcast_ether_addr(ext->addr.sa_data))
  169. key->hdr.multicast = 1;
  170. key->in_use = in_use;
  171. key->flags = ext->ext_flags;
  172. key->alg = alg;
  173. key->key_len = ext->key_len;
  174. memcpy(key->key, ext->key, ext->key_len);
  175. return key;
  176. }
  177. static int iwm_wext_giwrate(struct net_device *dev,
  178. struct iw_request_info *info,
  179. struct iw_param *rate, char *extra)
  180. {
  181. struct iwm_priv *iwm = ndev_to_iwm(dev);
  182. rate->value = iwm->rate * 1000000;
  183. return 0;
  184. }
  185. static int iwm_wext_siwencode(struct net_device *dev,
  186. struct iw_request_info *info,
  187. struct iw_point *erq, char *key_buf)
  188. {
  189. struct iwm_priv *iwm = ndev_to_iwm(dev);
  190. struct iwm_key *uninitialized_var(key);
  191. int idx, i, uninitialized_var(alg), remove = 0, ret;
  192. IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
  193. IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
  194. if (!iwm->umac_profile) {
  195. IWM_ERR(iwm, "UMAC profile not allocated yet\n");
  196. return -ENODEV;
  197. }
  198. if (erq->length == WLAN_KEY_LEN_WEP40) {
  199. alg = UMAC_CIPHER_TYPE_WEP_40;
  200. iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
  201. iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
  202. } else if (erq->length == WLAN_KEY_LEN_WEP104) {
  203. alg = UMAC_CIPHER_TYPE_WEP_104;
  204. iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
  205. iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
  206. }
  207. if (erq->flags & IW_ENCODE_RESTRICTED)
  208. iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
  209. else
  210. iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
  211. idx = erq->flags & IW_ENCODE_INDEX;
  212. if (idx == 0) {
  213. if (iwm->default_key)
  214. for (i = 0; i < IWM_NUM_KEYS; i++) {
  215. if (iwm->default_key == &iwm->keys[i]) {
  216. idx = i;
  217. break;
  218. }
  219. }
  220. else
  221. iwm->default_key = &iwm->keys[idx];
  222. } else if (idx < 1 || idx > 4) {
  223. return -EINVAL;
  224. } else
  225. idx--;
  226. if (erq->flags & IW_ENCODE_DISABLED)
  227. remove = 1;
  228. else if (erq->length == 0) {
  229. if (!iwm->keys[idx].in_use)
  230. return -EINVAL;
  231. iwm->default_key = &iwm->keys[idx];
  232. }
  233. if (erq->length) {
  234. key = &iwm->keys[idx];
  235. memset(key, 0, sizeof(struct iwm_key));
  236. memset(key->hdr.mac, 0xff, ETH_ALEN);
  237. key->hdr.key_idx = idx;
  238. key->hdr.multicast = 1;
  239. key->in_use = !remove;
  240. key->alg = alg;
  241. key->key_len = erq->length;
  242. memcpy(key->key, key_buf, erq->length);
  243. IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
  244. idx, !!iwm->default_key);
  245. }
  246. if (remove) {
  247. if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
  248. int j;
  249. for (j = 0; j < IWM_NUM_KEYS; j++)
  250. if (iwm->keys[j].in_use) {
  251. struct iwm_key *k = &iwm->keys[j];
  252. k->in_use = 0;
  253. ret = iwm_set_key(iwm, remove, 0, k);
  254. if (ret < 0)
  255. return ret;
  256. }
  257. iwm->umac_profile->sec.ucast_cipher =
  258. UMAC_CIPHER_TYPE_NONE;
  259. iwm->umac_profile->sec.mcast_cipher =
  260. UMAC_CIPHER_TYPE_NONE;
  261. iwm->umac_profile->sec.auth_type =
  262. UMAC_AUTH_TYPE_OPEN;
  263. return 0;
  264. } else {
  265. key->in_use = 0;
  266. return iwm_set_key(iwm, remove, 0, key);
  267. }
  268. }
  269. /*
  270. * If we havent set a profile yet, we cant set keys.
  271. * Keys will be pushed after we're associated.
  272. */
  273. if (!iwm->umac_profile_active)
  274. return 0;
  275. /*
  276. * If there is a current active profile, but no
  277. * default key, it's not worth trying to associate again.
  278. */
  279. if (!iwm->default_key)
  280. return 0;
  281. /*
  282. * Here we have an active profile, but a key setting changed.
  283. * We thus have to invalidate the current profile, and push the
  284. * new one. Keys will be pushed when association takes place.
  285. */
  286. ret = iwm_invalidate_mlme_profile(iwm);
  287. if (ret < 0) {
  288. IWM_ERR(iwm, "Couldn't invalidate profile\n");
  289. return ret;
  290. }
  291. return iwm_send_mlme_profile(iwm);
  292. }
  293. static int iwm_wext_giwencode(struct net_device *dev,
  294. struct iw_request_info *info,
  295. struct iw_point *erq, char *key)
  296. {
  297. struct iwm_priv *iwm = ndev_to_iwm(dev);
  298. int idx, i;
  299. idx = erq->flags & IW_ENCODE_INDEX;
  300. if (idx < 1 || idx > 4) {
  301. idx = -1;
  302. if (!iwm->default_key) {
  303. erq->length = 0;
  304. erq->flags |= IW_ENCODE_NOKEY;
  305. return 0;
  306. } else
  307. for (i = 0; i < IWM_NUM_KEYS; i++) {
  308. if (iwm->default_key == &iwm->keys[i]) {
  309. idx = i;
  310. break;
  311. }
  312. }
  313. if (idx < 0)
  314. return -EINVAL;
  315. } else
  316. idx--;
  317. erq->flags = idx + 1;
  318. if (!iwm->keys[idx].in_use) {
  319. erq->length = 0;
  320. erq->flags |= IW_ENCODE_DISABLED;
  321. return 0;
  322. }
  323. memcpy(key, iwm->keys[idx].key,
  324. min_t(int, erq->length, iwm->keys[idx].key_len));
  325. erq->length = iwm->keys[idx].key_len;
  326. erq->flags |= IW_ENCODE_ENABLED;
  327. if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
  328. switch (iwm->umac_profile->sec.auth_type) {
  329. case UMAC_AUTH_TYPE_OPEN:
  330. erq->flags |= IW_ENCODE_OPEN;
  331. break;
  332. default:
  333. erq->flags |= IW_ENCODE_RESTRICTED;
  334. break;
  335. }
  336. }
  337. return 0;
  338. }
  339. static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
  340. {
  341. if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
  342. iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
  343. else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
  344. iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
  345. else
  346. iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
  347. return 0;
  348. }
  349. static int iwm_wext_siwpower(struct net_device *dev,
  350. struct iw_request_info *info,
  351. struct iw_param *wrq, char *extra)
  352. {
  353. struct iwm_priv *iwm = ndev_to_iwm(dev);
  354. u32 power_index;
  355. if (wrq->disabled) {
  356. power_index = IWM_POWER_INDEX_MIN;
  357. goto set;
  358. } else
  359. power_index = IWM_POWER_INDEX_DEFAULT;
  360. switch (wrq->flags & IW_POWER_MODE) {
  361. case IW_POWER_ON:
  362. case IW_POWER_MODE:
  363. case IW_POWER_ALL_R:
  364. break;
  365. default:
  366. return -EINVAL;
  367. }
  368. set:
  369. if (power_index == iwm->conf.power_index)
  370. return 0;
  371. iwm->conf.power_index = power_index;
  372. return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
  373. CFG_POWER_INDEX, iwm->conf.power_index);
  374. }
  375. static int iwm_wext_giwpower(struct net_device *dev,
  376. struct iw_request_info *info,
  377. union iwreq_data *wrqu, char *extra)
  378. {
  379. struct iwm_priv *iwm = ndev_to_iwm(dev);
  380. wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
  381. return 0;
  382. }
  383. static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
  384. {
  385. u8 *auth_type = &iwm->umac_profile->sec.auth_type;
  386. if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
  387. *auth_type = UMAC_AUTH_TYPE_8021X;
  388. else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
  389. if (iwm->umac_profile->sec.flags &
  390. (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
  391. *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
  392. else
  393. *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
  394. } else {
  395. IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
  396. return -EINVAL;
  397. }
  398. return 0;
  399. }
  400. static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
  401. {
  402. u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
  403. &iwm->umac_profile->sec.mcast_cipher;
  404. switch (cipher) {
  405. case IW_AUTH_CIPHER_NONE:
  406. *profile_cipher = UMAC_CIPHER_TYPE_NONE;
  407. break;
  408. case IW_AUTH_CIPHER_WEP40:
  409. *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
  410. break;
  411. case IW_AUTH_CIPHER_TKIP:
  412. *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
  413. break;
  414. case IW_AUTH_CIPHER_CCMP:
  415. *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
  416. break;
  417. case IW_AUTH_CIPHER_WEP104:
  418. *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
  419. break;
  420. default:
  421. IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
  422. return -ENOTSUPP;
  423. }
  424. return 0;
  425. }
  426. static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
  427. {
  428. u8 *auth_type = &iwm->umac_profile->sec.auth_type;
  429. switch (auth_alg) {
  430. case IW_AUTH_ALG_OPEN_SYSTEM:
  431. *auth_type = UMAC_AUTH_TYPE_OPEN;
  432. break;
  433. case IW_AUTH_ALG_SHARED_KEY:
  434. if (iwm->umac_profile->sec.flags &
  435. (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
  436. if (*auth_type == UMAC_AUTH_TYPE_8021X)
  437. return -EINVAL;
  438. *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
  439. } else {
  440. *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
  441. }
  442. break;
  443. case IW_AUTH_ALG_LEAP:
  444. default:
  445. IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
  446. return -ENOTSUPP;
  447. }
  448. return 0;
  449. }
  450. static int iwm_wext_siwauth(struct net_device *dev,
  451. struct iw_request_info *info,
  452. struct iw_param *data, char *extra)
  453. {
  454. struct iwm_priv *iwm = ndev_to_iwm(dev);
  455. int ret;
  456. if ((data->flags) &
  457. (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
  458. IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
  459. /* We need to invalidate the current profile */
  460. if (iwm->umac_profile_active) {
  461. ret = iwm_invalidate_mlme_profile(iwm);
  462. if (ret < 0) {
  463. IWM_ERR(iwm, "Couldn't invalidate profile\n");
  464. return ret;
  465. }
  466. }
  467. }
  468. switch (data->flags & IW_AUTH_INDEX) {
  469. case IW_AUTH_WPA_VERSION:
  470. return iwm_set_wpa_version(iwm, data->value);
  471. break;
  472. case IW_AUTH_CIPHER_PAIRWISE:
  473. return iwm_set_cipher(iwm, data->value, 1);
  474. break;
  475. case IW_AUTH_CIPHER_GROUP:
  476. return iwm_set_cipher(iwm, data->value, 0);
  477. break;
  478. case IW_AUTH_KEY_MGMT:
  479. return iwm_set_key_mgt(iwm, data->value);
  480. break;
  481. case IW_AUTH_80211_AUTH_ALG:
  482. return iwm_set_auth_alg(iwm, data->value);
  483. break;
  484. default:
  485. return -ENOTSUPP;
  486. }
  487. return 0;
  488. }
  489. static int iwm_wext_giwauth(struct net_device *dev,
  490. struct iw_request_info *info,
  491. struct iw_param *data, char *extra)
  492. {
  493. return 0;
  494. }
  495. static int iwm_wext_siwencodeext(struct net_device *dev,
  496. struct iw_request_info *info,
  497. struct iw_point *erq, char *extra)
  498. {
  499. struct iwm_priv *iwm = ndev_to_iwm(dev);
  500. struct iwm_key *key;
  501. struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
  502. int uninitialized_var(alg), idx, i, remove = 0;
  503. IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
  504. IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
  505. IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
  506. IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
  507. IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
  508. switch (ext->alg) {
  509. case IW_ENCODE_ALG_NONE:
  510. remove = 1;
  511. break;
  512. case IW_ENCODE_ALG_WEP:
  513. if (ext->key_len == WLAN_KEY_LEN_WEP40)
  514. alg = UMAC_CIPHER_TYPE_WEP_40;
  515. else if (ext->key_len == WLAN_KEY_LEN_WEP104)
  516. alg = UMAC_CIPHER_TYPE_WEP_104;
  517. else {
  518. IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
  519. return -EINVAL;
  520. }
  521. break;
  522. case IW_ENCODE_ALG_TKIP:
  523. alg = UMAC_CIPHER_TYPE_TKIP;
  524. break;
  525. case IW_ENCODE_ALG_CCMP:
  526. alg = UMAC_CIPHER_TYPE_CCMP;
  527. break;
  528. default:
  529. return -EOPNOTSUPP;
  530. }
  531. idx = erq->flags & IW_ENCODE_INDEX;
  532. if (idx == 0) {
  533. if (iwm->default_key)
  534. for (i = 0; i < IWM_NUM_KEYS; i++) {
  535. if (iwm->default_key == &iwm->keys[i]) {
  536. idx = i;
  537. break;
  538. }
  539. }
  540. } else if (idx < 1 || idx > 4) {
  541. return -EINVAL;
  542. } else
  543. idx--;
  544. if (erq->flags & IW_ENCODE_DISABLED)
  545. remove = 1;
  546. else if ((erq->length == 0) ||
  547. (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
  548. iwm->default_key = &iwm->keys[idx];
  549. if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
  550. return iwm_set_tx_key(iwm, idx);
  551. }
  552. key = iwm_key_init(iwm, idx, !remove, ext, alg);
  553. return iwm_set_key(iwm, remove, !iwm->default_key, key);
  554. }
  555. static const iw_handler iwm_handlers[] =
  556. {
  557. (iw_handler) NULL, /* SIOCSIWCOMMIT */
  558. (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
  559. (iw_handler) NULL, /* SIOCSIWNWID */
  560. (iw_handler) NULL, /* SIOCGIWNWID */
  561. (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
  562. (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
  563. (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
  564. (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
  565. (iw_handler) NULL, /* SIOCSIWSENS */
  566. (iw_handler) NULL, /* SIOCGIWSENS */
  567. (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
  568. (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
  569. (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
  570. (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
  571. (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
  572. (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
  573. (iw_handler) NULL, /* SIOCSIWSPY */
  574. (iw_handler) NULL, /* SIOCGIWSPY */
  575. (iw_handler) NULL, /* SIOCSIWTHRSPY */
  576. (iw_handler) NULL, /* SIOCGIWTHRSPY */
  577. (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
  578. (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
  579. (iw_handler) NULL, /* SIOCSIWMLME */
  580. (iw_handler) NULL, /* SIOCGIWAPLIST */
  581. (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
  582. (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
  583. (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
  584. (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
  585. (iw_handler) NULL, /* SIOCSIWNICKN */
  586. (iw_handler) NULL, /* SIOCGIWNICKN */
  587. (iw_handler) NULL, /* -- hole -- */
  588. (iw_handler) NULL, /* -- hole -- */
  589. (iw_handler) NULL, /* SIOCSIWRATE */
  590. (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
  591. (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
  592. (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
  593. (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
  594. (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
  595. (iw_handler) NULL, /* SIOCSIWTXPOW */
  596. (iw_handler) NULL, /* SIOCGIWTXPOW */
  597. (iw_handler) NULL, /* SIOCSIWRETRY */
  598. (iw_handler) NULL, /* SIOCGIWRETRY */
  599. (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
  600. (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
  601. (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
  602. (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
  603. (iw_handler) NULL, /* -- hole -- */
  604. (iw_handler) NULL, /* -- hole -- */
  605. (iw_handler) NULL, /* SIOCSIWGENIE */
  606. (iw_handler) NULL, /* SIOCGIWGENIE */
  607. (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
  608. (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
  609. (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
  610. (iw_handler) NULL, /* SIOCGIWENCODEEXT */
  611. (iw_handler) NULL, /* SIOCSIWPMKSA */
  612. (iw_handler) NULL, /* -- hole -- */
  613. };
  614. const struct iw_handler_def iwm_iw_handler_def = {
  615. .num_standard = ARRAY_SIZE(iwm_handlers),
  616. .standard = (iw_handler *) iwm_handlers,
  617. .get_wireless_stats = iwm_get_wireless_stats,
  618. };