assoc.c 61 KB

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