bcm43xx_wx.c 28 KB

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