bcm43xx_wx.c 27 KB

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