iwinfo_nl80211.c 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751
  1. /*
  2. * iwinfo - Wireless Information Library - NL80211 Backend
  3. *
  4. * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
  5. *
  6. * The iwinfo library is free software: you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License version 2
  8. * as published by the Free Software Foundation.
  9. *
  10. * The iwinfo library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
  17. *
  18. * The signal handling code is derived from the official madwifi tools,
  19. * wlanconfig.c in particular. The encryption property handling was
  20. * inspired by the hostapd madwifi driver.
  21. *
  22. * Parts of this code are derived from the Linux iw utility.
  23. */
  24. #include <limits.h>
  25. #include <glob.h>
  26. #include <fnmatch.h>
  27. #include <stdarg.h>
  28. #include "iwinfo_nl80211.h"
  29. #define min(x, y) ((x) < (y)) ? (x) : (y)
  30. static struct nl80211_state *nls = NULL;
  31. static void nl80211_close(void)
  32. {
  33. if (nls)
  34. {
  35. if (nls->nlctrl)
  36. genl_family_put(nls->nlctrl);
  37. if (nls->nl80211)
  38. genl_family_put(nls->nl80211);
  39. if (nls->nl_sock)
  40. nl_socket_free(nls->nl_sock);
  41. if (nls->nl_cache)
  42. nl_cache_free(nls->nl_cache);
  43. free(nls);
  44. nls = NULL;
  45. }
  46. }
  47. static int nl80211_init(void)
  48. {
  49. int err, fd;
  50. if (!nls)
  51. {
  52. nls = malloc(sizeof(struct nl80211_state));
  53. if (!nls) {
  54. err = -ENOMEM;
  55. goto err;
  56. }
  57. memset(nls, 0, sizeof(*nls));
  58. nls->nl_sock = nl_socket_alloc();
  59. if (!nls->nl_sock) {
  60. err = -ENOMEM;
  61. goto err;
  62. }
  63. if (genl_connect(nls->nl_sock)) {
  64. err = -ENOLINK;
  65. goto err;
  66. }
  67. fd = nl_socket_get_fd(nls->nl_sock);
  68. if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) {
  69. err = -EINVAL;
  70. goto err;
  71. }
  72. if (genl_ctrl_alloc_cache(nls->nl_sock, &nls->nl_cache)) {
  73. err = -ENOMEM;
  74. goto err;
  75. }
  76. nls->nl80211 = genl_ctrl_search_by_name(nls->nl_cache, "nl80211");
  77. if (!nls->nl80211) {
  78. err = -ENOENT;
  79. goto err;
  80. }
  81. nls->nlctrl = genl_ctrl_search_by_name(nls->nl_cache, "nlctrl");
  82. if (!nls->nlctrl) {
  83. err = -ENOENT;
  84. goto err;
  85. }
  86. }
  87. return 0;
  88. err:
  89. nl80211_close();
  90. return err;
  91. }
  92. static int nl80211_readint(const char *path)
  93. {
  94. int fd;
  95. int rv = -1;
  96. char buffer[16];
  97. if ((fd = open(path, O_RDONLY)) > -1)
  98. {
  99. if (read(fd, buffer, sizeof(buffer)) > 0)
  100. rv = atoi(buffer);
  101. close(fd);
  102. }
  103. return rv;
  104. }
  105. static int nl80211_readstr(const char *path, char *buffer, int length)
  106. {
  107. int fd;
  108. int rv = -1;
  109. if ((fd = open(path, O_RDONLY)) > -1)
  110. {
  111. if ((rv = read(fd, buffer, length - 1)) > 0)
  112. {
  113. if (buffer[rv - 1] == '\n')
  114. rv--;
  115. buffer[rv] = 0;
  116. }
  117. close(fd);
  118. }
  119. return rv;
  120. }
  121. static int nl80211_msg_error(struct sockaddr_nl *nla,
  122. struct nlmsgerr *err, void *arg)
  123. {
  124. int *ret = arg;
  125. *ret = err->error;
  126. return NL_STOP;
  127. }
  128. static int nl80211_msg_finish(struct nl_msg *msg, void *arg)
  129. {
  130. int *ret = arg;
  131. *ret = 0;
  132. return NL_SKIP;
  133. }
  134. static int nl80211_msg_ack(struct nl_msg *msg, void *arg)
  135. {
  136. int *ret = arg;
  137. *ret = 0;
  138. return NL_STOP;
  139. }
  140. static int nl80211_msg_response(struct nl_msg *msg, void *arg)
  141. {
  142. return NL_SKIP;
  143. }
  144. static void nl80211_free(struct nl80211_msg_conveyor *cv)
  145. {
  146. if (cv)
  147. {
  148. if (cv->cb)
  149. nl_cb_put(cv->cb);
  150. if (cv->msg)
  151. nlmsg_free(cv->msg);
  152. cv->cb = NULL;
  153. cv->msg = NULL;
  154. }
  155. }
  156. static struct nl80211_msg_conveyor * nl80211_new(struct genl_family *family,
  157. int cmd, int flags)
  158. {
  159. static struct nl80211_msg_conveyor cv;
  160. struct nl_msg *req = NULL;
  161. struct nl_cb *cb = NULL;
  162. req = nlmsg_alloc();
  163. if (!req)
  164. goto err;
  165. cb = nl_cb_alloc(NL_CB_DEFAULT);
  166. if (!cb)
  167. goto err;
  168. genlmsg_put(req, 0, 0, genl_family_get_id(family), 0, flags, cmd, 0);
  169. cv.msg = req;
  170. cv.cb = cb;
  171. return &cv;
  172. err:
  173. if (cb)
  174. nl_cb_put(cb);
  175. if (req)
  176. nlmsg_free(req);
  177. return NULL;
  178. }
  179. static struct nl80211_msg_conveyor * nl80211_ctl(int cmd, int flags)
  180. {
  181. if (nl80211_init() < 0)
  182. return NULL;
  183. return nl80211_new(nls->nlctrl, cmd, flags);
  184. }
  185. static int nl80211_phy_idx_from_uci_path(struct uci_section *s)
  186. {
  187. const char *opt;
  188. char buf[128];
  189. int idx = -1;
  190. glob_t gl;
  191. opt = uci_lookup_option_string(uci_ctx, s, "path");
  192. if (!opt)
  193. return -1;
  194. snprintf(buf, sizeof(buf), "/sys/devices/%s/ieee80211/*/index", opt); /**/
  195. if (glob(buf, 0, NULL, &gl))
  196. return -1;
  197. if (gl.gl_pathc > 0)
  198. idx = nl80211_readint(gl.gl_pathv[0]);
  199. globfree(&gl);
  200. return idx;
  201. }
  202. static int nl80211_phy_idx_from_uci_macaddr(struct uci_section *s)
  203. {
  204. const char *opt;
  205. char buf[128];
  206. int i, idx = -1;
  207. glob_t gl;
  208. opt = uci_lookup_option_string(uci_ctx, s, "macaddr");
  209. if (!opt)
  210. return -1;
  211. snprintf(buf, sizeof(buf), "/sys/class/ieee80211/*"); /**/
  212. if (glob(buf, 0, NULL, &gl))
  213. return -1;
  214. for (i = 0; i < gl.gl_pathc; i++)
  215. {
  216. snprintf(buf, sizeof(buf), "%s/macaddress", gl.gl_pathv[i]);
  217. if (nl80211_readstr(buf, buf, sizeof(buf)) <= 0)
  218. continue;
  219. if (fnmatch(opt, buf, FNM_CASEFOLD))
  220. continue;
  221. snprintf(buf, sizeof(buf), "%s/index", gl.gl_pathv[i]);
  222. if ((idx = nl80211_readint(buf)) > -1)
  223. break;
  224. }
  225. globfree(&gl);
  226. return idx;
  227. }
  228. static int nl80211_phy_idx_from_uci_phy(struct uci_section *s)
  229. {
  230. const char *opt;
  231. char buf[128];
  232. opt = uci_lookup_option_string(uci_ctx, s, "phy");
  233. if (!opt)
  234. return -1;
  235. snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", opt);
  236. return nl80211_readint(buf);
  237. }
  238. static int nl80211_phy_idx_from_uci(const char *name)
  239. {
  240. struct uci_section *s;
  241. int idx = -1;
  242. s = iwinfo_uci_get_radio(name, "mac80211");
  243. if (!s)
  244. goto free;
  245. idx = nl80211_phy_idx_from_uci_path(s);
  246. if (idx < 0)
  247. idx = nl80211_phy_idx_from_uci_macaddr(s);
  248. if (idx < 0)
  249. idx = nl80211_phy_idx_from_uci_phy(s);
  250. free:
  251. iwinfo_uci_free();
  252. return idx;
  253. }
  254. static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname,
  255. int cmd, int flags)
  256. {
  257. int ifidx = -1, phyidx = -1;
  258. struct nl80211_msg_conveyor *cv;
  259. if (ifname == NULL)
  260. return NULL;
  261. if (nl80211_init() < 0)
  262. return NULL;
  263. if (!strncmp(ifname, "phy", 3))
  264. phyidx = atoi(&ifname[3]);
  265. else if (!strncmp(ifname, "radio", 5))
  266. phyidx = nl80211_phy_idx_from_uci(ifname);
  267. else if (!strncmp(ifname, "mon.", 4))
  268. ifidx = if_nametoindex(&ifname[4]);
  269. else
  270. ifidx = if_nametoindex(ifname);
  271. /* Valid ifidx must be greater than 0 */
  272. if ((ifidx <= 0) && (phyidx < 0))
  273. return NULL;
  274. cv = nl80211_new(nls->nl80211, cmd, flags);
  275. if (!cv)
  276. return NULL;
  277. if (ifidx > -1)
  278. NLA_PUT_U32(cv->msg, NL80211_ATTR_IFINDEX, ifidx);
  279. if (phyidx > -1)
  280. NLA_PUT_U32(cv->msg, NL80211_ATTR_WIPHY, phyidx);
  281. return cv;
  282. nla_put_failure:
  283. nl80211_free(cv);
  284. return NULL;
  285. }
  286. static struct nl80211_msg_conveyor * nl80211_send(
  287. struct nl80211_msg_conveyor *cv,
  288. int (*cb_func)(struct nl_msg *, void *), void *cb_arg
  289. ) {
  290. static struct nl80211_msg_conveyor rcv;
  291. int err = 1;
  292. if (cb_func)
  293. nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, cb_func, cb_arg);
  294. else
  295. nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_msg_response, &rcv);
  296. if (nl_send_auto_complete(nls->nl_sock, cv->msg) < 0)
  297. goto err;
  298. nl_cb_err(cv->cb, NL_CB_CUSTOM, nl80211_msg_error, &err);
  299. nl_cb_set(cv->cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_msg_finish, &err);
  300. nl_cb_set(cv->cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_msg_ack, &err);
  301. while (err > 0)
  302. nl_recvmsgs(nls->nl_sock, cv->cb);
  303. return &rcv;
  304. err:
  305. nl_cb_put(cv->cb);
  306. nlmsg_free(cv->msg);
  307. return NULL;
  308. }
  309. static struct nlattr ** nl80211_parse(struct nl_msg *msg)
  310. {
  311. struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
  312. static struct nlattr *attr[NL80211_ATTR_MAX + 1];
  313. nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
  314. genlmsg_attrlen(gnlh, 0), NULL);
  315. return attr;
  316. }
  317. static int nl80211_subscribe_cb(struct nl_msg *msg, void *arg)
  318. {
  319. struct nl80211_group_conveyor *cv = arg;
  320. struct nlattr **attr = nl80211_parse(msg);
  321. struct nlattr *mgrpinfo[CTRL_ATTR_MCAST_GRP_MAX + 1];
  322. struct nlattr *mgrp;
  323. int mgrpidx;
  324. if (!attr[CTRL_ATTR_MCAST_GROUPS])
  325. return NL_SKIP;
  326. nla_for_each_nested(mgrp, attr[CTRL_ATTR_MCAST_GROUPS], mgrpidx)
  327. {
  328. nla_parse(mgrpinfo, CTRL_ATTR_MCAST_GRP_MAX,
  329. nla_data(mgrp), nla_len(mgrp), NULL);
  330. if (mgrpinfo[CTRL_ATTR_MCAST_GRP_ID] &&
  331. mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME] &&
  332. !strncmp(nla_data(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME]),
  333. cv->name, nla_len(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME])))
  334. {
  335. cv->id = nla_get_u32(mgrpinfo[CTRL_ATTR_MCAST_GRP_ID]);
  336. break;
  337. }
  338. }
  339. return NL_SKIP;
  340. }
  341. static int nl80211_subscribe(const char *family, const char *group)
  342. {
  343. struct nl80211_group_conveyor cv = { .name = group, .id = -ENOENT };
  344. struct nl80211_msg_conveyor *req;
  345. req = nl80211_ctl(CTRL_CMD_GETFAMILY, 0);
  346. if (req)
  347. {
  348. NLA_PUT_STRING(req->msg, CTRL_ATTR_FAMILY_NAME, family);
  349. nl80211_send(req, nl80211_subscribe_cb, &cv);
  350. nla_put_failure:
  351. nl80211_free(req);
  352. }
  353. return nl_socket_add_membership(nls->nl_sock, cv.id);
  354. }
  355. static int nl80211_wait_cb(struct nl_msg *msg, void *arg)
  356. {
  357. struct nl80211_event_conveyor *cv = arg;
  358. struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
  359. if (gnlh->cmd == cv->wait)
  360. cv->recv = gnlh->cmd;
  361. return NL_SKIP;
  362. }
  363. static int nl80211_wait_seq_check(struct nl_msg *msg, void *arg)
  364. {
  365. return NL_OK;
  366. }
  367. static int nl80211_wait(const char *family, const char *group, int cmd)
  368. {
  369. struct nl80211_event_conveyor cv = { .wait = cmd };
  370. struct nl_cb *cb;
  371. if (nl80211_subscribe(family, group))
  372. return -ENOENT;
  373. cb = nl_cb_alloc(NL_CB_DEFAULT);
  374. if (!cb)
  375. return -ENOMEM;
  376. nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_wait_seq_check, NULL);
  377. nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wait_cb, &cv );
  378. while (!cv.recv)
  379. nl_recvmsgs(nls->nl_sock, cb);
  380. nl_cb_put(cb);
  381. return 0;
  382. }
  383. static int nl80211_freq2channel(int freq)
  384. {
  385. if (freq == 2484)
  386. return 14;
  387. else if (freq < 2484)
  388. return (freq - 2407) / 5;
  389. else if (freq >= 4910 && freq <= 4980)
  390. return (freq - 4000) / 5;
  391. else
  392. return (freq - 5000) / 5;
  393. }
  394. static int nl80211_channel2freq(int channel, const char *band)
  395. {
  396. if (!band || band[0] != 'a')
  397. {
  398. if (channel == 14)
  399. return 2484;
  400. else if (channel < 14)
  401. return (channel * 5) + 2407;
  402. }
  403. else
  404. {
  405. if (channel >= 182 && channel <= 196)
  406. return (channel * 5) + 4000;
  407. else
  408. return (channel * 5) + 5000;
  409. }
  410. return 0;
  411. }
  412. static int nl80211_ifname2phy_cb(struct nl_msg *msg, void *arg)
  413. {
  414. char *buf = arg;
  415. struct nlattr **attr = nl80211_parse(msg);
  416. if (attr[NL80211_ATTR_WIPHY_NAME])
  417. memcpy(buf, nla_data(attr[NL80211_ATTR_WIPHY_NAME]),
  418. nla_len(attr[NL80211_ATTR_WIPHY_NAME]));
  419. else
  420. buf[0] = 0;
  421. return NL_SKIP;
  422. }
  423. static char * nl80211_ifname2phy(const char *ifname)
  424. {
  425. static char phy[32] = { 0 };
  426. struct nl80211_msg_conveyor *req;
  427. memset(phy, 0, sizeof(phy));
  428. req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
  429. if (req)
  430. {
  431. nl80211_send(req, nl80211_ifname2phy_cb, phy);
  432. nl80211_free(req);
  433. }
  434. return phy[0] ? phy : NULL;
  435. }
  436. static char * nl80211_phy2ifname(const char *ifname)
  437. {
  438. int ifidx = -1, cifidx = -1, phyidx = -1;
  439. char buffer[64];
  440. static char nif[IFNAMSIZ] = { 0 };
  441. DIR *d;
  442. struct dirent *e;
  443. /* Only accept phy name of the form phy%d or radio%d */
  444. if (!ifname)
  445. return NULL;
  446. else if (!strncmp(ifname, "phy", 3))
  447. phyidx = atoi(&ifname[3]);
  448. else if (!strncmp(ifname, "radio", 5))
  449. phyidx = nl80211_phy_idx_from_uci(ifname);
  450. else
  451. return NULL;
  452. memset(nif, 0, sizeof(nif));
  453. if (phyidx > -1)
  454. {
  455. if ((d = opendir("/sys/class/net")) != NULL)
  456. {
  457. while ((e = readdir(d)) != NULL)
  458. {
  459. snprintf(buffer, sizeof(buffer),
  460. "/sys/class/net/%s/phy80211/index", e->d_name);
  461. if (nl80211_readint(buffer) == phyidx)
  462. {
  463. snprintf(buffer, sizeof(buffer),
  464. "/sys/class/net/%s/ifindex", e->d_name);
  465. if ((cifidx = nl80211_readint(buffer)) >= 0 &&
  466. ((ifidx < 0) || (cifidx < ifidx)))
  467. {
  468. ifidx = cifidx;
  469. strncpy(nif, e->d_name, sizeof(nif));
  470. }
  471. }
  472. }
  473. closedir(d);
  474. }
  475. }
  476. return nif[0] ? nif : NULL;
  477. }
  478. static int nl80211_get_mode_cb(struct nl_msg *msg, void *arg)
  479. {
  480. int *mode = arg;
  481. struct nlattr **tb = nl80211_parse(msg);
  482. const int ifmodes[NL80211_IFTYPE_MAX + 1] = {
  483. IWINFO_OPMODE_UNKNOWN, /* unspecified */
  484. IWINFO_OPMODE_ADHOC, /* IBSS */
  485. IWINFO_OPMODE_CLIENT, /* managed */
  486. IWINFO_OPMODE_MASTER, /* AP */
  487. IWINFO_OPMODE_AP_VLAN, /* AP/VLAN */
  488. IWINFO_OPMODE_WDS, /* WDS */
  489. IWINFO_OPMODE_MONITOR, /* monitor */
  490. IWINFO_OPMODE_MESHPOINT, /* mesh point */
  491. IWINFO_OPMODE_P2P_CLIENT, /* P2P-client */
  492. IWINFO_OPMODE_P2P_GO, /* P2P-GO */
  493. };
  494. if (tb[NL80211_ATTR_IFTYPE])
  495. *mode = ifmodes[nla_get_u32(tb[NL80211_ATTR_IFTYPE])];
  496. return NL_SKIP;
  497. }
  498. static int nl80211_get_mode(const char *ifname, int *buf)
  499. {
  500. char *res;
  501. struct nl80211_msg_conveyor *req;
  502. res = nl80211_phy2ifname(ifname);
  503. req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
  504. *buf = IWINFO_OPMODE_UNKNOWN;
  505. if (req)
  506. {
  507. nl80211_send(req, nl80211_get_mode_cb, buf);
  508. nl80211_free(req);
  509. }
  510. return (*buf == IWINFO_OPMODE_UNKNOWN) ? -1 : 0;
  511. }
  512. static int __nl80211_hostapd_query(const char *ifname, ...)
  513. {
  514. va_list ap, ap_cur;
  515. char *phy, *search, *dest, *key, *val, buf[128];
  516. int len, mode, found = 0, match = 1;
  517. FILE *fp;
  518. if (nl80211_get_mode(ifname, &mode))
  519. return 0;
  520. if (mode != IWINFO_OPMODE_MASTER && mode != IWINFO_OPMODE_AP_VLAN)
  521. return 0;
  522. phy = nl80211_ifname2phy(ifname);
  523. if (!phy)
  524. return 0;
  525. snprintf(buf, sizeof(buf), "/var/run/hostapd-%s.conf", phy);
  526. fp = fopen(buf, "r");
  527. if (!fp)
  528. return 0;
  529. va_start(ap, ifname);
  530. /* clear all destination buffers */
  531. va_copy(ap_cur, ap);
  532. while ((search = va_arg(ap_cur, char *)) != NULL)
  533. {
  534. dest = va_arg(ap_cur, char *);
  535. len = va_arg(ap_cur, int);
  536. memset(dest, 0, len);
  537. }
  538. va_end(ap_cur);
  539. /* iterate applicable lines and copy found values into dest buffers */
  540. while (fgets(buf, sizeof(buf), fp))
  541. {
  542. key = strtok(buf, " =\t\n");
  543. val = strtok(NULL, "\n");
  544. if (!key || !val || !*key || *key == '#')
  545. continue;
  546. if (!strcmp(key, "interface") || !strcmp(key, "bss"))
  547. match = !strcmp(ifname, val);
  548. if (!match)
  549. continue;
  550. va_copy(ap_cur, ap);
  551. while ((search = va_arg(ap_cur, char *)) != NULL)
  552. {
  553. dest = va_arg(ap_cur, char *);
  554. len = va_arg(ap_cur, int);
  555. if (!strcmp(search, key))
  556. {
  557. strncpy(dest, val, len - 1);
  558. found++;
  559. break;
  560. }
  561. }
  562. va_end(ap_cur);
  563. }
  564. fclose(fp);
  565. va_end(ap);
  566. return found;
  567. }
  568. #define nl80211_hostapd_query(ifname, ...) \
  569. __nl80211_hostapd_query(ifname, ##__VA_ARGS__, NULL)
  570. static inline int nl80211_wpactl_recv(int sock, char *buf, int blen)
  571. {
  572. fd_set rfds;
  573. struct timeval tv = { 0, 256000 };
  574. FD_ZERO(&rfds);
  575. FD_SET(sock, &rfds);
  576. memset(buf, 0, blen);
  577. if (select(sock + 1, &rfds, NULL, NULL, &tv) < 0)
  578. return -1;
  579. if (!FD_ISSET(sock, &rfds))
  580. return -1;
  581. return recv(sock, buf, blen - 1, 0);
  582. }
  583. static int nl80211_wpactl_connect(const char *ifname, struct sockaddr_un *local)
  584. {
  585. struct sockaddr_un remote = { 0 };
  586. size_t remote_length, local_length;
  587. int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
  588. if (sock < 0)
  589. return sock;
  590. remote.sun_family = AF_UNIX;
  591. remote_length = sizeof(remote.sun_family) +
  592. sprintf(remote.sun_path, "/var/run/wpa_supplicant-%s/%s",
  593. ifname, ifname);
  594. if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0)
  595. {
  596. close(sock);
  597. return -1;
  598. }
  599. if (connect(sock, (struct sockaddr *)&remote, remote_length))
  600. {
  601. remote_length = sizeof(remote.sun_family) +
  602. sprintf(remote.sun_path, "/var/run/wpa_supplicant/%s", ifname);
  603. if (connect(sock, (struct sockaddr *)&remote, remote_length))
  604. {
  605. close(sock);
  606. return -1;
  607. }
  608. }
  609. local->sun_family = AF_UNIX;
  610. local_length = sizeof(local->sun_family) +
  611. sprintf(local->sun_path, "/var/run/iwinfo-%s-%d", ifname, getpid());
  612. if (bind(sock, (struct sockaddr *)local, local_length) < 0)
  613. {
  614. close(sock);
  615. return -1;
  616. }
  617. return sock;
  618. }
  619. static int __nl80211_wpactl_query(const char *ifname, ...)
  620. {
  621. va_list ap, ap_cur;
  622. struct sockaddr_un local = { 0 };
  623. int len, mode, found = 0, sock = -1;
  624. char *search, *dest, *key, *val, *line, *pos, buf[512];
  625. if (nl80211_get_mode(ifname, &mode))
  626. return 0;
  627. if (mode != IWINFO_OPMODE_CLIENT && mode != IWINFO_OPMODE_ADHOC)
  628. return 0;
  629. sock = nl80211_wpactl_connect(ifname, &local);
  630. if (sock < 0)
  631. return 0;
  632. va_start(ap, ifname);
  633. /* clear all destination buffers */
  634. va_copy(ap_cur, ap);
  635. while ((search = va_arg(ap_cur, char *)) != NULL)
  636. {
  637. dest = va_arg(ap_cur, char *);
  638. len = va_arg(ap_cur, int);
  639. memset(dest, 0, len);
  640. }
  641. va_end(ap_cur);
  642. send(sock, "STATUS", 6, 0);
  643. while (true)
  644. {
  645. if (nl80211_wpactl_recv(sock, buf, sizeof(buf)) <= 0)
  646. break;
  647. if (buf[0] == '<')
  648. continue;
  649. for (line = strtok_r(buf, "\n", &pos);
  650. line != NULL;
  651. line = strtok_r(NULL, "\n", &pos))
  652. {
  653. key = strtok(line, "=");
  654. val = strtok(NULL, "\n");
  655. if (!key || !val)
  656. continue;
  657. va_copy(ap_cur, ap);
  658. while ((search = va_arg(ap_cur, char *)) != NULL)
  659. {
  660. dest = va_arg(ap_cur, char *);
  661. len = va_arg(ap_cur, int);
  662. if (!strcmp(search, key))
  663. {
  664. strncpy(dest, val, len - 1);
  665. found++;
  666. break;
  667. }
  668. }
  669. va_end(ap_cur);
  670. }
  671. break;
  672. }
  673. va_end(ap);
  674. close(sock);
  675. unlink(local.sun_path);
  676. return found;
  677. }
  678. #define nl80211_wpactl_query(ifname, ...) \
  679. __nl80211_wpactl_query(ifname, ##__VA_ARGS__, NULL)
  680. static char * nl80211_ifadd(const char *ifname)
  681. {
  682. char *rv = NULL, path[PATH_MAX];
  683. static char nif[IFNAMSIZ] = { 0 };
  684. struct nl80211_msg_conveyor *req;
  685. FILE *sysfs;
  686. req = nl80211_msg(ifname, NL80211_CMD_NEW_INTERFACE, 0);
  687. if (req)
  688. {
  689. snprintf(nif, sizeof(nif), "tmp.%s", ifname);
  690. NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, nif);
  691. NLA_PUT_U32(req->msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
  692. nl80211_send(req, NULL, NULL);
  693. snprintf(path, sizeof(path) - 1,
  694. "/proc/sys/net/ipv6/conf/%s/disable_ipv6", nif);
  695. if ((sysfs = fopen(path, "w")) != NULL)
  696. {
  697. fwrite("0\n", 1, 2, sysfs);
  698. fclose(sysfs);
  699. }
  700. rv = nif;
  701. nla_put_failure:
  702. nl80211_free(req);
  703. }
  704. return rv;
  705. }
  706. static void nl80211_ifdel(const char *ifname)
  707. {
  708. struct nl80211_msg_conveyor *req;
  709. req = nl80211_msg(ifname, NL80211_CMD_DEL_INTERFACE, 0);
  710. if (req)
  711. {
  712. NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, ifname);
  713. nl80211_send(req, NULL, NULL);
  714. nla_put_failure:
  715. nl80211_free(req);
  716. }
  717. }
  718. static void nl80211_hostapd_hup(const char *ifname)
  719. {
  720. int fd, pid = 0;
  721. char buf[32];
  722. char *phy = nl80211_ifname2phy(ifname);
  723. if (phy)
  724. {
  725. snprintf(buf, sizeof(buf), "/var/run/wifi-%s.pid", phy);
  726. if ((fd = open(buf, O_RDONLY)) > 0)
  727. {
  728. if (read(fd, buf, sizeof(buf)) > 0)
  729. pid = atoi(buf);
  730. close(fd);
  731. }
  732. if (pid > 0)
  733. kill(pid, 1);
  734. }
  735. }
  736. static int nl80211_probe(const char *ifname)
  737. {
  738. return !!nl80211_ifname2phy(ifname);
  739. }
  740. struct nl80211_ssid_bssid {
  741. unsigned char *ssid;
  742. unsigned char bssid[7];
  743. };
  744. static int nl80211_get_ssid_bssid_cb(struct nl_msg *msg, void *arg)
  745. {
  746. int ielen;
  747. unsigned char *ie;
  748. struct nl80211_ssid_bssid *sb = arg;
  749. struct nlattr **tb = nl80211_parse(msg);
  750. struct nlattr *bss[NL80211_BSS_MAX + 1];
  751. static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
  752. [NL80211_BSS_INFORMATION_ELEMENTS] = { 0 },
  753. [NL80211_BSS_STATUS] = { .type = NLA_U32 },
  754. };
  755. if (!tb[NL80211_ATTR_BSS] ||
  756. nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
  757. bss_policy) ||
  758. !bss[NL80211_BSS_BSSID] ||
  759. !bss[NL80211_BSS_STATUS] ||
  760. !bss[NL80211_BSS_INFORMATION_ELEMENTS])
  761. {
  762. return NL_SKIP;
  763. }
  764. switch (nla_get_u32(bss[NL80211_BSS_STATUS]))
  765. {
  766. case NL80211_BSS_STATUS_ASSOCIATED:
  767. case NL80211_BSS_STATUS_AUTHENTICATED:
  768. case NL80211_BSS_STATUS_IBSS_JOINED:
  769. if (sb->ssid)
  770. {
  771. ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
  772. ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
  773. while (ielen >= 2 && ielen >= ie[1])
  774. {
  775. if (ie[0] == 0)
  776. {
  777. memcpy(sb->ssid, ie + 2, min(ie[1], IWINFO_ESSID_MAX_SIZE));
  778. return NL_SKIP;
  779. }
  780. ielen -= ie[1] + 2;
  781. ie += ie[1] + 2;
  782. }
  783. }
  784. else
  785. {
  786. sb->bssid[0] = 1;
  787. memcpy(sb->bssid + 1, nla_data(bss[NL80211_BSS_BSSID]), 6);
  788. return NL_SKIP;
  789. }
  790. default:
  791. return NL_SKIP;
  792. }
  793. }
  794. static int nl80211_get_ssid(const char *ifname, char *buf)
  795. {
  796. char *res;
  797. struct nl80211_msg_conveyor *req;
  798. struct nl80211_ssid_bssid sb;
  799. /* try to find ssid from scan dump results */
  800. res = nl80211_phy2ifname(ifname);
  801. req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
  802. sb.ssid = (unsigned char *)buf;
  803. *buf = 0;
  804. if (req)
  805. {
  806. nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb);
  807. nl80211_free(req);
  808. }
  809. /* failed, try to find from hostapd info */
  810. if (*buf == 0)
  811. nl80211_hostapd_query(ifname, "ssid", buf, IWINFO_ESSID_MAX_SIZE + 1);
  812. return (*buf == 0) ? -1 : 0;
  813. }
  814. static int nl80211_get_bssid(const char *ifname, char *buf)
  815. {
  816. char *res, bssid[sizeof("FF:FF:FF:FF:FF:FF\0")];
  817. struct nl80211_msg_conveyor *req;
  818. struct nl80211_ssid_bssid sb;
  819. /* try to find bssid from scan dump results */
  820. res = nl80211_phy2ifname(ifname);
  821. req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
  822. sb.ssid = NULL;
  823. sb.bssid[0] = 0;
  824. if (req)
  825. {
  826. nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb);
  827. nl80211_free(req);
  828. }
  829. /* failed, try to find mac from hostapd info */
  830. if ((sb.bssid[0] == 0) &&
  831. nl80211_hostapd_query(ifname, "bssid", bssid, sizeof(bssid)))
  832. {
  833. sb.bssid[0] = 1;
  834. sb.bssid[1] = strtol(&bssid[0], NULL, 16);
  835. sb.bssid[2] = strtol(&bssid[3], NULL, 16);
  836. sb.bssid[3] = strtol(&bssid[6], NULL, 16);
  837. sb.bssid[4] = strtol(&bssid[9], NULL, 16);
  838. sb.bssid[5] = strtol(&bssid[12], NULL, 16);
  839. sb.bssid[6] = strtol(&bssid[15], NULL, 16);
  840. }
  841. if (sb.bssid[0])
  842. {
  843. sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
  844. sb.bssid[1], sb.bssid[2], sb.bssid[3],
  845. sb.bssid[4], sb.bssid[5], sb.bssid[6]);
  846. return 0;
  847. }
  848. return -1;
  849. }
  850. static int nl80211_get_frequency_scan_cb(struct nl_msg *msg, void *arg)
  851. {
  852. int *freq = arg;
  853. struct nlattr **attr = nl80211_parse(msg);
  854. struct nlattr *binfo[NL80211_BSS_MAX + 1];
  855. static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
  856. [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
  857. [NL80211_BSS_STATUS] = { .type = NLA_U32 },
  858. };
  859. if (attr[NL80211_ATTR_BSS] &&
  860. !nla_parse_nested(binfo, NL80211_BSS_MAX,
  861. attr[NL80211_ATTR_BSS], bss_policy))
  862. {
  863. if (binfo[NL80211_BSS_STATUS] && binfo[NL80211_BSS_FREQUENCY])
  864. *freq = nla_get_u32(binfo[NL80211_BSS_FREQUENCY]);
  865. }
  866. return NL_SKIP;
  867. }
  868. static int nl80211_get_frequency_info_cb(struct nl_msg *msg, void *arg)
  869. {
  870. int *freq = arg;
  871. struct nlattr **tb = nl80211_parse(msg);
  872. if (tb[NL80211_ATTR_WIPHY_FREQ])
  873. *freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
  874. return NL_SKIP;
  875. }
  876. static int nl80211_get_frequency(const char *ifname, int *buf)
  877. {
  878. char *res, channel[4], hwmode[2];
  879. struct nl80211_msg_conveyor *req;
  880. /* try to find frequency from interface info */
  881. res = nl80211_phy2ifname(ifname);
  882. req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
  883. *buf = 0;
  884. if (req)
  885. {
  886. nl80211_send(req, nl80211_get_frequency_info_cb, buf);
  887. nl80211_free(req);
  888. }
  889. /* failed, try to find frequency from hostapd info */
  890. if ((*buf == 0) &&
  891. nl80211_hostapd_query(ifname, "hw_mode", hwmode, sizeof(hwmode),
  892. "channel", channel, sizeof(channel)) == 2)
  893. {
  894. *buf = nl80211_channel2freq(atoi(channel), hwmode);
  895. }
  896. /* failed, try to find frequency from scan results */
  897. if (*buf == 0)
  898. {
  899. res = nl80211_phy2ifname(ifname);
  900. req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
  901. if (req)
  902. {
  903. nl80211_send(req, nl80211_get_frequency_scan_cb, buf);
  904. nl80211_free(req);
  905. }
  906. }
  907. return (*buf == 0) ? -1 : 0;
  908. }
  909. static int nl80211_get_channel(const char *ifname, int *buf)
  910. {
  911. if (!nl80211_get_frequency(ifname, buf))
  912. {
  913. *buf = nl80211_freq2channel(*buf);
  914. return 0;
  915. }
  916. return -1;
  917. }
  918. static int nl80211_get_txpower(const char *ifname, int *buf)
  919. {
  920. #if 0
  921. char *res;
  922. char path[PATH_MAX];
  923. res = nl80211_ifname2phy(ifname);
  924. snprintf(path, sizeof(path), "/sys/kernel/debug/ieee80211/%s/power",
  925. res ? res : ifname);
  926. if ((*buf = nl80211_readint(path)) > -1)
  927. return 0;
  928. #endif
  929. return wext_ops.txpower(ifname, buf);
  930. }
  931. static int nl80211_fill_signal_cb(struct nl_msg *msg, void *arg)
  932. {
  933. int8_t dbm;
  934. int16_t mbit;
  935. struct nl80211_rssi_rate *rr = arg;
  936. struct nlattr **attr = nl80211_parse(msg);
  937. struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
  938. struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
  939. static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
  940. [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
  941. [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
  942. [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
  943. [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
  944. [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
  945. [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
  946. [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
  947. [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
  948. [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
  949. [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
  950. };
  951. static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
  952. [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
  953. [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
  954. [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
  955. [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
  956. };
  957. if (attr[NL80211_ATTR_STA_INFO])
  958. {
  959. if (!nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
  960. attr[NL80211_ATTR_STA_INFO], stats_policy))
  961. {
  962. if (sinfo[NL80211_STA_INFO_SIGNAL])
  963. {
  964. dbm = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
  965. rr->rssi = rr->rssi ? (int8_t)((rr->rssi + dbm) / 2) : dbm;
  966. }
  967. if (sinfo[NL80211_STA_INFO_TX_BITRATE])
  968. {
  969. if (!nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
  970. sinfo[NL80211_STA_INFO_TX_BITRATE],
  971. rate_policy))
  972. {
  973. if (rinfo[NL80211_RATE_INFO_BITRATE])
  974. {
  975. mbit = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
  976. rr->rate = rr->rate
  977. ? (int16_t)((rr->rate + mbit) / 2) : mbit;
  978. }
  979. }
  980. }
  981. }
  982. }
  983. return NL_SKIP;
  984. }
  985. static void nl80211_fill_signal(const char *ifname, struct nl80211_rssi_rate *r)
  986. {
  987. DIR *d;
  988. struct dirent *de;
  989. struct nl80211_msg_conveyor *req;
  990. r->rssi = 0;
  991. r->rate = 0;
  992. if ((d = opendir("/sys/class/net")) != NULL)
  993. {
  994. while ((de = readdir(d)) != NULL)
  995. {
  996. if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
  997. (!de->d_name[strlen(ifname)] ||
  998. !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
  999. {
  1000. req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
  1001. NLM_F_DUMP);
  1002. if (req)
  1003. {
  1004. nl80211_send(req, nl80211_fill_signal_cb, r);
  1005. nl80211_free(req);
  1006. }
  1007. }
  1008. }
  1009. closedir(d);
  1010. }
  1011. }
  1012. static int nl80211_get_bitrate(const char *ifname, int *buf)
  1013. {
  1014. struct nl80211_rssi_rate rr;
  1015. nl80211_fill_signal(ifname, &rr);
  1016. if (rr.rate)
  1017. {
  1018. *buf = (rr.rate * 100);
  1019. return 0;
  1020. }
  1021. return -1;
  1022. }
  1023. static int nl80211_get_signal(const char *ifname, int *buf)
  1024. {
  1025. struct nl80211_rssi_rate rr;
  1026. nl80211_fill_signal(ifname, &rr);
  1027. if (rr.rssi)
  1028. {
  1029. *buf = rr.rssi;
  1030. return 0;
  1031. }
  1032. return -1;
  1033. }
  1034. static int nl80211_get_noise_cb(struct nl_msg *msg, void *arg)
  1035. {
  1036. int8_t *noise = arg;
  1037. struct nlattr **tb = nl80211_parse(msg);
  1038. struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1];
  1039. static struct nla_policy sp[NL80211_SURVEY_INFO_MAX + 1] = {
  1040. [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
  1041. [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
  1042. };
  1043. if (!tb[NL80211_ATTR_SURVEY_INFO])
  1044. return NL_SKIP;
  1045. if (nla_parse_nested(si, NL80211_SURVEY_INFO_MAX,
  1046. tb[NL80211_ATTR_SURVEY_INFO], sp))
  1047. return NL_SKIP;
  1048. if (!si[NL80211_SURVEY_INFO_NOISE])
  1049. return NL_SKIP;
  1050. if (!*noise || si[NL80211_SURVEY_INFO_IN_USE])
  1051. *noise = (int8_t)nla_get_u8(si[NL80211_SURVEY_INFO_NOISE]);
  1052. return NL_SKIP;
  1053. }
  1054. static int nl80211_get_noise(const char *ifname, int *buf)
  1055. {
  1056. int8_t noise;
  1057. struct nl80211_msg_conveyor *req;
  1058. req = nl80211_msg(ifname, NL80211_CMD_GET_SURVEY, NLM_F_DUMP);
  1059. if (req)
  1060. {
  1061. noise = 0;
  1062. nl80211_send(req, nl80211_get_noise_cb, &noise);
  1063. nl80211_free(req);
  1064. if (noise)
  1065. {
  1066. *buf = noise;
  1067. return 0;
  1068. }
  1069. }
  1070. return -1;
  1071. }
  1072. static int nl80211_get_quality(const char *ifname, int *buf)
  1073. {
  1074. int signal;
  1075. if (!nl80211_get_signal(ifname, &signal))
  1076. {
  1077. /* A positive signal level is usually just a quality
  1078. * value, pass through as-is */
  1079. if (signal >= 0)
  1080. {
  1081. *buf = signal;
  1082. }
  1083. /* The cfg80211 wext compat layer assumes a signal range
  1084. * of -110 dBm to -40 dBm, the quality value is derived
  1085. * by adding 110 to the signal level */
  1086. else
  1087. {
  1088. if (signal < -110)
  1089. signal = -110;
  1090. else if (signal > -40)
  1091. signal = -40;
  1092. *buf = (signal + 110);
  1093. }
  1094. return 0;
  1095. }
  1096. return -1;
  1097. }
  1098. static int nl80211_get_quality_max(const char *ifname, int *buf)
  1099. {
  1100. /* The cfg80211 wext compat layer assumes a maximum
  1101. * quality of 70 */
  1102. *buf = 70;
  1103. return 0;
  1104. }
  1105. static int nl80211_check_wepkey(const char *key)
  1106. {
  1107. if (key && *key)
  1108. {
  1109. switch (strlen(key))
  1110. {
  1111. case 5:
  1112. case 10:
  1113. return IWINFO_CIPHER_WEP40;
  1114. case 13:
  1115. case 26:
  1116. return IWINFO_CIPHER_WEP104;
  1117. }
  1118. }
  1119. return 0;
  1120. }
  1121. static int nl80211_get_encryption(const char *ifname, char *buf)
  1122. {
  1123. char wpa[2], wpa_key_mgmt[16], wpa_pairwise[16], wpa_groupwise[16];
  1124. char auth_algs[2], wep_key0[27], wep_key1[27], wep_key2[27], wep_key3[27];
  1125. struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf;
  1126. /* WPA supplicant */
  1127. if (nl80211_wpactl_query(ifname,
  1128. "pairwise_cipher", wpa_pairwise, sizeof(wpa_pairwise),
  1129. "group_cipher", wpa_groupwise, sizeof(wpa_groupwise),
  1130. "key_mgmt", wpa_key_mgmt, sizeof(wpa_key_mgmt)))
  1131. {
  1132. /* WEP */
  1133. if (!strcmp(wpa_key_mgmt, "NONE"))
  1134. {
  1135. if (strstr(wpa_pairwise, "WEP-40"))
  1136. c->pair_ciphers |= IWINFO_CIPHER_WEP40;
  1137. else if (strstr(wpa_pairwise, "WEP-104"))
  1138. c->pair_ciphers |= IWINFO_CIPHER_WEP104;
  1139. if (strstr(wpa_groupwise, "WEP-40"))
  1140. c->group_ciphers |= IWINFO_CIPHER_WEP40;
  1141. else if (strstr(wpa_groupwise, "WEP-104"))
  1142. c->group_ciphers |= IWINFO_CIPHER_WEP104;
  1143. c->enabled = !!(c->pair_ciphers | c->group_ciphers);
  1144. c->auth_suites |= IWINFO_KMGMT_NONE;
  1145. c->auth_algs |= IWINFO_AUTH_OPEN; /* XXX: assumption */
  1146. }
  1147. /* WPA */
  1148. else if (strstr(wpa_key_mgmt, "WPA"))
  1149. {
  1150. if (strstr(wpa_pairwise, "TKIP"))
  1151. c->pair_ciphers |= IWINFO_CIPHER_TKIP;
  1152. else if (strstr(wpa_pairwise, "CCMP"))
  1153. c->pair_ciphers |= IWINFO_CIPHER_CCMP;
  1154. else if (strstr(wpa_pairwise, "NONE"))
  1155. c->pair_ciphers |= IWINFO_CIPHER_NONE;
  1156. else if (strstr(wpa_pairwise, "WEP-40"))
  1157. c->pair_ciphers |= IWINFO_CIPHER_WEP40;
  1158. else if (strstr(wpa_pairwise, "WEP-104"))
  1159. c->pair_ciphers |= IWINFO_CIPHER_WEP104;
  1160. if (strstr(wpa_groupwise, "TKIP"))
  1161. c->group_ciphers |= IWINFO_CIPHER_TKIP;
  1162. else if (strstr(wpa_groupwise, "CCMP"))
  1163. c->group_ciphers |= IWINFO_CIPHER_CCMP;
  1164. else if (strstr(wpa_groupwise, "NONE"))
  1165. c->group_ciphers |= IWINFO_CIPHER_NONE;
  1166. else if (strstr(wpa_groupwise, "WEP-40"))
  1167. c->group_ciphers |= IWINFO_CIPHER_WEP40;
  1168. else if (strstr(wpa_groupwise, "WEP-104"))
  1169. c->group_ciphers |= IWINFO_CIPHER_WEP104;
  1170. if (strstr(wpa_key_mgmt, "WPA2"))
  1171. c->wpa_version = 2;
  1172. else if (strstr(wpa_key_mgmt, "WPA"))
  1173. c->wpa_version = 1;
  1174. if (strstr(wpa_key_mgmt, "PSK"))
  1175. c->auth_suites |= IWINFO_KMGMT_PSK;
  1176. else if (strstr(wpa_key_mgmt, "EAP") ||
  1177. strstr(wpa_key_mgmt, "802.1X"))
  1178. c->auth_suites |= IWINFO_KMGMT_8021x;
  1179. else if (strstr(wpa_key_mgmt, "NONE"))
  1180. c->auth_suites |= IWINFO_KMGMT_NONE;
  1181. c->enabled = !!(c->wpa_version && c->auth_suites);
  1182. }
  1183. return 0;
  1184. }
  1185. /* Hostapd */
  1186. else if (nl80211_hostapd_query(ifname,
  1187. "wpa", wpa, sizeof(wpa),
  1188. "wpa_key_mgmt", wpa_key_mgmt, sizeof(wpa_key_mgmt),
  1189. "wpa_pairwise", wpa_pairwise, sizeof(wpa_pairwise),
  1190. "auth_algs", auth_algs, sizeof(auth_algs),
  1191. "wep_key0", wep_key0, sizeof(wep_key0),
  1192. "wep_key1", wep_key1, sizeof(wep_key1),
  1193. "wep_key2", wep_key2, sizeof(wep_key2),
  1194. "wep_key3", wep_key3, sizeof(wep_key3)))
  1195. {
  1196. c->wpa_version = wpa[0] ? atoi(wpa) : 0;
  1197. if (wpa_key_mgmt[0])
  1198. {
  1199. if (strstr(wpa_key_mgmt, "PSK"))
  1200. c->auth_suites |= IWINFO_KMGMT_PSK;
  1201. if (strstr(wpa_key_mgmt, "EAP"))
  1202. c->auth_suites |= IWINFO_KMGMT_8021x;
  1203. if (strstr(wpa_key_mgmt, "NONE"))
  1204. c->auth_suites |= IWINFO_KMGMT_NONE;
  1205. }
  1206. else
  1207. {
  1208. c->auth_suites |= IWINFO_KMGMT_PSK;
  1209. }
  1210. if (wpa_pairwise[0])
  1211. {
  1212. if (strstr(wpa_pairwise, "TKIP"))
  1213. c->pair_ciphers |= IWINFO_CIPHER_TKIP;
  1214. if (strstr(wpa_pairwise, "CCMP"))
  1215. c->pair_ciphers |= IWINFO_CIPHER_CCMP;
  1216. if (strstr(wpa_pairwise, "NONE"))
  1217. c->pair_ciphers |= IWINFO_CIPHER_NONE;
  1218. }
  1219. if (auth_algs[0])
  1220. {
  1221. switch(atoi(auth_algs))
  1222. {
  1223. case 1:
  1224. c->auth_algs |= IWINFO_AUTH_OPEN;
  1225. break;
  1226. case 2:
  1227. c->auth_algs |= IWINFO_AUTH_SHARED;
  1228. break;
  1229. case 3:
  1230. c->auth_algs |= IWINFO_AUTH_OPEN;
  1231. c->auth_algs |= IWINFO_AUTH_SHARED;
  1232. break;
  1233. }
  1234. c->pair_ciphers |= nl80211_check_wepkey(wep_key0);
  1235. c->pair_ciphers |= nl80211_check_wepkey(wep_key1);
  1236. c->pair_ciphers |= nl80211_check_wepkey(wep_key2);
  1237. c->pair_ciphers |= nl80211_check_wepkey(wep_key3);
  1238. }
  1239. c->group_ciphers = c->pair_ciphers;
  1240. c->enabled = (c->wpa_version || c->pair_ciphers) ? 1 : 0;
  1241. return 0;
  1242. }
  1243. return -1;
  1244. }
  1245. static int nl80211_get_phyname(const char *ifname, char *buf)
  1246. {
  1247. const char *name;
  1248. name = nl80211_ifname2phy(ifname);
  1249. if (name)
  1250. {
  1251. strcpy(buf, name);
  1252. return 0;
  1253. }
  1254. else if ((name = nl80211_phy2ifname(ifname)) != NULL)
  1255. {
  1256. name = nl80211_ifname2phy(name);
  1257. if (name)
  1258. {
  1259. strcpy(buf, ifname);
  1260. return 0;
  1261. }
  1262. }
  1263. return -1;
  1264. }
  1265. static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg)
  1266. {
  1267. struct nl80211_array_buf *arr = arg;
  1268. struct iwinfo_assoclist_entry *e = arr->buf;
  1269. struct nlattr **attr = nl80211_parse(msg);
  1270. struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
  1271. struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
  1272. static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
  1273. [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
  1274. [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
  1275. [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
  1276. [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
  1277. [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
  1278. [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
  1279. };
  1280. static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
  1281. [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
  1282. [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
  1283. [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
  1284. [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
  1285. };
  1286. /* advance to end of array */
  1287. e += arr->count;
  1288. memset(e, 0, sizeof(*e));
  1289. if (attr[NL80211_ATTR_MAC])
  1290. memcpy(e->mac, nla_data(attr[NL80211_ATTR_MAC]), 6);
  1291. if (attr[NL80211_ATTR_STA_INFO] &&
  1292. !nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
  1293. attr[NL80211_ATTR_STA_INFO], stats_policy))
  1294. {
  1295. if (sinfo[NL80211_STA_INFO_SIGNAL])
  1296. e->signal = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
  1297. if (sinfo[NL80211_STA_INFO_INACTIVE_TIME])
  1298. e->inactive = nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]);
  1299. if (sinfo[NL80211_STA_INFO_RX_PACKETS])
  1300. e->rx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]);
  1301. if (sinfo[NL80211_STA_INFO_TX_PACKETS])
  1302. e->tx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]);
  1303. if (sinfo[NL80211_STA_INFO_RX_BITRATE] &&
  1304. !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
  1305. sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy))
  1306. {
  1307. if (rinfo[NL80211_RATE_INFO_BITRATE])
  1308. e->rx_rate.rate =
  1309. nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
  1310. if (rinfo[NL80211_RATE_INFO_MCS])
  1311. e->rx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
  1312. if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
  1313. e->rx_rate.is_40mhz = 1;
  1314. if (rinfo[NL80211_RATE_INFO_SHORT_GI])
  1315. e->rx_rate.is_short_gi = 1;
  1316. }
  1317. if (sinfo[NL80211_STA_INFO_TX_BITRATE] &&
  1318. !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
  1319. sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy))
  1320. {
  1321. if (rinfo[NL80211_RATE_INFO_BITRATE])
  1322. e->tx_rate.rate =
  1323. nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
  1324. if (rinfo[NL80211_RATE_INFO_MCS])
  1325. e->tx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
  1326. if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
  1327. e->tx_rate.is_40mhz = 1;
  1328. if (rinfo[NL80211_RATE_INFO_SHORT_GI])
  1329. e->tx_rate.is_short_gi = 1;
  1330. }
  1331. }
  1332. e->noise = 0; /* filled in by caller */
  1333. arr->count++;
  1334. return NL_SKIP;
  1335. }
  1336. static int nl80211_get_assoclist(const char *ifname, char *buf, int *len)
  1337. {
  1338. DIR *d;
  1339. int i, noise = 0;
  1340. struct dirent *de;
  1341. struct nl80211_msg_conveyor *req;
  1342. struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
  1343. struct iwinfo_assoclist_entry *e;
  1344. if ((d = opendir("/sys/class/net")) != NULL)
  1345. {
  1346. while ((de = readdir(d)) != NULL)
  1347. {
  1348. if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
  1349. (!de->d_name[strlen(ifname)] ||
  1350. !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
  1351. {
  1352. req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
  1353. NLM_F_DUMP);
  1354. if (req)
  1355. {
  1356. nl80211_send(req, nl80211_get_assoclist_cb, &arr);
  1357. nl80211_free(req);
  1358. }
  1359. }
  1360. }
  1361. closedir(d);
  1362. if (!nl80211_get_noise(ifname, &noise))
  1363. for (i = 0, e = arr.buf; i < arr.count; i++, e++)
  1364. e->noise = noise;
  1365. *len = (arr.count * sizeof(struct iwinfo_assoclist_entry));
  1366. return 0;
  1367. }
  1368. return -1;
  1369. }
  1370. static int nl80211_get_txpwrlist_cb(struct nl_msg *msg, void *arg)
  1371. {
  1372. int *dbm_max = arg;
  1373. int ch_cur, ch_cmp, bands_remain, freqs_remain;
  1374. struct nlattr **attr = nl80211_parse(msg);
  1375. struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
  1376. struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
  1377. struct nlattr *band, *freq;
  1378. static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
  1379. [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
  1380. [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
  1381. [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
  1382. [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
  1383. [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
  1384. [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
  1385. };
  1386. ch_cur = *dbm_max; /* value int* is initialized with channel by caller */
  1387. *dbm_max = -1;
  1388. nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
  1389. {
  1390. nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band),
  1391. nla_len(band), NULL);
  1392. nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
  1393. {
  1394. nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
  1395. nla_data(freq), nla_len(freq), freq_policy);
  1396. ch_cmp = nl80211_freq2channel(nla_get_u32(
  1397. freqs[NL80211_FREQUENCY_ATTR_FREQ]));
  1398. if ((!ch_cur || (ch_cmp == ch_cur)) &&
  1399. freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
  1400. {
  1401. *dbm_max = (int)(0.01 * nla_get_u32(
  1402. freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
  1403. break;
  1404. }
  1405. }
  1406. }
  1407. return NL_SKIP;
  1408. }
  1409. static int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len)
  1410. {
  1411. int ch_cur;
  1412. int dbm_max = -1, dbm_cur, dbm_cnt;
  1413. struct nl80211_msg_conveyor *req;
  1414. struct iwinfo_txpwrlist_entry entry;
  1415. if (nl80211_get_channel(ifname, &ch_cur))
  1416. ch_cur = 0;
  1417. req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
  1418. if (req)
  1419. {
  1420. /* initialize the value pointer with channel for callback */
  1421. dbm_max = ch_cur;
  1422. nl80211_send(req, nl80211_get_txpwrlist_cb, &dbm_max);
  1423. nl80211_free(req);
  1424. }
  1425. if (dbm_max > 0)
  1426. {
  1427. for (dbm_cur = 0, dbm_cnt = 0;
  1428. dbm_cur < dbm_max;
  1429. dbm_cur++, dbm_cnt++)
  1430. {
  1431. entry.dbm = dbm_cur;
  1432. entry.mw = iwinfo_dbm2mw(dbm_cur);
  1433. memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
  1434. }
  1435. entry.dbm = dbm_max;
  1436. entry.mw = iwinfo_dbm2mw(dbm_max);
  1437. memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
  1438. dbm_cnt++;
  1439. *len = dbm_cnt * sizeof(entry);
  1440. return 0;
  1441. }
  1442. return -1;
  1443. }
  1444. static void nl80211_get_scancrypto(const char *spec,
  1445. struct iwinfo_crypto_entry *c)
  1446. {
  1447. if (strstr(spec, "WPA") || strstr(spec, "WEP"))
  1448. {
  1449. c->enabled = 1;
  1450. if (strstr(spec, "WPA2-") && strstr(spec, "WPA-"))
  1451. c->wpa_version = 3;
  1452. else if (strstr(spec, "WPA2"))
  1453. c->wpa_version = 2;
  1454. else if (strstr(spec, "WPA"))
  1455. c->wpa_version = 1;
  1456. else if (strstr(spec, "WEP"))
  1457. c->auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
  1458. if (strstr(spec, "PSK"))
  1459. c->auth_suites |= IWINFO_KMGMT_PSK;
  1460. if (strstr(spec, "802.1X") || strstr(spec, "EAP"))
  1461. c->auth_suites |= IWINFO_KMGMT_8021x;
  1462. if (strstr(spec, "WPA-NONE"))
  1463. c->auth_suites |= IWINFO_KMGMT_NONE;
  1464. if (strstr(spec, "TKIP"))
  1465. c->pair_ciphers |= IWINFO_CIPHER_TKIP;
  1466. if (strstr(spec, "CCMP"))
  1467. c->pair_ciphers |= IWINFO_CIPHER_CCMP;
  1468. if (strstr(spec, "WEP-40"))
  1469. c->pair_ciphers |= IWINFO_CIPHER_WEP40;
  1470. if (strstr(spec, "WEP-104"))
  1471. c->pair_ciphers |= IWINFO_CIPHER_WEP104;
  1472. c->group_ciphers = c->pair_ciphers;
  1473. }
  1474. else
  1475. {
  1476. c->enabled = 0;
  1477. }
  1478. }
  1479. struct nl80211_scanlist {
  1480. struct iwinfo_scanlist_entry *e;
  1481. int len;
  1482. };
  1483. static void nl80211_get_scanlist_ie(struct nlattr **bss,
  1484. struct iwinfo_scanlist_entry *e)
  1485. {
  1486. int ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
  1487. unsigned char *ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
  1488. static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
  1489. int len;
  1490. while (ielen >= 2 && ielen >= ie[1])
  1491. {
  1492. switch (ie[0])
  1493. {
  1494. case 0: /* SSID */
  1495. len = min(ie[1], IWINFO_ESSID_MAX_SIZE);
  1496. memcpy(e->ssid, ie + 2, len);
  1497. e->ssid[len] = 0;
  1498. break;
  1499. case 48: /* RSN */
  1500. iwinfo_parse_rsn(&e->crypto, ie + 2, ie[1],
  1501. IWINFO_CIPHER_CCMP, IWINFO_KMGMT_8021x);
  1502. break;
  1503. case 221: /* Vendor */
  1504. if (ie[1] >= 4 && !memcmp(ie + 2, ms_oui, 3) && ie[5] == 1)
  1505. iwinfo_parse_rsn(&e->crypto, ie + 6, ie[1] - 4,
  1506. IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK);
  1507. break;
  1508. }
  1509. ielen -= ie[1] + 2;
  1510. ie += ie[1] + 2;
  1511. }
  1512. }
  1513. static int nl80211_get_scanlist_cb(struct nl_msg *msg, void *arg)
  1514. {
  1515. int8_t rssi;
  1516. uint16_t caps;
  1517. struct nl80211_scanlist *sl = arg;
  1518. struct nlattr **tb = nl80211_parse(msg);
  1519. struct nlattr *bss[NL80211_BSS_MAX + 1];
  1520. static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
  1521. [NL80211_BSS_TSF] = { .type = NLA_U64 },
  1522. [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
  1523. [NL80211_BSS_BSSID] = { 0 },
  1524. [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
  1525. [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
  1526. [NL80211_BSS_INFORMATION_ELEMENTS] = { 0 },
  1527. [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
  1528. [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
  1529. [NL80211_BSS_STATUS] = { .type = NLA_U32 },
  1530. [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
  1531. [NL80211_BSS_BEACON_IES] = { 0 },
  1532. };
  1533. if (!tb[NL80211_ATTR_BSS] ||
  1534. nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
  1535. bss_policy) ||
  1536. !bss[NL80211_BSS_BSSID])
  1537. {
  1538. return NL_SKIP;
  1539. }
  1540. if (bss[NL80211_BSS_CAPABILITY])
  1541. caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
  1542. else
  1543. caps = 0;
  1544. memset(sl->e, 0, sizeof(*sl->e));
  1545. memcpy(sl->e->mac, nla_data(bss[NL80211_BSS_BSSID]), 6);
  1546. if (caps & (1<<1))
  1547. sl->e->mode = IWINFO_OPMODE_ADHOC;
  1548. else if (caps & (1<<0))
  1549. sl->e->mode = IWINFO_OPMODE_MASTER;
  1550. else
  1551. sl->e->mode = IWINFO_OPMODE_MESHPOINT;
  1552. if (caps & (1<<4))
  1553. sl->e->crypto.enabled = 1;
  1554. if (bss[NL80211_BSS_FREQUENCY])
  1555. sl->e->channel = nl80211_freq2channel(nla_get_u32(
  1556. bss[NL80211_BSS_FREQUENCY]));
  1557. if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
  1558. nl80211_get_scanlist_ie(bss, sl->e);
  1559. if (bss[NL80211_BSS_SIGNAL_MBM])
  1560. {
  1561. sl->e->signal =
  1562. (uint8_t)((int32_t)nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]) / 100);
  1563. rssi = sl->e->signal - 0x100;
  1564. if (rssi < -110)
  1565. rssi = -110;
  1566. else if (rssi > -40)
  1567. rssi = -40;
  1568. sl->e->quality = (rssi + 110);
  1569. sl->e->quality_max = 70;
  1570. }
  1571. if (sl->e->crypto.enabled && !sl->e->crypto.wpa_version)
  1572. {
  1573. sl->e->crypto.auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
  1574. sl->e->crypto.pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104;
  1575. }
  1576. sl->e++;
  1577. sl->len++;
  1578. return NL_SKIP;
  1579. }
  1580. static int nl80211_get_scanlist_nl(const char *ifname, char *buf, int *len)
  1581. {
  1582. struct nl80211_msg_conveyor *req;
  1583. struct nl80211_scanlist sl = { .e = (struct iwinfo_scanlist_entry *)buf };
  1584. req = nl80211_msg(ifname, NL80211_CMD_TRIGGER_SCAN, 0);
  1585. if (req)
  1586. {
  1587. nl80211_send(req, NULL, NULL);
  1588. nl80211_free(req);
  1589. }
  1590. nl80211_wait("nl80211", "scan", NL80211_CMD_NEW_SCAN_RESULTS);
  1591. req = nl80211_msg(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
  1592. if (req)
  1593. {
  1594. nl80211_send(req, nl80211_get_scanlist_cb, &sl);
  1595. nl80211_free(req);
  1596. }
  1597. *len = sl.len * sizeof(struct iwinfo_scanlist_entry);
  1598. return *len ? 0 : -1;
  1599. }
  1600. static int wpasupp_ssid_decode(const char *in, char *out, int outlen)
  1601. {
  1602. #define hex(x) \
  1603. (((x) >= 'a') ? ((x) - 'a' + 10) : \
  1604. (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0')))
  1605. int len = 0;
  1606. while (*in)
  1607. {
  1608. if (len + 1 >= outlen)
  1609. break;
  1610. switch (*in)
  1611. {
  1612. case '\\':
  1613. in++;
  1614. switch (*in)
  1615. {
  1616. case 'n':
  1617. out[len++] = '\n'; in++;
  1618. break;
  1619. case 'r':
  1620. out[len++] = '\r'; in++;
  1621. break;
  1622. case 't':
  1623. out[len++] = '\t'; in++;
  1624. break;
  1625. case 'e':
  1626. out[len++] = '\033'; in++;
  1627. break;
  1628. case 'x':
  1629. if (isxdigit(*(in+1)) && isxdigit(*(in+2)))
  1630. out[len++] = hex(*(in+1)) * 16 + hex(*(in+2));
  1631. in += 3;
  1632. break;
  1633. default:
  1634. out[len++] = *in++;
  1635. break;
  1636. }
  1637. break;
  1638. default:
  1639. out[len++] = *in++;
  1640. break;
  1641. }
  1642. }
  1643. if (outlen > len)
  1644. out[len] = '\0';
  1645. return len;
  1646. }
  1647. static int nl80211_get_scanlist_wpactl(const char *ifname, char *buf, int *len)
  1648. {
  1649. int sock, qmax, rssi, tries, count = -1, ready = 0;
  1650. char *pos, *line, *bssid, *freq, *signal, *flags, *ssid, reply[4096];
  1651. struct sockaddr_un local = { 0 };
  1652. struct iwinfo_scanlist_entry *e = (struct iwinfo_scanlist_entry *)buf;
  1653. sock = nl80211_wpactl_connect(ifname, &local);
  1654. if (sock < 0)
  1655. return sock;
  1656. send(sock, "ATTACH", 6, 0);
  1657. send(sock, "SCAN", 4, 0);
  1658. /*
  1659. * wait for scan results:
  1660. * nl80211_wpactl_recv() will use a timeout of 256ms and we need to scan
  1661. * 72 channels at most. We'll also receive two "OK" messages acknowledging
  1662. * the "ATTACH" and "SCAN" commands and the driver might need a bit extra
  1663. * time to process the results, so try 72 + 2 + 1 times.
  1664. */
  1665. for (tries = 0; tries < 75; tries++)
  1666. {
  1667. if (nl80211_wpactl_recv(sock, reply, sizeof(reply)) <= 0)
  1668. continue;
  1669. /* got an event notification */
  1670. if (reply[0] == '<')
  1671. {
  1672. /* scan results are ready */
  1673. if (strstr(reply, "CTRL-EVENT-SCAN-RESULTS"))
  1674. {
  1675. /* send "SCAN_RESULTS" command */
  1676. ready = (send(sock, "SCAN_RESULTS", 12, 0) == 12);
  1677. break;
  1678. }
  1679. /* is another unrelated event, retry */
  1680. tries--;
  1681. }
  1682. }
  1683. /* receive and parse scan results if the wait above didn't time out */
  1684. if (ready && nl80211_wpactl_recv(sock, reply, sizeof(reply)) > 0)
  1685. {
  1686. nl80211_get_quality_max(ifname, &qmax);
  1687. for (line = strtok_r(reply, "\n", &pos);
  1688. line != NULL;
  1689. line = strtok_r(NULL, "\n", &pos))
  1690. {
  1691. /* skip header line */
  1692. if (count < 0)
  1693. {
  1694. count++;
  1695. continue;
  1696. }
  1697. bssid = strtok(line, "\t");
  1698. freq = strtok(NULL, "\t");
  1699. signal = strtok(NULL, "\t");
  1700. flags = strtok(NULL, "\t");
  1701. ssid = strtok(NULL, "\n");
  1702. if (!bssid || !freq || !signal || !flags || !ssid)
  1703. continue;
  1704. /* BSSID */
  1705. e->mac[0] = strtol(&bssid[0], NULL, 16);
  1706. e->mac[1] = strtol(&bssid[3], NULL, 16);
  1707. e->mac[2] = strtol(&bssid[6], NULL, 16);
  1708. e->mac[3] = strtol(&bssid[9], NULL, 16);
  1709. e->mac[4] = strtol(&bssid[12], NULL, 16);
  1710. e->mac[5] = strtol(&bssid[15], NULL, 16);
  1711. /* SSID */
  1712. wpasupp_ssid_decode(ssid, e->ssid, sizeof(e->ssid));
  1713. /* Mode */
  1714. if (strstr(flags, "[MESH]"))
  1715. e->mode = IWINFO_OPMODE_MESHPOINT;
  1716. else if (strstr(flags, "[IBSS]"))
  1717. e->mode = IWINFO_OPMODE_ADHOC;
  1718. else
  1719. e->mode = IWINFO_OPMODE_MASTER;
  1720. /* Channel */
  1721. e->channel = nl80211_freq2channel(atoi(freq));
  1722. /* Signal */
  1723. rssi = atoi(signal);
  1724. e->signal = rssi;
  1725. /* Quality */
  1726. if (rssi < 0)
  1727. {
  1728. /* The cfg80211 wext compat layer assumes a signal range
  1729. * of -110 dBm to -40 dBm, the quality value is derived
  1730. * by adding 110 to the signal level */
  1731. if (rssi < -110)
  1732. rssi = -110;
  1733. else if (rssi > -40)
  1734. rssi = -40;
  1735. e->quality = (rssi + 110);
  1736. }
  1737. else
  1738. {
  1739. e->quality = rssi;
  1740. }
  1741. /* Max. Quality */
  1742. e->quality_max = qmax;
  1743. /* Crypto */
  1744. nl80211_get_scancrypto(flags, &e->crypto);
  1745. count++;
  1746. e++;
  1747. }
  1748. *len = count * sizeof(struct iwinfo_scanlist_entry);
  1749. }
  1750. close(sock);
  1751. unlink(local.sun_path);
  1752. return (count >= 0) ? 0 : -1;
  1753. }
  1754. static int nl80211_get_scanlist(const char *ifname, char *buf, int *len)
  1755. {
  1756. char *res;
  1757. int rv, mode;
  1758. *len = 0;
  1759. /* Got a radioX pseudo interface, find some interface on it or create one */
  1760. if (!strncmp(ifname, "radio", 5))
  1761. {
  1762. /* Reuse existing interface */
  1763. if ((res = nl80211_phy2ifname(ifname)) != NULL)
  1764. {
  1765. return nl80211_get_scanlist(res, buf, len);
  1766. }
  1767. /* Need to spawn a temporary iface for scanning */
  1768. else if ((res = nl80211_ifadd(ifname)) != NULL)
  1769. {
  1770. rv = nl80211_get_scanlist(res, buf, len);
  1771. nl80211_ifdel(res);
  1772. return rv;
  1773. }
  1774. }
  1775. /* WPA supplicant */
  1776. if (!nl80211_get_scanlist_wpactl(ifname, buf, len))
  1777. {
  1778. return 0;
  1779. }
  1780. /* station / ad-hoc / monitor scan */
  1781. else if (!nl80211_get_mode(ifname, &mode) &&
  1782. (mode == IWINFO_OPMODE_ADHOC ||
  1783. mode == IWINFO_OPMODE_MASTER ||
  1784. mode == IWINFO_OPMODE_CLIENT ||
  1785. mode == IWINFO_OPMODE_MONITOR) &&
  1786. iwinfo_ifup(ifname))
  1787. {
  1788. return nl80211_get_scanlist_nl(ifname, buf, len);
  1789. }
  1790. /* AP scan */
  1791. else
  1792. {
  1793. /* Got a temp interface, don't create yet another one */
  1794. if (!strncmp(ifname, "tmp.", 4))
  1795. {
  1796. if (!iwinfo_ifup(ifname))
  1797. return -1;
  1798. rv = nl80211_get_scanlist_nl(ifname, buf, len);
  1799. iwinfo_ifdown(ifname);
  1800. return rv;
  1801. }
  1802. /* Spawn a new scan interface */
  1803. else
  1804. {
  1805. if (!(res = nl80211_ifadd(ifname)))
  1806. return -1;
  1807. iwinfo_ifmac(res);
  1808. /* if we can take the new interface up, the driver supports an
  1809. * additional interface and there's no need to tear down the ap */
  1810. if (iwinfo_ifup(res))
  1811. {
  1812. rv = nl80211_get_scanlist_nl(res, buf, len);
  1813. iwinfo_ifdown(res);
  1814. }
  1815. /* driver cannot create secondary interface, take down ap
  1816. * during scan */
  1817. else if (iwinfo_ifdown(ifname) && iwinfo_ifup(res))
  1818. {
  1819. rv = nl80211_get_scanlist_nl(res, buf, len);
  1820. iwinfo_ifdown(res);
  1821. iwinfo_ifup(ifname);
  1822. nl80211_hostapd_hup(ifname);
  1823. }
  1824. nl80211_ifdel(res);
  1825. return rv;
  1826. }
  1827. }
  1828. return -1;
  1829. }
  1830. static int nl80211_get_freqlist_cb(struct nl_msg *msg, void *arg)
  1831. {
  1832. int bands_remain, freqs_remain;
  1833. struct nl80211_array_buf *arr = arg;
  1834. struct iwinfo_freqlist_entry *e = arr->buf;
  1835. struct nlattr **attr = nl80211_parse(msg);
  1836. struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
  1837. struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
  1838. struct nlattr *band, *freq;
  1839. nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
  1840. {
  1841. nla_parse(bands, NL80211_BAND_ATTR_MAX,
  1842. nla_data(band), nla_len(band), NULL);
  1843. nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
  1844. {
  1845. nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
  1846. nla_data(freq), nla_len(freq), NULL);
  1847. if (!freqs[NL80211_FREQUENCY_ATTR_FREQ] ||
  1848. freqs[NL80211_FREQUENCY_ATTR_DISABLED])
  1849. continue;
  1850. e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
  1851. e->channel = nl80211_freq2channel(e->mhz);
  1852. e->restricted = (
  1853. freqs[NL80211_FREQUENCY_ATTR_NO_IR] &&
  1854. !freqs[NL80211_FREQUENCY_ATTR_RADAR]
  1855. ) ? 1 : 0;
  1856. e++;
  1857. arr->count++;
  1858. }
  1859. }
  1860. return NL_SKIP;
  1861. }
  1862. static int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
  1863. {
  1864. struct nl80211_msg_conveyor *req;
  1865. struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
  1866. req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
  1867. if (req)
  1868. {
  1869. nl80211_send(req, nl80211_get_freqlist_cb, &arr);
  1870. nl80211_free(req);
  1871. }
  1872. if (arr.count > 0)
  1873. {
  1874. *len = arr.count * sizeof(struct iwinfo_freqlist_entry);
  1875. return 0;
  1876. }
  1877. return -1;
  1878. }
  1879. static int nl80211_get_country_cb(struct nl_msg *msg, void *arg)
  1880. {
  1881. char *buf = arg;
  1882. struct nlattr **attr = nl80211_parse(msg);
  1883. if (attr[NL80211_ATTR_REG_ALPHA2])
  1884. memcpy(buf, nla_data(attr[NL80211_ATTR_REG_ALPHA2]), 2);
  1885. else
  1886. buf[0] = 0;
  1887. return NL_SKIP;
  1888. }
  1889. static int nl80211_get_country(const char *ifname, char *buf)
  1890. {
  1891. int rv = -1;
  1892. struct nl80211_msg_conveyor *req;
  1893. req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0);
  1894. if (req)
  1895. {
  1896. nl80211_send(req, nl80211_get_country_cb, buf);
  1897. nl80211_free(req);
  1898. if (buf[0])
  1899. rv = 0;
  1900. }
  1901. return rv;
  1902. }
  1903. static int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
  1904. {
  1905. int count;
  1906. struct iwinfo_country_entry *e = (struct iwinfo_country_entry *)buf;
  1907. const struct iwinfo_iso3166_label *l;
  1908. for (l = IWINFO_ISO3166_NAMES, count = 0; l->iso3166; l++, e++, count++)
  1909. {
  1910. e->iso3166 = l->iso3166;
  1911. e->ccode[0] = (l->iso3166 / 256);
  1912. e->ccode[1] = (l->iso3166 % 256);
  1913. }
  1914. *len = (count * sizeof(struct iwinfo_country_entry));
  1915. return 0;
  1916. }
  1917. struct nl80211_modes
  1918. {
  1919. bool ok;
  1920. uint32_t hw;
  1921. uint32_t ht;
  1922. };
  1923. static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
  1924. {
  1925. struct nl80211_modes *m = arg;
  1926. int bands_remain, freqs_remain;
  1927. uint16_t caps = 0;
  1928. uint32_t vht_caps = 0;
  1929. struct nlattr **attr = nl80211_parse(msg);
  1930. struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
  1931. struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
  1932. struct nlattr *band, *freq;
  1933. if (attr[NL80211_ATTR_WIPHY_BANDS])
  1934. {
  1935. nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
  1936. {
  1937. nla_parse(bands, NL80211_BAND_ATTR_MAX,
  1938. nla_data(band), nla_len(band), NULL);
  1939. if (bands[NL80211_BAND_ATTR_HT_CAPA])
  1940. caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]);
  1941. /* Treat any nonzero capability as 11n */
  1942. if (caps > 0)
  1943. {
  1944. m->hw |= IWINFO_80211_N;
  1945. m->ht |= IWINFO_HTMODE_HT20;
  1946. if (caps & (1 << 1))
  1947. m->ht |= IWINFO_HTMODE_HT40;
  1948. }
  1949. nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
  1950. freqs_remain)
  1951. {
  1952. nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
  1953. nla_data(freq), nla_len(freq), NULL);
  1954. if (!freqs[NL80211_FREQUENCY_ATTR_FREQ])
  1955. continue;
  1956. if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485)
  1957. {
  1958. m->hw |= IWINFO_80211_B;
  1959. m->hw |= IWINFO_80211_G;
  1960. }
  1961. else if (bands[NL80211_BAND_ATTR_VHT_CAPA])
  1962. {
  1963. vht_caps = nla_get_u32(bands[NL80211_BAND_ATTR_VHT_CAPA]);
  1964. /* Treat any nonzero capability as 11ac */
  1965. if (vht_caps > 0)
  1966. {
  1967. m->hw |= IWINFO_80211_AC;
  1968. m->ht |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 | IWINFO_HTMODE_VHT80;
  1969. switch ((vht_caps >> 2) & 3)
  1970. {
  1971. case 2:
  1972. m->ht |= IWINFO_HTMODE_VHT80_80;
  1973. /* fall through */
  1974. case 1:
  1975. m->ht |= IWINFO_HTMODE_VHT160;
  1976. }
  1977. }
  1978. }
  1979. else if (!(m->hw & IWINFO_80211_AC))
  1980. {
  1981. m->hw |= IWINFO_80211_A;
  1982. }
  1983. }
  1984. }
  1985. m->ok = 1;
  1986. }
  1987. return NL_SKIP;
  1988. }
  1989. static int nl80211_get_hwmodelist(const char *ifname, int *buf)
  1990. {
  1991. struct nl80211_msg_conveyor *req;
  1992. struct nl80211_modes m = { 0 };
  1993. req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
  1994. if (req)
  1995. {
  1996. nl80211_send(req, nl80211_get_modelist_cb, &m);
  1997. nl80211_free(req);
  1998. }
  1999. if (m.ok)
  2000. {
  2001. *buf = m.hw;
  2002. return 0;
  2003. }
  2004. return -1;
  2005. }
  2006. static int nl80211_get_htmodelist(const char *ifname, int *buf)
  2007. {
  2008. struct nl80211_msg_conveyor *req;
  2009. struct nl80211_modes m = { 0 };
  2010. req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
  2011. if (req)
  2012. {
  2013. nl80211_send(req, nl80211_get_modelist_cb, &m);
  2014. nl80211_free(req);
  2015. }
  2016. if (m.ok)
  2017. {
  2018. *buf = m.ht;
  2019. return 0;
  2020. }
  2021. return -1;
  2022. }
  2023. static int nl80211_get_ifcomb_cb(struct nl_msg *msg, void *arg)
  2024. {
  2025. struct nlattr **attr = nl80211_parse(msg);
  2026. struct nlattr *comb;
  2027. int *ret = arg;
  2028. int comb_rem, limit_rem, mode_rem;
  2029. *ret = 0;
  2030. if (!attr[NL80211_ATTR_INTERFACE_COMBINATIONS])
  2031. return NL_SKIP;
  2032. nla_for_each_nested(comb, attr[NL80211_ATTR_INTERFACE_COMBINATIONS], comb_rem)
  2033. {
  2034. static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
  2035. [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
  2036. [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
  2037. };
  2038. struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB+1];
  2039. static struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
  2040. [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
  2041. [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
  2042. };
  2043. struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT+1];
  2044. struct nlattr *limit;
  2045. nla_parse_nested(tb_comb, NUM_NL80211_IFACE_COMB, comb, iface_combination_policy);
  2046. if (!tb_comb[NL80211_IFACE_COMB_LIMITS])
  2047. continue;
  2048. nla_for_each_nested(limit, tb_comb[NL80211_IFACE_COMB_LIMITS], limit_rem)
  2049. {
  2050. struct nlattr *mode;
  2051. nla_parse_nested(tb_limit, NUM_NL80211_IFACE_LIMIT, limit, iface_limit_policy);
  2052. if (!tb_limit[NL80211_IFACE_LIMIT_TYPES] ||
  2053. !tb_limit[NL80211_IFACE_LIMIT_MAX])
  2054. continue;
  2055. if (nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX]) < 2)
  2056. continue;
  2057. nla_for_each_nested(mode, tb_limit[NL80211_IFACE_LIMIT_TYPES], mode_rem) {
  2058. if (nla_type(mode) == NL80211_IFTYPE_AP)
  2059. *ret = 1;
  2060. }
  2061. }
  2062. }
  2063. return NL_SKIP;
  2064. }
  2065. static int nl80211_get_mbssid_support(const char *ifname, int *buf)
  2066. {
  2067. struct nl80211_msg_conveyor *req;
  2068. req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
  2069. if (!req)
  2070. return -1;
  2071. nl80211_send(req, nl80211_get_ifcomb_cb, buf);
  2072. nl80211_free(req);
  2073. return 0;
  2074. }
  2075. static int nl80211_get_hardware_id(const char *ifname, char *buf)
  2076. {
  2077. int rv;
  2078. char *res;
  2079. /* Got a radioX pseudo interface, find some interface on it or create one */
  2080. if (!strncmp(ifname, "radio", 5))
  2081. {
  2082. /* Reuse existing interface */
  2083. if ((res = nl80211_phy2ifname(ifname)) != NULL)
  2084. {
  2085. rv = wext_ops.hardware_id(res, buf);
  2086. }
  2087. /* Need to spawn a temporary iface for finding IDs */
  2088. else if ((res = nl80211_ifadd(ifname)) != NULL)
  2089. {
  2090. rv = wext_ops.hardware_id(res, buf);
  2091. nl80211_ifdel(res);
  2092. }
  2093. }
  2094. else
  2095. {
  2096. rv = wext_ops.hardware_id(ifname, buf);
  2097. }
  2098. /* Failed to obtain hardware IDs, search board config */
  2099. if (rv)
  2100. {
  2101. rv = iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf);
  2102. }
  2103. return rv;
  2104. }
  2105. static const struct iwinfo_hardware_entry *
  2106. nl80211_get_hardware_entry(const char *ifname)
  2107. {
  2108. struct iwinfo_hardware_id id;
  2109. if (nl80211_get_hardware_id(ifname, (char *)&id))
  2110. return NULL;
  2111. return iwinfo_hardware(&id);
  2112. }
  2113. static int nl80211_get_hardware_name(const char *ifname, char *buf)
  2114. {
  2115. const struct iwinfo_hardware_entry *hw;
  2116. if (!(hw = nl80211_get_hardware_entry(ifname)))
  2117. sprintf(buf, "Generic MAC80211");
  2118. else
  2119. sprintf(buf, "%s %s", hw->vendor_name, hw->device_name);
  2120. return 0;
  2121. }
  2122. static int nl80211_get_txpower_offset(const char *ifname, int *buf)
  2123. {
  2124. const struct iwinfo_hardware_entry *hw;
  2125. if (!(hw = nl80211_get_hardware_entry(ifname)))
  2126. return -1;
  2127. *buf = hw->txpower_offset;
  2128. return 0;
  2129. }
  2130. static int nl80211_get_frequency_offset(const char *ifname, int *buf)
  2131. {
  2132. const struct iwinfo_hardware_entry *hw;
  2133. if (!(hw = nl80211_get_hardware_entry(ifname)))
  2134. return -1;
  2135. *buf = hw->frequency_offset;
  2136. return 0;
  2137. }
  2138. static int nl80211_lookup_phyname(const char *section, char *buf)
  2139. {
  2140. int idx;
  2141. if ((idx = nl80211_phy_idx_from_uci(section)) < 0)
  2142. return -1;
  2143. sprintf(buf, "phy%d", idx);
  2144. return 0;
  2145. }
  2146. const struct iwinfo_ops nl80211_ops = {
  2147. .name = "nl80211",
  2148. .probe = nl80211_probe,
  2149. .channel = nl80211_get_channel,
  2150. .frequency = nl80211_get_frequency,
  2151. .frequency_offset = nl80211_get_frequency_offset,
  2152. .txpower = nl80211_get_txpower,
  2153. .txpower_offset = nl80211_get_txpower_offset,
  2154. .bitrate = nl80211_get_bitrate,
  2155. .signal = nl80211_get_signal,
  2156. .noise = nl80211_get_noise,
  2157. .quality = nl80211_get_quality,
  2158. .quality_max = nl80211_get_quality_max,
  2159. .mbssid_support = nl80211_get_mbssid_support,
  2160. .hwmodelist = nl80211_get_hwmodelist,
  2161. .htmodelist = nl80211_get_htmodelist,
  2162. .mode = nl80211_get_mode,
  2163. .ssid = nl80211_get_ssid,
  2164. .bssid = nl80211_get_bssid,
  2165. .country = nl80211_get_country,
  2166. .hardware_id = nl80211_get_hardware_id,
  2167. .hardware_name = nl80211_get_hardware_name,
  2168. .encryption = nl80211_get_encryption,
  2169. .phyname = nl80211_get_phyname,
  2170. .assoclist = nl80211_get_assoclist,
  2171. .txpwrlist = nl80211_get_txpwrlist,
  2172. .scanlist = nl80211_get_scanlist,
  2173. .freqlist = nl80211_get_freqlist,
  2174. .countrylist = nl80211_get_countrylist,
  2175. .lookup_phy = nl80211_lookup_phyname,
  2176. .close = nl80211_close
  2177. };