ieee80211softmac_wx.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
  3. *
  4. * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
  5. * Joseph Jezak <josejx@gentoo.org>
  6. * Larry Finger <Larry.Finger@lwfinger.net>
  7. * Danny van Dyk <kugelfang@gentoo.org>
  8. * Michael Buesch <mbuesch@freenet.de>
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms of version 2 of the GNU General Public License as
  12. * published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. * more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * The full GNU General Public License is included in this distribution in the
  24. * file called COPYING.
  25. */
  26. #include "ieee80211softmac_priv.h"
  27. #include <net/iw_handler.h>
  28. int
  29. ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
  30. struct iw_request_info *info,
  31. union iwreq_data *data,
  32. char *extra)
  33. {
  34. struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  35. return ieee80211softmac_start_scan(sm);
  36. }
  37. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
  38. int
  39. ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
  40. struct iw_request_info *info,
  41. union iwreq_data *data,
  42. char *extra)
  43. {
  44. struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  45. return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
  46. }
  47. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
  48. int
  49. ieee80211softmac_wx_set_essid(struct net_device *net_dev,
  50. struct iw_request_info *info,
  51. union iwreq_data *data,
  52. char *extra)
  53. {
  54. struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  55. int length = 0;
  56. unsigned long flags;
  57. spin_lock_irqsave(&sm->lock, flags);
  58. sm->associnfo.static_essid = 0;
  59. if (data->essid.flags && data->essid.length && extra /*required?*/) {
  60. length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
  61. if (length) {
  62. memcpy(sm->associnfo.req_essid.data, extra, length);
  63. sm->associnfo.static_essid = 1;
  64. }
  65. }
  66. sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
  67. /* set our requested ESSID length.
  68. * If applicable, we have already copied the data in */
  69. sm->associnfo.req_essid.len = length;
  70. /* queue lower level code to do work (if necessary) */
  71. schedule_work(&sm->associnfo.work);
  72. spin_unlock_irqrestore(&sm->lock, flags);
  73. return 0;
  74. }
  75. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
  76. int
  77. ieee80211softmac_wx_get_essid(struct net_device *net_dev,
  78. struct iw_request_info *info,
  79. union iwreq_data *data,
  80. char *extra)
  81. {
  82. struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
  83. unsigned long flags;
  84. /* avoid getting inconsistent information */
  85. spin_lock_irqsave(&sm->lock, flags);
  86. /* If all fails, return ANY (empty) */
  87. data->essid.length = 0;
  88. data->essid.flags = 0; /* active */
  89. /* If we have a statically configured ESSID then return it */
  90. if (sm->associnfo.static_essid) {
  91. data->essid.length = sm->associnfo.req_essid.len;
  92. data->essid.flags = 1; /* active */
  93. memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
  94. }
  95. /* If we're associating/associated, return that */
  96. if (sm->associated || sm->associnfo.associating) {
  97. data->essid.length = sm->associnfo.associate_essid.len;
  98. data->essid.flags = 1; /* active */
  99. memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
  100. }
  101. spin_unlock_irqrestore(&sm->lock, flags);
  102. return 0;
  103. }
  104. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
  105. int
  106. ieee80211softmac_wx_set_rate(struct net_device *net_dev,
  107. struct iw_request_info *info,
  108. union iwreq_data *data,
  109. char *extra)
  110. {
  111. struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  112. struct ieee80211_device *ieee = mac->ieee;
  113. unsigned long flags;
  114. s32 in_rate = data->bitrate.value;
  115. u8 rate;
  116. int is_ofdm = 0;
  117. int err = -EINVAL;
  118. if (in_rate == -1) {
  119. /* FIXME: We don't correctly handle backing down to lower
  120. rates, so 801.11g devices start off at 11M for now. People
  121. can manually change it if they really need to, but 11M is
  122. more reliable. Note similar logic in
  123. ieee80211softmac_wx_set_rate() */
  124. if (ieee->modulation & IEEE80211_CCK_MODULATION)
  125. in_rate = 11000000;
  126. else
  127. in_rate = 54000000;
  128. }
  129. switch (in_rate) {
  130. case 1000000:
  131. rate = IEEE80211_CCK_RATE_1MB;
  132. break;
  133. case 2000000:
  134. rate = IEEE80211_CCK_RATE_2MB;
  135. break;
  136. case 5500000:
  137. rate = IEEE80211_CCK_RATE_5MB;
  138. break;
  139. case 11000000:
  140. rate = IEEE80211_CCK_RATE_11MB;
  141. break;
  142. case 6000000:
  143. rate = IEEE80211_OFDM_RATE_6MB;
  144. is_ofdm = 1;
  145. break;
  146. case 9000000:
  147. rate = IEEE80211_OFDM_RATE_9MB;
  148. is_ofdm = 1;
  149. break;
  150. case 12000000:
  151. rate = IEEE80211_OFDM_RATE_12MB;
  152. is_ofdm = 1;
  153. break;
  154. case 18000000:
  155. rate = IEEE80211_OFDM_RATE_18MB;
  156. is_ofdm = 1;
  157. break;
  158. case 24000000:
  159. rate = IEEE80211_OFDM_RATE_24MB;
  160. is_ofdm = 1;
  161. break;
  162. case 36000000:
  163. rate = IEEE80211_OFDM_RATE_36MB;
  164. is_ofdm = 1;
  165. break;
  166. case 48000000:
  167. rate = IEEE80211_OFDM_RATE_48MB;
  168. is_ofdm = 1;
  169. break;
  170. case 54000000:
  171. rate = IEEE80211_OFDM_RATE_54MB;
  172. is_ofdm = 1;
  173. break;
  174. default:
  175. goto out;
  176. }
  177. spin_lock_irqsave(&mac->lock, flags);
  178. /* Check if correct modulation for this PHY. */
  179. if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
  180. goto out_unlock;
  181. mac->txrates.default_rate = rate;
  182. mac->txrates.default_fallback = lower_rate(mac, rate);
  183. err = 0;
  184. out_unlock:
  185. spin_unlock_irqrestore(&mac->lock, flags);
  186. out:
  187. return err;
  188. }
  189. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
  190. int
  191. ieee80211softmac_wx_get_rate(struct net_device *net_dev,
  192. struct iw_request_info *info,
  193. union iwreq_data *data,
  194. char *extra)
  195. {
  196. struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  197. unsigned long flags;
  198. int err = -EINVAL;
  199. spin_lock_irqsave(&mac->lock, flags);
  200. switch (mac->txrates.default_rate) {
  201. case IEEE80211_CCK_RATE_1MB:
  202. data->bitrate.value = 1000000;
  203. break;
  204. case IEEE80211_CCK_RATE_2MB:
  205. data->bitrate.value = 2000000;
  206. break;
  207. case IEEE80211_CCK_RATE_5MB:
  208. data->bitrate.value = 5500000;
  209. break;
  210. case IEEE80211_CCK_RATE_11MB:
  211. data->bitrate.value = 11000000;
  212. break;
  213. case IEEE80211_OFDM_RATE_6MB:
  214. data->bitrate.value = 6000000;
  215. break;
  216. case IEEE80211_OFDM_RATE_9MB:
  217. data->bitrate.value = 9000000;
  218. break;
  219. case IEEE80211_OFDM_RATE_12MB:
  220. data->bitrate.value = 12000000;
  221. break;
  222. case IEEE80211_OFDM_RATE_18MB:
  223. data->bitrate.value = 18000000;
  224. break;
  225. case IEEE80211_OFDM_RATE_24MB:
  226. data->bitrate.value = 24000000;
  227. break;
  228. case IEEE80211_OFDM_RATE_36MB:
  229. data->bitrate.value = 36000000;
  230. break;
  231. case IEEE80211_OFDM_RATE_48MB:
  232. data->bitrate.value = 48000000;
  233. break;
  234. case IEEE80211_OFDM_RATE_54MB:
  235. data->bitrate.value = 54000000;
  236. break;
  237. default:
  238. assert(0);
  239. goto out_unlock;
  240. }
  241. err = 0;
  242. out_unlock:
  243. spin_unlock_irqrestore(&mac->lock, flags);
  244. return err;
  245. }
  246. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
  247. int
  248. ieee80211softmac_wx_get_wap(struct net_device *net_dev,
  249. struct iw_request_info *info,
  250. union iwreq_data *data,
  251. char *extra)
  252. {
  253. struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  254. int err = 0;
  255. unsigned long flags;
  256. spin_lock_irqsave(&mac->lock, flags);
  257. if (mac->associnfo.bssvalid)
  258. memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
  259. else
  260. memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
  261. data->ap_addr.sa_family = ARPHRD_ETHER;
  262. spin_unlock_irqrestore(&mac->lock, flags);
  263. return err;
  264. }
  265. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
  266. int
  267. ieee80211softmac_wx_set_wap(struct net_device *net_dev,
  268. struct iw_request_info *info,
  269. union iwreq_data *data,
  270. char *extra)
  271. {
  272. struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
  273. static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  274. static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  275. unsigned long flags;
  276. /* sanity check */
  277. if (data->ap_addr.sa_family != ARPHRD_ETHER) {
  278. return -EINVAL;
  279. }
  280. spin_lock_irqsave(&mac->lock, flags);
  281. if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
  282. !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
  283. schedule_work(&mac->associnfo.work);
  284. goto out;
  285. } else {
  286. if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
  287. if (mac->associnfo.associating || mac->associated) {
  288. /* bssid unchanged and associated or associating - just return */
  289. goto out;
  290. }
  291. } else {
  292. /* copy new value in data->ap_addr.sa_data to bssid */
  293. memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
  294. }
  295. /* queue associate if new bssid or (old one again and not associated) */
  296. schedule_work(&mac->associnfo.work);
  297. }
  298. out:
  299. spin_unlock_irqrestore(&mac->lock, flags);
  300. return 0;
  301. }
  302. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
  303. int
  304. ieee80211softmac_wx_set_genie(struct net_device *dev,
  305. struct iw_request_info *info,
  306. union iwreq_data *wrqu,
  307. char *extra)
  308. {
  309. struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  310. unsigned long flags;
  311. int err = 0;
  312. char *buf;
  313. int i;
  314. spin_lock_irqsave(&mac->lock, flags);
  315. /* bleh. shouldn't be locked for that kmalloc... */
  316. if (wrqu->data.length) {
  317. if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
  318. /* this is an IE, so the length must be
  319. * correct. Is it possible though that
  320. * more than one IE is passed in?
  321. */
  322. err = -EINVAL;
  323. goto out;
  324. }
  325. if (mac->wpa.IEbuflen <= wrqu->data.length) {
  326. buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
  327. if (!buf) {
  328. err = -ENOMEM;
  329. goto out;
  330. }
  331. kfree(mac->wpa.IE);
  332. mac->wpa.IE = buf;
  333. mac->wpa.IEbuflen = wrqu->data.length;
  334. }
  335. memcpy(mac->wpa.IE, extra, wrqu->data.length);
  336. dprintk(KERN_INFO PFX "generic IE set to ");
  337. for (i=0;i<wrqu->data.length;i++)
  338. dprintk("%.2x", mac->wpa.IE[i]);
  339. dprintk("\n");
  340. mac->wpa.IElen = wrqu->data.length;
  341. } else {
  342. kfree(mac->wpa.IE);
  343. mac->wpa.IE = NULL;
  344. mac->wpa.IElen = 0;
  345. mac->wpa.IEbuflen = 0;
  346. }
  347. out:
  348. spin_unlock_irqrestore(&mac->lock, flags);
  349. return err;
  350. }
  351. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
  352. int
  353. ieee80211softmac_wx_get_genie(struct net_device *dev,
  354. struct iw_request_info *info,
  355. union iwreq_data *wrqu,
  356. char *extra)
  357. {
  358. struct ieee80211softmac_device *mac = ieee80211_priv(dev);
  359. unsigned long flags;
  360. int err = 0;
  361. int space = wrqu->data.length;
  362. spin_lock_irqsave(&mac->lock, flags);
  363. wrqu->data.length = 0;
  364. if (mac->wpa.IE && mac->wpa.IElen) {
  365. wrqu->data.length = mac->wpa.IElen;
  366. if (mac->wpa.IElen <= space)
  367. memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
  368. else
  369. err = -E2BIG;
  370. }
  371. spin_unlock_irqrestore(&mac->lock, flags);
  372. return err;
  373. }
  374. EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);