iwinfo_wl.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. /*
  2. * iwinfo - Wireless Information Library - Broadcom wl.o Backend
  3. *
  4. * Copyright (C) 2009 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. * This code is based on the wlc.c utility published by OpenWrt.org .
  19. */
  20. #include "iwinfo.h"
  21. #include "api/broadcom.h"
  22. static int wl_ioctl(const char *name, int cmd, void *buf, int len)
  23. {
  24. struct ifreq ifr;
  25. wl_ioctl_t ioc;
  26. /* do it */
  27. ioc.cmd = cmd;
  28. ioc.buf = buf;
  29. ioc.len = len;
  30. strncpy(ifr.ifr_name, name, IFNAMSIZ);
  31. ifr.ifr_data = (caddr_t) &ioc;
  32. return iwinfo_ioctl(SIOCDEVPRIVATE, &ifr);
  33. }
  34. static int wl_iovar(const char *name, const char *cmd, const char *arg,
  35. int arglen, void *buf, int buflen)
  36. {
  37. int cmdlen = strlen(cmd) + 1;
  38. memcpy(buf, cmd, cmdlen);
  39. if (arg && arglen > 0)
  40. memcpy(buf + cmdlen, arg, arglen);
  41. return wl_ioctl(name, WLC_GET_VAR, buf, buflen);
  42. }
  43. static struct wl_maclist * wl_read_assoclist(const char *ifname)
  44. {
  45. struct wl_maclist *macs;
  46. int maclen = 4 + WL_MAX_STA_COUNT * 6;
  47. if (strstr(ifname, "wds"))
  48. return NULL;
  49. if ((macs = (struct wl_maclist *) malloc(maclen)) != NULL)
  50. {
  51. memset(macs, 0, maclen);
  52. macs->count = WL_MAX_STA_COUNT;
  53. if (!wl_ioctl(ifname, WLC_GET_ASSOCLIST, macs, maclen))
  54. return macs;
  55. free(macs);
  56. }
  57. return NULL;
  58. }
  59. static int wl_probe(const char *ifname)
  60. {
  61. int magic;
  62. return (!wl_ioctl(ifname, WLC_GET_MAGIC, &magic, sizeof(magic)) &&
  63. (magic == WLC_IOCTL_MAGIC));
  64. }
  65. static void wl_close(void)
  66. {
  67. /* Nop */
  68. }
  69. static int wl_get_mode(const char *ifname, int *buf)
  70. {
  71. int ret = -1;
  72. int ap, infra, passive;
  73. if ((ret = wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap))))
  74. return ret;
  75. if ((ret = wl_ioctl(ifname, WLC_GET_INFRA, &infra, sizeof(infra))))
  76. return ret;
  77. if ((ret = wl_ioctl(ifname, WLC_GET_PASSIVE, &passive, sizeof(passive))))
  78. return ret;
  79. if (passive)
  80. *buf = IWINFO_OPMODE_MONITOR;
  81. else if (!infra)
  82. *buf = IWINFO_OPMODE_ADHOC;
  83. else if (ap)
  84. *buf = IWINFO_OPMODE_MASTER;
  85. else
  86. *buf = IWINFO_OPMODE_CLIENT;
  87. return 0;
  88. }
  89. static int wl_get_ssid(const char *ifname, char *buf)
  90. {
  91. int ret = -1;
  92. wlc_ssid_t ssid;
  93. if (!(ret = wl_ioctl(ifname, WLC_GET_SSID, &ssid, sizeof(ssid))))
  94. memcpy(buf, ssid.ssid, ssid.ssid_len);
  95. return ret;
  96. }
  97. static int wl_get_bssid(const char *ifname, char *buf)
  98. {
  99. int ret = -1;
  100. char bssid[6];
  101. if (!(ret = wl_ioctl(ifname, WLC_GET_BSSID, bssid, 6)))
  102. sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
  103. (uint8_t)bssid[0], (uint8_t)bssid[1], (uint8_t)bssid[2],
  104. (uint8_t)bssid[3], (uint8_t)bssid[4], (uint8_t)bssid[5]
  105. );
  106. return ret;
  107. }
  108. static int wl_get_channel(const char *ifname, int *buf)
  109. {
  110. return wl_ioctl(ifname, WLC_GET_CHANNEL, buf, sizeof(buf));
  111. }
  112. static int wl_get_frequency(const char *ifname, int *buf)
  113. {
  114. return wext_ops.frequency(ifname, buf);
  115. }
  116. static int wl_get_txpower(const char *ifname, int *buf)
  117. {
  118. /* WLC_GET_VAR "qtxpower" */
  119. return wext_ops.txpower(ifname, buf);
  120. }
  121. static int wl_get_bitrate(const char *ifname, int *buf)
  122. {
  123. int ret = -1;
  124. int rate = 0;
  125. if( !(ret = wl_ioctl(ifname, WLC_GET_RATE, &rate, sizeof(rate))) && (rate > 0))
  126. *buf = ((rate / 2) * 1000) + ((rate & 1) ? 500 : 0);
  127. return ret;
  128. }
  129. static int wl_get_signal(const char *ifname, int *buf)
  130. {
  131. unsigned int ap, rssi, i, rssi_count;
  132. int ioctl_req_version = 0x2000;
  133. char tmp[WLC_IOCTL_MAXLEN];
  134. struct wl_maclist *macs = NULL;
  135. wl_sta_rssi_t starssi;
  136. memset(tmp, 0, WLC_IOCTL_MAXLEN);
  137. memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version));
  138. wl_ioctl(ifname, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN);
  139. if (!wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)) && !ap)
  140. {
  141. *buf = tmp[WL_BSS_RSSI_OFFSET];
  142. }
  143. else
  144. {
  145. rssi = rssi_count = 0;
  146. /* Calculate average rssi from conntected stations */
  147. if ((macs = wl_read_assoclist(ifname)) != NULL)
  148. {
  149. for (i = 0; i < macs->count; i++)
  150. {
  151. memcpy(starssi.mac, &macs->ea[i], 6);
  152. if (!wl_ioctl(ifname, WLC_GET_RSSI, &starssi, 12))
  153. {
  154. rssi -= starssi.rssi;
  155. rssi_count++;
  156. }
  157. }
  158. free(macs);
  159. }
  160. *buf = (rssi == 0 || rssi_count == 0) ? 1 : -(rssi / rssi_count);
  161. }
  162. return 0;
  163. }
  164. static int wl_get_noise(const char *ifname, int *buf)
  165. {
  166. unsigned int ap, noise;
  167. int ioctl_req_version = 0x2000;
  168. char tmp[WLC_IOCTL_MAXLEN];
  169. memset(tmp, 0, WLC_IOCTL_MAXLEN);
  170. memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version));
  171. wl_ioctl(ifname, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN);
  172. if ((wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)) < 0) || ap)
  173. {
  174. if (wl_ioctl(ifname, WLC_GET_PHY_NOISE, &noise, sizeof(noise)) < 0)
  175. noise = 0;
  176. }
  177. else
  178. {
  179. noise = tmp[WL_BSS_NOISE_OFFSET];
  180. }
  181. *buf = noise;
  182. return 0;
  183. }
  184. static int wl_get_quality(const char *ifname, int *buf)
  185. {
  186. return wext_ops.quality(ifname, buf);
  187. }
  188. static int wl_get_quality_max(const char *ifname, int *buf)
  189. {
  190. return wext_ops.quality_max(ifname, buf);
  191. }
  192. static int wl_get_encryption(const char *ifname, char *buf)
  193. {
  194. uint32_t wsec, wauth, wpa;
  195. struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf;
  196. if( wl_ioctl(ifname, WLC_GET_WPA_AUTH, &wpa, sizeof(uint32_t)) ||
  197. wl_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(uint32_t)) ||
  198. wl_ioctl(ifname, WLC_GET_AUTH, &wauth, sizeof(uint32_t)) )
  199. return -1;
  200. switch(wsec)
  201. {
  202. case 2:
  203. c->pair_ciphers |= IWINFO_CIPHER_TKIP;
  204. break;
  205. case 4:
  206. c->pair_ciphers |= IWINFO_CIPHER_CCMP;
  207. break;
  208. case 6:
  209. c->pair_ciphers |= IWINFO_CIPHER_TKIP;
  210. c->pair_ciphers |= IWINFO_CIPHER_CCMP;
  211. break;
  212. }
  213. switch(wpa)
  214. {
  215. case 0:
  216. if (wsec && !wauth)
  217. c->auth_algs |= IWINFO_AUTH_OPEN;
  218. else if (wsec && wauth)
  219. c->auth_algs |= IWINFO_AUTH_SHARED;
  220. /* ToDo: evaluate WEP key lengths */
  221. c->pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104;
  222. c->auth_suites |= IWINFO_KMGMT_NONE;
  223. break;
  224. case 2:
  225. c->wpa_version = 1;
  226. c->auth_suites |= IWINFO_KMGMT_8021x;
  227. break;
  228. case 4:
  229. c->wpa_version = 1;
  230. c->auth_suites |= IWINFO_KMGMT_PSK;
  231. break;
  232. case 32:
  233. case 64:
  234. c->wpa_version = 2;
  235. c->auth_suites |= IWINFO_KMGMT_8021x;
  236. break;
  237. case 66:
  238. c->wpa_version = 3;
  239. c->auth_suites |= IWINFO_KMGMT_8021x;
  240. break;
  241. case 128:
  242. c->wpa_version = 2;
  243. c->auth_suites |= IWINFO_KMGMT_PSK;
  244. break;
  245. case 132:
  246. c->wpa_version = 3;
  247. c->auth_suites |= IWINFO_KMGMT_PSK;
  248. break;
  249. default:
  250. break;
  251. }
  252. c->enabled = (c->wpa_version || c->auth_algs) ? 1 : 0;
  253. c->group_ciphers = c->pair_ciphers;
  254. return 0;
  255. }
  256. static int wl_get_phyname(const char *ifname, char *buf)
  257. {
  258. char *p;
  259. strcpy(buf, ifname);
  260. if ((p = strchr(buf, '.')) != NULL)
  261. *p = 0;
  262. return 0;
  263. }
  264. static int wl_get_enctype(const char *ifname, char *buf)
  265. {
  266. uint32_t wsec, wpa;
  267. char algo[11];
  268. if( wl_ioctl(ifname, WLC_GET_WPA_AUTH, &wpa, sizeof(uint32_t)) ||
  269. wl_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(uint32_t)) )
  270. return -1;
  271. switch(wsec)
  272. {
  273. case 2:
  274. sprintf(algo, "TKIP");
  275. break;
  276. case 4:
  277. sprintf(algo, "CCMP");
  278. break;
  279. case 6:
  280. sprintf(algo, "TKIP, CCMP");
  281. break;
  282. }
  283. switch(wpa)
  284. {
  285. case 0:
  286. sprintf(buf, "%s", wsec ? "WEP" : "None");
  287. break;
  288. case 2:
  289. sprintf(buf, "WPA 802.1X (%s)", algo);
  290. break;
  291. case 4:
  292. sprintf(buf, "WPA PSK (%s)", algo);
  293. break;
  294. case 32:
  295. sprintf(buf, "802.1X (%s)", algo);
  296. break;
  297. case 64:
  298. sprintf(buf, "WPA2 802.1X (%s)", algo);
  299. break;
  300. case 66:
  301. sprintf(buf, "mixed WPA/WPA2 802.1X (%s)", algo);
  302. break;
  303. case 128:
  304. sprintf(buf, "WPA2 PSK (%s)", algo);
  305. break;
  306. case 132:
  307. sprintf(buf, "mixed WPA/WPA2 PSK (%s)", algo);
  308. break;
  309. default:
  310. sprintf(buf, "Unknown");
  311. }
  312. return 0;
  313. }
  314. static void wl_get_assoclist_cb(const char *ifname,
  315. struct iwinfo_assoclist_entry *e)
  316. {
  317. wl_sta_info_t sta = { 0 };
  318. if (!wl_iovar(ifname, "sta_info", e->mac, 6, &sta, sizeof(sta)) &&
  319. (sta.ver >= 2))
  320. {
  321. e->inactive = sta.idle * 1000;
  322. e->rx_packets = sta.rx_ucast_pkts;
  323. e->tx_packets = sta.tx_pkts;
  324. e->rx_rate.rate = sta.rx_rate;
  325. e->tx_rate.rate = sta.tx_rate;
  326. /* ToDo: 11n */
  327. e->rx_rate.mcs = -1;
  328. e->tx_rate.mcs = -1;
  329. }
  330. }
  331. static int wl_get_assoclist(const char *ifname, char *buf, int *len)
  332. {
  333. int i, j, noise;
  334. int ap, infra, passive;
  335. char line[128];
  336. char macstr[18];
  337. char devstr[IFNAMSIZ];
  338. struct wl_maclist *macs;
  339. struct wl_sta_rssi rssi;
  340. struct iwinfo_assoclist_entry entry;
  341. FILE *arp;
  342. ap = infra = passive = 0;
  343. wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap));
  344. wl_ioctl(ifname, WLC_GET_INFRA, &infra, sizeof(infra));
  345. wl_ioctl(ifname, WLC_GET_PASSIVE, &passive, sizeof(passive));
  346. if (wl_get_noise(ifname, &noise))
  347. noise = 0;
  348. if ((ap || infra || passive) && ((macs = wl_read_assoclist(ifname)) != NULL))
  349. {
  350. for (i = 0, j = 0; i < macs->count; i++, j += sizeof(struct iwinfo_assoclist_entry))
  351. {
  352. memset(&entry, 0, sizeof(entry));
  353. memcpy(rssi.mac, &macs->ea[i], 6);
  354. if (!wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(struct wl_sta_rssi)))
  355. entry.signal = (rssi.rssi - 0x100);
  356. else
  357. entry.signal = 0;
  358. entry.noise = noise;
  359. memcpy(entry.mac, &macs->ea[i], 6);
  360. wl_get_assoclist_cb(ifname, &entry);
  361. memcpy(&buf[j], &entry, sizeof(entry));
  362. }
  363. *len = j;
  364. free(macs);
  365. return 0;
  366. }
  367. else if ((arp = fopen("/proc/net/arp", "r")) != NULL)
  368. {
  369. j = 0;
  370. while (fgets(line, sizeof(line), arp) != NULL)
  371. {
  372. if (sscanf(line, "%*s 0x%*d 0x%*d %17s %*s %s", macstr, devstr) && !strcmp(devstr, ifname))
  373. {
  374. rssi.mac[0] = strtol(&macstr[0], NULL, 16);
  375. rssi.mac[1] = strtol(&macstr[3], NULL, 16);
  376. rssi.mac[2] = strtol(&macstr[6], NULL, 16);
  377. rssi.mac[3] = strtol(&macstr[9], NULL, 16);
  378. rssi.mac[4] = strtol(&macstr[12], NULL, 16);
  379. rssi.mac[5] = strtol(&macstr[15], NULL, 16);
  380. if (!wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(struct wl_sta_rssi)))
  381. entry.signal = (rssi.rssi - 0x100);
  382. else
  383. entry.signal = 0;
  384. entry.noise = noise;
  385. memcpy(entry.mac, rssi.mac, 6);
  386. memcpy(&buf[j], &entry, sizeof(entry));
  387. j += sizeof(entry);
  388. }
  389. }
  390. *len = j;
  391. (void) fclose(arp);
  392. return 0;
  393. }
  394. return -1;
  395. }
  396. static int wl_get_txpwrlist(const char *ifname, char *buf, int *len)
  397. {
  398. struct iwinfo_txpwrlist_entry entry;
  399. uint8_t dbm[11] = { 0, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 };
  400. uint8_t mw[11] = { 1, 3, 6, 10, 15, 25, 39, 63, 100, 158, 251 };
  401. int i;
  402. for (i = 0; i < 11; i++)
  403. {
  404. entry.dbm = dbm[i];
  405. entry.mw = mw[i];
  406. memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry));
  407. }
  408. *len = 11 * sizeof(entry);
  409. return 0;
  410. }
  411. static int wl_get_scanlist(const char *ifname, char *buf, int *len)
  412. {
  413. return wext_ops.scanlist(ifname, buf, len);
  414. }
  415. static int wl_get_freqlist(const char *ifname, char *buf, int *len)
  416. {
  417. return wext_ops.freqlist(ifname, buf, len);
  418. }
  419. static int wl_get_country(const char *ifname, char *buf)
  420. {
  421. char ccode[WLC_CNTRY_BUF_SZ];
  422. if (!wl_ioctl(ifname, WLC_GET_COUNTRY, ccode, WLC_CNTRY_BUF_SZ))
  423. {
  424. /* IL0 -> World */
  425. if (!strcmp(ccode, "IL0"))
  426. sprintf(buf, "00");
  427. /* YU -> RS */
  428. else if (!strcmp(ccode, "YU"))
  429. sprintf(buf, "RS");
  430. else
  431. memcpy(buf, ccode, 2);
  432. return 0;
  433. }
  434. return -1;
  435. }
  436. static int wl_get_countrylist(const char *ifname, char *buf, int *len)
  437. {
  438. int i, count;
  439. char cdata[WLC_IOCTL_MAXLEN];
  440. struct iwinfo_country_entry *c = (struct iwinfo_country_entry *)buf;
  441. wl_country_list_t *cl = (wl_country_list_t *)cdata;
  442. cl->buflen = sizeof(cdata);
  443. if (!wl_ioctl(ifname, WLC_GET_COUNTRY_LIST, cl, cl->buflen))
  444. {
  445. for (i = 0, count = 0; i < cl->count; i++, c++)
  446. {
  447. snprintf(c->ccode, sizeof(c->ccode), "%s", &cl->country_abbrev[i * WLC_CNTRY_BUF_SZ]);
  448. c->iso3166 = c->ccode[0] * 256 + c->ccode[1];
  449. /* IL0 -> World */
  450. if (!strcmp(c->ccode, "IL0"))
  451. c->iso3166 = 0x3030;
  452. /* YU -> RS */
  453. else if (!strcmp(c->ccode, "YU"))
  454. c->iso3166 = 0x5253;
  455. }
  456. *len = (i * sizeof(struct iwinfo_country_entry));
  457. return 0;
  458. }
  459. return -1;
  460. }
  461. static int wl_get_hwmodelist(const char *ifname, int *buf)
  462. {
  463. int phytype;
  464. uint i, band[WLC_BAND_ALL], bands;
  465. if (!wl_ioctl(ifname, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)) &&
  466. !wl_ioctl(ifname, WLC_GET_BANDLIST, band, sizeof(band)))
  467. {
  468. *buf = 0;
  469. switch (phytype)
  470. {
  471. case WLC_PHY_TYPE_A:
  472. *buf = IWINFO_80211_A;
  473. break;
  474. case WLC_PHY_TYPE_B:
  475. *buf = IWINFO_80211_B;
  476. break;
  477. case WLC_PHY_TYPE_AC:
  478. *buf |= IWINFO_80211_AC;
  479. case WLC_PHY_TYPE_HT:
  480. case WLC_PHY_TYPE_N:
  481. *buf |= IWINFO_80211_N;
  482. case WLC_PHY_TYPE_LP:
  483. case WLC_PHY_TYPE_G:
  484. bands = 0;
  485. for (i = 1; i <= band[0]; i++)
  486. {
  487. bands |= band[i];
  488. }
  489. if (bands & WLC_BAND_5G)
  490. *buf |= IWINFO_80211_A;
  491. if (bands & WLC_BAND_2G)
  492. {
  493. *buf |= IWINFO_80211_B;
  494. *buf |= IWINFO_80211_G;
  495. }
  496. break;
  497. default:
  498. return -1;
  499. break;
  500. }
  501. return 0;
  502. }
  503. return -1;
  504. }
  505. static int wl_get_htmodelist(const char *ifname, int *buf)
  506. {
  507. int modes;
  508. if (!wl_get_hwmodelist(ifname, &modes))
  509. {
  510. *buf = 0;
  511. /* FIXME: determine real capabilities */
  512. if (modes & IWINFO_80211_N)
  513. *buf |= IWINFO_HTMODE_HT20 | IWINFO_HTMODE_HT40;
  514. if (modes & IWINFO_80211_AC)
  515. *buf |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 |
  516. IWINFO_HTMODE_VHT80;
  517. return 0;
  518. }
  519. return -1;
  520. }
  521. static int wl_get_mbssid_support(const char *ifname, int *buf)
  522. {
  523. wlc_rev_info_t revinfo;
  524. /* Multi bssid support only works on corerev >= 9 */
  525. if (!wl_ioctl(ifname, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)))
  526. {
  527. if (revinfo.corerev >= 9)
  528. {
  529. *buf = 1;
  530. return 0;
  531. }
  532. }
  533. return -1;
  534. }
  535. static int wl_get_hardware_id(const char *ifname, char *buf)
  536. {
  537. wlc_rev_info_t revinfo;
  538. struct iwinfo_hardware_id *ids = (struct iwinfo_hardware_id *)buf;
  539. if (wl_ioctl(ifname, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)))
  540. return -1;
  541. ids->vendor_id = revinfo.vendorid;
  542. ids->device_id = revinfo.deviceid;
  543. ids->subsystem_vendor_id = revinfo.boardvendor;
  544. ids->subsystem_device_id = revinfo.boardid;
  545. return 0;
  546. }
  547. static int wl_get_hardware_name(const char *ifname, char *buf)
  548. {
  549. struct iwinfo_hardware_id ids;
  550. if (wl_get_hardware_id(ifname, (char *)&ids))
  551. return -1;
  552. sprintf(buf, "Broadcom BCM%04X", ids.device_id);
  553. return 0;
  554. }
  555. static int wl_get_txpower_offset(const char *ifname, int *buf)
  556. {
  557. FILE *p;
  558. char off[8];
  559. *buf = 0;
  560. if ((p = popen("/usr/sbin/nvram get opo", "r")) != NULL)
  561. {
  562. if (fread(off, 1, sizeof(off), p))
  563. *buf = strtoul(off, NULL, 16);
  564. pclose(p);
  565. }
  566. return 0;
  567. }
  568. static int wl_get_frequency_offset(const char *ifname, int *buf)
  569. {
  570. /* Stub */
  571. *buf = 0;
  572. return -1;
  573. }
  574. const struct iwinfo_ops wl_ops = {
  575. .name = "wl",
  576. .probe = wl_probe,
  577. .channel = wl_get_channel,
  578. .frequency = wl_get_frequency,
  579. .frequency_offset = wl_get_frequency_offset,
  580. .txpower = wl_get_txpower,
  581. .txpower_offset = wl_get_txpower_offset,
  582. .bitrate = wl_get_bitrate,
  583. .signal = wl_get_signal,
  584. .noise = wl_get_noise,
  585. .quality = wl_get_quality,
  586. .quality_max = wl_get_quality_max,
  587. .mbssid_support = wl_get_mbssid_support,
  588. .hwmodelist = wl_get_hwmodelist,
  589. .htmodelist = wl_get_htmodelist,
  590. .mode = wl_get_mode,
  591. .ssid = wl_get_ssid,
  592. .bssid = wl_get_bssid,
  593. .country = wl_get_country,
  594. .hardware_id = wl_get_hardware_id,
  595. .hardware_name = wl_get_hardware_name,
  596. .encryption = wl_get_encryption,
  597. .phyname = wl_get_phyname,
  598. .assoclist = wl_get_assoclist,
  599. .txpwrlist = wl_get_txpwrlist,
  600. .scanlist = wl_get_scanlist,
  601. .freqlist = wl_get_freqlist,
  602. .countrylist = wl_get_countrylist,
  603. .close = wl_close
  604. };