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