bcm43xx_wx.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. /*
  2. Broadcom BCM43xx wireless driver
  3. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  4. Stefano Brivio <st3@riseup.net>
  5. Michael Buesch <mbuesch@freenet.de>
  6. Danny van Dyk <kugelfang@gentoo.org>
  7. Andreas Jaggi <andreas.jaggi@waterwave.ch>
  8. Some parts of the code in this file are derived from the ipw2200
  9. driver Copyright(c) 2003 - 2004 Intel Corporation.
  10. This program is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2 of the License, or
  13. (at your option) any later version.
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program; see the file COPYING. If not, write to
  20. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  21. Boston, MA 02110-1301, USA.
  22. */
  23. #include <linux/wireless.h>
  24. #include <net/iw_handler.h>
  25. #include <net/ieee80211softmac.h>
  26. #include <net/ieee80211softmac_wx.h>
  27. #include <linux/capability.h>
  28. #include <linux/delay.h>
  29. #include "bcm43xx.h"
  30. #include "bcm43xx_wx.h"
  31. #include "bcm43xx_main.h"
  32. #include "bcm43xx_radio.h"
  33. #include "bcm43xx_phy.h"
  34. /* The WIRELESS_EXT version, which is implemented by this driver. */
  35. #define BCM43xx_WX_VERSION 18
  36. #define MAX_WX_STRING 80
  37. static int bcm43xx_wx_get_name(struct net_device *net_dev,
  38. struct iw_request_info *info,
  39. union iwreq_data *data,
  40. char *extra)
  41. {
  42. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  43. int i;
  44. struct bcm43xx_phyinfo *phy;
  45. char suffix[7] = { 0 };
  46. int have_a = 0, have_b = 0, have_g = 0;
  47. mutex_lock(&bcm->mutex);
  48. for (i = 0; i < bcm->nr_80211_available; i++) {
  49. phy = &(bcm->core_80211_ext[i].phy);
  50. switch (phy->type) {
  51. case BCM43xx_PHYTYPE_A:
  52. have_a = 1;
  53. break;
  54. case BCM43xx_PHYTYPE_G:
  55. have_g = 1;
  56. case BCM43xx_PHYTYPE_B:
  57. have_b = 1;
  58. break;
  59. default:
  60. assert(0);
  61. }
  62. }
  63. mutex_unlock(&bcm->mutex);
  64. i = 0;
  65. if (have_a) {
  66. suffix[i++] = 'a';
  67. suffix[i++] = '/';
  68. }
  69. if (have_b) {
  70. suffix[i++] = 'b';
  71. suffix[i++] = '/';
  72. }
  73. if (have_g) {
  74. suffix[i++] = 'g';
  75. suffix[i++] = '/';
  76. }
  77. if (i != 0)
  78. suffix[i - 1] = '\0';
  79. snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix);
  80. return 0;
  81. }
  82. static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
  83. struct iw_request_info *info,
  84. union iwreq_data *data,
  85. char *extra)
  86. {
  87. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  88. unsigned long flags;
  89. u8 channel;
  90. s8 expon;
  91. int freq;
  92. int err = -EINVAL;
  93. mutex_lock(&bcm->mutex);
  94. spin_lock_irqsave(&bcm->irq_lock, flags);
  95. if ((data->freq.e == 0) &&
  96. (data->freq.m >= 0) && (data->freq.m <= 1000)) {
  97. channel = data->freq.m;
  98. freq = bcm43xx_channel_to_freq(bcm, channel);
  99. } else {
  100. freq = data->freq.m;
  101. expon = 6 - data->freq.e;
  102. while (--expon >= 0) /* scale down the frequency to MHz */
  103. freq /= 10;
  104. assert(freq > 1000);
  105. channel = bcm43xx_freq_to_channel(bcm, freq);
  106. }
  107. if (!ieee80211_is_valid_channel(bcm->ieee, channel))
  108. goto out_unlock;
  109. if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
  110. //ieee80211softmac_disassoc(softmac, $REASON);
  111. bcm43xx_mac_suspend(bcm);
  112. err = bcm43xx_radio_selectchannel(bcm, channel, 0);
  113. bcm43xx_mac_enable(bcm);
  114. } else {
  115. bcm43xx_current_radio(bcm)->initial_channel = channel;
  116. err = 0;
  117. }
  118. out_unlock:
  119. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  120. mutex_unlock(&bcm->mutex);
  121. return err;
  122. }
  123. static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
  124. struct iw_request_info *info,
  125. union iwreq_data *data,
  126. char *extra)
  127. {
  128. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  129. struct bcm43xx_radioinfo *radio;
  130. int err = -ENODEV;
  131. u16 channel;
  132. mutex_lock(&bcm->mutex);
  133. radio = bcm43xx_current_radio(bcm);
  134. channel = radio->channel;
  135. if (channel == 0xFF) {
  136. channel = radio->initial_channel;
  137. if (channel == 0xFF)
  138. goto out_unlock;
  139. }
  140. assert(channel > 0 && channel <= 1000);
  141. data->freq.e = 1;
  142. data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000;
  143. data->freq.flags = 1;
  144. err = 0;
  145. out_unlock:
  146. mutex_unlock(&bcm->mutex);
  147. return err;
  148. }
  149. static int bcm43xx_wx_set_mode(struct net_device *net_dev,
  150. struct iw_request_info *info,
  151. union iwreq_data *data,
  152. char *extra)
  153. {
  154. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  155. unsigned long flags;
  156. int mode;
  157. mode = data->mode;
  158. if (mode == IW_MODE_AUTO)
  159. mode = BCM43xx_INITIAL_IWMODE;
  160. mutex_lock(&bcm->mutex);
  161. spin_lock_irqsave(&bcm->irq_lock, flags);
  162. if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
  163. if (bcm->ieee->iw_mode != mode)
  164. bcm43xx_set_iwmode(bcm, mode);
  165. } else
  166. bcm->ieee->iw_mode = mode;
  167. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  168. mutex_unlock(&bcm->mutex);
  169. return 0;
  170. }
  171. static int bcm43xx_wx_get_mode(struct net_device *net_dev,
  172. struct iw_request_info *info,
  173. union iwreq_data *data,
  174. char *extra)
  175. {
  176. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  177. mutex_lock(&bcm->mutex);
  178. data->mode = bcm->ieee->iw_mode;
  179. mutex_unlock(&bcm->mutex);
  180. return 0;
  181. }
  182. static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
  183. struct iw_request_info *info,
  184. union iwreq_data *data,
  185. char *extra)
  186. {
  187. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  188. struct iw_range *range = (struct iw_range *)extra;
  189. const struct ieee80211_geo *geo;
  190. int i, j;
  191. struct bcm43xx_phyinfo *phy;
  192. data->data.length = sizeof(*range);
  193. memset(range, 0, sizeof(*range));
  194. //TODO: What about 802.11b?
  195. /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */
  196. range->throughput = 27 * 1000 * 1000;
  197. range->max_qual.qual = 100;
  198. range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
  199. range->max_qual.noise = 146;
  200. range->max_qual.updated = IW_QUAL_ALL_UPDATED;
  201. range->avg_qual.qual = 50;
  202. range->avg_qual.level = 0;
  203. range->avg_qual.noise = 0;
  204. range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
  205. range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
  206. range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
  207. range->min_frag = MIN_FRAG_THRESHOLD;
  208. range->max_frag = MAX_FRAG_THRESHOLD;
  209. range->encoding_size[0] = 5;
  210. range->encoding_size[1] = 13;
  211. range->num_encoding_sizes = 2;
  212. range->max_encoding_tokens = WEP_KEYS;
  213. range->we_version_compiled = WIRELESS_EXT;
  214. range->we_version_source = BCM43xx_WX_VERSION;
  215. range->enc_capa = IW_ENC_CAPA_WPA |
  216. IW_ENC_CAPA_WPA2 |
  217. IW_ENC_CAPA_CIPHER_TKIP |
  218. IW_ENC_CAPA_CIPHER_CCMP;
  219. mutex_lock(&bcm->mutex);
  220. phy = bcm43xx_current_phy(bcm);
  221. range->num_bitrates = 0;
  222. i = 0;
  223. if (phy->type == BCM43xx_PHYTYPE_A ||
  224. phy->type == BCM43xx_PHYTYPE_G) {
  225. range->num_bitrates = 8;
  226. range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
  227. range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
  228. range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
  229. range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
  230. range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
  231. range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
  232. range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
  233. range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
  234. }
  235. if (phy->type == BCM43xx_PHYTYPE_B ||
  236. phy->type == BCM43xx_PHYTYPE_G) {
  237. range->num_bitrates += 4;
  238. range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
  239. range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
  240. range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
  241. range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
  242. }
  243. geo = ieee80211_get_geo(bcm->ieee);
  244. range->num_channels = geo->a_channels + geo->bg_channels;
  245. j = 0;
  246. for (i = 0; i < geo->a_channels; i++) {
  247. if (j == IW_MAX_FREQUENCIES)
  248. break;
  249. range->freq[j].i = j + 1;
  250. range->freq[j].m = geo->a[i].freq * 100000;
  251. range->freq[j].e = 1;
  252. j++;
  253. }
  254. for (i = 0; i < geo->bg_channels; i++) {
  255. if (j == IW_MAX_FREQUENCIES)
  256. break;
  257. range->freq[j].i = j + 1;
  258. range->freq[j].m = geo->bg[i].freq * 100000;
  259. range->freq[j].e = 1;
  260. j++;
  261. }
  262. range->num_frequency = j;
  263. mutex_unlock(&bcm->mutex);
  264. return 0;
  265. }
  266. static int bcm43xx_wx_set_nick(struct net_device *net_dev,
  267. struct iw_request_info *info,
  268. union iwreq_data *data,
  269. char *extra)
  270. {
  271. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  272. size_t len;
  273. mutex_lock(&bcm->mutex);
  274. len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
  275. memcpy(bcm->nick, extra, len);
  276. bcm->nick[len] = '\0';
  277. mutex_unlock(&bcm->mutex);
  278. return 0;
  279. }
  280. static int bcm43xx_wx_get_nick(struct net_device *net_dev,
  281. struct iw_request_info *info,
  282. union iwreq_data *data,
  283. char *extra)
  284. {
  285. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  286. size_t len;
  287. mutex_lock(&bcm->mutex);
  288. len = strlen(bcm->nick);
  289. memcpy(extra, bcm->nick, len);
  290. data->data.length = (__u16)len;
  291. data->data.flags = 1;
  292. mutex_unlock(&bcm->mutex);
  293. return 0;
  294. }
  295. static int bcm43xx_wx_set_rts(struct net_device *net_dev,
  296. struct iw_request_info *info,
  297. union iwreq_data *data,
  298. char *extra)
  299. {
  300. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  301. unsigned long flags;
  302. int err = -EINVAL;
  303. mutex_lock(&bcm->mutex);
  304. spin_lock_irqsave(&bcm->irq_lock, flags);
  305. if (data->rts.disabled) {
  306. bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
  307. err = 0;
  308. } else {
  309. if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD &&
  310. data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) {
  311. bcm->rts_threshold = data->rts.value;
  312. err = 0;
  313. }
  314. }
  315. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  316. mutex_unlock(&bcm->mutex);
  317. return err;
  318. }
  319. static int bcm43xx_wx_get_rts(struct net_device *net_dev,
  320. struct iw_request_info *info,
  321. union iwreq_data *data,
  322. char *extra)
  323. {
  324. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  325. mutex_lock(&bcm->mutex);
  326. data->rts.value = bcm->rts_threshold;
  327. data->rts.fixed = 0;
  328. data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
  329. mutex_unlock(&bcm->mutex);
  330. return 0;
  331. }
  332. static int bcm43xx_wx_set_frag(struct net_device *net_dev,
  333. struct iw_request_info *info,
  334. union iwreq_data *data,
  335. char *extra)
  336. {
  337. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  338. unsigned long flags;
  339. int err = -EINVAL;
  340. mutex_lock(&bcm->mutex);
  341. spin_lock_irqsave(&bcm->irq_lock, flags);
  342. if (data->frag.disabled) {
  343. bcm->ieee->fts = MAX_FRAG_THRESHOLD;
  344. err = 0;
  345. } else {
  346. if (data->frag.value >= MIN_FRAG_THRESHOLD &&
  347. data->frag.value <= MAX_FRAG_THRESHOLD) {
  348. bcm->ieee->fts = data->frag.value & ~0x1;
  349. err = 0;
  350. }
  351. }
  352. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  353. mutex_unlock(&bcm->mutex);
  354. return err;
  355. }
  356. static int bcm43xx_wx_get_frag(struct net_device *net_dev,
  357. struct iw_request_info *info,
  358. union iwreq_data *data,
  359. char *extra)
  360. {
  361. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  362. mutex_lock(&bcm->mutex);
  363. data->frag.value = bcm->ieee->fts;
  364. data->frag.fixed = 0;
  365. data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
  366. mutex_unlock(&bcm->mutex);
  367. return 0;
  368. }
  369. static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
  370. struct iw_request_info *info,
  371. union iwreq_data *data,
  372. char *extra)
  373. {
  374. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  375. struct bcm43xx_radioinfo *radio;
  376. struct bcm43xx_phyinfo *phy;
  377. unsigned long flags;
  378. int err = -ENODEV;
  379. u16 maxpower;
  380. if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
  381. printk(PFX KERN_ERR "TX power not in dBm.\n");
  382. return -EOPNOTSUPP;
  383. }
  384. mutex_lock(&bcm->mutex);
  385. spin_lock_irqsave(&bcm->irq_lock, flags);
  386. if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
  387. goto out_unlock;
  388. radio = bcm43xx_current_radio(bcm);
  389. phy = bcm43xx_current_phy(bcm);
  390. if (data->txpower.disabled != (!(radio->enabled))) {
  391. if (data->txpower.disabled)
  392. bcm43xx_radio_turn_off(bcm);
  393. else
  394. bcm43xx_radio_turn_on(bcm);
  395. }
  396. if (data->txpower.value > 0) {
  397. /* desired and maxpower dBm values are in Q5.2 */
  398. if (phy->type == BCM43xx_PHYTYPE_A)
  399. maxpower = bcm->sprom.maxpower_aphy;
  400. else
  401. maxpower = bcm->sprom.maxpower_bgphy;
  402. radio->txpower_desired = limit_value(data->txpower.value << 2,
  403. 0, maxpower);
  404. bcm43xx_phy_xmitpower(bcm);
  405. }
  406. err = 0;
  407. out_unlock:
  408. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  409. mutex_unlock(&bcm->mutex);
  410. return err;
  411. }
  412. static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
  413. struct iw_request_info *info,
  414. union iwreq_data *data,
  415. char *extra)
  416. {
  417. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  418. struct bcm43xx_radioinfo *radio;
  419. int err = -ENODEV;
  420. mutex_lock(&bcm->mutex);
  421. if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
  422. goto out_unlock;
  423. radio = bcm43xx_current_radio(bcm);
  424. /* desired dBm value is in Q5.2 */
  425. data->txpower.value = radio->txpower_desired >> 2;
  426. data->txpower.fixed = 1;
  427. data->txpower.flags = IW_TXPOW_DBM;
  428. data->txpower.disabled = !(radio->enabled);
  429. err = 0;
  430. out_unlock:
  431. mutex_unlock(&bcm->mutex);
  432. return err;
  433. }
  434. static int bcm43xx_wx_set_encoding(struct net_device *net_dev,
  435. struct iw_request_info *info,
  436. union iwreq_data *data,
  437. char *extra)
  438. {
  439. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  440. int err;
  441. err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra);
  442. return err;
  443. }
  444. static int bcm43xx_wx_set_encodingext(struct net_device *net_dev,
  445. struct iw_request_info *info,
  446. union iwreq_data *data,
  447. char *extra)
  448. {
  449. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  450. int err;
  451. err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra);
  452. return err;
  453. }
  454. static int bcm43xx_wx_get_encoding(struct net_device *net_dev,
  455. struct iw_request_info *info,
  456. union iwreq_data *data,
  457. char *extra)
  458. {
  459. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  460. int err;
  461. err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra);
  462. return err;
  463. }
  464. static int bcm43xx_wx_get_encodingext(struct net_device *net_dev,
  465. struct iw_request_info *info,
  466. union iwreq_data *data,
  467. char *extra)
  468. {
  469. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  470. int err;
  471. err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra);
  472. return err;
  473. }
  474. static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
  475. struct iw_request_info *info,
  476. union iwreq_data *data,
  477. char *extra)
  478. {
  479. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  480. unsigned long flags;
  481. int mode, err = 0;
  482. mode = *((int *)extra);
  483. switch (mode) {
  484. case 0:
  485. mode = BCM43xx_RADIO_INTERFMODE_NONE;
  486. break;
  487. case 1:
  488. mode = BCM43xx_RADIO_INTERFMODE_NONWLAN;
  489. break;
  490. case 2:
  491. mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN;
  492. break;
  493. case 3:
  494. mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN;
  495. break;
  496. default:
  497. printk(KERN_ERR PFX "set_interfmode allowed parameters are: "
  498. "0 => None, 1 => Non-WLAN, 2 => WLAN, "
  499. "3 => Auto-WLAN\n");
  500. return -EINVAL;
  501. }
  502. mutex_lock(&bcm->mutex);
  503. spin_lock_irqsave(&bcm->irq_lock, flags);
  504. if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
  505. err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
  506. if (err) {
  507. printk(KERN_ERR PFX "Interference Mitigation not "
  508. "supported by device\n");
  509. }
  510. } else {
  511. if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) {
  512. printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN "
  513. "not supported while the interface is down.\n");
  514. err = -ENODEV;
  515. } else
  516. bcm43xx_current_radio(bcm)->interfmode = mode;
  517. }
  518. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  519. mutex_unlock(&bcm->mutex);
  520. return err;
  521. }
  522. static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
  523. struct iw_request_info *info,
  524. union iwreq_data *data,
  525. char *extra)
  526. {
  527. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  528. int mode;
  529. mutex_lock(&bcm->mutex);
  530. mode = bcm43xx_current_radio(bcm)->interfmode;
  531. mutex_unlock(&bcm->mutex);
  532. switch (mode) {
  533. case BCM43xx_RADIO_INTERFMODE_NONE:
  534. strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING);
  535. break;
  536. case BCM43xx_RADIO_INTERFMODE_NONWLAN:
  537. strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING);
  538. break;
  539. case BCM43xx_RADIO_INTERFMODE_MANUALWLAN:
  540. strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING);
  541. break;
  542. default:
  543. assert(0);
  544. }
  545. data->data.length = strlen(extra) + 1;
  546. return 0;
  547. }
  548. static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
  549. struct iw_request_info *info,
  550. union iwreq_data *data,
  551. char *extra)
  552. {
  553. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  554. unsigned long flags;
  555. int on;
  556. on = *((int *)extra);
  557. mutex_lock(&bcm->mutex);
  558. spin_lock_irqsave(&bcm->irq_lock, flags);
  559. bcm->short_preamble = !!on;
  560. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  561. mutex_unlock(&bcm->mutex);
  562. return 0;
  563. }
  564. static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
  565. struct iw_request_info *info,
  566. union iwreq_data *data,
  567. char *extra)
  568. {
  569. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  570. int on;
  571. mutex_lock(&bcm->mutex);
  572. on = bcm->short_preamble;
  573. mutex_unlock(&bcm->mutex);
  574. if (on)
  575. strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
  576. else
  577. strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING);
  578. data->data.length = strlen(extra) + 1;
  579. return 0;
  580. }
  581. static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
  582. struct iw_request_info *info,
  583. union iwreq_data *data,
  584. char *extra)
  585. {
  586. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  587. unsigned long flags;
  588. int on;
  589. on = *((int *)extra);
  590. mutex_lock(&bcm->mutex);
  591. spin_lock_irqsave(&bcm->irq_lock, flags);
  592. bcm->ieee->host_encrypt = !!on;
  593. bcm->ieee->host_decrypt = !!on;
  594. bcm->ieee->host_build_iv = !on;
  595. bcm->ieee->host_strip_iv_icv = !on;
  596. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  597. mutex_unlock(&bcm->mutex);
  598. return 0;
  599. }
  600. static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
  601. struct iw_request_info *info,
  602. union iwreq_data *data,
  603. char *extra)
  604. {
  605. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  606. int on;
  607. mutex_lock(&bcm->mutex);
  608. on = bcm->ieee->host_encrypt;
  609. mutex_unlock(&bcm->mutex);
  610. if (on)
  611. strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
  612. else
  613. strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING);
  614. data->data.length = strlen(extra + 1);
  615. return 0;
  616. }
  617. /* Enough buffer to hold a hexdump of the sprom data. */
  618. #define SPROM_BUFFERSIZE 512
  619. static int sprom2hex(const u16 *sprom, char *dump)
  620. {
  621. int i, pos = 0;
  622. for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {
  623. pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1,
  624. "%04X", swab16(sprom[i]) & 0xFFFF);
  625. }
  626. return pos + 1;
  627. }
  628. static int hex2sprom(u16 *sprom, const char *dump, unsigned int len)
  629. {
  630. char tmp[5] = { 0 };
  631. int cnt = 0;
  632. unsigned long parsed;
  633. if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2)
  634. return -EINVAL;
  635. while (cnt < BCM43xx_SPROM_SIZE) {
  636. memcpy(tmp, dump, 4);
  637. dump += 4;
  638. parsed = simple_strtoul(tmp, NULL, 16);
  639. sprom[cnt++] = swab16((u16)parsed);
  640. }
  641. return 0;
  642. }
  643. static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
  644. struct iw_request_info *info,
  645. union iwreq_data *data,
  646. char *extra)
  647. {
  648. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  649. int err = -EPERM;
  650. u16 *sprom;
  651. unsigned long flags;
  652. if (!capable(CAP_SYS_RAWIO))
  653. goto out;
  654. err = -ENOMEM;
  655. sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
  656. GFP_KERNEL);
  657. if (!sprom)
  658. goto out;
  659. mutex_lock(&bcm->mutex);
  660. spin_lock_irqsave(&bcm->irq_lock, flags);
  661. err = -ENODEV;
  662. if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
  663. err = bcm43xx_sprom_read(bcm, sprom);
  664. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  665. mutex_unlock(&bcm->mutex);
  666. if (!err)
  667. data->data.length = sprom2hex(sprom, extra);
  668. kfree(sprom);
  669. out:
  670. return err;
  671. }
  672. static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
  673. struct iw_request_info *info,
  674. union iwreq_data *data,
  675. char *extra)
  676. {
  677. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  678. int err = -EPERM;
  679. u16 *sprom;
  680. unsigned long flags;
  681. char *input;
  682. unsigned int len;
  683. if (!capable(CAP_SYS_RAWIO))
  684. goto out;
  685. err = -ENOMEM;
  686. sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom),
  687. GFP_KERNEL);
  688. if (!sprom)
  689. goto out;
  690. len = data->data.length;
  691. extra[len - 1] = '\0';
  692. input = strchr(extra, ':');
  693. if (input) {
  694. input++;
  695. len -= input - extra;
  696. } else
  697. input = extra;
  698. err = hex2sprom(sprom, input, len);
  699. if (err)
  700. goto out_kfree;
  701. mutex_lock(&bcm->mutex);
  702. spin_lock_irqsave(&bcm->irq_lock, flags);
  703. spin_lock(&bcm->leds_lock);
  704. err = -ENODEV;
  705. if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
  706. err = bcm43xx_sprom_write(bcm, sprom);
  707. spin_unlock(&bcm->leds_lock);
  708. spin_unlock_irqrestore(&bcm->irq_lock, flags);
  709. mutex_unlock(&bcm->mutex);
  710. out_kfree:
  711. kfree(sprom);
  712. out:
  713. return err;
  714. }
  715. /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
  716. static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev)
  717. {
  718. struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
  719. struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  720. struct iw_statistics *wstats;
  721. struct ieee80211_network *network = NULL;
  722. static int tmp_level = 0;
  723. static int tmp_qual = 0;
  724. unsigned long flags;
  725. wstats = &bcm->stats.wstats;
  726. if (!mac->associnfo.associated) {
  727. wstats->miss.beacon = 0;
  728. // bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
  729. wstats->discard.retries = 0;
  730. // bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question
  731. wstats->discard.nwid = 0;
  732. // bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto
  733. wstats->discard.code = 0;
  734. // bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here
  735. wstats->discard.fragment = 0;
  736. wstats->discard.misc = 0;
  737. wstats->qual.qual = 0;
  738. wstats->qual.level = 0;
  739. wstats->qual.noise = 0;
  740. wstats->qual.updated = 7;
  741. wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
  742. return wstats;
  743. }
  744. /* fill in the real statistics when iface associated */
  745. spin_lock_irqsave(&mac->ieee->lock, flags);
  746. list_for_each_entry(network, &mac->ieee->network_list, list) {
  747. if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
  748. if (!tmp_level) { /* get initial values */
  749. tmp_level = network->stats.signal;
  750. tmp_qual = network->stats.rssi;
  751. } else { /* smooth results */
  752. tmp_level = (15 * tmp_level + network->stats.signal)/16;
  753. tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
  754. }
  755. break;
  756. }
  757. }
  758. spin_unlock_irqrestore(&mac->ieee->lock, flags);
  759. wstats->qual.level = tmp_level;
  760. wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
  761. wstats->qual.noise = bcm->stats.noise;
  762. wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
  763. wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
  764. wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
  765. wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
  766. wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments;
  767. wstats->discard.misc = 0; // FIXME
  768. wstats->miss.beacon = 0; // FIXME
  769. return wstats;
  770. }
  771. #ifdef WX
  772. # undef WX
  773. #endif
  774. #define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT]
  775. static const iw_handler bcm43xx_wx_handlers[] = {
  776. /* Wireless Identification */
  777. WX(SIOCGIWNAME) = bcm43xx_wx_get_name,
  778. /* Basic operations */
  779. WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq,
  780. WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq,
  781. WX(SIOCSIWMODE) = bcm43xx_wx_set_mode,
  782. WX(SIOCGIWMODE) = bcm43xx_wx_get_mode,
  783. /* Informative stuff */
  784. WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams,
  785. /* Access Point manipulation */
  786. WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
  787. WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
  788. WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
  789. WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
  790. /* 802.11 specific support */
  791. WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
  792. WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
  793. WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick,
  794. WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick,
  795. /* Other parameters */
  796. WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
  797. WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
  798. WX(SIOCSIWRTS) = bcm43xx_wx_set_rts,
  799. WX(SIOCGIWRTS) = bcm43xx_wx_get_rts,
  800. WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag,
  801. WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag,
  802. WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower,
  803. WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower,
  804. //TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry,
  805. //TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry,
  806. /* Encoding */
  807. WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding,
  808. WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding,
  809. WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext,
  810. WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext,
  811. /* Power saving */
  812. //TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power,
  813. //TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power,
  814. WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
  815. WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
  816. WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
  817. WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
  818. };
  819. #undef WX
  820. static const iw_handler bcm43xx_priv_wx_handlers[] = {
  821. /* Set Interference Mitigation Mode. */
  822. bcm43xx_wx_set_interfmode,
  823. /* Get Interference Mitigation Mode. */
  824. bcm43xx_wx_get_interfmode,
  825. /* Enable/Disable Short Preamble mode. */
  826. bcm43xx_wx_set_shortpreamble,
  827. /* Get Short Preamble mode. */
  828. bcm43xx_wx_get_shortpreamble,
  829. /* Enable/Disable Software Encryption mode */
  830. bcm43xx_wx_set_swencryption,
  831. /* Get Software Encryption mode */
  832. bcm43xx_wx_get_swencryption,
  833. /* Write SRPROM data. */
  834. bcm43xx_wx_sprom_write,
  835. /* Read SPROM data. */
  836. bcm43xx_wx_sprom_read,
  837. };
  838. #define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0)
  839. #define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1)
  840. #define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2)
  841. #define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3)
  842. #define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4)
  843. #define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5)
  844. #define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6)
  845. #define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7)
  846. #define PRIV_WX_DUMMY(ioctl) \
  847. { \
  848. .cmd = (ioctl), \
  849. .name = "__unused" \
  850. }
  851. static const struct iw_priv_args bcm43xx_priv_wx_args[] = {
  852. {
  853. .cmd = PRIV_WX_SET_INTERFMODE,
  854. .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  855. .name = "set_interfmode",
  856. },
  857. {
  858. .cmd = PRIV_WX_GET_INTERFMODE,
  859. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
  860. .name = "get_interfmode",
  861. },
  862. {
  863. .cmd = PRIV_WX_SET_SHORTPREAMBLE,
  864. .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  865. .name = "set_shortpreamb",
  866. },
  867. {
  868. .cmd = PRIV_WX_GET_SHORTPREAMBLE,
  869. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
  870. .name = "get_shortpreamb",
  871. },
  872. {
  873. .cmd = PRIV_WX_SET_SWENCRYPTION,
  874. .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  875. .name = "set_swencrypt",
  876. },
  877. {
  878. .cmd = PRIV_WX_GET_SWENCRYPTION,
  879. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
  880. .name = "get_swencrypt",
  881. },
  882. {
  883. .cmd = PRIV_WX_SPROM_WRITE,
  884. .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE,
  885. .name = "write_sprom",
  886. },
  887. {
  888. .cmd = PRIV_WX_SPROM_READ,
  889. .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE,
  890. .name = "read_sprom",
  891. },
  892. };
  893. const struct iw_handler_def bcm43xx_wx_handlers_def = {
  894. .standard = bcm43xx_wx_handlers,
  895. .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers),
  896. .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers),
  897. .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args),
  898. .private = bcm43xx_priv_wx_handlers,
  899. .private_args = bcm43xx_priv_wx_args,
  900. .get_wireless_stats = bcm43xx_get_wireless_stats,
  901. };