bcm43xx_wx.c 27 KB

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