bcm43xx_wx.c 26 KB

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