bcm43xx_wx.c 25 KB

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