rtllib_softmac_wx.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /* IEEE 802.11 SoftMAC layer
  2. * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  3. *
  4. * Mostly extracted from the rtl8180-sa2400 driver for the
  5. * in-kernel generic ieee802.11 stack.
  6. *
  7. * Some pieces of code might be stolen from ipw2100 driver
  8. * copyright of who own it's copyright ;-)
  9. *
  10. * PS wx handler mostly stolen from hostap, copyright who
  11. * own it's copyright ;-)
  12. *
  13. * released under the GPL
  14. */
  15. #include <linux/etherdevice.h>
  16. #include "rtllib.h"
  17. #include "dot11d.h"
  18. /* FIXME: add A freqs */
  19. const long rtllib_wlan_frequencies[] = {
  20. 2412, 2417, 2422, 2427,
  21. 2432, 2437, 2442, 2447,
  22. 2452, 2457, 2462, 2467,
  23. 2472, 2484
  24. };
  25. EXPORT_SYMBOL(rtllib_wlan_frequencies);
  26. int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
  27. union iwreq_data *wrqu, char *b)
  28. {
  29. int ret;
  30. struct iw_freq *fwrq = &wrqu->freq;
  31. down(&ieee->wx_sem);
  32. if (ieee->iw_mode == IW_MODE_INFRA) {
  33. ret = 0;
  34. goto out;
  35. }
  36. /* if setting by freq convert to channel */
  37. if (fwrq->e == 1) {
  38. if ((fwrq->m >= (int) 2.412e8 &&
  39. fwrq->m <= (int) 2.487e8)) {
  40. int f = fwrq->m / 100000;
  41. int c = 0;
  42. while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
  43. c++;
  44. /* hack to fall through */
  45. fwrq->e = 0;
  46. fwrq->m = c + 1;
  47. }
  48. }
  49. if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
  50. ret = -EOPNOTSUPP;
  51. goto out;
  52. } else { /* Set the channel */
  53. if (ieee->active_channel_map[fwrq->m] != 1) {
  54. ret = -EINVAL;
  55. goto out;
  56. }
  57. ieee->current_network.channel = fwrq->m;
  58. ieee->set_chan(ieee->dev, ieee->current_network.channel);
  59. if (ieee->iw_mode == IW_MODE_ADHOC ||
  60. ieee->iw_mode == IW_MODE_MASTER)
  61. if (ieee->state == RTLLIB_LINKED) {
  62. rtllib_stop_send_beacons(ieee);
  63. rtllib_start_send_beacons(ieee);
  64. }
  65. }
  66. ret = 0;
  67. out:
  68. up(&ieee->wx_sem);
  69. return ret;
  70. }
  71. EXPORT_SYMBOL(rtllib_wx_set_freq);
  72. int rtllib_wx_get_freq(struct rtllib_device *ieee,
  73. struct iw_request_info *a,
  74. union iwreq_data *wrqu, char *b)
  75. {
  76. struct iw_freq *fwrq = &wrqu->freq;
  77. if (ieee->current_network.channel == 0)
  78. return -1;
  79. fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
  80. 100000;
  81. fwrq->e = 1;
  82. return 0;
  83. }
  84. EXPORT_SYMBOL(rtllib_wx_get_freq);
  85. int rtllib_wx_get_wap(struct rtllib_device *ieee,
  86. struct iw_request_info *info,
  87. union iwreq_data *wrqu, char *extra)
  88. {
  89. unsigned long flags;
  90. wrqu->ap_addr.sa_family = ARPHRD_ETHER;
  91. if (ieee->iw_mode == IW_MODE_MONITOR)
  92. return -1;
  93. /* We want avoid to give to the user inconsistent infos*/
  94. spin_lock_irqsave(&ieee->lock, flags);
  95. if (ieee->state != RTLLIB_LINKED &&
  96. ieee->state != RTLLIB_LINKED_SCANNING &&
  97. ieee->wap_set == 0)
  98. eth_zero_addr(wrqu->ap_addr.sa_data);
  99. else
  100. memcpy(wrqu->ap_addr.sa_data,
  101. ieee->current_network.bssid, ETH_ALEN);
  102. spin_unlock_irqrestore(&ieee->lock, flags);
  103. return 0;
  104. }
  105. EXPORT_SYMBOL(rtllib_wx_get_wap);
  106. int rtllib_wx_set_wap(struct rtllib_device *ieee,
  107. struct iw_request_info *info,
  108. union iwreq_data *awrq,
  109. char *extra)
  110. {
  111. int ret = 0;
  112. unsigned long flags;
  113. short ifup = ieee->proto_started;
  114. struct sockaddr *temp = (struct sockaddr *)awrq;
  115. rtllib_stop_scan_syncro(ieee);
  116. down(&ieee->wx_sem);
  117. /* use ifconfig hw ether */
  118. if (ieee->iw_mode == IW_MODE_MASTER) {
  119. ret = -1;
  120. goto out;
  121. }
  122. if (temp->sa_family != ARPHRD_ETHER) {
  123. ret = -EINVAL;
  124. goto out;
  125. }
  126. if (is_zero_ether_addr(temp->sa_data)) {
  127. spin_lock_irqsave(&ieee->lock, flags);
  128. ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
  129. ieee->wap_set = 0;
  130. spin_unlock_irqrestore(&ieee->lock, flags);
  131. ret = -1;
  132. goto out;
  133. }
  134. if (ifup)
  135. rtllib_stop_protocol(ieee, true);
  136. /* just to avoid to give inconsistent infos in the
  137. * get wx method. not really needed otherwise
  138. */
  139. spin_lock_irqsave(&ieee->lock, flags);
  140. ieee->cannot_notify = false;
  141. ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
  142. ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
  143. spin_unlock_irqrestore(&ieee->lock, flags);
  144. if (ifup)
  145. rtllib_start_protocol(ieee);
  146. out:
  147. up(&ieee->wx_sem);
  148. return ret;
  149. }
  150. EXPORT_SYMBOL(rtllib_wx_set_wap);
  151. int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
  152. union iwreq_data *wrqu, char *b)
  153. {
  154. int len, ret = 0;
  155. unsigned long flags;
  156. if (ieee->iw_mode == IW_MODE_MONITOR)
  157. return -1;
  158. /* We want avoid to give to the user inconsistent infos*/
  159. spin_lock_irqsave(&ieee->lock, flags);
  160. if (ieee->current_network.ssid[0] == '\0' ||
  161. ieee->current_network.ssid_len == 0) {
  162. ret = -1;
  163. goto out;
  164. }
  165. if (ieee->state != RTLLIB_LINKED &&
  166. ieee->state != RTLLIB_LINKED_SCANNING &&
  167. ieee->ssid_set == 0) {
  168. ret = -1;
  169. goto out;
  170. }
  171. len = ieee->current_network.ssid_len;
  172. wrqu->essid.length = len;
  173. strncpy(b, ieee->current_network.ssid, len);
  174. wrqu->essid.flags = 1;
  175. out:
  176. spin_unlock_irqrestore(&ieee->lock, flags);
  177. return ret;
  178. }
  179. EXPORT_SYMBOL(rtllib_wx_get_essid);
  180. int rtllib_wx_set_rate(struct rtllib_device *ieee,
  181. struct iw_request_info *info,
  182. union iwreq_data *wrqu, char *extra)
  183. {
  184. u32 target_rate = wrqu->bitrate.value;
  185. ieee->rate = target_rate/100000;
  186. return 0;
  187. }
  188. EXPORT_SYMBOL(rtllib_wx_set_rate);
  189. int rtllib_wx_get_rate(struct rtllib_device *ieee,
  190. struct iw_request_info *info,
  191. union iwreq_data *wrqu, char *extra)
  192. {
  193. u32 tmp_rate = 0;
  194. tmp_rate = TxCountToDataRate(ieee,
  195. ieee->softmac_stats.CurrentShowTxate);
  196. wrqu->bitrate.value = tmp_rate * 500000;
  197. return 0;
  198. }
  199. EXPORT_SYMBOL(rtllib_wx_get_rate);
  200. int rtllib_wx_set_rts(struct rtllib_device *ieee,
  201. struct iw_request_info *info,
  202. union iwreq_data *wrqu, char *extra)
  203. {
  204. if (wrqu->rts.disabled || !wrqu->rts.fixed)
  205. ieee->rts = DEFAULT_RTS_THRESHOLD;
  206. else {
  207. if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
  208. wrqu->rts.value > MAX_RTS_THRESHOLD)
  209. return -EINVAL;
  210. ieee->rts = wrqu->rts.value;
  211. }
  212. return 0;
  213. }
  214. EXPORT_SYMBOL(rtllib_wx_set_rts);
  215. int rtllib_wx_get_rts(struct rtllib_device *ieee,
  216. struct iw_request_info *info,
  217. union iwreq_data *wrqu, char *extra)
  218. {
  219. wrqu->rts.value = ieee->rts;
  220. wrqu->rts.fixed = 0; /* no auto select */
  221. wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
  222. return 0;
  223. }
  224. EXPORT_SYMBOL(rtllib_wx_get_rts);
  225. int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
  226. union iwreq_data *wrqu, char *b)
  227. {
  228. int set_mode_status = 0;
  229. rtllib_stop_scan_syncro(ieee);
  230. down(&ieee->wx_sem);
  231. switch (wrqu->mode) {
  232. case IW_MODE_MONITOR:
  233. case IW_MODE_ADHOC:
  234. case IW_MODE_INFRA:
  235. break;
  236. case IW_MODE_AUTO:
  237. wrqu->mode = IW_MODE_INFRA;
  238. break;
  239. default:
  240. set_mode_status = -EINVAL;
  241. goto out;
  242. }
  243. if (wrqu->mode == ieee->iw_mode)
  244. goto out;
  245. if (wrqu->mode == IW_MODE_MONITOR) {
  246. ieee->dev->type = ARPHRD_IEEE80211;
  247. rtllib_EnableNetMonitorMode(ieee->dev, false);
  248. } else {
  249. ieee->dev->type = ARPHRD_ETHER;
  250. if (ieee->iw_mode == IW_MODE_MONITOR)
  251. rtllib_DisableNetMonitorMode(ieee->dev, false);
  252. }
  253. if (!ieee->proto_started) {
  254. ieee->iw_mode = wrqu->mode;
  255. } else {
  256. rtllib_stop_protocol(ieee, true);
  257. ieee->iw_mode = wrqu->mode;
  258. rtllib_start_protocol(ieee);
  259. }
  260. out:
  261. up(&ieee->wx_sem);
  262. return set_mode_status;
  263. }
  264. EXPORT_SYMBOL(rtllib_wx_set_mode);
  265. void rtllib_wx_sync_scan_wq(void *data)
  266. {
  267. struct rtllib_device *ieee = container_of_work_rsl(data,
  268. struct rtllib_device, wx_sync_scan_wq);
  269. short chan;
  270. enum ht_extchnl_offset chan_offset = 0;
  271. enum ht_channel_width bandwidth = 0;
  272. int b40M = 0;
  273. if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
  274. rtllib_start_scan_syncro(ieee, 0);
  275. goto out;
  276. }
  277. chan = ieee->current_network.channel;
  278. if (ieee->LeisurePSLeave)
  279. ieee->LeisurePSLeave(ieee->dev);
  280. /* notify AP to be in PS mode */
  281. rtllib_sta_ps_send_null_frame(ieee, 1);
  282. rtllib_sta_ps_send_null_frame(ieee, 1);
  283. rtllib_stop_all_queues(ieee);
  284. if (ieee->data_hard_stop)
  285. ieee->data_hard_stop(ieee->dev);
  286. rtllib_stop_send_beacons(ieee);
  287. ieee->state = RTLLIB_LINKED_SCANNING;
  288. ieee->link_change(ieee->dev);
  289. /* wait for ps packet to be kicked out successfully */
  290. msleep(50);
  291. if (ieee->ScanOperationBackupHandler)
  292. ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
  293. if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
  294. ieee->pHTInfo->bCurBW40MHz) {
  295. b40M = 1;
  296. chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
  297. bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
  298. RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
  299. chan_offset, bandwidth);
  300. ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
  301. HT_EXTCHNL_OFFSET_NO_EXT);
  302. }
  303. rtllib_start_scan_syncro(ieee, 0);
  304. if (b40M) {
  305. RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
  306. if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
  307. ieee->set_chan(ieee->dev, chan + 2);
  308. else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
  309. ieee->set_chan(ieee->dev, chan - 2);
  310. else
  311. ieee->set_chan(ieee->dev, chan);
  312. ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
  313. } else {
  314. ieee->set_chan(ieee->dev, chan);
  315. }
  316. if (ieee->ScanOperationBackupHandler)
  317. ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
  318. ieee->state = RTLLIB_LINKED;
  319. ieee->link_change(ieee->dev);
  320. /* Notify AP that I wake up again */
  321. rtllib_sta_ps_send_null_frame(ieee, 0);
  322. if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
  323. ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
  324. ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
  325. ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
  326. }
  327. if (ieee->data_hard_resume)
  328. ieee->data_hard_resume(ieee->dev);
  329. if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
  330. rtllib_start_send_beacons(ieee);
  331. rtllib_wake_all_queues(ieee);
  332. out:
  333. up(&ieee->wx_sem);
  334. }
  335. int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
  336. union iwreq_data *wrqu, char *b)
  337. {
  338. int ret = 0;
  339. down(&ieee->wx_sem);
  340. if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
  341. ret = -1;
  342. goto out;
  343. }
  344. if (ieee->state == RTLLIB_LINKED) {
  345. queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq);
  346. /* intentionally forget to up sem */
  347. return 0;
  348. }
  349. out:
  350. up(&ieee->wx_sem);
  351. return ret;
  352. }
  353. EXPORT_SYMBOL(rtllib_wx_set_scan);
  354. int rtllib_wx_set_essid(struct rtllib_device *ieee,
  355. struct iw_request_info *a,
  356. union iwreq_data *wrqu, char *extra)
  357. {
  358. int ret = 0, len, i;
  359. short proto_started;
  360. unsigned long flags;
  361. rtllib_stop_scan_syncro(ieee);
  362. down(&ieee->wx_sem);
  363. proto_started = ieee->proto_started;
  364. len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
  365. if (ieee->iw_mode == IW_MODE_MONITOR) {
  366. ret = -1;
  367. goto out;
  368. }
  369. for (i = 0; i < len; i++) {
  370. if (extra[i] < 0) {
  371. ret = -1;
  372. goto out;
  373. }
  374. }
  375. if (proto_started)
  376. rtllib_stop_protocol(ieee, true);
  377. /* this is just to be sure that the GET wx callback
  378. * has consistent infos. not needed otherwise
  379. */
  380. spin_lock_irqsave(&ieee->lock, flags);
  381. if (wrqu->essid.flags && wrqu->essid.length) {
  382. strncpy(ieee->current_network.ssid, extra, len);
  383. ieee->current_network.ssid_len = len;
  384. ieee->cannot_notify = false;
  385. ieee->ssid_set = 1;
  386. } else {
  387. ieee->ssid_set = 0;
  388. ieee->current_network.ssid[0] = '\0';
  389. ieee->current_network.ssid_len = 0;
  390. }
  391. spin_unlock_irqrestore(&ieee->lock, flags);
  392. if (proto_started)
  393. rtllib_start_protocol(ieee);
  394. out:
  395. up(&ieee->wx_sem);
  396. return ret;
  397. }
  398. EXPORT_SYMBOL(rtllib_wx_set_essid);
  399. int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
  400. union iwreq_data *wrqu, char *b)
  401. {
  402. wrqu->mode = ieee->iw_mode;
  403. return 0;
  404. }
  405. EXPORT_SYMBOL(rtllib_wx_get_mode);
  406. int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
  407. struct iw_request_info *info,
  408. union iwreq_data *wrqu, char *extra)
  409. {
  410. int *parms = (int *)extra;
  411. int enable = (parms[0] > 0);
  412. short prev = ieee->raw_tx;
  413. down(&ieee->wx_sem);
  414. if (enable)
  415. ieee->raw_tx = 1;
  416. else
  417. ieee->raw_tx = 0;
  418. netdev_info(ieee->dev, "raw TX is %s\n",
  419. ieee->raw_tx ? "enabled" : "disabled");
  420. if (ieee->iw_mode == IW_MODE_MONITOR) {
  421. if (prev == 0 && ieee->raw_tx) {
  422. if (ieee->data_hard_resume)
  423. ieee->data_hard_resume(ieee->dev);
  424. netif_carrier_on(ieee->dev);
  425. }
  426. if (prev && ieee->raw_tx == 1)
  427. netif_carrier_off(ieee->dev);
  428. }
  429. up(&ieee->wx_sem);
  430. return 0;
  431. }
  432. EXPORT_SYMBOL(rtllib_wx_set_rawtx);
  433. int rtllib_wx_get_name(struct rtllib_device *ieee,
  434. struct iw_request_info *info,
  435. union iwreq_data *wrqu, char *extra)
  436. {
  437. strcpy(wrqu->name, "802.11");
  438. if (ieee->modulation & RTLLIB_CCK_MODULATION)
  439. strcat(wrqu->name, "b");
  440. if (ieee->modulation & RTLLIB_OFDM_MODULATION)
  441. strcat(wrqu->name, "g");
  442. if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
  443. strcat(wrqu->name, "n");
  444. return 0;
  445. }
  446. EXPORT_SYMBOL(rtllib_wx_get_name);
  447. /* this is mostly stolen from hostap */
  448. int rtllib_wx_set_power(struct rtllib_device *ieee,
  449. struct iw_request_info *info,
  450. union iwreq_data *wrqu, char *extra)
  451. {
  452. int ret = 0;
  453. if ((!ieee->sta_wake_up) ||
  454. (!ieee->enter_sleep_state) ||
  455. (!ieee->ps_is_queue_empty)) {
  456. netdev_warn(ieee->dev,
  457. "%s(): PS mode is tried to be use but driver missed a callback\n",
  458. __func__);
  459. return -1;
  460. }
  461. down(&ieee->wx_sem);
  462. if (wrqu->power.disabled) {
  463. RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
  464. ieee->ps = RTLLIB_PS_DISABLED;
  465. goto exit;
  466. }
  467. if (wrqu->power.flags & IW_POWER_TIMEOUT) {
  468. ieee->ps_timeout = wrqu->power.value / 1000;
  469. RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
  470. ieee->ps_timeout);
  471. }
  472. if (wrqu->power.flags & IW_POWER_PERIOD)
  473. ieee->ps_period = wrqu->power.value / 1000;
  474. switch (wrqu->power.flags & IW_POWER_MODE) {
  475. case IW_POWER_UNICAST_R:
  476. ieee->ps = RTLLIB_PS_UNICAST;
  477. break;
  478. case IW_POWER_MULTICAST_R:
  479. ieee->ps = RTLLIB_PS_MBCAST;
  480. break;
  481. case IW_POWER_ALL_R:
  482. ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
  483. break;
  484. case IW_POWER_ON:
  485. break;
  486. default:
  487. ret = -EINVAL;
  488. goto exit;
  489. }
  490. exit:
  491. up(&ieee->wx_sem);
  492. return ret;
  493. }
  494. EXPORT_SYMBOL(rtllib_wx_set_power);
  495. /* this is stolen from hostap */
  496. int rtllib_wx_get_power(struct rtllib_device *ieee,
  497. struct iw_request_info *info,
  498. union iwreq_data *wrqu, char *extra)
  499. {
  500. down(&ieee->wx_sem);
  501. if (ieee->ps == RTLLIB_PS_DISABLED) {
  502. wrqu->power.disabled = 1;
  503. goto exit;
  504. }
  505. wrqu->power.disabled = 0;
  506. if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
  507. wrqu->power.flags = IW_POWER_TIMEOUT;
  508. wrqu->power.value = ieee->ps_timeout * 1000;
  509. } else {
  510. wrqu->power.flags = IW_POWER_PERIOD;
  511. wrqu->power.value = ieee->ps_period * 1000;
  512. }
  513. if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
  514. (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
  515. wrqu->power.flags |= IW_POWER_ALL_R;
  516. else if (ieee->ps & RTLLIB_PS_MBCAST)
  517. wrqu->power.flags |= IW_POWER_MULTICAST_R;
  518. else
  519. wrqu->power.flags |= IW_POWER_UNICAST_R;
  520. exit:
  521. up(&ieee->wx_sem);
  522. return 0;
  523. }
  524. EXPORT_SYMBOL(rtllib_wx_get_power);