bcm43xx_wx.c 25 KB

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