assoc.c 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244
  1. /* Copyright (C) 2006, Red Hat, Inc. */
  2. #include <linux/types.h>
  3. #include <linux/etherdevice.h>
  4. #include <linux/ieee80211.h>
  5. #include <linux/if_arp.h>
  6. #include <linux/slab.h>
  7. #include <net/lib80211.h>
  8. #include "assoc.h"
  9. #include "decl.h"
  10. #include "host.h"
  11. #include "scan.h"
  12. #include "cmd.h"
  13. static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
  14. { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  15. static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
  16. { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  17. /* The firmware needs the following bits masked out of the beacon-derived
  18. * capability field when associating/joining to a BSS:
  19. * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
  20. */
  21. #define CAPINFO_MASK (~(0xda00))
  22. /**
  23. * 802.11b/g supported bitrates (in 500Kb/s units)
  24. */
  25. u8 lbs_bg_rates[MAX_RATES] =
  26. { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
  27. 0x00, 0x00 };
  28. /**
  29. * @brief This function finds common rates between rates and card rates.
  30. *
  31. * It will fill common rates in rates as output if found.
  32. *
  33. * NOTE: Setting the MSB of the basic rates need to be taken
  34. * care, either before or after calling this function
  35. *
  36. * @param priv A pointer to struct lbs_private structure
  37. * @param rates the buffer which keeps input and output
  38. * @param rates_size the size of rates buffer; new size of buffer on return,
  39. * which will be less than or equal to original rates_size
  40. *
  41. * @return 0 on success, or -1 on error
  42. */
  43. static int get_common_rates(struct lbs_private *priv,
  44. u8 *rates,
  45. u16 *rates_size)
  46. {
  47. int i, j;
  48. u8 intersection[MAX_RATES];
  49. u16 intersection_size;
  50. u16 num_rates = 0;
  51. intersection_size = min_t(u16, *rates_size, ARRAY_SIZE(intersection));
  52. /* Allow each rate from 'rates' that is supported by the hardware */
  53. for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && lbs_bg_rates[i]; i++) {
  54. for (j = 0; j < intersection_size && rates[j]; j++) {
  55. if (rates[j] == lbs_bg_rates[i])
  56. intersection[num_rates++] = rates[j];
  57. }
  58. }
  59. lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
  60. lbs_deb_hex(LBS_DEB_JOIN, "card rates ", lbs_bg_rates,
  61. ARRAY_SIZE(lbs_bg_rates));
  62. lbs_deb_hex(LBS_DEB_JOIN, "common rates", intersection, num_rates);
  63. lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
  64. if (!priv->enablehwauto) {
  65. for (i = 0; i < num_rates; i++) {
  66. if (intersection[i] == priv->cur_rate)
  67. goto done;
  68. }
  69. lbs_pr_alert("Previously set fixed data rate %#x isn't "
  70. "compatible with the network.\n", priv->cur_rate);
  71. return -1;
  72. }
  73. done:
  74. memset(rates, 0, *rates_size);
  75. *rates_size = num_rates;
  76. memcpy(rates, intersection, num_rates);
  77. return 0;
  78. }
  79. /**
  80. * @brief Sets the MSB on basic rates as the firmware requires
  81. *
  82. * Scan through an array and set the MSB for basic data rates.
  83. *
  84. * @param rates buffer of data rates
  85. * @param len size of buffer
  86. */
  87. static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
  88. {
  89. int i;
  90. for (i = 0; i < len; i++) {
  91. if (rates[i] == 0x02 || rates[i] == 0x04 ||
  92. rates[i] == 0x0b || rates[i] == 0x16)
  93. rates[i] |= 0x80;
  94. }
  95. }
  96. static u8 iw_auth_to_ieee_auth(u8 auth)
  97. {
  98. if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
  99. return 0x00;
  100. else if (auth == IW_AUTH_ALG_SHARED_KEY)
  101. return 0x01;
  102. else if (auth == IW_AUTH_ALG_LEAP)
  103. return 0x80;
  104. lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
  105. return 0;
  106. }
  107. /**
  108. * @brief This function prepares the authenticate command. AUTHENTICATE only
  109. * sets the authentication suite for future associations, as the firmware
  110. * handles authentication internally during the ASSOCIATE command.
  111. *
  112. * @param priv A pointer to struct lbs_private structure
  113. * @param bssid The peer BSSID with which to authenticate
  114. * @param auth The authentication mode to use (from wireless.h)
  115. *
  116. * @return 0 or -1
  117. */
  118. static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
  119. {
  120. struct cmd_ds_802_11_authenticate cmd;
  121. int ret = -1;
  122. lbs_deb_enter(LBS_DEB_JOIN);
  123. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  124. memcpy(cmd.bssid, bssid, ETH_ALEN);
  125. cmd.authtype = iw_auth_to_ieee_auth(auth);
  126. lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
  127. ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
  128. lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
  129. return ret;
  130. }
  131. int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
  132. struct assoc_request *assoc)
  133. {
  134. struct cmd_ds_802_11_set_wep cmd;
  135. int ret = 0;
  136. lbs_deb_enter(LBS_DEB_CMD);
  137. memset(&cmd, 0, sizeof(cmd));
  138. cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
  139. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  140. cmd.action = cpu_to_le16(cmd_action);
  141. if (cmd_action == CMD_ACT_ADD) {
  142. int i;
  143. /* default tx key index */
  144. cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
  145. CMD_WEP_KEY_INDEX_MASK);
  146. /* Copy key types and material to host command structure */
  147. for (i = 0; i < 4; i++) {
  148. struct enc_key *pkey = &assoc->wep_keys[i];
  149. switch (pkey->len) {
  150. case KEY_LEN_WEP_40:
  151. cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
  152. memmove(cmd.keymaterial[i], pkey->key, pkey->len);
  153. lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
  154. break;
  155. case KEY_LEN_WEP_104:
  156. cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
  157. memmove(cmd.keymaterial[i], pkey->key, pkey->len);
  158. lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
  159. break;
  160. case 0:
  161. break;
  162. default:
  163. lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
  164. i, pkey->len);
  165. ret = -1;
  166. goto done;
  167. break;
  168. }
  169. }
  170. } else if (cmd_action == CMD_ACT_REMOVE) {
  171. /* ACT_REMOVE clears _all_ WEP keys */
  172. /* default tx key index */
  173. cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
  174. CMD_WEP_KEY_INDEX_MASK);
  175. lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
  176. }
  177. ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
  178. done:
  179. lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
  180. return ret;
  181. }
  182. int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
  183. uint16_t *enable)
  184. {
  185. struct cmd_ds_802_11_enable_rsn cmd;
  186. int ret;
  187. lbs_deb_enter(LBS_DEB_CMD);
  188. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  189. cmd.action = cpu_to_le16(cmd_action);
  190. if (cmd_action == CMD_ACT_GET)
  191. cmd.enable = 0;
  192. else {
  193. if (*enable)
  194. cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
  195. else
  196. cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
  197. lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
  198. }
  199. ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
  200. if (!ret && cmd_action == CMD_ACT_GET)
  201. *enable = le16_to_cpu(cmd.enable);
  202. lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
  203. return ret;
  204. }
  205. static void set_one_wpa_key(struct MrvlIEtype_keyParamSet *keyparam,
  206. struct enc_key *key)
  207. {
  208. lbs_deb_enter(LBS_DEB_CMD);
  209. if (key->flags & KEY_INFO_WPA_ENABLED)
  210. keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
  211. if (key->flags & KEY_INFO_WPA_UNICAST)
  212. keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
  213. if (key->flags & KEY_INFO_WPA_MCAST)
  214. keyparam->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
  215. keyparam->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
  216. keyparam->keytypeid = cpu_to_le16(key->type);
  217. keyparam->keylen = cpu_to_le16(key->len);
  218. memcpy(keyparam->key, key->key, key->len);
  219. /* Length field doesn't include the {type,length} header */
  220. keyparam->length = cpu_to_le16(sizeof(*keyparam) - 4);
  221. lbs_deb_leave(LBS_DEB_CMD);
  222. }
  223. int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action,
  224. struct assoc_request *assoc)
  225. {
  226. struct cmd_ds_802_11_key_material cmd;
  227. int ret = 0;
  228. int index = 0;
  229. lbs_deb_enter(LBS_DEB_CMD);
  230. cmd.action = cpu_to_le16(cmd_action);
  231. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  232. if (cmd_action == CMD_ACT_GET) {
  233. cmd.hdr.size = cpu_to_le16(sizeof(struct cmd_header) + 2);
  234. } else {
  235. memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet));
  236. if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc->flags)) {
  237. set_one_wpa_key(&cmd.keyParamSet[index],
  238. &assoc->wpa_unicast_key);
  239. index++;
  240. }
  241. if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc->flags)) {
  242. set_one_wpa_key(&cmd.keyParamSet[index],
  243. &assoc->wpa_mcast_key);
  244. index++;
  245. }
  246. /* The common header and as many keys as we included */
  247. cmd.hdr.size = cpu_to_le16(offsetof(typeof(cmd),
  248. keyParamSet[index]));
  249. }
  250. ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd);
  251. /* Copy the returned key to driver private data */
  252. if (!ret && cmd_action == CMD_ACT_GET) {
  253. void *buf_ptr = cmd.keyParamSet;
  254. void *resp_end = &(&cmd)[1];
  255. while (buf_ptr < resp_end) {
  256. struct MrvlIEtype_keyParamSet *keyparam = buf_ptr;
  257. struct enc_key *key;
  258. uint16_t param_set_len = le16_to_cpu(keyparam->length);
  259. uint16_t key_len = le16_to_cpu(keyparam->keylen);
  260. uint16_t key_flags = le16_to_cpu(keyparam->keyinfo);
  261. uint16_t key_type = le16_to_cpu(keyparam->keytypeid);
  262. void *end;
  263. end = (void *)keyparam + sizeof(keyparam->type)
  264. + sizeof(keyparam->length) + param_set_len;
  265. /* Make sure we don't access past the end of the IEs */
  266. if (end > resp_end)
  267. break;
  268. if (key_flags & KEY_INFO_WPA_UNICAST)
  269. key = &priv->wpa_unicast_key;
  270. else if (key_flags & KEY_INFO_WPA_MCAST)
  271. key = &priv->wpa_mcast_key;
  272. else
  273. break;
  274. /* Copy returned key into driver */
  275. memset(key, 0, sizeof(struct enc_key));
  276. if (key_len > sizeof(key->key))
  277. break;
  278. key->type = key_type;
  279. key->flags = key_flags;
  280. key->len = key_len;
  281. memcpy(key->key, keyparam->key, key->len);
  282. buf_ptr = end + 1;
  283. }
  284. }
  285. lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
  286. return ret;
  287. }
  288. static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
  289. {
  290. /* Bit Rate
  291. * 15:13 Reserved
  292. * 12 54 Mbps
  293. * 11 48 Mbps
  294. * 10 36 Mbps
  295. * 9 24 Mbps
  296. * 8 18 Mbps
  297. * 7 12 Mbps
  298. * 6 9 Mbps
  299. * 5 6 Mbps
  300. * 4 Reserved
  301. * 3 11 Mbps
  302. * 2 5.5 Mbps
  303. * 1 2 Mbps
  304. * 0 1 Mbps
  305. **/
  306. uint16_t ratemask;
  307. int i = lbs_data_rate_to_fw_index(rate);
  308. if (lower_rates_ok)
  309. ratemask = (0x1fef >> (12 - i));
  310. else
  311. ratemask = (1 << i);
  312. return cpu_to_le16(ratemask);
  313. }
  314. int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
  315. uint16_t cmd_action)
  316. {
  317. struct cmd_ds_802_11_rate_adapt_rateset cmd;
  318. int ret;
  319. lbs_deb_enter(LBS_DEB_CMD);
  320. if (!priv->cur_rate && !priv->enablehwauto)
  321. return -EINVAL;
  322. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  323. cmd.action = cpu_to_le16(cmd_action);
  324. cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
  325. cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
  326. ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
  327. if (!ret && cmd_action == CMD_ACT_GET)
  328. priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
  329. lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
  330. return ret;
  331. }
  332. /**
  333. * @brief Set the data rate
  334. *
  335. * @param priv A pointer to struct lbs_private structure
  336. * @param rate The desired data rate, or 0 to clear a locked rate
  337. *
  338. * @return 0 on success, error on failure
  339. */
  340. int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
  341. {
  342. struct cmd_ds_802_11_data_rate cmd;
  343. int ret = 0;
  344. lbs_deb_enter(LBS_DEB_CMD);
  345. memset(&cmd, 0, sizeof(cmd));
  346. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  347. if (rate > 0) {
  348. cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
  349. cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
  350. if (cmd.rates[0] == 0) {
  351. lbs_deb_cmd("DATA_RATE: invalid requested rate of"
  352. " 0x%02X\n", rate);
  353. ret = 0;
  354. goto out;
  355. }
  356. lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
  357. } else {
  358. cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
  359. lbs_deb_cmd("DATA_RATE: setting auto\n");
  360. }
  361. ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
  362. if (ret)
  363. goto out;
  364. lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof(cmd));
  365. /* FIXME: get actual rates FW can do if this command actually returns
  366. * all data rates supported.
  367. */
  368. priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
  369. lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
  370. out:
  371. lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
  372. return ret;
  373. }
  374. int lbs_cmd_802_11_rssi(struct lbs_private *priv,
  375. struct cmd_ds_command *cmd)
  376. {
  377. lbs_deb_enter(LBS_DEB_CMD);
  378. cmd->command = cpu_to_le16(CMD_802_11_RSSI);
  379. cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) +
  380. sizeof(struct cmd_header));
  381. cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
  382. /* reset Beacon SNR/NF/RSSI values */
  383. priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
  384. priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
  385. priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
  386. priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
  387. priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
  388. priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
  389. lbs_deb_leave(LBS_DEB_CMD);
  390. return 0;
  391. }
  392. int lbs_ret_802_11_rssi(struct lbs_private *priv,
  393. struct cmd_ds_command *resp)
  394. {
  395. struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
  396. lbs_deb_enter(LBS_DEB_CMD);
  397. /* store the non average value */
  398. priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
  399. priv->NF[TYPE_BEACON][TYPE_NOAVG] =
  400. get_unaligned_le16(&rssirsp->noisefloor);
  401. priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
  402. priv->NF[TYPE_BEACON][TYPE_AVG] =
  403. get_unaligned_le16(&rssirsp->avgnoisefloor);
  404. priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
  405. CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
  406. priv->NF[TYPE_BEACON][TYPE_NOAVG]);
  407. priv->RSSI[TYPE_BEACON][TYPE_AVG] =
  408. CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
  409. priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
  410. lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
  411. priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
  412. priv->RSSI[TYPE_BEACON][TYPE_AVG]);
  413. lbs_deb_leave(LBS_DEB_CMD);
  414. return 0;
  415. }
  416. int lbs_cmd_bcn_ctrl(struct lbs_private *priv,
  417. struct cmd_ds_command *cmd,
  418. u16 cmd_action)
  419. {
  420. struct cmd_ds_802_11_beacon_control
  421. *bcn_ctrl = &cmd->params.bcn_ctrl;
  422. lbs_deb_enter(LBS_DEB_CMD);
  423. cmd->size =
  424. cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
  425. + sizeof(struct cmd_header));
  426. cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
  427. bcn_ctrl->action = cpu_to_le16(cmd_action);
  428. bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
  429. bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
  430. lbs_deb_leave(LBS_DEB_CMD);
  431. return 0;
  432. }
  433. int lbs_ret_802_11_bcn_ctrl(struct lbs_private *priv,
  434. struct cmd_ds_command *resp)
  435. {
  436. struct cmd_ds_802_11_beacon_control *bcn_ctrl =
  437. &resp->params.bcn_ctrl;
  438. lbs_deb_enter(LBS_DEB_CMD);
  439. if (bcn_ctrl->action == CMD_ACT_GET) {
  440. priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
  441. priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
  442. }
  443. lbs_deb_enter(LBS_DEB_CMD);
  444. return 0;
  445. }
  446. static int lbs_assoc_post(struct lbs_private *priv,
  447. struct cmd_ds_802_11_associate_response *resp)
  448. {
  449. int ret = 0;
  450. union iwreq_data wrqu;
  451. struct bss_descriptor *bss;
  452. u16 status_code;
  453. lbs_deb_enter(LBS_DEB_ASSOC);
  454. if (!priv->in_progress_assoc_req) {
  455. lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
  456. ret = -1;
  457. goto done;
  458. }
  459. bss = &priv->in_progress_assoc_req->bss;
  460. /*
  461. * Older FW versions map the IEEE 802.11 Status Code in the association
  462. * response to the following values returned in resp->statuscode:
  463. *
  464. * IEEE Status Code Marvell Status Code
  465. * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
  466. * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
  467. * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
  468. * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
  469. * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
  470. * others -> 0x0003 ASSOC_RESULT_REFUSED
  471. *
  472. * Other response codes:
  473. * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
  474. * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
  475. * association response from the AP)
  476. */
  477. status_code = le16_to_cpu(resp->statuscode);
  478. if (priv->fwrelease < 0x09000000) {
  479. switch (status_code) {
  480. case 0x00:
  481. break;
  482. case 0x01:
  483. lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
  484. break;
  485. case 0x02:
  486. lbs_deb_assoc("ASSOC_RESP: internal timer "
  487. "expired while waiting for the AP\n");
  488. break;
  489. case 0x03:
  490. lbs_deb_assoc("ASSOC_RESP: association "
  491. "refused by AP\n");
  492. break;
  493. case 0x04:
  494. lbs_deb_assoc("ASSOC_RESP: authentication "
  495. "refused by AP\n");
  496. break;
  497. default:
  498. lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
  499. " unknown\n", status_code);
  500. break;
  501. }
  502. } else {
  503. /* v9+ returns the AP's association response */
  504. lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
  505. }
  506. if (status_code) {
  507. lbs_mac_event_disconnected(priv);
  508. ret = -1;
  509. goto done;
  510. }
  511. lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
  512. (void *) (resp + sizeof (resp->hdr)),
  513. le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
  514. /* Send a Media Connected event, according to the Spec */
  515. priv->connect_status = LBS_CONNECTED;
  516. /* Update current SSID and BSSID */
  517. memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
  518. priv->curbssparams.ssid_len = bss->ssid_len;
  519. memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
  520. priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
  521. priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
  522. memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
  523. memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
  524. priv->nextSNRNF = 0;
  525. priv->numSNRNF = 0;
  526. netif_carrier_on(priv->dev);
  527. if (!priv->tx_pending_len)
  528. netif_wake_queue(priv->dev);
  529. memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
  530. wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  531. wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
  532. done:
  533. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  534. return ret;
  535. }
  536. /**
  537. * @brief This function prepares an association-class command.
  538. *
  539. * @param priv A pointer to struct lbs_private structure
  540. * @param assoc_req The association request describing the BSS to associate
  541. * or reassociate with
  542. * @param command The actual command, either CMD_802_11_ASSOCIATE or
  543. * CMD_802_11_REASSOCIATE
  544. *
  545. * @return 0 or -1
  546. */
  547. static int lbs_associate(struct lbs_private *priv,
  548. struct assoc_request *assoc_req,
  549. u16 command)
  550. {
  551. struct cmd_ds_802_11_associate cmd;
  552. int ret = 0;
  553. struct bss_descriptor *bss = &assoc_req->bss;
  554. u8 *pos = &(cmd.iebuf[0]);
  555. u16 tmpcap, tmplen, tmpauth;
  556. struct mrvl_ie_ssid_param_set *ssid;
  557. struct mrvl_ie_ds_param_set *ds;
  558. struct mrvl_ie_cf_param_set *cf;
  559. struct mrvl_ie_rates_param_set *rates;
  560. struct mrvl_ie_rsn_param_set *rsn;
  561. struct mrvl_ie_auth_type *auth;
  562. lbs_deb_enter(LBS_DEB_ASSOC);
  563. BUG_ON((command != CMD_802_11_ASSOCIATE) &&
  564. (command != CMD_802_11_REASSOCIATE));
  565. memset(&cmd, 0, sizeof(cmd));
  566. cmd.hdr.command = cpu_to_le16(command);
  567. /* Fill in static fields */
  568. memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
  569. cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
  570. /* Capability info */
  571. tmpcap = (bss->capability & CAPINFO_MASK);
  572. if (bss->mode == IW_MODE_INFRA)
  573. tmpcap |= WLAN_CAPABILITY_ESS;
  574. cmd.capability = cpu_to_le16(tmpcap);
  575. lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
  576. /* SSID */
  577. ssid = (struct mrvl_ie_ssid_param_set *) pos;
  578. ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
  579. tmplen = bss->ssid_len;
  580. ssid->header.len = cpu_to_le16(tmplen);
  581. memcpy(ssid->ssid, bss->ssid, tmplen);
  582. pos += sizeof(ssid->header) + tmplen;
  583. ds = (struct mrvl_ie_ds_param_set *) pos;
  584. ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
  585. ds->header.len = cpu_to_le16(1);
  586. ds->channel = bss->phy.ds.channel;
  587. pos += sizeof(ds->header) + 1;
  588. cf = (struct mrvl_ie_cf_param_set *) pos;
  589. cf->header.type = cpu_to_le16(TLV_TYPE_CF);
  590. tmplen = sizeof(*cf) - sizeof (cf->header);
  591. cf->header.len = cpu_to_le16(tmplen);
  592. /* IE payload should be zeroed, firmware fills it in for us */
  593. pos += sizeof(*cf);
  594. rates = (struct mrvl_ie_rates_param_set *) pos;
  595. rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
  596. tmplen = min_t(u16, ARRAY_SIZE(bss->rates), MAX_RATES);
  597. memcpy(&rates->rates, &bss->rates, tmplen);
  598. if (get_common_rates(priv, rates->rates, &tmplen)) {
  599. ret = -1;
  600. goto done;
  601. }
  602. pos += sizeof(rates->header) + tmplen;
  603. rates->header.len = cpu_to_le16(tmplen);
  604. lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
  605. /* Copy the infra. association rates into Current BSS state structure */
  606. memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
  607. memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
  608. /* Set MSB on basic rates as the firmware requires, but _after_
  609. * copying to current bss rates.
  610. */
  611. lbs_set_basic_rate_flags(rates->rates, tmplen);
  612. /* Firmware v9+ indicate authentication suites as a TLV */
  613. if (priv->fwrelease >= 0x09000000) {
  614. auth = (struct mrvl_ie_auth_type *) pos;
  615. auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
  616. auth->header.len = cpu_to_le16(2);
  617. tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
  618. auth->auth = cpu_to_le16(tmpauth);
  619. pos += sizeof(auth->header) + 2;
  620. lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
  621. bss->bssid, priv->secinfo.auth_mode);
  622. }
  623. /* WPA/WPA2 IEs */
  624. if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
  625. rsn = (struct mrvl_ie_rsn_param_set *) pos;
  626. /* WPA_IE or WPA2_IE */
  627. rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
  628. tmplen = (u16) assoc_req->wpa_ie[1];
  629. rsn->header.len = cpu_to_le16(tmplen);
  630. memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
  631. lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
  632. sizeof(rsn->header) + tmplen);
  633. pos += sizeof(rsn->header) + tmplen;
  634. }
  635. cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
  636. (u16)(pos - (u8 *) &cmd.iebuf));
  637. /* update curbssparams */
  638. priv->channel = bss->phy.ds.channel;
  639. ret = lbs_cmd_with_response(priv, command, &cmd);
  640. if (ret == 0) {
  641. ret = lbs_assoc_post(priv,
  642. (struct cmd_ds_802_11_associate_response *) &cmd);
  643. }
  644. done:
  645. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  646. return ret;
  647. }
  648. /**
  649. * @brief Associate to a specific BSS discovered in a scan
  650. *
  651. * @param priv A pointer to struct lbs_private structure
  652. * @param assoc_req The association request describing the BSS to associate with
  653. *
  654. * @return 0-success, otherwise fail
  655. */
  656. static int lbs_try_associate(struct lbs_private *priv,
  657. struct assoc_request *assoc_req)
  658. {
  659. int ret;
  660. u8 preamble = RADIO_PREAMBLE_LONG;
  661. lbs_deb_enter(LBS_DEB_ASSOC);
  662. /* FW v9 and higher indicate authentication suites as a TLV in the
  663. * association command, not as a separate authentication command.
  664. */
  665. if (priv->fwrelease < 0x09000000) {
  666. ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
  667. priv->secinfo.auth_mode);
  668. if (ret)
  669. goto out;
  670. }
  671. /* Use short preamble only when both the BSS and firmware support it */
  672. if (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
  673. preamble = RADIO_PREAMBLE_SHORT;
  674. ret = lbs_set_radio(priv, preamble, 1);
  675. if (ret)
  676. goto out;
  677. ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
  678. out:
  679. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  680. return ret;
  681. }
  682. static int lbs_adhoc_post(struct lbs_private *priv,
  683. struct cmd_ds_802_11_ad_hoc_result *resp)
  684. {
  685. int ret = 0;
  686. u16 command = le16_to_cpu(resp->hdr.command);
  687. u16 result = le16_to_cpu(resp->hdr.result);
  688. union iwreq_data wrqu;
  689. struct bss_descriptor *bss;
  690. DECLARE_SSID_BUF(ssid);
  691. lbs_deb_enter(LBS_DEB_JOIN);
  692. if (!priv->in_progress_assoc_req) {
  693. lbs_deb_join("ADHOC_RESP: no in-progress association "
  694. "request\n");
  695. ret = -1;
  696. goto done;
  697. }
  698. bss = &priv->in_progress_assoc_req->bss;
  699. /*
  700. * Join result code 0 --> SUCCESS
  701. */
  702. if (result) {
  703. lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
  704. if (priv->connect_status == LBS_CONNECTED)
  705. lbs_mac_event_disconnected(priv);
  706. ret = -1;
  707. goto done;
  708. }
  709. /* Send a Media Connected event, according to the Spec */
  710. priv->connect_status = LBS_CONNECTED;
  711. if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
  712. /* Update the created network descriptor with the new BSSID */
  713. memcpy(bss->bssid, resp->bssid, ETH_ALEN);
  714. }
  715. /* Set the BSSID from the joined/started descriptor */
  716. memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
  717. /* Set the new SSID to current SSID */
  718. memcpy(&priv->curbssparams.ssid, &bss->ssid, IEEE80211_MAX_SSID_LEN);
  719. priv->curbssparams.ssid_len = bss->ssid_len;
  720. netif_carrier_on(priv->dev);
  721. if (!priv->tx_pending_len)
  722. netif_wake_queue(priv->dev);
  723. memset(&wrqu, 0, sizeof(wrqu));
  724. memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
  725. wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  726. wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
  727. lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
  728. print_ssid(ssid, bss->ssid, bss->ssid_len),
  729. priv->curbssparams.bssid,
  730. priv->channel);
  731. done:
  732. lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
  733. return ret;
  734. }
  735. /**
  736. * @brief Join an adhoc network found in a previous scan
  737. *
  738. * @param priv A pointer to struct lbs_private structure
  739. * @param assoc_req The association request describing the BSS to join
  740. *
  741. * @return 0 on success, error on failure
  742. */
  743. static int lbs_adhoc_join(struct lbs_private *priv,
  744. struct assoc_request *assoc_req)
  745. {
  746. struct cmd_ds_802_11_ad_hoc_join cmd;
  747. struct bss_descriptor *bss = &assoc_req->bss;
  748. u8 preamble = RADIO_PREAMBLE_LONG;
  749. DECLARE_SSID_BUF(ssid);
  750. u16 ratesize = 0;
  751. int ret = 0;
  752. lbs_deb_enter(LBS_DEB_ASSOC);
  753. lbs_deb_join("current SSID '%s', ssid length %u\n",
  754. print_ssid(ssid, priv->curbssparams.ssid,
  755. priv->curbssparams.ssid_len),
  756. priv->curbssparams.ssid_len);
  757. lbs_deb_join("requested ssid '%s', ssid length %u\n",
  758. print_ssid(ssid, bss->ssid, bss->ssid_len),
  759. bss->ssid_len);
  760. /* check if the requested SSID is already joined */
  761. if (priv->curbssparams.ssid_len &&
  762. !lbs_ssid_cmp(priv->curbssparams.ssid,
  763. priv->curbssparams.ssid_len,
  764. bss->ssid, bss->ssid_len) &&
  765. (priv->mode == IW_MODE_ADHOC) &&
  766. (priv->connect_status == LBS_CONNECTED)) {
  767. union iwreq_data wrqu;
  768. lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
  769. "current, not attempting to re-join");
  770. /* Send the re-association event though, because the association
  771. * request really was successful, even if just a null-op.
  772. */
  773. memset(&wrqu, 0, sizeof(wrqu));
  774. memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
  775. ETH_ALEN);
  776. wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  777. wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
  778. goto out;
  779. }
  780. /* Use short preamble only when both the BSS and firmware support it */
  781. if (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
  782. lbs_deb_join("AdhocJoin: Short preamble\n");
  783. preamble = RADIO_PREAMBLE_SHORT;
  784. }
  785. ret = lbs_set_radio(priv, preamble, 1);
  786. if (ret)
  787. goto out;
  788. lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
  789. lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
  790. priv->adhoccreate = 0;
  791. priv->channel = bss->channel;
  792. /* Build the join command */
  793. memset(&cmd, 0, sizeof(cmd));
  794. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  795. cmd.bss.type = CMD_BSS_TYPE_IBSS;
  796. cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
  797. memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
  798. memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
  799. memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
  800. memcpy(&cmd.bss.ibss, &bss->ss.ibss,
  801. sizeof(struct ieee_ie_ibss_param_set));
  802. cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
  803. lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
  804. bss->capability, CAPINFO_MASK);
  805. /* information on BSSID descriptor passed to FW */
  806. lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n",
  807. cmd.bss.bssid, cmd.bss.ssid);
  808. /* Only v8 and below support setting these */
  809. if (priv->fwrelease < 0x09000000) {
  810. /* failtimeout */
  811. cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
  812. /* probedelay */
  813. cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
  814. }
  815. /* Copy Data rates from the rates recorded in scan response */
  816. memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
  817. ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), ARRAY_SIZE (bss->rates));
  818. memcpy(cmd.bss.rates, bss->rates, ratesize);
  819. if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
  820. lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
  821. ret = -1;
  822. goto out;
  823. }
  824. /* Copy the ad-hoc creation rates into Current BSS state structure */
  825. memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
  826. memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize);
  827. /* Set MSB on basic rates as the firmware requires, but _after_
  828. * copying to current bss rates.
  829. */
  830. lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
  831. cmd.bss.ibss.atimwindow = bss->atimwindow;
  832. if (assoc_req->secinfo.wep_enabled) {
  833. u16 tmp = le16_to_cpu(cmd.bss.capability);
  834. tmp |= WLAN_CAPABILITY_PRIVACY;
  835. cmd.bss.capability = cpu_to_le16(tmp);
  836. }
  837. if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
  838. __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM);
  839. /* wake up first */
  840. ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
  841. CMD_ACT_SET, 0, 0,
  842. &local_ps_mode);
  843. if (ret) {
  844. ret = -1;
  845. goto out;
  846. }
  847. }
  848. ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
  849. if (ret == 0) {
  850. ret = lbs_adhoc_post(priv,
  851. (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
  852. }
  853. out:
  854. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  855. return ret;
  856. }
  857. /**
  858. * @brief Start an Adhoc Network
  859. *
  860. * @param priv A pointer to struct lbs_private structure
  861. * @param assoc_req The association request describing the BSS to start
  862. *
  863. * @return 0 on success, error on failure
  864. */
  865. static int lbs_adhoc_start(struct lbs_private *priv,
  866. struct assoc_request *assoc_req)
  867. {
  868. struct cmd_ds_802_11_ad_hoc_start cmd;
  869. u8 preamble = RADIO_PREAMBLE_SHORT;
  870. size_t ratesize = 0;
  871. u16 tmpcap = 0;
  872. int ret = 0;
  873. DECLARE_SSID_BUF(ssid);
  874. lbs_deb_enter(LBS_DEB_ASSOC);
  875. ret = lbs_set_radio(priv, preamble, 1);
  876. if (ret)
  877. goto out;
  878. /* Build the start command */
  879. memset(&cmd, 0, sizeof(cmd));
  880. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  881. memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len);
  882. lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n",
  883. print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
  884. assoc_req->ssid_len);
  885. cmd.bsstype = CMD_BSS_TYPE_IBSS;
  886. if (priv->beacon_period == 0)
  887. priv->beacon_period = MRVDRV_BEACON_INTERVAL;
  888. cmd.beaconperiod = cpu_to_le16(priv->beacon_period);
  889. WARN_ON(!assoc_req->channel);
  890. /* set Physical parameter set */
  891. cmd.ds.header.id = WLAN_EID_DS_PARAMS;
  892. cmd.ds.header.len = 1;
  893. cmd.ds.channel = assoc_req->channel;
  894. /* set IBSS parameter set */
  895. cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
  896. cmd.ibss.header.len = 2;
  897. cmd.ibss.atimwindow = cpu_to_le16(0);
  898. /* set capability info */
  899. tmpcap = WLAN_CAPABILITY_IBSS;
  900. if (assoc_req->secinfo.wep_enabled ||
  901. assoc_req->secinfo.WPAenabled ||
  902. assoc_req->secinfo.WPA2enabled) {
  903. lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
  904. tmpcap |= WLAN_CAPABILITY_PRIVACY;
  905. } else
  906. lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
  907. cmd.capability = cpu_to_le16(tmpcap);
  908. /* Only v8 and below support setting probe delay */
  909. if (priv->fwrelease < 0x09000000)
  910. cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
  911. ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates));
  912. memcpy(cmd.rates, lbs_bg_rates, ratesize);
  913. /* Copy the ad-hoc creating rates into Current BSS state structure */
  914. memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
  915. memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize);
  916. /* Set MSB on basic rates as the firmware requires, but _after_
  917. * copying to current bss rates.
  918. */
  919. lbs_set_basic_rate_flags(cmd.rates, ratesize);
  920. lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n",
  921. cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]);
  922. lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n",
  923. assoc_req->channel, assoc_req->band);
  924. priv->adhoccreate = 1;
  925. priv->mode = IW_MODE_ADHOC;
  926. ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
  927. if (ret == 0)
  928. ret = lbs_adhoc_post(priv,
  929. (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
  930. out:
  931. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  932. return ret;
  933. }
  934. /**
  935. * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode
  936. *
  937. * @param priv A pointer to struct lbs_private structure
  938. * @return 0 on success, or an error
  939. */
  940. int lbs_adhoc_stop(struct lbs_private *priv)
  941. {
  942. struct cmd_ds_802_11_ad_hoc_stop cmd;
  943. int ret;
  944. lbs_deb_enter(LBS_DEB_JOIN);
  945. memset(&cmd, 0, sizeof (cmd));
  946. cmd.hdr.size = cpu_to_le16 (sizeof (cmd));
  947. ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
  948. /* Clean up everything even if there was an error */
  949. lbs_mac_event_disconnected(priv);
  950. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  951. return ret;
  952. }
  953. static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
  954. struct bss_descriptor *match_bss)
  955. {
  956. if (!secinfo->wep_enabled &&
  957. !secinfo->WPAenabled && !secinfo->WPA2enabled &&
  958. match_bss->wpa_ie[0] != WLAN_EID_GENERIC &&
  959. match_bss->rsn_ie[0] != WLAN_EID_RSN &&
  960. !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
  961. return 1;
  962. else
  963. return 0;
  964. }
  965. static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
  966. struct bss_descriptor *match_bss)
  967. {
  968. if (secinfo->wep_enabled &&
  969. !secinfo->WPAenabled && !secinfo->WPA2enabled &&
  970. (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
  971. return 1;
  972. else
  973. return 0;
  974. }
  975. static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
  976. struct bss_descriptor *match_bss)
  977. {
  978. if (!secinfo->wep_enabled && secinfo->WPAenabled &&
  979. (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
  980. /* privacy bit may NOT be set in some APs like LinkSys WRT54G
  981. && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
  982. )
  983. return 1;
  984. else
  985. return 0;
  986. }
  987. static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
  988. struct bss_descriptor *match_bss)
  989. {
  990. if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
  991. (match_bss->rsn_ie[0] == WLAN_EID_RSN)
  992. /* privacy bit may NOT be set in some APs like LinkSys WRT54G
  993. (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
  994. )
  995. return 1;
  996. else
  997. return 0;
  998. }
  999. static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
  1000. struct bss_descriptor *match_bss)
  1001. {
  1002. if (!secinfo->wep_enabled &&
  1003. !secinfo->WPAenabled && !secinfo->WPA2enabled &&
  1004. (match_bss->wpa_ie[0] != WLAN_EID_GENERIC) &&
  1005. (match_bss->rsn_ie[0] != WLAN_EID_RSN) &&
  1006. (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
  1007. return 1;
  1008. else
  1009. return 0;
  1010. }
  1011. /**
  1012. * @brief Check if a scanned network compatible with the driver settings
  1013. *
  1014. * WEP WPA WPA2 ad-hoc encrypt Network
  1015. * enabled enabled enabled AES mode privacy WPA WPA2 Compatible
  1016. * 0 0 0 0 NONE 0 0 0 yes No security
  1017. * 1 0 0 0 NONE 1 0 0 yes Static WEP
  1018. * 0 1 0 0 x 1x 1 x yes WPA
  1019. * 0 0 1 0 x 1x x 1 yes WPA2
  1020. * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
  1021. * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
  1022. *
  1023. *
  1024. * @param priv A pointer to struct lbs_private
  1025. * @param index Index in scantable to check against current driver settings
  1026. * @param mode Network mode: Infrastructure or IBSS
  1027. *
  1028. * @return Index in scantable, or error code if negative
  1029. */
  1030. static int is_network_compatible(struct lbs_private *priv,
  1031. struct bss_descriptor *bss, uint8_t mode)
  1032. {
  1033. int matched = 0;
  1034. lbs_deb_enter(LBS_DEB_SCAN);
  1035. if (bss->mode != mode)
  1036. goto done;
  1037. matched = match_bss_no_security(&priv->secinfo, bss);
  1038. if (matched)
  1039. goto done;
  1040. matched = match_bss_static_wep(&priv->secinfo, bss);
  1041. if (matched)
  1042. goto done;
  1043. matched = match_bss_wpa(&priv->secinfo, bss);
  1044. if (matched) {
  1045. lbs_deb_scan("is_network_compatible() WPA: wpa_ie 0x%x "
  1046. "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
  1047. "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
  1048. priv->secinfo.wep_enabled ? "e" : "d",
  1049. priv->secinfo.WPAenabled ? "e" : "d",
  1050. priv->secinfo.WPA2enabled ? "e" : "d",
  1051. (bss->capability & WLAN_CAPABILITY_PRIVACY));
  1052. goto done;
  1053. }
  1054. matched = match_bss_wpa2(&priv->secinfo, bss);
  1055. if (matched) {
  1056. lbs_deb_scan("is_network_compatible() WPA2: wpa_ie 0x%x "
  1057. "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
  1058. "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
  1059. priv->secinfo.wep_enabled ? "e" : "d",
  1060. priv->secinfo.WPAenabled ? "e" : "d",
  1061. priv->secinfo.WPA2enabled ? "e" : "d",
  1062. (bss->capability & WLAN_CAPABILITY_PRIVACY));
  1063. goto done;
  1064. }
  1065. matched = match_bss_dynamic_wep(&priv->secinfo, bss);
  1066. if (matched) {
  1067. lbs_deb_scan("is_network_compatible() dynamic WEP: "
  1068. "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
  1069. bss->wpa_ie[0], bss->rsn_ie[0],
  1070. (bss->capability & WLAN_CAPABILITY_PRIVACY));
  1071. goto done;
  1072. }
  1073. /* bss security settings don't match those configured on card */
  1074. lbs_deb_scan("is_network_compatible() FAILED: wpa_ie 0x%x "
  1075. "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
  1076. bss->wpa_ie[0], bss->rsn_ie[0],
  1077. priv->secinfo.wep_enabled ? "e" : "d",
  1078. priv->secinfo.WPAenabled ? "e" : "d",
  1079. priv->secinfo.WPA2enabled ? "e" : "d",
  1080. (bss->capability & WLAN_CAPABILITY_PRIVACY));
  1081. done:
  1082. lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
  1083. return matched;
  1084. }
  1085. /**
  1086. * @brief This function finds a specific compatible BSSID in the scan list
  1087. *
  1088. * Used in association code
  1089. *
  1090. * @param priv A pointer to struct lbs_private
  1091. * @param bssid BSSID to find in the scan list
  1092. * @param mode Network mode: Infrastructure or IBSS
  1093. *
  1094. * @return index in BSSID list, or error return code (< 0)
  1095. */
  1096. static struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
  1097. uint8_t *bssid, uint8_t mode)
  1098. {
  1099. struct bss_descriptor *iter_bss;
  1100. struct bss_descriptor *found_bss = NULL;
  1101. lbs_deb_enter(LBS_DEB_SCAN);
  1102. if (!bssid)
  1103. goto out;
  1104. lbs_deb_hex(LBS_DEB_SCAN, "looking for", bssid, ETH_ALEN);
  1105. /* Look through the scan table for a compatible match. The loop will
  1106. * continue past a matched bssid that is not compatible in case there
  1107. * is an AP with multiple SSIDs assigned to the same BSSID
  1108. */
  1109. mutex_lock(&priv->lock);
  1110. list_for_each_entry(iter_bss, &priv->network_list, list) {
  1111. if (compare_ether_addr(iter_bss->bssid, bssid))
  1112. continue; /* bssid doesn't match */
  1113. switch (mode) {
  1114. case IW_MODE_INFRA:
  1115. case IW_MODE_ADHOC:
  1116. if (!is_network_compatible(priv, iter_bss, mode))
  1117. break;
  1118. found_bss = iter_bss;
  1119. break;
  1120. default:
  1121. found_bss = iter_bss;
  1122. break;
  1123. }
  1124. }
  1125. mutex_unlock(&priv->lock);
  1126. out:
  1127. lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
  1128. return found_bss;
  1129. }
  1130. /**
  1131. * @brief This function finds ssid in ssid list.
  1132. *
  1133. * Used in association code
  1134. *
  1135. * @param priv A pointer to struct lbs_private
  1136. * @param ssid SSID to find in the list
  1137. * @param bssid BSSID to qualify the SSID selection (if provided)
  1138. * @param mode Network mode: Infrastructure or IBSS
  1139. *
  1140. * @return index in BSSID list
  1141. */
  1142. static struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
  1143. uint8_t *ssid, uint8_t ssid_len,
  1144. uint8_t *bssid, uint8_t mode,
  1145. int channel)
  1146. {
  1147. u32 bestrssi = 0;
  1148. struct bss_descriptor *iter_bss = NULL;
  1149. struct bss_descriptor *found_bss = NULL;
  1150. struct bss_descriptor *tmp_oldest = NULL;
  1151. lbs_deb_enter(LBS_DEB_SCAN);
  1152. mutex_lock(&priv->lock);
  1153. list_for_each_entry(iter_bss, &priv->network_list, list) {
  1154. if (!tmp_oldest ||
  1155. (iter_bss->last_scanned < tmp_oldest->last_scanned))
  1156. tmp_oldest = iter_bss;
  1157. if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
  1158. ssid, ssid_len) != 0)
  1159. continue; /* ssid doesn't match */
  1160. if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
  1161. continue; /* bssid doesn't match */
  1162. if ((channel > 0) && (iter_bss->channel != channel))
  1163. continue; /* channel doesn't match */
  1164. switch (mode) {
  1165. case IW_MODE_INFRA:
  1166. case IW_MODE_ADHOC:
  1167. if (!is_network_compatible(priv, iter_bss, mode))
  1168. break;
  1169. if (bssid) {
  1170. /* Found requested BSSID */
  1171. found_bss = iter_bss;
  1172. goto out;
  1173. }
  1174. if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
  1175. bestrssi = SCAN_RSSI(iter_bss->rssi);
  1176. found_bss = iter_bss;
  1177. }
  1178. break;
  1179. case IW_MODE_AUTO:
  1180. default:
  1181. if (SCAN_RSSI(iter_bss->rssi) > bestrssi) {
  1182. bestrssi = SCAN_RSSI(iter_bss->rssi);
  1183. found_bss = iter_bss;
  1184. }
  1185. break;
  1186. }
  1187. }
  1188. out:
  1189. mutex_unlock(&priv->lock);
  1190. lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
  1191. return found_bss;
  1192. }
  1193. static int assoc_helper_essid(struct lbs_private *priv,
  1194. struct assoc_request * assoc_req)
  1195. {
  1196. int ret = 0;
  1197. struct bss_descriptor * bss;
  1198. int channel = -1;
  1199. DECLARE_SSID_BUF(ssid);
  1200. lbs_deb_enter(LBS_DEB_ASSOC);
  1201. /* FIXME: take channel into account when picking SSIDs if a channel
  1202. * is set.
  1203. */
  1204. if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
  1205. channel = assoc_req->channel;
  1206. lbs_deb_assoc("SSID '%s' requested\n",
  1207. print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len));
  1208. if (assoc_req->mode == IW_MODE_INFRA) {
  1209. lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
  1210. assoc_req->ssid_len);
  1211. bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
  1212. assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
  1213. if (bss != NULL) {
  1214. memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
  1215. ret = lbs_try_associate(priv, assoc_req);
  1216. } else {
  1217. lbs_deb_assoc("SSID not found; cannot associate\n");
  1218. }
  1219. } else if (assoc_req->mode == IW_MODE_ADHOC) {
  1220. /* Scan for the network, do not save previous results. Stale
  1221. * scan data will cause us to join a non-existant adhoc network
  1222. */
  1223. lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
  1224. assoc_req->ssid_len);
  1225. /* Search for the requested SSID in the scan table */
  1226. bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
  1227. assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
  1228. if (bss != NULL) {
  1229. lbs_deb_assoc("SSID found, will join\n");
  1230. memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
  1231. lbs_adhoc_join(priv, assoc_req);
  1232. } else {
  1233. /* else send START command */
  1234. lbs_deb_assoc("SSID not found, creating adhoc network\n");
  1235. memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
  1236. IEEE80211_MAX_SSID_LEN);
  1237. assoc_req->bss.ssid_len = assoc_req->ssid_len;
  1238. lbs_adhoc_start(priv, assoc_req);
  1239. }
  1240. }
  1241. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1242. return ret;
  1243. }
  1244. static int assoc_helper_bssid(struct lbs_private *priv,
  1245. struct assoc_request * assoc_req)
  1246. {
  1247. int ret = 0;
  1248. struct bss_descriptor * bss;
  1249. lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid);
  1250. /* Search for index position in list for requested MAC */
  1251. bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
  1252. assoc_req->mode);
  1253. if (bss == NULL) {
  1254. lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, "
  1255. "cannot associate.\n", assoc_req->bssid);
  1256. goto out;
  1257. }
  1258. memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
  1259. if (assoc_req->mode == IW_MODE_INFRA) {
  1260. ret = lbs_try_associate(priv, assoc_req);
  1261. lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
  1262. ret);
  1263. } else if (assoc_req->mode == IW_MODE_ADHOC) {
  1264. lbs_adhoc_join(priv, assoc_req);
  1265. }
  1266. out:
  1267. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1268. return ret;
  1269. }
  1270. static int assoc_helper_associate(struct lbs_private *priv,
  1271. struct assoc_request * assoc_req)
  1272. {
  1273. int ret = 0, done = 0;
  1274. lbs_deb_enter(LBS_DEB_ASSOC);
  1275. /* If we're given and 'any' BSSID, try associating based on SSID */
  1276. if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
  1277. if (compare_ether_addr(bssid_any, assoc_req->bssid) &&
  1278. compare_ether_addr(bssid_off, assoc_req->bssid)) {
  1279. ret = assoc_helper_bssid(priv, assoc_req);
  1280. done = 1;
  1281. }
  1282. }
  1283. if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
  1284. ret = assoc_helper_essid(priv, assoc_req);
  1285. }
  1286. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1287. return ret;
  1288. }
  1289. static int assoc_helper_mode(struct lbs_private *priv,
  1290. struct assoc_request * assoc_req)
  1291. {
  1292. int ret = 0;
  1293. lbs_deb_enter(LBS_DEB_ASSOC);
  1294. if (assoc_req->mode == priv->mode)
  1295. goto done;
  1296. if (assoc_req->mode == IW_MODE_INFRA) {
  1297. if (priv->psstate != PS_STATE_FULL_POWER)
  1298. lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
  1299. priv->psmode = LBS802_11POWERMODECAM;
  1300. }
  1301. priv->mode = assoc_req->mode;
  1302. ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE,
  1303. assoc_req->mode == IW_MODE_ADHOC ? 2 : 1);
  1304. done:
  1305. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1306. return ret;
  1307. }
  1308. static int assoc_helper_channel(struct lbs_private *priv,
  1309. struct assoc_request * assoc_req)
  1310. {
  1311. int ret = 0;
  1312. lbs_deb_enter(LBS_DEB_ASSOC);
  1313. ret = lbs_update_channel(priv);
  1314. if (ret) {
  1315. lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
  1316. goto done;
  1317. }
  1318. if (assoc_req->channel == priv->channel)
  1319. goto done;
  1320. if (priv->mesh_dev) {
  1321. /* Change mesh channel first; 21.p21 firmware won't let
  1322. you change channel otherwise (even though it'll return
  1323. an error to this */
  1324. lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
  1325. assoc_req->channel);
  1326. }
  1327. lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
  1328. priv->channel, assoc_req->channel);
  1329. ret = lbs_set_channel(priv, assoc_req->channel);
  1330. if (ret < 0)
  1331. lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
  1332. /* FIXME: shouldn't need to grab the channel _again_ after setting
  1333. * it since the firmware is supposed to return the new channel, but
  1334. * whatever... */
  1335. ret = lbs_update_channel(priv);
  1336. if (ret) {
  1337. lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
  1338. goto done;
  1339. }
  1340. if (assoc_req->channel != priv->channel) {
  1341. lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
  1342. assoc_req->channel);
  1343. goto restore_mesh;
  1344. }
  1345. if (assoc_req->secinfo.wep_enabled &&
  1346. (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
  1347. assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)) {
  1348. /* Make sure WEP keys are re-sent to firmware */
  1349. set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
  1350. }
  1351. /* Must restart/rejoin adhoc networks after channel change */
  1352. set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
  1353. restore_mesh:
  1354. if (priv->mesh_dev)
  1355. lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
  1356. priv->channel);
  1357. done:
  1358. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1359. return ret;
  1360. }
  1361. static int assoc_helper_wep_keys(struct lbs_private *priv,
  1362. struct assoc_request *assoc_req)
  1363. {
  1364. int i;
  1365. int ret = 0;
  1366. lbs_deb_enter(LBS_DEB_ASSOC);
  1367. /* Set or remove WEP keys */
  1368. if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
  1369. assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
  1370. ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
  1371. else
  1372. ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
  1373. if (ret)
  1374. goto out;
  1375. /* enable/disable the MAC's WEP packet filter */
  1376. if (assoc_req->secinfo.wep_enabled)
  1377. priv->mac_control |= CMD_ACT_MAC_WEP_ENABLE;
  1378. else
  1379. priv->mac_control &= ~CMD_ACT_MAC_WEP_ENABLE;
  1380. lbs_set_mac_control(priv);
  1381. mutex_lock(&priv->lock);
  1382. /* Copy WEP keys into priv wep key fields */
  1383. for (i = 0; i < 4; i++) {
  1384. memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
  1385. sizeof(struct enc_key));
  1386. }
  1387. priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
  1388. mutex_unlock(&priv->lock);
  1389. out:
  1390. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1391. return ret;
  1392. }
  1393. static int assoc_helper_secinfo(struct lbs_private *priv,
  1394. struct assoc_request * assoc_req)
  1395. {
  1396. int ret = 0;
  1397. uint16_t do_wpa;
  1398. uint16_t rsn = 0;
  1399. lbs_deb_enter(LBS_DEB_ASSOC);
  1400. memcpy(&priv->secinfo, &assoc_req->secinfo,
  1401. sizeof(struct lbs_802_11_security));
  1402. lbs_set_mac_control(priv);
  1403. /* If RSN is already enabled, don't try to enable it again, since
  1404. * ENABLE_RSN resets internal state machines and will clobber the
  1405. * 4-way WPA handshake.
  1406. */
  1407. /* Get RSN enabled/disabled */
  1408. ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
  1409. if (ret) {
  1410. lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
  1411. goto out;
  1412. }
  1413. /* Don't re-enable RSN if it's already enabled */
  1414. do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
  1415. if (do_wpa == rsn)
  1416. goto out;
  1417. /* Set RSN enabled/disabled */
  1418. ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
  1419. out:
  1420. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1421. return ret;
  1422. }
  1423. static int assoc_helper_wpa_keys(struct lbs_private *priv,
  1424. struct assoc_request * assoc_req)
  1425. {
  1426. int ret = 0;
  1427. unsigned int flags = assoc_req->flags;
  1428. lbs_deb_enter(LBS_DEB_ASSOC);
  1429. /* Work around older firmware bug where WPA unicast and multicast
  1430. * keys must be set independently. Seen in SDIO parts with firmware
  1431. * version 5.0.11p0.
  1432. */
  1433. if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
  1434. clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
  1435. ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
  1436. assoc_req->flags = flags;
  1437. }
  1438. if (ret)
  1439. goto out;
  1440. memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
  1441. sizeof(struct enc_key));
  1442. if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
  1443. clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
  1444. ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
  1445. assoc_req->flags = flags;
  1446. memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
  1447. sizeof(struct enc_key));
  1448. }
  1449. out:
  1450. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1451. return ret;
  1452. }
  1453. static int assoc_helper_wpa_ie(struct lbs_private *priv,
  1454. struct assoc_request * assoc_req)
  1455. {
  1456. int ret = 0;
  1457. lbs_deb_enter(LBS_DEB_ASSOC);
  1458. if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
  1459. memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
  1460. priv->wpa_ie_len = assoc_req->wpa_ie_len;
  1461. } else {
  1462. memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
  1463. priv->wpa_ie_len = 0;
  1464. }
  1465. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1466. return ret;
  1467. }
  1468. static int should_deauth_infrastructure(struct lbs_private *priv,
  1469. struct assoc_request * assoc_req)
  1470. {
  1471. int ret = 0;
  1472. if (priv->connect_status != LBS_CONNECTED)
  1473. return 0;
  1474. lbs_deb_enter(LBS_DEB_ASSOC);
  1475. if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
  1476. lbs_deb_assoc("Deauthenticating due to new SSID\n");
  1477. ret = 1;
  1478. goto out;
  1479. }
  1480. if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
  1481. if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
  1482. lbs_deb_assoc("Deauthenticating due to new security\n");
  1483. ret = 1;
  1484. goto out;
  1485. }
  1486. }
  1487. if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
  1488. lbs_deb_assoc("Deauthenticating due to new BSSID\n");
  1489. ret = 1;
  1490. goto out;
  1491. }
  1492. if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
  1493. lbs_deb_assoc("Deauthenticating due to channel switch\n");
  1494. ret = 1;
  1495. goto out;
  1496. }
  1497. /* FIXME: deal with 'auto' mode somehow */
  1498. if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
  1499. if (assoc_req->mode != IW_MODE_INFRA) {
  1500. lbs_deb_assoc("Deauthenticating due to leaving "
  1501. "infra mode\n");
  1502. ret = 1;
  1503. goto out;
  1504. }
  1505. }
  1506. out:
  1507. lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
  1508. return ret;
  1509. }
  1510. static int should_stop_adhoc(struct lbs_private *priv,
  1511. struct assoc_request * assoc_req)
  1512. {
  1513. lbs_deb_enter(LBS_DEB_ASSOC);
  1514. if (priv->connect_status != LBS_CONNECTED)
  1515. return 0;
  1516. if (lbs_ssid_cmp(priv->curbssparams.ssid,
  1517. priv->curbssparams.ssid_len,
  1518. assoc_req->ssid, assoc_req->ssid_len) != 0)
  1519. return 1;
  1520. /* FIXME: deal with 'auto' mode somehow */
  1521. if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
  1522. if (assoc_req->mode != IW_MODE_ADHOC)
  1523. return 1;
  1524. }
  1525. if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
  1526. if (assoc_req->channel != priv->channel)
  1527. return 1;
  1528. }
  1529. lbs_deb_leave(LBS_DEB_ASSOC);
  1530. return 0;
  1531. }
  1532. /**
  1533. * @brief This function finds the best SSID in the Scan List
  1534. *
  1535. * Search the scan table for the best SSID that also matches the current
  1536. * adapter network preference (infrastructure or adhoc)
  1537. *
  1538. * @param priv A pointer to struct lbs_private
  1539. *
  1540. * @return index in BSSID list
  1541. */
  1542. static struct bss_descriptor *lbs_find_best_ssid_in_list(
  1543. struct lbs_private *priv, uint8_t mode)
  1544. {
  1545. uint8_t bestrssi = 0;
  1546. struct bss_descriptor *iter_bss;
  1547. struct bss_descriptor *best_bss = NULL;
  1548. lbs_deb_enter(LBS_DEB_SCAN);
  1549. mutex_lock(&priv->lock);
  1550. list_for_each_entry(iter_bss, &priv->network_list, list) {
  1551. switch (mode) {
  1552. case IW_MODE_INFRA:
  1553. case IW_MODE_ADHOC:
  1554. if (!is_network_compatible(priv, iter_bss, mode))
  1555. break;
  1556. if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
  1557. break;
  1558. bestrssi = SCAN_RSSI(iter_bss->rssi);
  1559. best_bss = iter_bss;
  1560. break;
  1561. case IW_MODE_AUTO:
  1562. default:
  1563. if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
  1564. break;
  1565. bestrssi = SCAN_RSSI(iter_bss->rssi);
  1566. best_bss = iter_bss;
  1567. break;
  1568. }
  1569. }
  1570. mutex_unlock(&priv->lock);
  1571. lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
  1572. return best_bss;
  1573. }
  1574. /**
  1575. * @brief Find the best AP
  1576. *
  1577. * Used from association worker.
  1578. *
  1579. * @param priv A pointer to struct lbs_private structure
  1580. * @param pSSID A pointer to AP's ssid
  1581. *
  1582. * @return 0--success, otherwise--fail
  1583. */
  1584. static int lbs_find_best_network_ssid(struct lbs_private *priv,
  1585. uint8_t *out_ssid, uint8_t *out_ssid_len, uint8_t preferred_mode,
  1586. uint8_t *out_mode)
  1587. {
  1588. int ret = -1;
  1589. struct bss_descriptor *found;
  1590. lbs_deb_enter(LBS_DEB_SCAN);
  1591. priv->scan_ssid_len = 0;
  1592. lbs_scan_networks(priv, 1);
  1593. if (priv->surpriseremoved)
  1594. goto out;
  1595. found = lbs_find_best_ssid_in_list(priv, preferred_mode);
  1596. if (found && (found->ssid_len > 0)) {
  1597. memcpy(out_ssid, &found->ssid, IEEE80211_MAX_SSID_LEN);
  1598. *out_ssid_len = found->ssid_len;
  1599. *out_mode = found->mode;
  1600. ret = 0;
  1601. }
  1602. out:
  1603. lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
  1604. return ret;
  1605. }
  1606. void lbs_association_worker(struct work_struct *work)
  1607. {
  1608. struct lbs_private *priv = container_of(work, struct lbs_private,
  1609. assoc_work.work);
  1610. struct assoc_request * assoc_req = NULL;
  1611. int ret = 0;
  1612. int find_any_ssid = 0;
  1613. DECLARE_SSID_BUF(ssid);
  1614. lbs_deb_enter(LBS_DEB_ASSOC);
  1615. mutex_lock(&priv->lock);
  1616. assoc_req = priv->pending_assoc_req;
  1617. priv->pending_assoc_req = NULL;
  1618. priv->in_progress_assoc_req = assoc_req;
  1619. mutex_unlock(&priv->lock);
  1620. if (!assoc_req)
  1621. goto done;
  1622. lbs_deb_assoc(
  1623. "Association Request:\n"
  1624. " flags: 0x%08lx\n"
  1625. " SSID: '%s'\n"
  1626. " chann: %d\n"
  1627. " band: %d\n"
  1628. " mode: %d\n"
  1629. " BSSID: %pM\n"
  1630. " secinfo: %s%s%s\n"
  1631. " auth_mode: %d\n",
  1632. assoc_req->flags,
  1633. print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len),
  1634. assoc_req->channel, assoc_req->band, assoc_req->mode,
  1635. assoc_req->bssid,
  1636. assoc_req->secinfo.WPAenabled ? " WPA" : "",
  1637. assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
  1638. assoc_req->secinfo.wep_enabled ? " WEP" : "",
  1639. assoc_req->secinfo.auth_mode);
  1640. /* If 'any' SSID was specified, find an SSID to associate with */
  1641. if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) &&
  1642. !assoc_req->ssid_len)
  1643. find_any_ssid = 1;
  1644. /* But don't use 'any' SSID if there's a valid locked BSSID to use */
  1645. if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
  1646. if (compare_ether_addr(assoc_req->bssid, bssid_any) &&
  1647. compare_ether_addr(assoc_req->bssid, bssid_off))
  1648. find_any_ssid = 0;
  1649. }
  1650. if (find_any_ssid) {
  1651. u8 new_mode = assoc_req->mode;
  1652. ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
  1653. &assoc_req->ssid_len, assoc_req->mode, &new_mode);
  1654. if (ret) {
  1655. lbs_deb_assoc("Could not find best network\n");
  1656. ret = -ENETUNREACH;
  1657. goto out;
  1658. }
  1659. /* Ensure we switch to the mode of the AP */
  1660. if (assoc_req->mode == IW_MODE_AUTO) {
  1661. set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
  1662. assoc_req->mode = new_mode;
  1663. }
  1664. }
  1665. /*
  1666. * Check if the attributes being changing require deauthentication
  1667. * from the currently associated infrastructure access point.
  1668. */
  1669. if (priv->mode == IW_MODE_INFRA) {
  1670. if (should_deauth_infrastructure(priv, assoc_req)) {
  1671. ret = lbs_cmd_80211_deauthenticate(priv,
  1672. priv->curbssparams.bssid,
  1673. WLAN_REASON_DEAUTH_LEAVING);
  1674. if (ret) {
  1675. lbs_deb_assoc("Deauthentication due to new "
  1676. "configuration request failed: %d\n",
  1677. ret);
  1678. }
  1679. }
  1680. } else if (priv->mode == IW_MODE_ADHOC) {
  1681. if (should_stop_adhoc(priv, assoc_req)) {
  1682. ret = lbs_adhoc_stop(priv);
  1683. if (ret) {
  1684. lbs_deb_assoc("Teardown of AdHoc network due to "
  1685. "new configuration request failed: %d\n",
  1686. ret);
  1687. }
  1688. }
  1689. }
  1690. /* Send the various configuration bits to the firmware */
  1691. if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
  1692. ret = assoc_helper_mode(priv, assoc_req);
  1693. if (ret)
  1694. goto out;
  1695. }
  1696. if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
  1697. ret = assoc_helper_channel(priv, assoc_req);
  1698. if (ret)
  1699. goto out;
  1700. }
  1701. if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
  1702. ret = assoc_helper_secinfo(priv, assoc_req);
  1703. if (ret)
  1704. goto out;
  1705. }
  1706. if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
  1707. ret = assoc_helper_wpa_ie(priv, assoc_req);
  1708. if (ret)
  1709. goto out;
  1710. }
  1711. /*
  1712. * v10 FW wants WPA keys to be set/cleared before WEP key operations,
  1713. * otherwise it will fail to correctly associate to WEP networks.
  1714. * Other firmware versions don't appear to care.
  1715. */
  1716. if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) ||
  1717. test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
  1718. ret = assoc_helper_wpa_keys(priv, assoc_req);
  1719. if (ret)
  1720. goto out;
  1721. }
  1722. if (test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) ||
  1723. test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
  1724. ret = assoc_helper_wep_keys(priv, assoc_req);
  1725. if (ret)
  1726. goto out;
  1727. }
  1728. /* SSID/BSSID should be the _last_ config option set, because they
  1729. * trigger the association attempt.
  1730. */
  1731. if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) ||
  1732. test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
  1733. int success = 1;
  1734. ret = assoc_helper_associate(priv, assoc_req);
  1735. if (ret) {
  1736. lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
  1737. ret);
  1738. success = 0;
  1739. }
  1740. if (priv->connect_status != LBS_CONNECTED) {
  1741. lbs_deb_assoc("ASSOC: association unsuccessful, "
  1742. "not connected\n");
  1743. success = 0;
  1744. }
  1745. if (success) {
  1746. lbs_deb_assoc("associated to %pM\n",
  1747. priv->curbssparams.bssid);
  1748. lbs_prepare_and_send_command(priv,
  1749. CMD_802_11_RSSI,
  1750. 0, CMD_OPTION_WAITFORRSP, 0, NULL);
  1751. } else {
  1752. ret = -1;
  1753. }
  1754. }
  1755. out:
  1756. if (ret) {
  1757. lbs_deb_assoc("ASSOC: reconfiguration attempt unsuccessful: %d\n",
  1758. ret);
  1759. }
  1760. mutex_lock(&priv->lock);
  1761. priv->in_progress_assoc_req = NULL;
  1762. mutex_unlock(&priv->lock);
  1763. kfree(assoc_req);
  1764. done:
  1765. lbs_deb_leave(LBS_DEB_ASSOC);
  1766. }
  1767. /*
  1768. * Caller MUST hold any necessary locks
  1769. */
  1770. struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
  1771. {
  1772. struct assoc_request * assoc_req;
  1773. lbs_deb_enter(LBS_DEB_ASSOC);
  1774. if (!priv->pending_assoc_req) {
  1775. priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
  1776. GFP_KERNEL);
  1777. if (!priv->pending_assoc_req) {
  1778. lbs_pr_info("Not enough memory to allocate association"
  1779. " request!\n");
  1780. return NULL;
  1781. }
  1782. }
  1783. /* Copy current configuration attributes to the association request,
  1784. * but don't overwrite any that are already set.
  1785. */
  1786. assoc_req = priv->pending_assoc_req;
  1787. if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
  1788. memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
  1789. IEEE80211_MAX_SSID_LEN);
  1790. assoc_req->ssid_len = priv->curbssparams.ssid_len;
  1791. }
  1792. if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
  1793. assoc_req->channel = priv->channel;
  1794. if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
  1795. assoc_req->band = priv->curbssparams.band;
  1796. if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
  1797. assoc_req->mode = priv->mode;
  1798. if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
  1799. memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
  1800. ETH_ALEN);
  1801. }
  1802. if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
  1803. int i;
  1804. for (i = 0; i < 4; i++) {
  1805. memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
  1806. sizeof(struct enc_key));
  1807. }
  1808. }
  1809. if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
  1810. assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
  1811. if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
  1812. memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
  1813. sizeof(struct enc_key));
  1814. }
  1815. if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
  1816. memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
  1817. sizeof(struct enc_key));
  1818. }
  1819. if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
  1820. memcpy(&assoc_req->secinfo, &priv->secinfo,
  1821. sizeof(struct lbs_802_11_security));
  1822. }
  1823. if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
  1824. memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
  1825. MAX_WPA_IE_LEN);
  1826. assoc_req->wpa_ie_len = priv->wpa_ie_len;
  1827. }
  1828. lbs_deb_leave(LBS_DEB_ASSOC);
  1829. return assoc_req;
  1830. }
  1831. /**
  1832. * @brief Deauthenticate from a specific BSS
  1833. *
  1834. * @param priv A pointer to struct lbs_private structure
  1835. * @param bssid The specific BSS to deauthenticate from
  1836. * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating
  1837. *
  1838. * @return 0 on success, error on failure
  1839. */
  1840. int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
  1841. u16 reason)
  1842. {
  1843. struct cmd_ds_802_11_deauthenticate cmd;
  1844. int ret;
  1845. lbs_deb_enter(LBS_DEB_JOIN);
  1846. memset(&cmd, 0, sizeof(cmd));
  1847. cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  1848. memcpy(cmd.macaddr, &bssid[0], ETH_ALEN);
  1849. cmd.reasoncode = cpu_to_le16(reason);
  1850. ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd);
  1851. /* Clean up everything even if there was an error; can't assume that
  1852. * we're still authenticated to the AP after trying to deauth.
  1853. */
  1854. lbs_mac_event_disconnected(priv);
  1855. lbs_deb_leave(LBS_DEB_JOIN);
  1856. return ret;
  1857. }