isl_ioctl.c 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745
  1. /*
  2. *
  3. * Copyright (C) 2002 Intersil Americas Inc.
  4. * (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
  5. * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  6. * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. */
  22. #include <linux/version.h>
  23. #include <linux/module.h>
  24. #include <linux/kernel.h>
  25. #include <linux/if_arp.h>
  26. #include <linux/pci.h>
  27. #include <asm/uaccess.h>
  28. #include "prismcompat.h"
  29. #include "isl_ioctl.h"
  30. #include "islpci_mgt.h"
  31. #include "isl_oid.h" /* additional types and defs for isl38xx fw */
  32. #include "oid_mgt.h"
  33. #include <net/iw_handler.h> /* New driver API */
  34. static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
  35. u8 *wpa_ie, size_t wpa_ie_len);
  36. static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
  37. static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
  38. __u32 *, char *);
  39. /**
  40. * prism54_mib_mode_helper - MIB change mode helper function
  41. * @mib: the &struct islpci_mib object to modify
  42. * @iw_mode: new mode (%IW_MODE_*)
  43. *
  44. * This is a helper function, hence it does not lock. Make sure
  45. * caller deals with locking *if* necessary. This function sets the
  46. * mode-dependent mib values and does the mapping of the Linux
  47. * Wireless API modes to Device firmware modes. It also checks for
  48. * correct valid Linux wireless modes.
  49. */
  50. static int
  51. prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
  52. {
  53. u32 config = INL_CONFIG_MANUALRUN;
  54. u32 mode, bsstype;
  55. /* For now, just catch early the Repeater and Secondary modes here */
  56. if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
  57. printk(KERN_DEBUG
  58. "%s(): Sorry, Repeater mode and Secondary mode "
  59. "are not yet supported by this driver.\n", __FUNCTION__);
  60. return -EINVAL;
  61. }
  62. priv->iw_mode = iw_mode;
  63. switch (iw_mode) {
  64. case IW_MODE_AUTO:
  65. mode = INL_MODE_CLIENT;
  66. bsstype = DOT11_BSSTYPE_ANY;
  67. break;
  68. case IW_MODE_ADHOC:
  69. mode = INL_MODE_CLIENT;
  70. bsstype = DOT11_BSSTYPE_IBSS;
  71. break;
  72. case IW_MODE_INFRA:
  73. mode = INL_MODE_CLIENT;
  74. bsstype = DOT11_BSSTYPE_INFRA;
  75. break;
  76. case IW_MODE_MASTER:
  77. mode = INL_MODE_AP;
  78. bsstype = DOT11_BSSTYPE_INFRA;
  79. break;
  80. case IW_MODE_MONITOR:
  81. mode = INL_MODE_PROMISCUOUS;
  82. bsstype = DOT11_BSSTYPE_ANY;
  83. config |= INL_CONFIG_RXANNEX;
  84. break;
  85. default:
  86. return -EINVAL;
  87. }
  88. if (init_wds)
  89. config |= INL_CONFIG_WDS;
  90. mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype);
  91. mgt_set(priv, OID_INL_CONFIG, &config);
  92. mgt_set(priv, OID_INL_MODE, &mode);
  93. return 0;
  94. }
  95. /**
  96. * prism54_mib_init - fill MIB cache with defaults
  97. *
  98. * this function initializes the struct given as @mib with defaults,
  99. * of which many are retrieved from the global module parameter
  100. * variables.
  101. */
  102. void
  103. prism54_mib_init(islpci_private *priv)
  104. {
  105. u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
  106. struct obj_buffer psm_buffer = {
  107. .size = PSM_BUFFER_SIZE,
  108. .addr = priv->device_psm_buffer
  109. };
  110. channel = CARD_DEFAULT_CHANNEL;
  111. authen = CARD_DEFAULT_AUTHEN;
  112. wep = CARD_DEFAULT_WEP;
  113. filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
  114. dot1x = CARD_DEFAULT_DOT1X;
  115. mlme = CARD_DEFAULT_MLME_MODE;
  116. conformance = CARD_DEFAULT_CONFORMANCE;
  117. power = 127;
  118. mode = CARD_DEFAULT_IW_MODE;
  119. mgt_set(priv, DOT11_OID_CHANNEL, &channel);
  120. mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
  121. mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep);
  122. mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
  123. mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
  124. mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
  125. mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
  126. mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
  127. mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
  128. /* This sets all of the mode-dependent values */
  129. prism54_mib_mode_helper(priv, mode);
  130. }
  131. /* this will be executed outside of atomic context thanks to
  132. * schedule_work(), thus we can as well use sleeping semaphore
  133. * locking */
  134. void
  135. prism54_update_stats(islpci_private *priv)
  136. {
  137. char *data;
  138. int j;
  139. struct obj_bss bss, *bss2;
  140. union oid_res_t r;
  141. if (down_interruptible(&priv->stats_sem))
  142. return;
  143. /* Noise floor.
  144. * I'm not sure if the unit is dBm.
  145. * Note : If we are not connected, this value seems to be irrelevant. */
  146. mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
  147. priv->local_iwstatistics.qual.noise = r.u;
  148. /* Get the rssi of the link. To do this we need to retrieve a bss. */
  149. /* First get the MAC address of the AP we are associated with. */
  150. mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
  151. data = r.ptr;
  152. /* copy this MAC to the bss */
  153. memcpy(bss.address, data, 6);
  154. kfree(data);
  155. /* now ask for the corresponding bss */
  156. j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r);
  157. bss2 = r.ptr;
  158. /* report the rssi and use it to calculate
  159. * link quality through a signal-noise
  160. * ratio */
  161. priv->local_iwstatistics.qual.level = bss2->rssi;
  162. priv->local_iwstatistics.qual.qual =
  163. bss2->rssi - priv->iwstatistics.qual.noise;
  164. kfree(bss2);
  165. /* report that the stats are new */
  166. priv->local_iwstatistics.qual.updated = 0x7;
  167. /* Rx : unable to decrypt the MPDU */
  168. mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r);
  169. priv->local_iwstatistics.discard.code = r.u;
  170. /* Tx : Max MAC retries num reached */
  171. mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
  172. priv->local_iwstatistics.discard.retries = r.u;
  173. up(&priv->stats_sem);
  174. return;
  175. }
  176. struct iw_statistics *
  177. prism54_get_wireless_stats(struct net_device *ndev)
  178. {
  179. islpci_private *priv = netdev_priv(ndev);
  180. /* If the stats are being updated return old data */
  181. if (down_trylock(&priv->stats_sem) == 0) {
  182. memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
  183. sizeof (struct iw_statistics));
  184. /* They won't be marked updated for the next time */
  185. priv->local_iwstatistics.qual.updated = 0;
  186. up(&priv->stats_sem);
  187. } else
  188. priv->iwstatistics.qual.updated = 0;
  189. /* Update our wireless stats, but do not schedule to often
  190. * (max 1 HZ) */
  191. if ((priv->stats_timestamp == 0) ||
  192. time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
  193. schedule_work(&priv->stats_work);
  194. priv->stats_timestamp = jiffies;
  195. }
  196. return &priv->iwstatistics;
  197. }
  198. static int
  199. prism54_commit(struct net_device *ndev, struct iw_request_info *info,
  200. char *cwrq, char *extra)
  201. {
  202. islpci_private *priv = netdev_priv(ndev);
  203. /* simply re-set the last set SSID, this should commit most stuff */
  204. /* Commit in Monitor mode is not necessary, also setting essid
  205. * in Monitor mode does not make sense and isn't allowed for this
  206. * device's firmware */
  207. if (priv->iw_mode != IW_MODE_MONITOR)
  208. return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
  209. return 0;
  210. }
  211. static int
  212. prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
  213. char *cwrq, char *extra)
  214. {
  215. islpci_private *priv = netdev_priv(ndev);
  216. char *capabilities;
  217. union oid_res_t r;
  218. int rvalue;
  219. if (islpci_get_state(priv) < PRV_STATE_INIT) {
  220. strncpy(cwrq, "NOT READY!", IFNAMSIZ);
  221. return 0;
  222. }
  223. rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r);
  224. switch (r.u) {
  225. case INL_PHYCAP_5000MHZ:
  226. capabilities = "IEEE 802.11a/b/g";
  227. break;
  228. case INL_PHYCAP_FAA:
  229. capabilities = "IEEE 802.11b/g - FAA Support";
  230. break;
  231. case INL_PHYCAP_2400MHZ:
  232. default:
  233. capabilities = "IEEE 802.11b/g"; /* Default */
  234. break;
  235. }
  236. strncpy(cwrq, capabilities, IFNAMSIZ);
  237. return rvalue;
  238. }
  239. static int
  240. prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
  241. struct iw_freq *fwrq, char *extra)
  242. {
  243. islpci_private *priv = netdev_priv(ndev);
  244. int rvalue;
  245. u32 c;
  246. if (fwrq->m < 1000)
  247. /* we have a channel number */
  248. c = fwrq->m;
  249. else
  250. c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
  251. rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
  252. /* Call commit handler */
  253. return (rvalue ? rvalue : -EINPROGRESS);
  254. }
  255. static int
  256. prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
  257. struct iw_freq *fwrq, char *extra)
  258. {
  259. islpci_private *priv = netdev_priv(ndev);
  260. union oid_res_t r;
  261. int rvalue;
  262. rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
  263. fwrq->i = r.u;
  264. rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r);
  265. fwrq->m = r.u;
  266. fwrq->e = 3;
  267. return rvalue;
  268. }
  269. static int
  270. prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
  271. __u32 * uwrq, char *extra)
  272. {
  273. islpci_private *priv = netdev_priv(ndev);
  274. u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
  275. /* Let's see if the user passed a valid Linux Wireless mode */
  276. if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
  277. printk(KERN_DEBUG
  278. "%s: %s() You passed a non-valid init_mode.\n",
  279. priv->ndev->name, __FUNCTION__);
  280. return -EINVAL;
  281. }
  282. down_write(&priv->mib_sem);
  283. if (prism54_mib_mode_helper(priv, *uwrq)) {
  284. up_write(&priv->mib_sem);
  285. return -EOPNOTSUPP;
  286. }
  287. /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an
  288. * extended one.
  289. */
  290. if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN))
  291. mlmeautolevel = DOT11_MLME_INTERMEDIATE;
  292. if (priv->wpa)
  293. mlmeautolevel = DOT11_MLME_EXTENDED;
  294. mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
  295. if (mgt_commit(priv)) {
  296. up_write(&priv->mib_sem);
  297. return -EIO;
  298. }
  299. priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
  300. ? priv->monitor_type : ARPHRD_ETHER;
  301. up_write(&priv->mib_sem);
  302. return 0;
  303. }
  304. /* Use mib cache */
  305. static int
  306. prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
  307. __u32 * uwrq, char *extra)
  308. {
  309. islpci_private *priv = netdev_priv(ndev);
  310. BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
  311. IW_MODE_MONITOR));
  312. *uwrq = priv->iw_mode;
  313. return 0;
  314. }
  315. /* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
  316. * emit data if (sensitivity > rssi - noise) (in dBm).
  317. * prism54_set_sens does not seem to work.
  318. */
  319. static int
  320. prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
  321. struct iw_param *vwrq, char *extra)
  322. {
  323. islpci_private *priv = netdev_priv(ndev);
  324. u32 sens;
  325. /* by default the card sets this to 20. */
  326. sens = vwrq->disabled ? 20 : vwrq->value;
  327. return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
  328. }
  329. static int
  330. prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
  331. struct iw_param *vwrq, char *extra)
  332. {
  333. islpci_private *priv = netdev_priv(ndev);
  334. union oid_res_t r;
  335. int rvalue;
  336. rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r);
  337. vwrq->value = r.u;
  338. vwrq->disabled = (vwrq->value == 0);
  339. vwrq->fixed = 1;
  340. return rvalue;
  341. }
  342. static int
  343. prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
  344. struct iw_point *dwrq, char *extra)
  345. {
  346. struct iw_range *range = (struct iw_range *) extra;
  347. islpci_private *priv = netdev_priv(ndev);
  348. u8 *data;
  349. int i, m, rvalue;
  350. struct obj_frequencies *freq;
  351. union oid_res_t r;
  352. memset(range, 0, sizeof (struct iw_range));
  353. dwrq->length = sizeof (struct iw_range);
  354. /* set the wireless extension version number */
  355. range->we_version_source = SUPPORTED_WIRELESS_EXT;
  356. range->we_version_compiled = WIRELESS_EXT;
  357. /* Now the encoding capabilities */
  358. range->num_encoding_sizes = 3;
  359. /* 64(40) bits WEP */
  360. range->encoding_size[0] = 5;
  361. /* 128(104) bits WEP */
  362. range->encoding_size[1] = 13;
  363. /* 256 bits for WPA-PSK */
  364. range->encoding_size[2] = 32;
  365. /* 4 keys are allowed */
  366. range->max_encoding_tokens = 4;
  367. /* we don't know the quality range... */
  368. range->max_qual.level = 0;
  369. range->max_qual.noise = 0;
  370. range->max_qual.qual = 0;
  371. /* these value describe an average quality. Needs more tweaking... */
  372. range->avg_qual.level = -80; /* -80 dBm */
  373. range->avg_qual.noise = 0; /* don't know what to put here */
  374. range->avg_qual.qual = 0;
  375. range->sensitivity = 200;
  376. /* retry limit capabilities */
  377. range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
  378. range->retry_flags = IW_RETRY_LIMIT;
  379. range->r_time_flags = IW_RETRY_LIFETIME;
  380. /* I don't know the range. Put stupid things here */
  381. range->min_retry = 1;
  382. range->max_retry = 65535;
  383. range->min_r_time = 1024;
  384. range->max_r_time = 65535 * 1024;
  385. /* txpower is supported in dBm's */
  386. range->txpower_capa = IW_TXPOW_DBM;
  387. /* Event capability (kernel + driver) */
  388. range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
  389. IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
  390. IW_EVENT_CAPA_MASK(SIOCGIWAP));
  391. range->event_capa[1] = IW_EVENT_CAPA_K_1;
  392. range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
  393. if (islpci_get_state(priv) < PRV_STATE_INIT)
  394. return 0;
  395. /* Request the device for the supported frequencies
  396. * not really relevant since some devices will report the 5 GHz band
  397. * frequencies even if they don't support them.
  398. */
  399. rvalue =
  400. mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
  401. freq = r.ptr;
  402. range->num_channels = freq->nr;
  403. range->num_frequency = freq->nr;
  404. m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
  405. for (i = 0; i < m; i++) {
  406. range->freq[i].m = freq->mhz[i];
  407. range->freq[i].e = 6;
  408. range->freq[i].i = channel_of_freq(freq->mhz[i]);
  409. }
  410. kfree(freq);
  411. rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
  412. data = r.ptr;
  413. /* We got an array of char. It is NULL terminated. */
  414. i = 0;
  415. while ((i < IW_MAX_BITRATES) && (*data != 0)) {
  416. /* the result must be in bps. The card gives us 500Kbps */
  417. range->bitrate[i] = *data * 500000;
  418. i++;
  419. data++;
  420. }
  421. range->num_bitrates = i;
  422. kfree(r.ptr);
  423. return rvalue;
  424. }
  425. /* Set AP address*/
  426. static int
  427. prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
  428. struct sockaddr *awrq, char *extra)
  429. {
  430. islpci_private *priv = netdev_priv(ndev);
  431. char bssid[6];
  432. int rvalue;
  433. if (awrq->sa_family != ARPHRD_ETHER)
  434. return -EINVAL;
  435. /* prepare the structure for the set object */
  436. memcpy(&bssid[0], awrq->sa_data, 6);
  437. /* set the bssid -- does this make sense when in AP mode? */
  438. rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid);
  439. return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */
  440. }
  441. /* get AP address*/
  442. static int
  443. prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
  444. struct sockaddr *awrq, char *extra)
  445. {
  446. islpci_private *priv = netdev_priv(ndev);
  447. union oid_res_t r;
  448. int rvalue;
  449. rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
  450. memcpy(awrq->sa_data, r.ptr, 6);
  451. awrq->sa_family = ARPHRD_ETHER;
  452. kfree(r.ptr);
  453. return rvalue;
  454. }
  455. static int
  456. prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
  457. struct iw_param *vwrq, char *extra)
  458. {
  459. /* hehe the device does this automagicaly */
  460. return 0;
  461. }
  462. /* a little helper that will translate our data into a card independent
  463. * format that the Wireless Tools will understand. This was inspired by
  464. * the "Aironet driver for 4500 and 4800 series cards" (GPL)
  465. */
  466. static char *
  467. prism54_translate_bss(struct net_device *ndev, char *current_ev,
  468. char *end_buf, struct obj_bss *bss, char noise)
  469. {
  470. struct iw_event iwe; /* Temporary buffer */
  471. short cap;
  472. islpci_private *priv = netdev_priv(ndev);
  473. /* The first entry must be the MAC address */
  474. memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
  475. iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
  476. iwe.cmd = SIOCGIWAP;
  477. current_ev =
  478. iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
  479. /* The following entries will be displayed in the same order we give them */
  480. /* The ESSID. */
  481. iwe.u.data.length = bss->ssid.length;
  482. iwe.u.data.flags = 1;
  483. iwe.cmd = SIOCGIWESSID;
  484. current_ev = iwe_stream_add_point(current_ev, end_buf,
  485. &iwe, bss->ssid.octets);
  486. /* Capabilities */
  487. #define CAP_ESS 0x01
  488. #define CAP_IBSS 0x02
  489. #define CAP_CRYPT 0x10
  490. /* Mode */
  491. cap = bss->capinfo;
  492. iwe.u.mode = 0;
  493. if (cap & CAP_ESS)
  494. iwe.u.mode = IW_MODE_MASTER;
  495. else if (cap & CAP_IBSS)
  496. iwe.u.mode = IW_MODE_ADHOC;
  497. iwe.cmd = SIOCGIWMODE;
  498. if (iwe.u.mode)
  499. current_ev =
  500. iwe_stream_add_event(current_ev, end_buf, &iwe,
  501. IW_EV_UINT_LEN);
  502. /* Encryption capability */
  503. if (cap & CAP_CRYPT)
  504. iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
  505. else
  506. iwe.u.data.flags = IW_ENCODE_DISABLED;
  507. iwe.u.data.length = 0;
  508. iwe.cmd = SIOCGIWENCODE;
  509. current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
  510. /* Add frequency. (short) bss->channel is the frequency in MHz */
  511. iwe.u.freq.m = bss->channel;
  512. iwe.u.freq.e = 6;
  513. iwe.cmd = SIOCGIWFREQ;
  514. current_ev =
  515. iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
  516. /* Add quality statistics */
  517. iwe.u.qual.level = bss->rssi;
  518. iwe.u.qual.noise = noise;
  519. /* do a simple SNR for quality */
  520. iwe.u.qual.qual = bss->rssi - noise;
  521. iwe.cmd = IWEVQUAL;
  522. current_ev =
  523. iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
  524. if (priv->wpa) {
  525. u8 wpa_ie[MAX_WPA_IE_LEN];
  526. char *buf, *p;
  527. size_t wpa_ie_len;
  528. int i;
  529. wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
  530. if (wpa_ie_len > 0 &&
  531. (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
  532. p = buf;
  533. p += sprintf(p, "wpa_ie=");
  534. for (i = 0; i < wpa_ie_len; i++) {
  535. p += sprintf(p, "%02x", wpa_ie[i]);
  536. }
  537. memset(&iwe, 0, sizeof (iwe));
  538. iwe.cmd = IWEVCUSTOM;
  539. iwe.u.data.length = strlen(buf);
  540. current_ev = iwe_stream_add_point(current_ev, end_buf,
  541. &iwe, buf);
  542. kfree(buf);
  543. }
  544. }
  545. return current_ev;
  546. }
  547. static int
  548. prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
  549. struct iw_point *dwrq, char *extra)
  550. {
  551. islpci_private *priv = netdev_priv(ndev);
  552. int i, rvalue;
  553. struct obj_bsslist *bsslist;
  554. u32 noise = 0;
  555. char *current_ev = extra;
  556. union oid_res_t r;
  557. if (islpci_get_state(priv) < PRV_STATE_INIT) {
  558. /* device is not ready, fail gently */
  559. dwrq->length = 0;
  560. return 0;
  561. }
  562. /* first get the noise value. We will use it to report the link quality */
  563. rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
  564. noise = r.u;
  565. /* Ask the device for a list of known bss.
  566. * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
  567. * The new API, using SIOCGIWSCAN, is only limited by the buffer size.
  568. * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
  569. * Starting with WE-17, the buffer can be as big as needed.
  570. * But the device won't repport anything if you change the value
  571. * of IWMAX_BSS=24. */
  572. rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
  573. bsslist = r.ptr;
  574. /* ok now, scan the list and translate its info */
  575. for (i = 0; i < (int) bsslist->nr; i++) {
  576. current_ev = prism54_translate_bss(ndev, current_ev,
  577. extra + dwrq->length,
  578. &(bsslist->bsslist[i]),
  579. noise);
  580. /* Check if there is space for one more entry */
  581. if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
  582. /* Ask user space to try again with a bigger buffer */
  583. rvalue = -E2BIG;
  584. break;
  585. }
  586. }
  587. kfree(bsslist);
  588. dwrq->length = (current_ev - extra);
  589. dwrq->flags = 0; /* todo */
  590. return rvalue;
  591. }
  592. static int
  593. prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
  594. struct iw_point *dwrq, char *extra)
  595. {
  596. islpci_private *priv = netdev_priv(ndev);
  597. struct obj_ssid essid;
  598. memset(essid.octets, 0, 33);
  599. /* Check if we were asked for `any' */
  600. if (dwrq->flags && dwrq->length) {
  601. if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
  602. return -E2BIG;
  603. essid.length = dwrq->length - 1;
  604. memcpy(essid.octets, extra, dwrq->length);
  605. } else
  606. essid.length = 0;
  607. if (priv->iw_mode != IW_MODE_MONITOR)
  608. return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
  609. /* If in monitor mode, just save to mib */
  610. mgt_set(priv, DOT11_OID_SSID, &essid);
  611. return 0;
  612. }
  613. static int
  614. prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
  615. struct iw_point *dwrq, char *extra)
  616. {
  617. islpci_private *priv = netdev_priv(ndev);
  618. struct obj_ssid *essid;
  619. union oid_res_t r;
  620. int rvalue;
  621. rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r);
  622. essid = r.ptr;
  623. if (essid->length) {
  624. dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */
  625. /* if it is to big, trunk it */
  626. dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1);
  627. } else {
  628. dwrq->flags = 0;
  629. dwrq->length = 0;
  630. }
  631. essid->octets[essid->length] = '\0';
  632. memcpy(extra, essid->octets, dwrq->length);
  633. kfree(essid);
  634. return rvalue;
  635. }
  636. /* Provides no functionality, just completes the ioctl. In essence this is a
  637. * just a cosmetic ioctl.
  638. */
  639. static int
  640. prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
  641. struct iw_point *dwrq, char *extra)
  642. {
  643. islpci_private *priv = netdev_priv(ndev);
  644. if (dwrq->length > IW_ESSID_MAX_SIZE)
  645. return -E2BIG;
  646. down_write(&priv->mib_sem);
  647. memset(priv->nickname, 0, sizeof (priv->nickname));
  648. memcpy(priv->nickname, extra, dwrq->length);
  649. up_write(&priv->mib_sem);
  650. return 0;
  651. }
  652. static int
  653. prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
  654. struct iw_point *dwrq, char *extra)
  655. {
  656. islpci_private *priv = netdev_priv(ndev);
  657. dwrq->length = 0;
  658. down_read(&priv->mib_sem);
  659. dwrq->length = strlen(priv->nickname) + 1;
  660. memcpy(extra, priv->nickname, dwrq->length);
  661. up_read(&priv->mib_sem);
  662. return 0;
  663. }
  664. /* Set the allowed Bitrates */
  665. static int
  666. prism54_set_rate(struct net_device *ndev,
  667. struct iw_request_info *info,
  668. struct iw_param *vwrq, char *extra)
  669. {
  670. islpci_private *priv = netdev_priv(ndev);
  671. u32 rate, profile;
  672. char *data;
  673. int ret, i;
  674. union oid_res_t r;
  675. if (vwrq->value == -1) {
  676. /* auto mode. No limit. */
  677. profile = 1;
  678. return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
  679. }
  680. ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
  681. if (ret) {
  682. kfree(r.ptr);
  683. return ret;
  684. }
  685. rate = (u32) (vwrq->value / 500000);
  686. data = r.ptr;
  687. i = 0;
  688. while (data[i]) {
  689. if (rate && (data[i] == rate)) {
  690. break;
  691. }
  692. if (vwrq->value == i) {
  693. break;
  694. }
  695. data[i] |= 0x80;
  696. i++;
  697. }
  698. if (!data[i]) {
  699. kfree(r.ptr);
  700. return -EINVAL;
  701. }
  702. data[i] |= 0x80;
  703. data[i + 1] = 0;
  704. /* Now, check if we want a fixed or auto value */
  705. if (vwrq->fixed) {
  706. data[0] = data[i];
  707. data[1] = 0;
  708. }
  709. /*
  710. i = 0;
  711. printk("prism54 rate: ");
  712. while(data[i]) {
  713. printk("%u ", data[i]);
  714. i++;
  715. }
  716. printk("0\n");
  717. */
  718. profile = -1;
  719. ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
  720. ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
  721. ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
  722. kfree(r.ptr);
  723. return ret;
  724. }
  725. /* Get the current bit rate */
  726. static int
  727. prism54_get_rate(struct net_device *ndev,
  728. struct iw_request_info *info,
  729. struct iw_param *vwrq, char *extra)
  730. {
  731. islpci_private *priv = netdev_priv(ndev);
  732. int rvalue;
  733. char *data;
  734. union oid_res_t r;
  735. /* Get the current bit rate */
  736. if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
  737. return rvalue;
  738. vwrq->value = r.u * 500000;
  739. /* request the device for the enabled rates */
  740. rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r);
  741. if (rvalue) {
  742. kfree(r.ptr);
  743. return rvalue;
  744. }
  745. data = r.ptr;
  746. vwrq->fixed = (data[0] != 0) && (data[1] == 0);
  747. kfree(r.ptr);
  748. return 0;
  749. }
  750. static int
  751. prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
  752. struct iw_param *vwrq, char *extra)
  753. {
  754. islpci_private *priv = netdev_priv(ndev);
  755. return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
  756. }
  757. static int
  758. prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
  759. struct iw_param *vwrq, char *extra)
  760. {
  761. islpci_private *priv = netdev_priv(ndev);
  762. union oid_res_t r;
  763. int rvalue;
  764. /* get the rts threshold */
  765. rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r);
  766. vwrq->value = r.u;
  767. return rvalue;
  768. }
  769. static int
  770. prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
  771. struct iw_param *vwrq, char *extra)
  772. {
  773. islpci_private *priv = netdev_priv(ndev);
  774. return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
  775. }
  776. static int
  777. prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
  778. struct iw_param *vwrq, char *extra)
  779. {
  780. islpci_private *priv = netdev_priv(ndev);
  781. union oid_res_t r;
  782. int rvalue;
  783. rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r);
  784. vwrq->value = r.u;
  785. return rvalue;
  786. }
  787. /* Here we have (min,max) = max retries for (small frames, big frames). Where
  788. * big frame <=> bigger than the rts threshold
  789. * small frame <=> smaller than the rts threshold
  790. * This is not really the behavior expected by the wireless tool but it seems
  791. * to be a common behavior in other drivers.
  792. */
  793. static int
  794. prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
  795. struct iw_param *vwrq, char *extra)
  796. {
  797. islpci_private *priv = netdev_priv(ndev);
  798. u32 slimit = 0, llimit = 0; /* short and long limit */
  799. u32 lifetime = 0;
  800. int rvalue = 0;
  801. if (vwrq->disabled)
  802. /* we cannot disable this feature */
  803. return -EINVAL;
  804. if (vwrq->flags & IW_RETRY_LIMIT) {
  805. if (vwrq->flags & IW_RETRY_MIN)
  806. slimit = vwrq->value;
  807. else if (vwrq->flags & IW_RETRY_MAX)
  808. llimit = vwrq->value;
  809. else {
  810. /* we are asked to set both */
  811. slimit = vwrq->value;
  812. llimit = vwrq->value;
  813. }
  814. }
  815. if (vwrq->flags & IW_RETRY_LIFETIME)
  816. /* Wireless tools use us unit while the device uses 1024 us unit */
  817. lifetime = vwrq->value / 1024;
  818. /* now set what is requested */
  819. if (slimit)
  820. rvalue =
  821. mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
  822. if (llimit)
  823. rvalue |=
  824. mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
  825. if (lifetime)
  826. rvalue |=
  827. mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
  828. &lifetime);
  829. return rvalue;
  830. }
  831. static int
  832. prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
  833. struct iw_param *vwrq, char *extra)
  834. {
  835. islpci_private *priv = netdev_priv(ndev);
  836. union oid_res_t r;
  837. int rvalue = 0;
  838. vwrq->disabled = 0; /* It cannot be disabled */
  839. if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
  840. /* we are asked for the life time */
  841. rvalue =
  842. mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
  843. vwrq->value = r.u * 1024;
  844. vwrq->flags = IW_RETRY_LIFETIME;
  845. } else if ((vwrq->flags & IW_RETRY_MAX)) {
  846. /* we are asked for the long retry limit */
  847. rvalue |=
  848. mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
  849. vwrq->value = r.u;
  850. vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
  851. } else {
  852. /* default. get the short retry limit */
  853. rvalue |=
  854. mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
  855. vwrq->value = r.u;
  856. vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
  857. }
  858. return rvalue;
  859. }
  860. static int
  861. prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
  862. struct iw_point *dwrq, char *extra)
  863. {
  864. islpci_private *priv = netdev_priv(ndev);
  865. int rvalue = 0, force = 0;
  866. int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
  867. union oid_res_t r;
  868. /* with the new API, it's impossible to get a NULL pointer.
  869. * New version of iwconfig set the IW_ENCODE_NOKEY flag
  870. * when no key is given, but older versions don't. */
  871. if (dwrq->length > 0) {
  872. /* we have a key to set */
  873. int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
  874. int current_index;
  875. struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
  876. /* get the current key index */
  877. rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
  878. current_index = r.u;
  879. /* Verify that the key is not marked as invalid */
  880. if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
  881. key.length = dwrq->length > sizeof (key.key) ?
  882. sizeof (key.key) : dwrq->length;
  883. memcpy(key.key, extra, key.length);
  884. if (key.length == 32)
  885. /* we want WPA-PSK */
  886. key.type = DOT11_PRIV_TKIP;
  887. if ((index < 0) || (index > 3))
  888. /* no index provided use the current one */
  889. index = current_index;
  890. /* now send the key to the card */
  891. rvalue |=
  892. mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
  893. &key);
  894. }
  895. /*
  896. * If a valid key is set, encryption should be enabled
  897. * (user may turn it off later).
  898. * This is also how "iwconfig ethX key on" works
  899. */
  900. if ((index == current_index) && (key.length > 0))
  901. force = 1;
  902. } else {
  903. int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
  904. if ((index >= 0) && (index <= 3)) {
  905. /* we want to set the key index */
  906. rvalue |=
  907. mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
  908. &index);
  909. } else {
  910. if (!dwrq->flags & IW_ENCODE_MODE) {
  911. /* we cannot do anything. Complain. */
  912. return -EINVAL;
  913. }
  914. }
  915. }
  916. /* now read the flags */
  917. if (dwrq->flags & IW_ENCODE_DISABLED) {
  918. /* Encoding disabled,
  919. * authen = DOT11_AUTH_OS;
  920. * invoke = 0;
  921. * exunencrypt = 0; */
  922. }
  923. if (dwrq->flags & IW_ENCODE_OPEN)
  924. /* Encode but accept non-encoded packets. No auth */
  925. invoke = 1;
  926. if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) {
  927. /* Refuse non-encoded packets. Auth */
  928. authen = DOT11_AUTH_BOTH;
  929. invoke = 1;
  930. exunencrypt = 1;
  931. }
  932. /* do the change if requested */
  933. if ((dwrq->flags & IW_ENCODE_MODE) || force) {
  934. rvalue |=
  935. mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
  936. rvalue |=
  937. mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
  938. rvalue |=
  939. mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
  940. &exunencrypt);
  941. }
  942. return rvalue;
  943. }
  944. static int
  945. prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
  946. struct iw_point *dwrq, char *extra)
  947. {
  948. islpci_private *priv = netdev_priv(ndev);
  949. struct obj_key *key;
  950. u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
  951. u32 authen = 0, invoke = 0, exunencrypt = 0;
  952. int rvalue;
  953. union oid_res_t r;
  954. /* first get the flags */
  955. rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
  956. authen = r.u;
  957. rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
  958. invoke = r.u;
  959. rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
  960. exunencrypt = r.u;
  961. if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt)
  962. dwrq->flags = IW_ENCODE_RESTRICTED;
  963. else if ((authen == DOT11_AUTH_OS) && !exunencrypt) {
  964. if (invoke)
  965. dwrq->flags = IW_ENCODE_OPEN;
  966. else
  967. dwrq->flags = IW_ENCODE_DISABLED;
  968. } else
  969. /* The card should not work in this state */
  970. dwrq->flags = 0;
  971. /* get the current device key index */
  972. rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
  973. devindex = r.u;
  974. /* Now get the key, return it */
  975. if ((index < 0) || (index > 3))
  976. /* no index provided, use the current one */
  977. index = devindex;
  978. rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
  979. key = r.ptr;
  980. dwrq->length = key->length;
  981. memcpy(extra, key->key, dwrq->length);
  982. kfree(key);
  983. /* return the used key index */
  984. dwrq->flags |= devindex + 1;
  985. return rvalue;
  986. }
  987. static int
  988. prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
  989. struct iw_param *vwrq, char *extra)
  990. {
  991. islpci_private *priv = netdev_priv(ndev);
  992. union oid_res_t r;
  993. int rvalue;
  994. rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
  995. /* intersil firmware operates in 0.25 dBm (1/4 dBm) */
  996. vwrq->value = (s32) r.u / 4;
  997. vwrq->fixed = 1;
  998. /* radio is not turned of
  999. * btw: how is possible to turn off only the radio
  1000. */
  1001. vwrq->disabled = 0;
  1002. return rvalue;
  1003. }
  1004. static int
  1005. prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
  1006. struct iw_param *vwrq, char *extra)
  1007. {
  1008. islpci_private *priv = netdev_priv(ndev);
  1009. s32 u = vwrq->value;
  1010. /* intersil firmware operates in 0.25 dBm (1/4) */
  1011. u *= 4;
  1012. if (vwrq->disabled) {
  1013. /* don't know how to disable radio */
  1014. printk(KERN_DEBUG
  1015. "%s: %s() disabling radio is not yet supported.\n",
  1016. priv->ndev->name, __FUNCTION__);
  1017. return -ENOTSUPP;
  1018. } else if (vwrq->fixed)
  1019. /* currently only fixed value is supported */
  1020. return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u);
  1021. else {
  1022. printk(KERN_DEBUG
  1023. "%s: %s() auto power will be implemented later.\n",
  1024. priv->ndev->name, __FUNCTION__);
  1025. return -ENOTSUPP;
  1026. }
  1027. }
  1028. static int
  1029. prism54_reset(struct net_device *ndev, struct iw_request_info *info,
  1030. __u32 * uwrq, char *extra)
  1031. {
  1032. islpci_reset(netdev_priv(ndev), 0);
  1033. return 0;
  1034. }
  1035. static int
  1036. prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
  1037. struct iw_point *dwrq, char *extra)
  1038. {
  1039. union oid_res_t r;
  1040. int rvalue;
  1041. enum oid_num_t n = dwrq->flags;
  1042. rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
  1043. dwrq->length = mgt_response_to_str(n, &r, extra);
  1044. if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
  1045. kfree(r.ptr);
  1046. return rvalue;
  1047. }
  1048. static int
  1049. prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
  1050. __u32 * uwrq, char *extra)
  1051. {
  1052. u32 oid = uwrq[0], u = uwrq[1];
  1053. return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
  1054. }
  1055. static int
  1056. prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
  1057. struct iw_point *dwrq, char *extra)
  1058. {
  1059. u32 oid = dwrq->flags;
  1060. return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
  1061. }
  1062. void
  1063. prism54_acl_init(struct islpci_acl *acl)
  1064. {
  1065. sema_init(&acl->sem, 1);
  1066. INIT_LIST_HEAD(&acl->mac_list);
  1067. acl->size = 0;
  1068. acl->policy = MAC_POLICY_OPEN;
  1069. }
  1070. static void
  1071. prism54_clear_mac(struct islpci_acl *acl)
  1072. {
  1073. struct list_head *ptr, *next;
  1074. struct mac_entry *entry;
  1075. if (down_interruptible(&acl->sem))
  1076. return;
  1077. if (acl->size == 0) {
  1078. up(&acl->sem);
  1079. return;
  1080. }
  1081. for (ptr = acl->mac_list.next, next = ptr->next;
  1082. ptr != &acl->mac_list; ptr = next, next = ptr->next) {
  1083. entry = list_entry(ptr, struct mac_entry, _list);
  1084. list_del(ptr);
  1085. kfree(entry);
  1086. }
  1087. acl->size = 0;
  1088. up(&acl->sem);
  1089. }
  1090. void
  1091. prism54_acl_clean(struct islpci_acl *acl)
  1092. {
  1093. prism54_clear_mac(acl);
  1094. }
  1095. static int
  1096. prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
  1097. struct sockaddr *awrq, char *extra)
  1098. {
  1099. islpci_private *priv = netdev_priv(ndev);
  1100. struct islpci_acl *acl = &priv->acl;
  1101. struct mac_entry *entry;
  1102. struct sockaddr *addr = (struct sockaddr *) extra;
  1103. if (addr->sa_family != ARPHRD_ETHER)
  1104. return -EOPNOTSUPP;
  1105. entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL);
  1106. if (entry == NULL)
  1107. return -ENOMEM;
  1108. memcpy(entry->addr, addr->sa_data, ETH_ALEN);
  1109. if (down_interruptible(&acl->sem)) {
  1110. kfree(entry);
  1111. return -ERESTARTSYS;
  1112. }
  1113. list_add_tail(&entry->_list, &acl->mac_list);
  1114. acl->size++;
  1115. up(&acl->sem);
  1116. return 0;
  1117. }
  1118. static int
  1119. prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
  1120. struct sockaddr *awrq, char *extra)
  1121. {
  1122. islpci_private *priv = netdev_priv(ndev);
  1123. struct islpci_acl *acl = &priv->acl;
  1124. struct mac_entry *entry;
  1125. struct list_head *ptr;
  1126. struct sockaddr *addr = (struct sockaddr *) extra;
  1127. if (addr->sa_family != ARPHRD_ETHER)
  1128. return -EOPNOTSUPP;
  1129. if (down_interruptible(&acl->sem))
  1130. return -ERESTARTSYS;
  1131. for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
  1132. entry = list_entry(ptr, struct mac_entry, _list);
  1133. if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
  1134. list_del(ptr);
  1135. acl->size--;
  1136. kfree(entry);
  1137. up(&acl->sem);
  1138. return 0;
  1139. }
  1140. }
  1141. up(&acl->sem);
  1142. return -EINVAL;
  1143. }
  1144. static int
  1145. prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
  1146. struct iw_point *dwrq, char *extra)
  1147. {
  1148. islpci_private *priv = netdev_priv(ndev);
  1149. struct islpci_acl *acl = &priv->acl;
  1150. struct mac_entry *entry;
  1151. struct list_head *ptr;
  1152. struct sockaddr *dst = (struct sockaddr *) extra;
  1153. dwrq->length = 0;
  1154. if (down_interruptible(&acl->sem))
  1155. return -ERESTARTSYS;
  1156. for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
  1157. entry = list_entry(ptr, struct mac_entry, _list);
  1158. memcpy(dst->sa_data, entry->addr, ETH_ALEN);
  1159. dst->sa_family = ARPHRD_ETHER;
  1160. dwrq->length++;
  1161. dst++;
  1162. }
  1163. up(&acl->sem);
  1164. return 0;
  1165. }
  1166. /* Setting policy also clears the MAC acl, even if we don't change the defaut
  1167. * policy
  1168. */
  1169. static int
  1170. prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
  1171. __u32 * uwrq, char *extra)
  1172. {
  1173. islpci_private *priv = netdev_priv(ndev);
  1174. struct islpci_acl *acl = &priv->acl;
  1175. u32 mlmeautolevel;
  1176. prism54_clear_mac(acl);
  1177. if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))
  1178. return -EINVAL;
  1179. down_write(&priv->mib_sem);
  1180. acl->policy = *uwrq;
  1181. /* the ACL code needs an intermediate mlmeautolevel */
  1182. if ((priv->iw_mode == IW_MODE_MASTER) &&
  1183. (acl->policy != MAC_POLICY_OPEN))
  1184. mlmeautolevel = DOT11_MLME_INTERMEDIATE;
  1185. else
  1186. mlmeautolevel = CARD_DEFAULT_MLME_MODE;
  1187. if (priv->wpa)
  1188. mlmeautolevel = DOT11_MLME_EXTENDED;
  1189. mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
  1190. /* restart the card with our new policy */
  1191. if (mgt_commit(priv)) {
  1192. up_write(&priv->mib_sem);
  1193. return -EIO;
  1194. }
  1195. up_write(&priv->mib_sem);
  1196. return 0;
  1197. }
  1198. static int
  1199. prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
  1200. __u32 * uwrq, char *extra)
  1201. {
  1202. islpci_private *priv = netdev_priv(ndev);
  1203. struct islpci_acl *acl = &priv->acl;
  1204. *uwrq = acl->policy;
  1205. return 0;
  1206. }
  1207. /* Return 1 only if client should be accepted. */
  1208. static int
  1209. prism54_mac_accept(struct islpci_acl *acl, char *mac)
  1210. {
  1211. struct list_head *ptr;
  1212. struct mac_entry *entry;
  1213. int res = 0;
  1214. if (down_interruptible(&acl->sem))
  1215. return -ERESTARTSYS;
  1216. if (acl->policy == MAC_POLICY_OPEN) {
  1217. up(&acl->sem);
  1218. return 1;
  1219. }
  1220. for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
  1221. entry = list_entry(ptr, struct mac_entry, _list);
  1222. if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
  1223. res = 1;
  1224. break;
  1225. }
  1226. }
  1227. res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
  1228. up(&acl->sem);
  1229. return res;
  1230. }
  1231. static int
  1232. prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
  1233. struct iw_point *dwrq, char *extra)
  1234. {
  1235. struct obj_mlme *mlme;
  1236. int rvalue;
  1237. mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
  1238. if (mlme == NULL)
  1239. return -ENOMEM;
  1240. /* Tell the card to kick every client */
  1241. mlme->id = 0;
  1242. rvalue =
  1243. mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
  1244. kfree(mlme);
  1245. return rvalue;
  1246. }
  1247. static int
  1248. prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
  1249. struct sockaddr *awrq, char *extra)
  1250. {
  1251. struct obj_mlme *mlme;
  1252. struct sockaddr *addr = (struct sockaddr *) extra;
  1253. int rvalue;
  1254. if (addr->sa_family != ARPHRD_ETHER)
  1255. return -EOPNOTSUPP;
  1256. mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
  1257. if (mlme == NULL)
  1258. return -ENOMEM;
  1259. /* Tell the card to only kick the corresponding bastard */
  1260. memcpy(mlme->address, addr->sa_data, ETH_ALEN);
  1261. mlme->id = -1;
  1262. rvalue =
  1263. mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
  1264. kfree(mlme);
  1265. return rvalue;
  1266. }
  1267. /* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
  1268. static void
  1269. format_event(islpci_private *priv, char *dest, const char *str,
  1270. const struct obj_mlme *mlme, u16 *length, int error)
  1271. {
  1272. const u8 *a = mlme->address;
  1273. int n = snprintf(dest, IW_CUSTOM_MAX,
  1274. "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
  1275. str,
  1276. ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
  1277. a[0], a[1], a[2], a[3], a[4], a[5],
  1278. (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
  1279. : ""), mlme->code);
  1280. BUG_ON(n > IW_CUSTOM_MAX);
  1281. *length = n;
  1282. }
  1283. static void
  1284. send_formatted_event(islpci_private *priv, const char *str,
  1285. const struct obj_mlme *mlme, int error)
  1286. {
  1287. union iwreq_data wrqu;
  1288. char *memptr;
  1289. memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
  1290. if (!memptr)
  1291. return;
  1292. wrqu.data.pointer = memptr;
  1293. wrqu.data.length = 0;
  1294. format_event(priv, memptr, str, mlme, &wrqu.data.length,
  1295. error);
  1296. wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
  1297. kfree(memptr);
  1298. }
  1299. static void
  1300. send_simple_event(islpci_private *priv, const char *str)
  1301. {
  1302. union iwreq_data wrqu;
  1303. char *memptr;
  1304. int n = strlen(str);
  1305. memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
  1306. if (!memptr)
  1307. return;
  1308. BUG_ON(n > IW_CUSTOM_MAX);
  1309. wrqu.data.pointer = memptr;
  1310. wrqu.data.length = n;
  1311. strcpy(memptr, str);
  1312. wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
  1313. kfree(memptr);
  1314. }
  1315. static void
  1316. link_changed(struct net_device *ndev, u32 bitrate)
  1317. {
  1318. islpci_private *priv = netdev_priv(ndev);
  1319. if (bitrate) {
  1320. if (priv->iw_mode == IW_MODE_INFRA) {
  1321. union iwreq_data uwrq;
  1322. prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
  1323. NULL);
  1324. wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
  1325. } else
  1326. send_simple_event(netdev_priv(ndev),
  1327. "Link established");
  1328. } else
  1329. send_simple_event(netdev_priv(ndev), "Link lost");
  1330. }
  1331. /* Beacon/ProbeResp payload header */
  1332. struct ieee80211_beacon_phdr {
  1333. u8 timestamp[8];
  1334. u16 beacon_int;
  1335. u16 capab_info;
  1336. } __attribute__ ((packed));
  1337. #define WLAN_EID_GENERIC 0xdd
  1338. static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
  1339. #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
  1340. #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
  1341. static void
  1342. prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
  1343. u8 *wpa_ie, size_t wpa_ie_len)
  1344. {
  1345. struct list_head *ptr;
  1346. struct islpci_bss_wpa_ie *bss = NULL;
  1347. if (wpa_ie_len > MAX_WPA_IE_LEN)
  1348. wpa_ie_len = MAX_WPA_IE_LEN;
  1349. if (down_interruptible(&priv->wpa_sem))
  1350. return;
  1351. /* try to use existing entry */
  1352. list_for_each(ptr, &priv->bss_wpa_list) {
  1353. bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
  1354. if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
  1355. list_move(&bss->list, &priv->bss_wpa_list);
  1356. break;
  1357. }
  1358. bss = NULL;
  1359. }
  1360. if (bss == NULL) {
  1361. /* add a new BSS entry; if max number of entries is already
  1362. * reached, replace the least recently updated */
  1363. if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
  1364. bss = list_entry(priv->bss_wpa_list.prev,
  1365. struct islpci_bss_wpa_ie, list);
  1366. list_del(&bss->list);
  1367. } else {
  1368. bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
  1369. if (bss != NULL) {
  1370. priv->num_bss_wpa++;
  1371. memset(bss, 0, sizeof (*bss));
  1372. }
  1373. }
  1374. if (bss != NULL) {
  1375. memcpy(bss->bssid, bssid, ETH_ALEN);
  1376. list_add(&bss->list, &priv->bss_wpa_list);
  1377. }
  1378. }
  1379. if (bss != NULL) {
  1380. memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
  1381. bss->wpa_ie_len = wpa_ie_len;
  1382. bss->last_update = jiffies;
  1383. } else {
  1384. printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
  1385. "\n", MAC2STR(bssid));
  1386. }
  1387. /* expire old entries from WPA list */
  1388. while (priv->num_bss_wpa > 0) {
  1389. bss = list_entry(priv->bss_wpa_list.prev,
  1390. struct islpci_bss_wpa_ie, list);
  1391. if (!time_after(jiffies, bss->last_update + 60 * HZ))
  1392. break;
  1393. list_del(&bss->list);
  1394. priv->num_bss_wpa--;
  1395. kfree(bss);
  1396. }
  1397. up(&priv->wpa_sem);
  1398. }
  1399. static size_t
  1400. prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
  1401. {
  1402. struct list_head *ptr;
  1403. struct islpci_bss_wpa_ie *bss = NULL;
  1404. size_t len = 0;
  1405. if (down_interruptible(&priv->wpa_sem))
  1406. return 0;
  1407. list_for_each(ptr, &priv->bss_wpa_list) {
  1408. bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
  1409. if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
  1410. break;
  1411. bss = NULL;
  1412. }
  1413. if (bss) {
  1414. len = bss->wpa_ie_len;
  1415. memcpy(wpa_ie, bss->wpa_ie, len);
  1416. }
  1417. up(&priv->wpa_sem);
  1418. return len;
  1419. }
  1420. void
  1421. prism54_wpa_ie_init(islpci_private *priv)
  1422. {
  1423. INIT_LIST_HEAD(&priv->bss_wpa_list);
  1424. sema_init(&priv->wpa_sem, 1);
  1425. }
  1426. void
  1427. prism54_wpa_ie_clean(islpci_private *priv)
  1428. {
  1429. struct list_head *ptr, *n;
  1430. list_for_each_safe(ptr, n, &priv->bss_wpa_list) {
  1431. struct islpci_bss_wpa_ie *bss;
  1432. bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
  1433. kfree(bss);
  1434. }
  1435. }
  1436. static void
  1437. prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
  1438. u8 *payload, size_t len)
  1439. {
  1440. struct ieee80211_beacon_phdr *hdr;
  1441. u8 *pos, *end;
  1442. if (!priv->wpa)
  1443. return;
  1444. hdr = (struct ieee80211_beacon_phdr *) payload;
  1445. pos = (u8 *) (hdr + 1);
  1446. end = payload + len;
  1447. while (pos < end) {
  1448. if (pos + 2 + pos[1] > end) {
  1449. printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
  1450. "for " MACSTR "\n", MAC2STR(addr));
  1451. return;
  1452. }
  1453. if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
  1454. memcmp(pos + 2, wpa_oid, 4) == 0) {
  1455. prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
  1456. return;
  1457. }
  1458. pos += 2 + pos[1];
  1459. }
  1460. }
  1461. static void
  1462. handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
  1463. {
  1464. if (((mlme->state == DOT11_STATE_AUTHING) ||
  1465. (mlme->state == DOT11_STATE_ASSOCING))
  1466. && mgt_mlme_answer(priv)) {
  1467. /* Someone is requesting auth and we must respond. Just send back
  1468. * the trap with error code set accordingly.
  1469. */
  1470. mlme->code = prism54_mac_accept(&priv->acl,
  1471. mlme->address) ? 0 : 1;
  1472. mgt_set_request(priv, oid, 0, mlme);
  1473. }
  1474. }
  1475. static int
  1476. prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
  1477. char *data)
  1478. {
  1479. struct obj_mlme *mlme = (struct obj_mlme *) data;
  1480. struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
  1481. struct obj_mlmeex *confirm;
  1482. u8 wpa_ie[MAX_WPA_IE_LEN];
  1483. int wpa_ie_len;
  1484. size_t len = 0; /* u16, better? */
  1485. u8 *payload = NULL, *pos = NULL;
  1486. int ret;
  1487. /* I think all trapable objects are listed here.
  1488. * Some oids have a EX version. The difference is that they are emitted
  1489. * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
  1490. * with more info.
  1491. * The few events already defined by the wireless tools are not really
  1492. * suited. We use the more flexible custom event facility.
  1493. */
  1494. if (oid >= DOT11_OID_BEACON) {
  1495. len = mlmeex->size;
  1496. payload = pos = mlmeex->data;
  1497. }
  1498. /* I fear prism54_process_bss_data won't work with big endian data */
  1499. if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
  1500. prism54_process_bss_data(priv, oid, mlmeex->address,
  1501. payload, len);
  1502. mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
  1503. switch (oid) {
  1504. case GEN_OID_LINKSTATE:
  1505. link_changed(priv->ndev, (u32) *data);
  1506. break;
  1507. case DOT11_OID_MICFAILURE:
  1508. send_simple_event(priv, "Mic failure");
  1509. break;
  1510. case DOT11_OID_DEAUTHENTICATE:
  1511. send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
  1512. break;
  1513. case DOT11_OID_AUTHENTICATE:
  1514. handle_request(priv, mlme, oid);
  1515. send_formatted_event(priv, "Authenticate request", mlme, 1);
  1516. break;
  1517. case DOT11_OID_DISASSOCIATE:
  1518. send_formatted_event(priv, "Disassociate request", mlme, 0);
  1519. break;
  1520. case DOT11_OID_ASSOCIATE:
  1521. handle_request(priv, mlme, oid);
  1522. send_formatted_event(priv, "Associate request", mlme, 1);
  1523. break;
  1524. case DOT11_OID_REASSOCIATE:
  1525. handle_request(priv, mlme, oid);
  1526. send_formatted_event(priv, "ReAssociate request", mlme, 1);
  1527. break;
  1528. case DOT11_OID_BEACON:
  1529. send_formatted_event(priv,
  1530. "Received a beacon from an unkown AP",
  1531. mlme, 0);
  1532. break;
  1533. case DOT11_OID_PROBE:
  1534. /* we received a probe from a client. */
  1535. send_formatted_event(priv, "Received a probe from client", mlme,
  1536. 0);
  1537. break;
  1538. /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
  1539. * is backward compatible layout-wise with "struct obj_mlme".
  1540. */
  1541. case DOT11_OID_DEAUTHENTICATEEX:
  1542. send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
  1543. break;
  1544. case DOT11_OID_AUTHENTICATEEX:
  1545. handle_request(priv, mlme, oid);
  1546. send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
  1547. if (priv->iw_mode != IW_MODE_MASTER
  1548. && mlmeex->state != DOT11_STATE_AUTHING)
  1549. break;
  1550. confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
  1551. if (!confirm)
  1552. break;
  1553. memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
  1554. printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
  1555. mlmeex->address[0],
  1556. mlmeex->address[1],
  1557. mlmeex->address[2],
  1558. mlmeex->address[3],
  1559. mlmeex->address[4],
  1560. mlmeex->address[5]
  1561. );
  1562. confirm->id = -1; /* or mlmeex->id ? */
  1563. confirm->state = 0; /* not used */
  1564. confirm->code = 0;
  1565. confirm->size = 6;
  1566. confirm->data[0] = 0x00;
  1567. confirm->data[1] = 0x00;
  1568. confirm->data[2] = 0x02;
  1569. confirm->data[3] = 0x00;
  1570. confirm->data[4] = 0x00;
  1571. confirm->data[5] = 0x00;
  1572. ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
  1573. kfree(confirm);
  1574. if (ret)
  1575. return ret;
  1576. break;
  1577. case DOT11_OID_DISASSOCIATEEX:
  1578. send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
  1579. break;
  1580. case DOT11_OID_ASSOCIATEEX:
  1581. handle_request(priv, mlme, oid);
  1582. send_formatted_event(priv, "Associate request (ex)", mlme, 1);
  1583. if (priv->iw_mode != IW_MODE_MASTER
  1584. && mlmeex->state != DOT11_STATE_AUTHING)
  1585. break;
  1586. confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
  1587. if (!confirm)
  1588. break;
  1589. memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
  1590. confirm->id = ((struct obj_mlmeex *)mlme)->id;
  1591. confirm->state = 0; /* not used */
  1592. confirm->code = 0;
  1593. wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
  1594. if (!wpa_ie_len) {
  1595. printk(KERN_DEBUG "No WPA IE found from "
  1596. "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
  1597. mlmeex->address[0],
  1598. mlmeex->address[1],
  1599. mlmeex->address[2],
  1600. mlmeex->address[3],
  1601. mlmeex->address[4],
  1602. mlmeex->address[5]
  1603. );
  1604. kfree(confirm);
  1605. break;
  1606. }
  1607. confirm->size = wpa_ie_len;
  1608. memcpy(&confirm->data, wpa_ie, wpa_ie_len);
  1609. mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
  1610. kfree(confirm);
  1611. break;
  1612. case DOT11_OID_REASSOCIATEEX:
  1613. handle_request(priv, mlme, oid);
  1614. send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
  1615. if (priv->iw_mode != IW_MODE_MASTER
  1616. && mlmeex->state != DOT11_STATE_ASSOCING)
  1617. break;
  1618. confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
  1619. if (!confirm)
  1620. break;
  1621. memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
  1622. confirm->id = mlmeex->id;
  1623. confirm->state = 0; /* not used */
  1624. confirm->code = 0;
  1625. wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
  1626. if (!wpa_ie_len) {
  1627. printk(KERN_DEBUG "No WPA IE found from "
  1628. "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
  1629. mlmeex->address[0],
  1630. mlmeex->address[1],
  1631. mlmeex->address[2],
  1632. mlmeex->address[3],
  1633. mlmeex->address[4],
  1634. mlmeex->address[5]
  1635. );
  1636. kfree(confirm);
  1637. break;
  1638. }
  1639. confirm->size = wpa_ie_len;
  1640. memcpy(&confirm->data, wpa_ie, wpa_ie_len);
  1641. mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
  1642. kfree(confirm);
  1643. break;
  1644. default:
  1645. return -EINVAL;
  1646. }
  1647. return 0;
  1648. }
  1649. /*
  1650. * Process a device trap. This is called via schedule_work(), outside of
  1651. * interrupt context, no locks held.
  1652. */
  1653. void
  1654. prism54_process_trap(void *data)
  1655. {
  1656. struct islpci_mgmtframe *frame = data;
  1657. struct net_device *ndev = frame->ndev;
  1658. enum oid_num_t n = mgt_oidtonum(frame->header->oid);
  1659. if (n != OID_NUM_LAST)
  1660. prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
  1661. islpci_mgt_release(frame);
  1662. }
  1663. int
  1664. prism54_set_mac_address(struct net_device *ndev, void *addr)
  1665. {
  1666. islpci_private *priv = netdev_priv(ndev);
  1667. int ret;
  1668. if (ndev->addr_len != 6)
  1669. return -EINVAL;
  1670. ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
  1671. &((struct sockaddr *) addr)->sa_data);
  1672. if (!ret)
  1673. memcpy(priv->ndev->dev_addr,
  1674. &((struct sockaddr *) addr)->sa_data, 6);
  1675. return ret;
  1676. }
  1677. /* Note: currently, use hostapd ioctl from the Host AP driver for WPA
  1678. * support. This is to be replaced with Linux wireless extensions once they
  1679. * get WPA support. */
  1680. /* Note II: please leave all this together as it will be easier to remove later,
  1681. * once wireless extensions add WPA support -mcgrof */
  1682. /* PRISM54_HOSTAPD ioctl() cmd: */
  1683. enum {
  1684. PRISM2_SET_ENCRYPTION = 6,
  1685. PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
  1686. PRISM2_HOSTAPD_MLME = 13,
  1687. PRISM2_HOSTAPD_SCAN_REQ = 14,
  1688. };
  1689. #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
  1690. #define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
  1691. #define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
  1692. #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
  1693. #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
  1694. ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
  1695. /* Maximum length for algorithm names (-1 for nul termination)
  1696. * used in ioctl() */
  1697. #define HOSTAP_CRYPT_ALG_NAME_LEN 16
  1698. struct prism2_hostapd_param {
  1699. u32 cmd;
  1700. u8 sta_addr[ETH_ALEN];
  1701. union {
  1702. struct {
  1703. u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
  1704. u32 flags;
  1705. u32 err;
  1706. u8 idx;
  1707. u8 seq[8]; /* sequence counter (set: RX, get: TX) */
  1708. u16 key_len;
  1709. u8 key[0];
  1710. } crypt;
  1711. struct {
  1712. u8 len;
  1713. u8 data[0];
  1714. } generic_elem;
  1715. struct {
  1716. #define MLME_STA_DEAUTH 0
  1717. #define MLME_STA_DISASSOC 1
  1718. u16 cmd;
  1719. u16 reason_code;
  1720. } mlme;
  1721. struct {
  1722. u8 ssid_len;
  1723. u8 ssid[32];
  1724. } scan_req;
  1725. } u;
  1726. };
  1727. static int
  1728. prism2_ioctl_set_encryption(struct net_device *dev,
  1729. struct prism2_hostapd_param *param,
  1730. int param_len)
  1731. {
  1732. islpci_private *priv = netdev_priv(dev);
  1733. int rvalue = 0, force = 0;
  1734. int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
  1735. union oid_res_t r;
  1736. /* with the new API, it's impossible to get a NULL pointer.
  1737. * New version of iwconfig set the IW_ENCODE_NOKEY flag
  1738. * when no key is given, but older versions don't. */
  1739. if (param->u.crypt.key_len > 0) {
  1740. /* we have a key to set */
  1741. int index = param->u.crypt.idx;
  1742. int current_index;
  1743. struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
  1744. /* get the current key index */
  1745. rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
  1746. current_index = r.u;
  1747. /* Verify that the key is not marked as invalid */
  1748. if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
  1749. key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
  1750. sizeof (param->u.crypt.key) : param->u.crypt.key_len;
  1751. memcpy(key.key, param->u.crypt.key, key.length);
  1752. if (key.length == 32)
  1753. /* we want WPA-PSK */
  1754. key.type = DOT11_PRIV_TKIP;
  1755. if ((index < 0) || (index > 3))
  1756. /* no index provided use the current one */
  1757. index = current_index;
  1758. /* now send the key to the card */
  1759. rvalue |=
  1760. mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
  1761. &key);
  1762. }
  1763. /*
  1764. * If a valid key is set, encryption should be enabled
  1765. * (user may turn it off later).
  1766. * This is also how "iwconfig ethX key on" works
  1767. */
  1768. if ((index == current_index) && (key.length > 0))
  1769. force = 1;
  1770. } else {
  1771. int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
  1772. if ((index >= 0) && (index <= 3)) {
  1773. /* we want to set the key index */
  1774. rvalue |=
  1775. mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
  1776. &index);
  1777. } else {
  1778. if (!param->u.crypt.flags & IW_ENCODE_MODE) {
  1779. /* we cannot do anything. Complain. */
  1780. return -EINVAL;
  1781. }
  1782. }
  1783. }
  1784. /* now read the flags */
  1785. if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
  1786. /* Encoding disabled,
  1787. * authen = DOT11_AUTH_OS;
  1788. * invoke = 0;
  1789. * exunencrypt = 0; */
  1790. }
  1791. if (param->u.crypt.flags & IW_ENCODE_OPEN)
  1792. /* Encode but accept non-encoded packets. No auth */
  1793. invoke = 1;
  1794. if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
  1795. /* Refuse non-encoded packets. Auth */
  1796. authen = DOT11_AUTH_BOTH;
  1797. invoke = 1;
  1798. exunencrypt = 1;
  1799. }
  1800. /* do the change if requested */
  1801. if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
  1802. rvalue |=
  1803. mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
  1804. rvalue |=
  1805. mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
  1806. rvalue |=
  1807. mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
  1808. &exunencrypt);
  1809. }
  1810. return rvalue;
  1811. }
  1812. static int
  1813. prism2_ioctl_set_generic_element(struct net_device *ndev,
  1814. struct prism2_hostapd_param *param,
  1815. int param_len)
  1816. {
  1817. islpci_private *priv = netdev_priv(ndev);
  1818. int max_len, len, alen, ret=0;
  1819. struct obj_attachment *attach;
  1820. len = param->u.generic_elem.len;
  1821. max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
  1822. if (max_len < 0 || max_len < len)
  1823. return -EINVAL;
  1824. alen = sizeof(*attach) + len;
  1825. attach = kmalloc(alen, GFP_KERNEL);
  1826. if (attach == NULL)
  1827. return -ENOMEM;
  1828. memset(attach, 0, alen);
  1829. #define WLAN_FC_TYPE_MGMT 0
  1830. #define WLAN_FC_STYPE_ASSOC_REQ 0
  1831. #define WLAN_FC_STYPE_REASSOC_REQ 2
  1832. /* Note: endianness is covered by mgt_set_varlen */
  1833. attach->type = (WLAN_FC_TYPE_MGMT << 2) |
  1834. (WLAN_FC_STYPE_ASSOC_REQ << 4);
  1835. attach->id = -1;
  1836. attach->size = len;
  1837. memcpy(attach->data, param->u.generic_elem.data, len);
  1838. ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
  1839. if (ret == 0) {
  1840. attach->type = (WLAN_FC_TYPE_MGMT << 2) |
  1841. (WLAN_FC_STYPE_REASSOC_REQ << 4);
  1842. ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
  1843. if (ret == 0)
  1844. printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
  1845. ndev->name);
  1846. }
  1847. kfree(attach);
  1848. return ret;
  1849. }
  1850. static int
  1851. prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
  1852. {
  1853. return -EOPNOTSUPP;
  1854. }
  1855. static int
  1856. prism2_ioctl_scan_req(struct net_device *ndev,
  1857. struct prism2_hostapd_param *param)
  1858. {
  1859. islpci_private *priv = netdev_priv(ndev);
  1860. int i, rvalue;
  1861. struct obj_bsslist *bsslist;
  1862. u32 noise = 0;
  1863. char *extra = "";
  1864. char *current_ev = "foo";
  1865. union oid_res_t r;
  1866. if (islpci_get_state(priv) < PRV_STATE_INIT) {
  1867. /* device is not ready, fail gently */
  1868. return 0;
  1869. }
  1870. /* first get the noise value. We will use it to report the link quality */
  1871. rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
  1872. noise = r.u;
  1873. /* Ask the device for a list of known bss. We can report at most
  1874. * IW_MAX_AP=64 to the range struct. But the device won't repport anything
  1875. * if you change the value of IWMAX_BSS=24.
  1876. */
  1877. rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
  1878. bsslist = r.ptr;
  1879. /* ok now, scan the list and translate its info */
  1880. for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
  1881. current_ev = prism54_translate_bss(ndev, current_ev,
  1882. extra + IW_SCAN_MAX_DATA,
  1883. &(bsslist->bsslist[i]),
  1884. noise);
  1885. kfree(bsslist);
  1886. return rvalue;
  1887. }
  1888. static int
  1889. prism54_hostapd(struct net_device *ndev, struct iw_point *p)
  1890. {
  1891. struct prism2_hostapd_param *param;
  1892. int ret = 0;
  1893. u32 uwrq;
  1894. printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
  1895. if (p->length < sizeof(struct prism2_hostapd_param) ||
  1896. p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
  1897. return -EINVAL;
  1898. param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
  1899. if (param == NULL)
  1900. return -ENOMEM;
  1901. if (copy_from_user(param, p->pointer, p->length)) {
  1902. kfree(param);
  1903. return -EFAULT;
  1904. }
  1905. switch (param->cmd) {
  1906. case PRISM2_SET_ENCRYPTION:
  1907. printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
  1908. ndev->name);
  1909. ret = prism2_ioctl_set_encryption(ndev, param, p->length);
  1910. break;
  1911. case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
  1912. printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
  1913. ndev->name);
  1914. ret = prism2_ioctl_set_generic_element(ndev, param,
  1915. p->length);
  1916. break;
  1917. case PRISM2_HOSTAPD_MLME:
  1918. printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
  1919. ndev->name);
  1920. ret = prism2_ioctl_mlme(ndev, param);
  1921. break;
  1922. case PRISM2_HOSTAPD_SCAN_REQ:
  1923. printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
  1924. ndev->name);
  1925. ret = prism2_ioctl_scan_req(ndev, param);
  1926. break;
  1927. case PRISM54_SET_WPA:
  1928. printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
  1929. ndev->name);
  1930. uwrq = 1;
  1931. ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
  1932. break;
  1933. case PRISM54_DROP_UNENCRYPTED:
  1934. printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
  1935. ndev->name);
  1936. #if 0
  1937. uwrq = 0x01;
  1938. mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
  1939. down_write(&priv->mib_sem);
  1940. mgt_commit(priv);
  1941. up_write(&priv->mib_sem);
  1942. #endif
  1943. /* Not necessary, as set_wpa does it, should we just do it here though? */
  1944. ret = 0;
  1945. break;
  1946. default:
  1947. printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
  1948. ndev->name);
  1949. ret = -EOPNOTSUPP;
  1950. break;
  1951. }
  1952. if (ret == 0 && copy_to_user(p->pointer, param, p->length))
  1953. ret = -EFAULT;
  1954. kfree(param);
  1955. return ret;
  1956. }
  1957. static int
  1958. prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
  1959. __u32 * uwrq, char *extra)
  1960. {
  1961. islpci_private *priv = netdev_priv(ndev);
  1962. u32 mlme, authen, dot1x, filter, wep;
  1963. if (islpci_get_state(priv) < PRV_STATE_INIT)
  1964. return 0;
  1965. wep = 1; /* For privacy invoked */
  1966. filter = 1; /* Filter out all unencrypted frames */
  1967. dot1x = 0x01; /* To enable eap filter */
  1968. mlme = DOT11_MLME_EXTENDED;
  1969. authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
  1970. down_write(&priv->mib_sem);
  1971. priv->wpa = *uwrq;
  1972. switch (priv->wpa) {
  1973. default:
  1974. case 0: /* Clears/disables WPA and friends */
  1975. wep = 0;
  1976. filter = 0; /* Do not filter un-encrypted data */
  1977. dot1x = 0;
  1978. mlme = DOT11_MLME_AUTO;
  1979. printk("%s: Disabling WPA\n", ndev->name);
  1980. break;
  1981. case 2:
  1982. case 1: /* WPA */
  1983. printk("%s: Enabling WPA\n", ndev->name);
  1984. break;
  1985. }
  1986. up_write(&priv->mib_sem);
  1987. mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
  1988. mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
  1989. mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
  1990. mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
  1991. mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
  1992. return 0;
  1993. }
  1994. static int
  1995. prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
  1996. __u32 * uwrq, char *extra)
  1997. {
  1998. islpci_private *priv = netdev_priv(ndev);
  1999. *uwrq = priv->wpa;
  2000. return 0;
  2001. }
  2002. static int
  2003. prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
  2004. __u32 * uwrq, char *extra)
  2005. {
  2006. islpci_private *priv = netdev_priv(ndev);
  2007. priv->monitor_type =
  2008. (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
  2009. if (priv->iw_mode == IW_MODE_MONITOR)
  2010. priv->ndev->type = priv->monitor_type;
  2011. return 0;
  2012. }
  2013. static int
  2014. prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
  2015. __u32 * uwrq, char *extra)
  2016. {
  2017. islpci_private *priv = netdev_priv(ndev);
  2018. *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
  2019. return 0;
  2020. }
  2021. static int
  2022. prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
  2023. __u32 * uwrq, char *extra)
  2024. {
  2025. islpci_private *priv = netdev_priv(ndev);
  2026. priv->priv_oid = *uwrq;
  2027. printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
  2028. return 0;
  2029. }
  2030. static int
  2031. prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
  2032. struct iw_point *data, char *extra)
  2033. {
  2034. islpci_private *priv = netdev_priv(ndev);
  2035. struct islpci_mgmtframe *response;
  2036. int ret = -EIO;
  2037. printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
  2038. data->length = 0;
  2039. if (islpci_get_state(priv) >= PRV_STATE_INIT) {
  2040. ret =
  2041. islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
  2042. priv->priv_oid, extra, 256,
  2043. &response);
  2044. printk("%s: ret: %i\n", ndev->name, ret);
  2045. if (ret || !response
  2046. || response->header->operation == PIMFOR_OP_ERROR) {
  2047. if (response) {
  2048. islpci_mgt_release(response);
  2049. }
  2050. printk("%s: EIO\n", ndev->name);
  2051. ret = -EIO;
  2052. }
  2053. if (!ret) {
  2054. data->length = response->header->length;
  2055. memcpy(extra, response->data, data->length);
  2056. islpci_mgt_release(response);
  2057. printk("%s: len: %i\n", ndev->name, data->length);
  2058. }
  2059. }
  2060. return ret;
  2061. }
  2062. static int
  2063. prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
  2064. struct iw_point *data, char *extra)
  2065. {
  2066. islpci_private *priv = netdev_priv(ndev);
  2067. struct islpci_mgmtframe *response;
  2068. int ret = 0, response_op = PIMFOR_OP_ERROR;
  2069. printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
  2070. data->length);
  2071. if (islpci_get_state(priv) >= PRV_STATE_INIT) {
  2072. ret =
  2073. islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
  2074. priv->priv_oid, extra, data->length,
  2075. &response);
  2076. printk("%s: ret: %i\n", ndev->name, ret);
  2077. if (ret || !response
  2078. || response->header->operation == PIMFOR_OP_ERROR) {
  2079. if (response) {
  2080. islpci_mgt_release(response);
  2081. }
  2082. printk("%s: EIO\n", ndev->name);
  2083. ret = -EIO;
  2084. }
  2085. if (!ret) {
  2086. response_op = response->header->operation;
  2087. printk("%s: response_op: %i\n", ndev->name,
  2088. response_op);
  2089. islpci_mgt_release(response);
  2090. }
  2091. }
  2092. return (ret ? ret : -EINPROGRESS);
  2093. }
  2094. static int
  2095. prism54_set_spy(struct net_device *ndev,
  2096. struct iw_request_info *info,
  2097. union iwreq_data *uwrq, char *extra)
  2098. {
  2099. islpci_private *priv = netdev_priv(ndev);
  2100. u32 u, oid = OID_INL_CONFIG;
  2101. down_write(&priv->mib_sem);
  2102. mgt_get(priv, OID_INL_CONFIG, &u);
  2103. if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
  2104. /* disable spy */
  2105. u &= ~INL_CONFIG_RXANNEX;
  2106. else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
  2107. /* enable spy */
  2108. u |= INL_CONFIG_RXANNEX;
  2109. mgt_set(priv, OID_INL_CONFIG, &u);
  2110. mgt_commit_list(priv, &oid, 1);
  2111. up_write(&priv->mib_sem);
  2112. return iw_handler_set_spy(ndev, info, uwrq, extra);
  2113. }
  2114. static const iw_handler prism54_handler[] = {
  2115. (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */
  2116. (iw_handler) prism54_get_name, /* SIOCGIWNAME */
  2117. (iw_handler) NULL, /* SIOCSIWNWID */
  2118. (iw_handler) NULL, /* SIOCGIWNWID */
  2119. (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */
  2120. (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */
  2121. (iw_handler) prism54_set_mode, /* SIOCSIWMODE */
  2122. (iw_handler) prism54_get_mode, /* SIOCGIWMODE */
  2123. (iw_handler) prism54_set_sens, /* SIOCSIWSENS */
  2124. (iw_handler) prism54_get_sens, /* SIOCGIWSENS */
  2125. (iw_handler) NULL, /* SIOCSIWRANGE */
  2126. (iw_handler) prism54_get_range, /* SIOCGIWRANGE */
  2127. (iw_handler) NULL, /* SIOCSIWPRIV */
  2128. (iw_handler) NULL, /* SIOCGIWPRIV */
  2129. (iw_handler) NULL, /* SIOCSIWSTATS */
  2130. (iw_handler) NULL, /* SIOCGIWSTATS */
  2131. prism54_set_spy, /* SIOCSIWSPY */
  2132. iw_handler_get_spy, /* SIOCGIWSPY */
  2133. iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
  2134. iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
  2135. (iw_handler) prism54_set_wap, /* SIOCSIWAP */
  2136. (iw_handler) prism54_get_wap, /* SIOCGIWAP */
  2137. (iw_handler) NULL, /* -- hole -- */
  2138. (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */
  2139. (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */
  2140. (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */
  2141. (iw_handler) prism54_set_essid, /* SIOCSIWESSID */
  2142. (iw_handler) prism54_get_essid, /* SIOCGIWESSID */
  2143. (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */
  2144. (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */
  2145. (iw_handler) NULL, /* -- hole -- */
  2146. (iw_handler) NULL, /* -- hole -- */
  2147. (iw_handler) prism54_set_rate, /* SIOCSIWRATE */
  2148. (iw_handler) prism54_get_rate, /* SIOCGIWRATE */
  2149. (iw_handler) prism54_set_rts, /* SIOCSIWRTS */
  2150. (iw_handler) prism54_get_rts, /* SIOCGIWRTS */
  2151. (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */
  2152. (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */
  2153. (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */
  2154. (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */
  2155. (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */
  2156. (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */
  2157. (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */
  2158. (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
  2159. (iw_handler) NULL, /* SIOCSIWPOWER */
  2160. (iw_handler) NULL, /* SIOCGIWPOWER */
  2161. };
  2162. /* The low order bit identify a SET (0) or a GET (1) ioctl. */
  2163. #define PRISM54_RESET SIOCIWFIRSTPRIV
  2164. #define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1
  2165. #define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2
  2166. #define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3
  2167. #define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4
  2168. #define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6
  2169. #define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8
  2170. #define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10
  2171. #define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11
  2172. #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
  2173. #define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14
  2174. #define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15
  2175. #define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16
  2176. #define PRISM54_GET_OID SIOCIWFIRSTPRIV+17
  2177. #define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18
  2178. #define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20
  2179. #define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22
  2180. #define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23
  2181. #define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24
  2182. #define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
  2183. #define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
  2184. #define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
  2185. #define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
  2186. #define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
  2187. #define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
  2188. #define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
  2189. /* Note : limited to 128 private ioctls (wireless tools 26) */
  2190. static const struct iw_priv_args prism54_private_args[] = {
  2191. /*{ cmd, set_args, get_args, name } */
  2192. {PRISM54_RESET, 0, 0, "reset"},
  2193. {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  2194. "get_prismhdr"},
  2195. {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
  2196. "set_prismhdr"},
  2197. {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  2198. "getPolicy"},
  2199. {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
  2200. "setPolicy"},
  2201. {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
  2202. {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
  2203. "addMac"},
  2204. {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
  2205. "delMac"},
  2206. {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
  2207. "kickMac"},
  2208. {PRISM54_KICK_ALL, 0, 0, "kickAll"},
  2209. {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  2210. "get_wpa"},
  2211. {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
  2212. "set_wpa"},
  2213. {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
  2214. "dbg_oid"},
  2215. {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
  2216. {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
  2217. /* --- sub-ioctls handlers --- */
  2218. {PRISM54_GET_OID,
  2219. 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
  2220. {PRISM54_SET_OID_U32,
  2221. IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
  2222. {PRISM54_SET_OID_STR,
  2223. IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
  2224. {PRISM54_SET_OID_ADDR,
  2225. IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
  2226. /* --- sub-ioctls definitions --- */
  2227. IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
  2228. IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
  2229. IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
  2230. IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
  2231. IWPRIV_U32(DOT11_OID_STATE, "state"),
  2232. IWPRIV_U32(DOT11_OID_AID, "aid"),
  2233. IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
  2234. IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
  2235. IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
  2236. IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
  2237. IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
  2238. IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
  2239. IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
  2240. IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
  2241. IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
  2242. IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
  2243. IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
  2244. IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
  2245. IWPRIV_U32(DOT11_OID_PSM, "psm"),
  2246. IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
  2247. IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
  2248. IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
  2249. IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
  2250. IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
  2251. IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
  2252. IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
  2253. IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
  2254. IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
  2255. IWPRIV_GET(DOT11_OID_RATES, "rates"),
  2256. IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
  2257. IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
  2258. IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
  2259. IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
  2260. IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
  2261. IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
  2262. IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
  2263. IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
  2264. IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
  2265. IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
  2266. IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
  2267. IWPRIV_U32(OID_INL_MODE, "mode"),
  2268. IWPRIV_U32(OID_INL_CONFIG, "config"),
  2269. IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
  2270. IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
  2271. IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
  2272. };
  2273. static const iw_handler prism54_private_handler[] = {
  2274. (iw_handler) prism54_reset,
  2275. (iw_handler) prism54_get_policy,
  2276. (iw_handler) prism54_set_policy,
  2277. (iw_handler) prism54_get_mac,
  2278. (iw_handler) prism54_add_mac,
  2279. (iw_handler) NULL,
  2280. (iw_handler) prism54_del_mac,
  2281. (iw_handler) NULL,
  2282. (iw_handler) prism54_kick_mac,
  2283. (iw_handler) NULL,
  2284. (iw_handler) prism54_kick_all,
  2285. (iw_handler) prism54_get_wpa,
  2286. (iw_handler) prism54_set_wpa,
  2287. (iw_handler) NULL,
  2288. (iw_handler) prism54_debug_oid,
  2289. (iw_handler) prism54_debug_get_oid,
  2290. (iw_handler) prism54_debug_set_oid,
  2291. (iw_handler) prism54_get_oid,
  2292. (iw_handler) prism54_set_u32,
  2293. (iw_handler) NULL,
  2294. (iw_handler) prism54_set_raw,
  2295. (iw_handler) NULL,
  2296. (iw_handler) prism54_set_raw,
  2297. (iw_handler) prism54_get_prismhdr,
  2298. (iw_handler) prism54_set_prismhdr,
  2299. };
  2300. const struct iw_handler_def prism54_handler_def = {
  2301. .num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
  2302. .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
  2303. .num_private_args =
  2304. sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
  2305. .standard = (iw_handler *) prism54_handler,
  2306. .private = (iw_handler *) prism54_private_handler,
  2307. .private_args = (struct iw_priv_args *) prism54_private_args,
  2308. .get_wireless_stats = prism54_get_wireless_stats,
  2309. };
  2310. /* For wpa_supplicant */
  2311. int
  2312. prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
  2313. {
  2314. struct iwreq *wrq = (struct iwreq *) rq;
  2315. int ret = -1;
  2316. switch (cmd) {
  2317. case PRISM54_HOSTAPD:
  2318. if (!capable(CAP_NET_ADMIN))
  2319. return -EPERM;
  2320. ret = prism54_hostapd(ndev, &wrq->u.data);
  2321. return ret;
  2322. }
  2323. return -EOPNOTSUPP;
  2324. }