source: src/router/libutils/wl.c @ 31679

Last change on this file since 31679 was 31679, checked in by brainslayer, 6 weeks ago

fix wrong max rate, sgi was ignored due missing zero termination

  • Property svn:executable set to *
File size: 60.4 KB
Line 
1/*
2 * Wireless network adapter utilities
3 *
4 * Copyright 2001-2003, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: wl.c,v 1.3 2005/11/11 09:26:19 seg Exp $
13 */
14#include <string.h>
15#include <unistd.h>
16
17#include <typedefs.h>
18#include <bcmutils.h>
19#include <wlutils.h>
20#include <shutils.h>
21#include <utils.h>
22#include <bcmnvram.h>
23#include <syslog.h>
24#include <fcntl.h>
25//#include <math.h>
26#ifdef HAVE_ATH9K
27#include <glob.h>
28#endif
29
30/*
31 * DD-WRT addition (loaned from radauth)
32 */
33
34int ieee80211_mhz2ieee(int freq)
35{
36        if (freq == 2484)
37                return 14;
38        if (freq == 2407)
39                return 0;
40        if (freq < 2484 && freq > 2407)
41                return (freq - 2407) / 5;
42        if (freq < 2412) {
43                return ((freq - 2407) / 5) + 256;
44        }
45        if (freq > 2484 && freq < 4000)
46                return (freq - 2414) / 5;
47        if (freq < 4990 && freq > 4940)
48                return ((freq * 10) + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
49        // 5000 will become  channel 200
50        if (freq >= 4800 && freq < 5005)
51                return (freq - 4000) / 5;
52        if (freq < 5000)
53                return 15 + ((freq - 2512) / 20);
54        if (freq == 58320)
55                return 1;
56        if (freq == 60480)
57                return 2;
58        if (freq == 62640)
59                return 3;
60        if (freq == 64800)
61                return 4;
62
63        return (freq - 5000) / 5;
64}
65
66#ifndef HAVE_MADWIFI
67
68unsigned int ieee80211_ieee2mhz(unsigned int chan)
69{
70        if (chan == 14)
71                return 2484;
72        if (chan < 14)
73                return ((2407) + chan * 5);
74        else if (chan < 27)
75                return ((2512) + ((chan - 15) * 20));
76        else
77                return ((5000) + (chan * 5));
78}
79
80#if defined(HAVE_RT2880) || defined(HAVE_RT61)
81char *getRADev(char *prefix)
82{
83        char *ifname = NULL;
84
85        if (!strcmp(prefix, "wl0"))
86                ifname = "ra0";
87        if (!strcmp(prefix, "wl0.1"))
88                ifname = "ra1";
89        if (!strcmp(prefix, "wl0.2"))
90                ifname = "ra2";
91        if (!strcmp(prefix, "wl0.3"))
92                ifname = "ra3";
93        if (!strcmp(prefix, "wl0.4"))
94                ifname = "ra4";
95        if (!strcmp(prefix, "wl0.5"))
96                ifname = "ra5";
97        if (!strcmp(prefix, "wl0.6"))
98                ifname = "ra6";
99        if (!strcmp(prefix, "wl0.7"))
100                ifname = "ra7";
101
102        if (!strcmp(prefix, "wl1"))
103                ifname = "ba0";
104        if (!strcmp(prefix, "wl1.1"))
105                ifname = "ba1";
106        if (!strcmp(prefix, "wl1.2"))
107                ifname = "ba2";
108        if (!strcmp(prefix, "wl1.3"))
109                ifname = "ba3";
110        if (!strcmp(prefix, "wl1.4"))
111                ifname = "ba4";
112        if (!strcmp(prefix, "wl1.5"))
113                ifname = "ba5";
114        if (!strcmp(prefix, "wl1.6"))
115                ifname = "ba6";
116        if (!strcmp(prefix, "wl1.7"))
117                ifname = "ba7";
118
119        if (ifname)
120                return ifname;
121        else
122                return prefix;
123}
124
125int has_5ghz(char *prefix)
126{
127        if (!strcmp(prefix, "wl0"))
128                return 0;
129        return 1;
130}
131
132int has_2ghz(char *prefix)
133{
134        if (!strcmp(prefix, "wl0"))
135                return 1;
136        return 0;
137}
138
139int getchannels(unsigned int *list, char *ifname)
140{
141        if (!strcmp(ifname, "ra0")) {
142                list[0] = 1;
143                list[1] = 2;
144                list[2] = 3;
145                list[3] = 4;
146                list[4] = 5;
147                list[5] = 6;
148                list[6] = 7;
149                list[7] = 8;
150                list[8] = 9;
151                list[9] = 10;
152                list[10] = 11;
153                list[11] = 12;
154                list[12] = 13;
155                list[13] = 14;
156#ifdef HAVE_BUFFALO
157                // temporal solution, needs to be done right
158                if (nvram_match("region", "EU"))
159                        return 11;
160                else if (nvram_match("region", "RU"))
161                        return 11;
162                else if (nvram_match("region", "US"))
163                        return 11;
164                else if (nvram_match("region", "JP"))
165                        return 13;
166                else
167                        return 11;
168#else
169                return 14;
170#endif
171        } else {
172                int i;
173                int cnt = 0;
174#ifdef HAVE_BUFFALO
175                if (nvram_match("region", "EU")) {
176                        for (i = 0; i < 4; i++)
177                                list[cnt++] = 36 + (i * 4);
178                } else if (nvram_match("region", "RU")) {
179                        for (i = 0; i < 4; i++)
180                                list[cnt++] = 36 + (i * 4);
181                } else if (nvram_match("region", "US")) {
182                        for (i = 0; i < 4; i++)
183                                list[cnt++] = 36 + (i * 4);
184                        for (i = 0; i < 5; i++)
185                                list[cnt++] = 149 + (i * 4);
186                } else if (nvram_match("region", "JP")) {
187                        for (i = 0; i < 8; i++)
188                                list[cnt++] = 36 + (i * 4);
189                        for (i = 0; i < 11; i++)
190                                list[cnt++] = 100 + (i * 4);
191                } else {
192                        for (i = 0; i < 4; i++)
193                                list[cnt++] = 36 + (i * 4);
194                }
195
196#else
197                for (i = 0; i < 8; i++)
198                        list[cnt++] = 36 + (i * 4);
199
200                for (i = 0; i < 11; i++)
201                        list[cnt++] = 100 + (i * 4);
202
203                for (i = 0; i < 7; i++)
204                        list[cnt++] = 149 + (i * 4);
205#endif
206                return cnt;
207        }
208}
209
210#include <sys/types.h>
211#include <sys/file.h>
212#include <sys/ioctl.h>
213#include <sys/socket.h>
214#include <stdio.h>
215#include <stdlib.h>
216#include <string.h>
217#include <stdint.h>
218#include <ctype.h>
219#include <getopt.h>
220#include <err.h>
221#include <linux/socket.h>
222#include <linux/if.h>
223#define __user
224#include "wireless.h"
225
226static int wrqfreq_to_int(struct iwreq *wrq)
227{
228        int freq, i;
229        freq = wrq->u.freq.m;
230        if (freq < 1000) {
231                return freq;
232        }
233        int divisor = 1000000;
234        int e = wrq->u.freq.e;
235        for (i = 0; i < e; i++)
236                divisor /= 10;
237        if (divisor)
238                freq /= divisor;
239        return freq;
240}
241
242struct wifi_interface *wifi_getfreq(char *ifname)
243{
244        struct iwreq wrq;
245        int freq;
246
247        (void)memset(&wrq, 0, sizeof(struct iwreq));
248        strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
249        ioctl(getsocket(), SIOCGIWFREQ, &wrq);
250        closesocket();
251        freq = wrq.u.freq.m;
252        struct wifi_interface *interface = (struct wifi_interface *)malloc(sizeof(struct wifi_interface));
253        if (freq < 1000) {
254                interface->freq = ieee80211_ieee2mhz(freq);
255                return interface;
256        }
257        interface->freq = wrqfreq_to_int(&wrq);
258        return interface;
259}
260
261int wifi_getchannel(char *ifname)
262{
263        struct wifi_interface *interface = wifi_getfreq(ifname);
264        int channel = ieee80211_mhz2ieee(interface->freq);
265        free(interface);
266        return channel;
267}
268
269long long wifi_getrate(char *ifname)
270{
271        struct iwreq wrq;
272
273        (void)memset(&wrq, 0, sizeof(struct iwreq));
274        strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
275        ioctl(getsocket(), SIOCGIWRATE, &wrq);
276        closesocket();
277        return wrq.u.bitrate.value;
278}
279
280int get_radiostate(char *ifname)
281{
282        if (nvram_nmatch("disabled", "%s_net_mode", ifname))
283                return 0;
284        if (!strcmp(ifname, "wl0"))
285                ifname = "ra0";
286        if (!strcmp(ifname, "wl1"))
287                ifname = "ba0";
288        struct ifreq ifr;
289        int skfd = getsocket();
290
291        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
292        if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
293                closesocket();
294                return -1;
295        }
296        if ((ifr.ifr_flags & IFF_UP)) {
297                closesocket();
298                return 1;
299        }
300        closesocket();
301        return 0;
302}
303
304static const char *ieee80211_ntoa(const uint8_t mac[6])
305{
306        static char a[18];
307        int i;
308
309        i = snprintf(a, sizeof(a), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
310        return (i < 17 ? NULL : a);
311}
312
313typedef union _MACHTTRANSMIT_SETTING {
314        struct {
315                unsigned short MCS:7;   // MCS
316                unsigned short BW:1;    //channel bandwidth 20MHz or 40 MHz
317                unsigned short ShortGI:1;
318                unsigned short STBC:2;  //SPACE
319                unsigned short rsv:3;
320                unsigned short MODE:2;  // Use definition MODE_xxx.
321        } field;
322        unsigned short word;
323} MACHTTRANSMIT_SETTING;
324
325typedef struct _RT_802_11_MAC_ENTRY {
326        unsigned char ApIdx;
327        unsigned char Addr[6];
328        unsigned char Aid;
329        unsigned char Psm;      // 0:PWR_ACTIVE, 1:PWR_SAVE
330        unsigned char MimoPs;   // 0:MMPS_STATIC, 1:MMPS_DYNAMIC, 3:MMPS_Enabled
331        char AvgRssi0;
332        char AvgRssi1;
333        char AvgRssi2;
334        unsigned int ConnectedTime;
335        MACHTTRANSMIT_SETTING TxRate;
336//#ifdef RTMP_RBUS_SUPPORT
337        unsigned int LastRxRate;
338        int StreamSnr[3];
339        int SoundingRespSnr[3];
340//#endif // RTMP_RBUS_SUPPORT //
341} RT_802_11_MAC_ENTRY;
342
343typedef struct _RT_802_11_MAC_TABLE {
344        unsigned long Num;
345        RT_802_11_MAC_ENTRY Entry[128]; //MAX_LEN_OF_MAC_TABLE = 32
346} RT_802_11_MAC_TABLE;
347
348typedef struct STAINFO {
349        char mac[6];
350        char rssi;
351        char noise;
352        char ifname[32];
353} STAINFO;
354
355int OidQueryInformation(unsigned long OidQueryCode, int socket_id, char *DeviceName, void *ptr, unsigned long PtrLength)
356{
357        struct iwreq wrq;
358
359        strcpy(wrq.ifr_name, DeviceName);
360        wrq.u.data.length = PtrLength;
361        wrq.u.data.pointer = (caddr_t) ptr;
362        wrq.u.data.flags = OidQueryCode;
363
364        return (ioctl(socket_id, (SIOCIWFIRSTPRIV + 0x0E), &wrq));
365}
366
367#include "stapriv.h"
368#include "oid.h"
369
370STAINFO *getRaStaInfo(char *ifname)
371{
372        char G_bRadio = 1;      //TRUE
373
374        int ConnectStatus = 0;
375        unsigned char BssidQuery[6];
376
377        if (!nvram_nmatch("sta", "%s_mode", ifname)
378            && !nvram_nmatch("apsta", "%s_mode", ifname)
379            && !nvram_nmatch("apstawet", "%s_mode", ifname)) {
380                return NULL;
381        }
382        char *ifn = "ra0";
383        if (!strcmp(ifname, "wl1"))
384                ifn = "ba0";
385
386        if (nvram_nmatch("apsta", "%s_mode", ifname)
387            || nvram_nmatch("apstawet", "%s_mode", ifname)) {
388                ifn = "apcli0";
389                if (!strcmp(ifname, "wl1"))
390                        ifn = "apcli1";
391        }
392
393        int s;
394
395        s = getsocket();
396        if (OidQueryInformation(OID_GEN_MEDIA_CONNECT_STATUS, s, ifn, &ConnectStatus, sizeof(ConnectStatus)) < 0) {
397                return NULL;
398        }
399        if (OidQueryInformation(RT_OID_802_11_RADIO, s, ifn, &G_bRadio, sizeof(G_bRadio)) < 0) {
400                return NULL;
401        }
402        if (G_bRadio && ConnectStatus == 1) {
403                memset(&BssidQuery, 0x00, sizeof(BssidQuery));
404                OidQueryInformation(OID_802_11_BSSID, s, ifn, &BssidQuery, sizeof(BssidQuery));
405                long RSSI;
406                int nNoiseDbm;
407                unsigned char lNoise;   // this value is (ULONG) in Ndis driver (NOTICE!!!)
408
409                OidQueryInformation(RT_OID_802_11_RSSI, s, ifn, &RSSI, sizeof(RSSI));
410                OidQueryInformation(RT_OID_802_11_QUERY_NOISE_LEVEL, s, ifn, &lNoise, sizeof(lNoise));
411                nNoiseDbm = lNoise;
412                nNoiseDbm -= 143;
413
414                STAINFO *ret = safe_malloc(sizeof(STAINFO));
415
416                memcpy(ret->mac, BssidQuery, 6);
417                strcpy(ret->ifname, ifn);
418                ret->rssi = RSSI;
419                ret->noise = -nNoiseDbm;
420                return ret;
421        }
422        return NULL;
423
424}
425
426#define RTPRIV_IOCTL_GET_MAC_TABLE              (SIOCIWFIRSTPRIV + 0x0F)
427
428int getassoclist(char *ifname, unsigned char *list)
429{
430        struct iwreq iwr;
431        unsigned int *count = (unsigned int *)list;
432
433        RT_802_11_MAC_TABLE table = { 0 };
434        int s, i;
435
436        if (nvram_nmatch("disabled", "%s_net_mode", ifname)) {
437                return 0;
438        }
439
440        int state = get_radiostate(ifname);
441        int ignore = 0;
442
443        if (state == 0 || state == -1) {
444                ignore = 1;
445        }
446        if (!ignore) {
447                s = getsocket();
448                if (s < 0) {
449                        ignore = 1;
450                }
451                (void)memset(&iwr, 0, sizeof(struct iwreq));
452                (void)strncpy(iwr.ifr_name, getRADev(ifname), sizeof(iwr.ifr_name));
453
454                iwr.u.data.pointer = (caddr_t) & table;
455                if (ioctl(s, RTPRIV_IOCTL_GET_MAC_TABLE, &iwr) < 0) {
456                        ignore = 1;
457                }
458        }
459
460        unsigned char *l = (unsigned char *)list;
461
462        count[0] = 0;
463        l += 4;
464        STAINFO *sta = getRaStaInfo(ifname);
465
466        if (sta != NULL) {
467                memcpy(l, sta->mac, 6);
468                l += 6;
469                count[0]++;
470                free(sta);
471        }
472        if (!ignore && table.Num < 128)
473                for (i = 0; i < table.Num; i++) {
474                        memcpy(l, &table.Entry[i].Addr, 6);
475                        if (l[0] == 0 && l[1] == 0 && l[2] == 0 && l[3] == 0 && l[4] == 0 && l[5] == 0)
476                                break;
477                        l += 6;
478                        count[0]++;
479                }
480
481        return count[0];
482}
483
484int getRssi(char *ifname, unsigned char *mac)
485{
486        struct iwreq iwr;
487
488        RT_802_11_MAC_TABLE table = { 0 };
489        int s, i;
490
491        if (nvram_nmatch("disabled", "%s_net_mode", ifname)) {
492                return 0;
493        }
494
495        int state = get_radiostate(ifname);
496        int ignore = 0;
497
498        if (state == 0 || state == -1) {
499                ignore = 1;
500        }
501        if (!ignore) {
502                s = getsocket();
503                if (s < 0) {
504                        ignore = 1;
505                }
506                (void)memset(&iwr, 0, sizeof(struct iwreq));
507                (void)strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));
508
509                iwr.u.data.pointer = (caddr_t) & table;
510                if (ioctl(s, RTPRIV_IOCTL_GET_MAC_TABLE, &iwr) < 0) {
511                        ignore = 1;
512                }
513        }
514
515        STAINFO *sta = getRaStaInfo(ifname);
516
517        if (sta != NULL) {
518                if (!memcmp(mac, sta->mac, 6)) {
519                        int retu = sta->rssi;
520
521                        free(sta);
522                        return -95 + retu;
523                }
524                free(sta);
525        }
526        if (!ignore && table.Num < 128)
527                for (i = 0; i < table.Num; i++) {
528                        if (!memcmp(mac, &table.Entry[i].Addr, 6)) {
529                                return -95 + table.Entry[i].AvgRssi0;
530                        }
531                }
532        return 0;
533}
534
535int getNoise(char *ifname, unsigned char *mac)
536{
537
538        return -95;
539
540}
541
542int getUptime(char *ifname, unsigned char *mac)
543{
544        return 0;
545}
546
547void radio_off(int idx)
548{
549        switch (idx) {
550        case -1:
551                idx = 1;
552        case 0:
553                if (!nvram_match("wl0_net_mode", "disabled")) {
554                        eval("iwpriv", "ra0", "set", "RadioOn=0");
555                        eval("iwpriv", "ra0", "set", "WlanLed=0");
556                }
557        case 1:
558                if (!nvram_match("wl1_net_mode", "disabled") && idx == 1) {
559                        eval("iwpriv", "ba0", "set", "RadioOn=0");
560                        eval("iwpriv", "ba0", "set", "WlanLed=0");
561                }
562
563        }
564        led_control(LED_WLAN0, LED_OFF);
565}
566
567void radio_on(int idx)
568{
569        switch (idx) {
570        case -1:
571                idx = 1;
572        case 0:
573                if (!nvram_match("wl0_net_mode", "disabled")) {
574                        eval("iwpriv", "ra0", "set", "RadioOn=1");
575                        eval("iwpriv", "ra0", "set", "WlanLed=1");
576                }
577        case 1:
578                if (!nvram_match("wl1_net_mode", "disabled") && idx == 1) {
579                        eval("iwpriv", "ba0", "set", "RadioOn=1");
580                        eval("iwpriv", "ba0", "set", "WlanLed=1");
581                }
582
583        }
584        led_control(LED_WLAN0, LED_ON);
585}
586
587#else
588#ifdef WL_CHANSPEC_BW_8080
589
590static const uint8 wf_chspec_bw_mhz[] = { 5, 10, 20, 40, 80, 160, 160 };
591
592#define WF_NUM_BW \
593        (sizeof(wf_chspec_bw_mhz)/sizeof(uint8))
594
595/* 40MHz channels in 5GHz band */
596static const uint8 wf_5g_40m_chans[] = { 38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159 };
597
598#define WF_NUM_5G_40M_CHANS \
599        (sizeof(wf_5g_40m_chans)/sizeof(uint8))
600
601/* 80MHz channels in 5GHz band */
602static const uint8 wf_5g_80m_chans[] = { 42, 58, 106, 122, 138, 155 };
603
604#define WF_NUM_5G_80M_CHANS \
605        (sizeof(wf_5g_80m_chans)/sizeof(uint8))
606
607/* 160MHz channels in 5GHz band */
608static const uint8 wf_5g_160m_chans[] = { 50, 114 };
609
610#define WF_NUM_5G_160M_CHANS \
611        (sizeof(wf_5g_160m_chans)/sizeof(uint8))
612
613static uint8 center_chan_to_edge(uint bw)
614{
615        /* edge channels separated by BW - 10MHz on each side
616         * delta from cf to edge is half of that,
617         * MHz to channel num conversion is 5MHz/channel
618         */
619        return (uint8) (((bw - 20) / 2) / 5);
620}
621
622static uint8 channel_low_edge(uint center_ch, uint bw)
623{
624        return (uint8) (center_ch - center_chan_to_edge(bw));
625}
626
627/* return control channel given center channel and side band */
628static uint8 channel_to_ctl_chan(uint center_ch, uint bw, uint sb)
629{
630        return (uint8) (channel_low_edge(center_ch, bw) + sb * 4);
631}
632
633/* convert bandwidth from chanspec to MHz */
634static uint bw_chspec_to_mhz(chanspec_t chspec)
635{
636        uint bw;
637
638        bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT;
639        return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]);
640}
641
642uint8 wf_chspec_ctlchan(chanspec_t chspec)
643{
644        uint center_chan;
645        uint bw_mhz;
646        uint sb;
647
648        /* Is there a sideband ? */
649        if (CHSPEC_IS20(chspec)) {
650                return CHSPEC_CHANNEL(chspec);
651        } else {
652                sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
653
654                if (CHSPEC_IS8080(chspec)) {
655                        bw_mhz = 80;
656
657                        if (sb < 4) {
658                                center_chan = CHSPEC_CHAN1(chspec);
659                        } else {
660                                center_chan = CHSPEC_CHAN2(chspec);
661                                sb -= 4;
662                        }
663
664                        /* convert from channel index to channel number */
665                        center_chan = wf_5g_80m_chans[center_chan];
666                } else {
667                        bw_mhz = bw_chspec_to_mhz(chspec);
668                        center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT;
669                }
670
671                return (channel_to_ctl_chan(center_chan, bw_mhz, sb));
672        }
673}
674
675static int getcenterchannel(chanspec_t chspec)
676{
677        const char *band;
678        uint ctl_chan;
679
680        /* ctl channel */
681        return wf_chspec_ctlchan(chspec);
682}
683
684#else
685
686#ifndef CHSPEC_IS40
687#define WL_CHANSPEC_CTL_SB_MASK         0x0300
688#define WL_CHANSPEC_CTL_SB_LOWER        0x0100
689#define WL_CHANSPEC_CTL_SB_UPPER        0x0200
690
691#define WL_CHANSPEC_BW_MASK             0x0C00
692#define WL_CHANSPEC_BW_40               0x0C00
693
694#define CHSPEC_CHANNEL(chspec)  ((uint8)(chspec & 0xff))
695
696#define CHSPEC_IS40(chspec)     (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
697#define CHSPEC_SB_UPPER(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER)
698#define CHSPEC_SB_LOWER(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER)
699#endif
700
701static int getcenterchannel(chanspec_t chspec)
702{
703        const char *band;
704        uint ctl_chan;
705        int channel;
706        channel = CHSPEC_CHANNEL(chspec);
707        /* check for non-default band spec */
708
709        if (CHSPEC_IS40(chspec)) {
710                if (CHSPEC_SB_UPPER(chspec)) {
711                        channel += 2;
712                } else {
713                        channel -= 2;
714                }
715        }
716        return channel;
717}
718#endif
719#ifdef HAVE_80211AC
720int has_beamforming(char *prefix)
721{
722        wlc_rev_info_t rev;
723        int c = 0;
724        if (!strcmp(prefix, "wl0"))
725                c = 0;
726        else if (!strcmp(prefix, "wl1"))
727                c = 1;
728        else if (!strcmp(prefix, "wl2"))
729                c = 2;
730
731        char *name = get_wl_instance_name(c);
732        wl_ioctl(name, WLC_GET_REVINFO, &rev, sizeof(rev));
733
734        if (rev.corerev < 40)
735                return 0;       /* TxBF unsupported */
736
737        return 1;
738
739}
740#endif
741
742int getchannels(unsigned int *retlist, char *ifname)
743{
744#ifdef HAVE_80211AC
745        char buf[WLC_IOCTL_MAXLEN];
746        int buflen;
747        int ret;
748        int count = 0;
749        int i;
750        chanspec_t c = 0, *chanspec;
751
752        char abbrev[WLC_CNTRY_BUF_SZ] = "";     /* default.. current locale */
753        wl_uint32_list_t *list;
754
755        memset(buf, 0, WLC_IOCTL_MAXLEN);
756        strcpy(buf, "chanspecs");
757        buflen = strlen(buf) + 1;
758
759        chanspec = (chanspec_t *) (buf + buflen);
760        *chanspec = c;
761        buflen += (sizeof(chanspec_t));
762
763        strncpy(buf + buflen, abbrev, WLC_CNTRY_BUF_SZ);
764
765        buflen += WLC_CNTRY_BUF_SZ;
766
767        list = (wl_uint32_list_t *) (buf + buflen);
768        list->count = WL_NUMCHANSPECS;
769        buflen += sizeof(uint32) * (WL_NUMCHANSPECS + 1);
770
771        if ((ret = wl_ioctl(ifname, WLC_GET_VAR, &buf[0], buflen)))
772                if (ret < 0)
773                        return 0;
774
775        int wl = get_wl_instance(ifname);
776
777        list = (wl_uint32_list_t *) buf;
778
779        int mask = 0;
780        int bw = atoi(nvram_nget("wl%d_nbw", wl));
781        if (!bw)
782                bw = 20;
783
784        int spec = 0;
785#ifdef WL_CHANSPEC_BW_8080
786        if (nvram_nmatch("8080", "wl%d_nbw", wl))
787                mask = WL_CHANSPEC_BW_8080;
788        else if (nvram_nmatch("160", "wl%d_nbw", wl))
789                mask = WL_CHANSPEC_BW_160;
790        else if (nvram_nmatch("80", "wl%d_nbw", wl))
791                mask = WL_CHANSPEC_BW_80;
792        else
793#endif
794        if (nvram_nmatch("40", "wl%d_nbw", wl))
795                mask = WL_CHANSPEC_BW_40;
796        else if (nvram_nmatch("20", "wl%d_nbw", wl))
797                mask = WL_CHANSPEC_BW_20;
798        else if (nvram_nmatch("0", "wl%d_nbw", wl))
799                mask = WL_CHANSPEC_BW_20;
800        else if (nvram_nmatch("10", "wl%d_nbw", wl))
801                mask = WL_CHANSPEC_BW_10;
802#ifdef WL_CHANSPEC_BW_5
803        else if (nvram_nmatch("5", "wl%d_nbw", wl))
804                mask = WL_CHANSPEC_BW_5;
805#endif
806
807        if (bw > 20) {
808#ifdef WL_CHANSPEC_CTL_SB_UU
809                if (bw == 80) {
810                        if (nvram_nmatch("lower", "wl%d_nctrlsb", wl) || nvram_nmatch("upper", "wl%d_nctrlsb", wl))
811                                nvram_nset("ll", "wl%d_nctrlsb", wl);
812                }
813                if (nvram_nmatch("uu", "wl%d_nctrlsb", wl))
814                        spec = WL_CHANSPEC_CTL_SB_UU;
815                else if (nvram_nmatch("ul", "wl%d_nctrlsb", wl))
816                        spec = WL_CHANSPEC_CTL_SB_UL;
817                else if (nvram_nmatch("lu", "wl%d_nctrlsb", wl))
818                        spec = WL_CHANSPEC_CTL_SB_LU;
819                else if (nvram_nmatch("ll", "wl%d_nctrlsb", wl))
820                        spec = WL_CHANSPEC_CTL_SB_LL;
821#endif
822                if (bw == 40) {
823                        if (nvram_nmatch("uu", "wl%d_nctrlsb", wl) || nvram_nmatch("ul", "wl%d_nctrlsb", wl) || nvram_nmatch("lu", "wl%d_nctrlsb", wl) || nvram_nmatch("ll", "wl%d_nctrlsb", wl))
824                                nvram_nset("lower", "wl%d_nctrlsb", wl);
825                }
826                if (nvram_nmatch("lower", "wl%d_nctrlsb", wl))
827                        spec = WL_CHANSPEC_CTL_SB_LOWER;
828                else if (nvram_nmatch("upper", "wl%d_nctrlsb", wl))
829                        spec = WL_CHANSPEC_CTL_SB_UPPER;
830        }
831
832        for (i = 0; i < list->count; i++) {
833
834                c = list->element[i];
835                int cspec = c & 0x700;
836                int cbw = c & 0x3800;
837                //        fprintf(stderr,"wl%d: %X spec %d, cbw %d\n",wl,c,cbw,cspec);
838                if ((cbw == mask) && (cspec == spec)) {
839                        //        fprintf(stderr,"take wl%d: %X spec %d, cbw %d\n",wl,c,cbw,cspec);
840
841                        int channel = getcenterchannel(c);
842
843                        int a;
844                        int inlist = 0;
845                        for (a = 0; a < count; a++)
846                                if (retlist[a] == channel) {
847                                        inlist = 1;
848                                        break;
849                                }
850                        if (!inlist) {
851                                retlist[count++] = channel;
852                        }
853                }
854        }
855        int a;
856        // sort
857        for (a = 0; a < count; a++) {
858                for (i = 0; i < count - 1; i++) {
859                        if (retlist[i + 1] < retlist[i]) {
860                                int cc = retlist[i + 1];
861                                retlist[i + 1] = retlist[i];
862                                retlist[i] = cc;
863                        }
864                }
865        }
866
867        return count;
868
869#else                           //HAVE_80211AC
870
871        // int ret, num;
872        // num = (sizeof (*list) - 4) / 6; /* Maximum number of entries in the
873        // buffer */
874        // memcpy (list, &num, 4); /* First 4 bytes are the number of ent. */
875
876        // ret = wl_ioctl (name, WLC_GET_VALID_CHANNELS, list, 128);
877        // fprintf(stderr,"get channels\n");
878        char exec[64];
879
880        sprintf(exec, "wl -i %s channels", ifname);
881        FILE *in = popen(exec, "r");
882
883        int chan;
884        int count = 0;
885
886        while (!feof(in) && fscanf(in, "%d", &chan) == 1) {
887                retlist[count++] = chan;
888        }
889        pclose(in);
890#ifdef BUFFALO_JP
891        return count - 1;
892#else
893        return count;
894#endif
895
896#endif
897}
898
899#ifdef TEST
900
901void main(int argc, char *argv[])
902{
903        char buf[1024];
904        getchannels(buf, "eth1");
905}
906#endif
907int has_5ghz(char *prefix)
908{
909#ifdef HAVE_QTN
910        if (!strcmp(prefix, "wl1"))
911                return 1;
912#endif
913        if (strstr(nvram_nget("%s_bandlist", prefix), "a"))
914                return 1;
915
916        return 0;
917}
918
919int has_2ghz(char *prefix)
920{
921        if (strstr(nvram_nget("%s_bandlist", prefix), "b"))
922                return 1;
923
924        return 0;
925}
926
927int wifi_getchannel(char *ifn)
928{
929        channel_info_t ci;
930        char name[32];
931        sprintf(name, "%s_ifname", ifn);
932        char *ifname = nvram_safe_get(name);
933
934        memset(&ci, 0, sizeof(ci));
935        wl_ioctl(ifname, WLC_GET_CHANNEL, &ci, sizeof(ci));
936        if (ci.scan_channel > 0) {
937                return ci.scan_channel;
938        } else if (ci.hw_channel > 0) {
939                return ci.hw_channel;
940        } else
941                return -1;
942}
943
944int wl_getbssid(char *wl, char *mac)
945{
946        int ret;
947        struct ether_addr ea;
948
949        wl_ioctl(wl, WLC_GET_BSSID, &ea, ETHER_ADDR_LEN);
950        ether_etoa(&ea, mac);
951        return 0;
952}
953
954int getassoclist(char *name, unsigned char *list)
955{
956#ifdef HAVE_QTN
957        if (has_qtn(name))
958                return getassoclist_qtn(name, list);
959#endif
960
961        // int ap;
962        // if ((wl_ioctl(name, WLC_GET_AP, &ap, sizeof(ap)) < 0) || ap)
963        // {
964        int ret;
965        unsigned int num;
966
967        num = (sizeof(*list) - 4) / 6;  /* Maximum number of entries in the
968                                         * buffer */
969        memcpy(list, &num, 4);  /* First 4 bytes are the number of ent. */
970
971        ret = wl_ioctl(name, WLC_GET_ASSOCLIST, list, 8192);
972        unsigned int *count = (unsigned int *)list;
973
974        // }else
975        // {
976        // char buf[WLC_IOCTL_MAXLEN];
977        /*
978         * wl_bss_info_t *bss_info = (wl_bss_info_t *) buf;
979         * memset(buf,0,WLC_IOCTL_MAXLEN); if (wl_ioctl(name, WLC_GET_BSS_INFO,
980         * bss_info, WLC_IOCTL_MAXLEN)<0)return 0; struct maclist *l = (struct
981         * maclist*)list;
982         */
983        /*
984         * sta_info_t *sta_info = (sta_info_t *) buf;
985         * memset(buf,0,WLC_IOCTL_MAXLEN); if (wl_ioctl(name, WLC_GET_VAR,
986         * sta_info, WLC_IOCTL_MAXLEN)<0)return 0;
987         *
988         * struct maclist *l = (struct maclist*)list; l->count=1;
989         * memcpy(&l->ea,&sta_info->ea,6);
990         */
991        if (ret < 0)
992                return -1;
993        return count[0];
994}
995#endif
996
997int getwdslist(char *name, unsigned char *list)
998{
999        int ret, num;
1000
1001        num = (sizeof(*list) - 4) / 6;  /* Maximum number of entries in the
1002                                         * buffer */
1003        memcpy(list, &num, 4);  /* First 4 bytes are the number of ent. */
1004
1005        ret = wl_ioctl(name, WLC_GET_WDSLIST, list, 8192);
1006
1007        return (ret);
1008}
1009
1010#if !defined(HAVE_RT2880) && !defined(HAVE_RT61)
1011int getNoise(char *ifname, unsigned char *macname)
1012{
1013        unsigned int noise;
1014
1015        // rssi = 0;
1016        // char buf[WLC_IOCTL_MAXLEN];
1017        wl_ioctl(ifname, WLC_GET_PHY_NOISE, &noise, sizeof(noise));
1018
1019        /*
1020         * wl_bss_info_t *bss_info = (wl_bss_info_t *) buf;
1021         * memset(buf,0,WLC_IOCTL_MAXLEN);
1022         *
1023         * wl_ioctl(name, WLC_GET_BSS_INFO, bss_info, WLC_IOCTL_MAXLEN); if
1024         * ((wl_ioctl(name, WLC_GET_AP, &ap, sizeof(ap)) < 0) || ap) { if
1025         * (wl_ioctl(name, WLC_GET_PHY_NOISE, &noise, sizeof(noise)) < 0) noise =
1026         * 0; } else { // somehow the structure doesn't fit here rssi = buf[82];
1027         * noise = buf[84]; }
1028         */
1029        return noise;
1030}
1031
1032int getUptime(char *ifname, unsigned char *mac)
1033{
1034        return 0;
1035}
1036
1037#endif
1038
1039#else
1040#include <sys/types.h>
1041#include <sys/file.h>
1042#include <sys/ioctl.h>
1043#include <sys/socket.h>
1044#include <stdio.h>
1045#include <stdlib.h>
1046#include <string.h>
1047#include <stdint.h>
1048#include <ctype.h>
1049#include <getopt.h>
1050#include <err.h>
1051
1052#include "wireless.h"
1053#undef WPA_OUI
1054#undef WME_OUI
1055#include "../madwifi.dev/madwifi.dev/net80211/ieee80211.h"
1056#include "../madwifi.dev/madwifi.dev/net80211/ieee80211_crypto.h"
1057#include "../madwifi.dev/madwifi.dev/net80211/ieee80211_ioctl.h"
1058
1059static int wrqfreq_to_int(struct iwreq *wrq)
1060{
1061        int freq, i;
1062        freq = wrq->u.freq.m;
1063        if (freq < 1000) {
1064                return freq;
1065        }
1066        int divisor = 1000000;
1067        int e = wrq->u.freq.e;
1068        for (i = 0; i < e; i++)
1069                divisor /= 10;
1070        if (divisor)
1071                freq /= divisor;
1072        return freq;
1073}
1074
1075/*
1076 * Atheros
1077 */
1078
1079#define IOCTL_ERR(x) [x - SIOCIWFIRSTPRIV] "ioctl[" #x "]"
1080static int set80211priv(struct iwreq *iwr, const char *ifname, int op, void *data, size_t len)
1081{
1082#define N(a)    (sizeof(a)/sizeof(a[0]))
1083
1084        memset(iwr, 0, sizeof(struct iwreq));
1085        strncpy(iwr->ifr_name, ifname, IFNAMSIZ);
1086        if (len < IFNAMSIZ) {
1087                /*
1088                 * Argument data fits inline; put it there.
1089                 */
1090                memcpy(iwr->u.name, data, len);
1091        } else {
1092                /*
1093                 * Argument data too big for inline transfer; setup a
1094                 * parameter block instead; the kernel will transfer
1095                 * the data for the driver.
1096                 */
1097                iwr->u.data.pointer = data;
1098                iwr->u.data.length = len;
1099        }
1100
1101        if (ioctl(getsocket(), op, iwr) < 0) {
1102                static const char *opnames[] = {
1103                        IOCTL_ERR(IEEE80211_IOCTL_SETPARAM),
1104                        IOCTL_ERR(IEEE80211_IOCTL_GETPARAM),
1105                        IOCTL_ERR(IEEE80211_IOCTL_SETMODE),
1106                        IOCTL_ERR(IEEE80211_IOCTL_GETMODE),
1107                        IOCTL_ERR(IEEE80211_IOCTL_SETWMMPARAMS),
1108                        IOCTL_ERR(IEEE80211_IOCTL_GETWMMPARAMS),
1109                        IOCTL_ERR(IEEE80211_IOCTL_SETCHANLIST),
1110                        IOCTL_ERR(IEEE80211_IOCTL_GETCHANLIST),
1111                        IOCTL_ERR(IEEE80211_IOCTL_CHANSWITCH),
1112                        IOCTL_ERR(IEEE80211_IOCTL_GETCHANINFO),
1113                        IOCTL_ERR(IEEE80211_IOCTL_SETOPTIE),
1114                        IOCTL_ERR(IEEE80211_IOCTL_GETOPTIE),
1115                        IOCTL_ERR(IEEE80211_IOCTL_SETMLME),
1116                        IOCTL_ERR(IEEE80211_IOCTL_SETKEY),
1117                        IOCTL_ERR(IEEE80211_IOCTL_DELKEY),
1118                        IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
1119                        IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
1120                };
1121                op -= SIOCIWFIRSTPRIV;
1122                if (0 <= op && op < N(opnames))
1123                        perror(opnames[op]);
1124                else
1125                        perror("ioctl[unknown???]");
1126                return -1;
1127        }
1128        return 0;
1129#undef N
1130}
1131
1132int do80211priv(const char *ifname, int op, void *data, size_t len)
1133{
1134        struct iwreq iwr;
1135
1136        if (set80211priv(&iwr, ifname, op, data, len) < 0)
1137                return -1;
1138        if (len < IFNAMSIZ)
1139                memcpy(data, iwr.u.name, len);
1140        return iwr.u.data.length;
1141}
1142
1143#define KILO    1000
1144
1145long long wifi_getrate(char *ifname)
1146{
1147#if defined(HAVE_ATH9K) && !defined(HAVE_MVEBU)
1148        if (is_ath9k(ifname)) {
1149                char physical[32];
1150                memset(physical,0,sizeof(physical));
1151                strncpy(physical, ifname, 4);
1152                if (nvram_nmatch("b-only", "%s_net_mode", physical))
1153                        return 11000 * KILO;
1154                if (nvram_nmatch("g-only", "%s_net_mode", physical))
1155                        return 54000 * KILO;
1156                if (nvram_nmatch("a-only", "%s_net_mode", physical))
1157                        return 54000 * KILO;
1158                if (nvram_nmatch("bg-mixed", "%s_net_mode", physical))
1159                        return 54000 * KILO;
1160                struct wifi_interface *interface = mac80211_get_interface(ifname);
1161                if (!interface)
1162                        return -1;
1163                long long rate;
1164                int sgi = has_shortgi(physical);
1165                int vhtmcs = -1;
1166                //fprintf(stderr,"sgi %d, width %d\n",sgi, interface->width);
1167                if (nvram_nmatch("mixed", "%s_net_mode", physical) ||   //
1168                    nvram_nmatch("ac-only", "%s_net_mode", physical) || //
1169                    nvram_nmatch("1", "%s_turbo_qam", physical) ||      //
1170                    nvram_nmatch("acn-mixed", "%s_net_mode", physical)) //
1171                        vhtmcs = mac80211_get_maxvhtmcs(physical);
1172                int mcs = mac80211_get_maxmcs(physical);
1173                int novht = 0;
1174#ifdef HAVE_ATH10K
1175                if (is_ath10k(ifname) && has_2ghz(physical))
1176                        novht = nvram_nmatch("0", "%s_turbo_qam", physical);
1177#endif
1178                sgi = sgi ? nvram_nmatch("1", "%s_shortgi", physical) : 0;
1179                switch (interface->width) {
1180                case 2:
1181                        rate = 54000;
1182                        break;
1183                case 5:
1184                        rate = 54000 / 4;
1185                        break;
1186                case 10:
1187                        rate = 54000 / 2;
1188                        break;
1189                case 20:
1190                case 40:
1191                case 80:
1192                case 160:
1193                        rate = VHTTxRate(mcs, novht ? -1 : vhtmcs, sgi, interface->width);
1194                        break;
1195                case 8080:
1196                        rate = VHTTxRate(mcs, novht ? -1 : vhtmcs, sgi, 160);
1197                        break;
1198                default:
1199                        rate = 54000;
1200                }
1201                free(interface);
1202                return rate * KILO;
1203        } else
1204#endif
1205        {
1206
1207                struct iwreq wrq;
1208
1209                (void)memset(&wrq, 0, sizeof(struct iwreq));
1210                strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1211                ioctl(getsocket(), SIOCGIWRATE, &wrq);
1212                return wrq.u.bitrate.value;
1213        }
1214}
1215
1216/*
1217 * For doing log10/exp10 without libm
1218 */
1219#define LOG10_MAGIC     1.25892541179
1220
1221int iw_mwatt2dbm(int in)
1222{
1223        /*
1224         * Version without libm : slower
1225         */
1226        double fin = (double)in;
1227        int res = 0;
1228
1229        /*
1230         * Split integral and floating part to avoid accumulating rounding errors
1231         */
1232        while (fin > 10.0) {
1233                res += 10;
1234                fin /= 10.0;
1235        }
1236        while (fin > 1.000001) {        /* Eliminate rounding errors, take ceil */
1237                res += 1;
1238                fin /= LOG10_MAGIC;
1239        }
1240        return (res);
1241}
1242
1243static int checkid(char *ifname, int vendorid, int productid)   //checks if its usually a emp card (no concrete detection possible)
1244{
1245#ifdef HAVE_MVEBU
1246        return 0;
1247#endif
1248        int vendor;
1249        int product;
1250        int devcount;
1251        char readid[64];
1252
1253        strcpy(readid, ifname);
1254        sscanf(readid, "ath%d", &devcount);
1255        sprintf(readid, "/proc/sys/dev/wifi%d/idvendor", devcount);
1256        FILE *in = fopen(readid, "rb");
1257        vendor = 0;
1258        if (in) {
1259                fscanf(in, "%d", &vendor);
1260                fclose(in);
1261        }
1262        sprintf(readid, "/proc/sys/dev/wifi%d/idproduct", devcount);
1263        in = fopen(readid, "rb");
1264        product = 0;
1265        if (in) {
1266                fscanf(in, "%d", &product);
1267                fclose(in);
1268        }
1269        if (vendor == vendorid && product == productid) //XR3.3/XR3.6/XR3.7 share the same pci id's
1270                return 1;
1271        return 0;
1272
1273}
1274
1275int isEMP(char *ifname)         //checks if its usually a emp card (no concrete detection possible)
1276{
1277        if (checkid(ifname, 0x168c, 0x2062))
1278                return 1;
1279        if (checkid(ifname, 0x168c, 0x2063))    //will include more suspicius cards.
1280                return 1;
1281        return 0;
1282
1283}
1284
1285int isXR36(char *ifname)        //checks if its usually a emp card (no concrete detection possible)
1286{
1287        return checkid(ifname, 0x0777, 0x3c03);
1288}
1289
1290int isFXXN_PRO(char *ifname)    //checks if its usualla a DBII Networks FxxN-PRO card (no correct detection possible)
1291{
1292        char cproduct[30];
1293        char cvendor[30];
1294        char readid[64];
1295        int devcount;
1296
1297        strcpy(readid, ifname);
1298        sscanf(readid, "ath%d", &devcount);
1299        sprintf(readid, "/sys/class/ieee80211/phy%d/device/subsystem_vendor", devcount);
1300        FILE *in = fopen(readid, "rb");
1301        if (in) {
1302                fscanf(in, "%s\n", cvendor);
1303                fclose(in);
1304        }
1305        sprintf(readid, "/sys/class/ieee80211/phy%d/device/subsystem_device", devcount);
1306        in = fopen(readid, "rb");
1307        if (in) {
1308                fscanf(in, "%s\n", cproduct);
1309                fclose(in);
1310        }
1311
1312        if (!strcmp(cvendor, "0x168c") && !strcmp(cproduct, "0x2096")) {        //F36N-PRO / F64N-PRO shares the same id's
1313                return 1;
1314        } else if (!strcmp(cvendor, "0xdb11") && !strcmp(cproduct, "0x0f50")) { // F50N-PRO
1315                return 2;
1316        }
1317        return 0;
1318}
1319
1320int isSR71E(char *ifname)
1321{
1322
1323        char cproduct[30];
1324        char cvendor[30];
1325        char readid[64];
1326        int devcount;
1327
1328        strcpy(readid, ifname);
1329        sscanf(readid, "ath%d", &devcount);
1330        sprintf(readid, "/sys/class/ieee80211/phy%d/device/subsystem_vendor", devcount);
1331        FILE *in = fopen(readid, "rb");
1332        if (in) {
1333                fscanf(in, "%s\n", cvendor);
1334                fclose(in);
1335        }
1336        sprintf(readid, "/sys/class/ieee80211/phy%d/device/subsystem_device", devcount);
1337        in = fopen(readid, "rb");
1338        if (in) {
1339                fscanf(in, "%s\n", cproduct);
1340                fclose(in);
1341        }
1342
1343        if (!strcmp(cvendor, "0x0777") && !strcmp(cproduct, "0x4e05")) {        // SR71-E
1344                return 1;
1345        }
1346        if (!strcmp(cvendor, "0x0777") && !strcmp(cproduct, "0x4082")) {        // SR71
1347                return 1;
1348        }
1349        if (!strcmp(cvendor, "0x168c") && !strcmp(cproduct, "0x2082")) {        // SR71-A
1350                return 1;
1351        }
1352        if (!strcmp(cvendor, "0x0777") && !strcmp(cproduct, "0x4005")) {        // SR71-15
1353                return 1;
1354        }
1355        if (!strcmp(cvendor, "0x0777") && !strcmp(cproduct, "0x4002")) {        // SR71-12
1356                return 1;
1357        }
1358        return 0;
1359
1360}
1361
1362int isDL4600(char *ifname)
1363{
1364        int vendor;
1365        int product;
1366        int devcount;
1367        char readid[64];
1368
1369        strcpy(readid, ifname);
1370        sscanf(readid, "ath%d", &devcount);
1371        sprintf(readid, "/proc/sys/dev/wifi%d/idvendor", devcount);
1372        FILE *in = fopen(readid, "rb");
1373        vendor = 0;
1374        if (in) {
1375                fscanf(in, "%d", &vendor);
1376                fclose(in);
1377        }
1378        sprintf(readid, "/proc/sys/dev/wifi%d/idproduct", devcount);
1379        in = fopen(readid, "rb");
1380        product = 0;
1381        if (in) {
1382                fscanf(in, "%d", &product);
1383                fclose(in);
1384        }
1385        if (vendor == 0x1C14 && product == 0x19)
1386                return 1;
1387        return 0;
1388}
1389
1390int wifi_gettxpower(char *ifname)
1391{
1392        int poweroffset = wifi_gettxpoweroffset(ifname);
1393        struct iwreq wrq;
1394
1395        (void)memset(&wrq, 0, sizeof(struct iwreq));
1396
1397        strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1398
1399        ioctl(getsocket(), SIOCGIWTXPOW, &wrq);
1400        closesocket();
1401        struct iw_param *txpower = &wrq.u.txpower;
1402
1403        if (txpower->disabled) {
1404                return 0;
1405        } else {
1406                /*
1407                 * Check for relative values
1408                 */
1409                if (txpower->flags & IW_TXPOW_RELATIVE) {
1410                        return txpower->value + poweroffset;
1411                } else {
1412                        int dbm = 0;
1413
1414                        /*
1415                         * Convert everything to dBm
1416                         */
1417                        if (txpower->flags & IW_TXPOW_MWATT)
1418                                dbm = iw_mwatt2dbm(txpower->value);
1419                        else
1420                                dbm = txpower->value;
1421                        return dbm + poweroffset;
1422                }
1423        }
1424}
1425
1426int wifi_gettxpoweroffset(char *ifname)
1427{
1428        int poweroffset = 0;
1429
1430#ifdef HAVE_ALPHA
1431        poweroffset = 10;
1432#elif HAVE_EOC1650
1433        poweroffset = 0;
1434#elif HAVE_BWRG1000
1435        poweroffset = 12;       //?? guess
1436#elif HAVE_EAP3660
1437        poweroffset = 8;
1438#elif HAVE_EOC2610
1439        poweroffset = 8;
1440#elif HAVE_ECB3500
1441        poweroffset = 8;
1442#elif HAVE_EOC5610
1443        poweroffset = 0;
1444#elif HAVE_NS2
1445        poweroffset = 10;
1446#elif HAVE_LC2
1447        poweroffset = 10;
1448#elif HAVE_BS2
1449        poweroffset = 0;
1450#elif HAVE_PICO2
1451        poweroffset = 0;
1452#elif HAVE_PICO2HP
1453        poweroffset = 10;
1454#elif HAVE_MS2
1455        poweroffset = 10;
1456#elif HAVE_BS2HP
1457        poweroffset = 10;
1458#elif HAVE_NS5
1459        poweroffset = 5;
1460#elif HAVE_PICO5
1461        poweroffset = 5;
1462#elif HAVE_NS3
1463        poweroffset = 5;
1464#elif HAVE_LC5
1465        poweroffset = 5;
1466#elif HAVE_DLM101
1467        poweroffset = 5;
1468#elif HAVE_BS5
1469        poweroffset = 5;
1470#elif HAVE_LS5
1471        poweroffset = 5;
1472#else
1473        if (isEMP(ifname)) {
1474                if (nvram_nmatch("2", "%s_cardtype", ifname))
1475                        return 8;
1476                if (nvram_nmatch("3", "%s_cardtype", ifname))
1477                        return 8;
1478                if (nvram_nmatch("5", "%s_cardtype", ifname))
1479                        return 8;
1480                if (nvram_nmatch("6", "%s_cardtype", ifname))
1481                        return 7;
1482                if (nvram_nmatch("7", "%s_cardtype", ifname))
1483                        return 10;
1484        }
1485
1486        if (isDL4600(ifname))
1487                return 10;
1488
1489#ifdef HAVE_ATH9K
1490        if (isFXXN_PRO(ifname))
1491                return 5;
1492        else if (isSR71E(ifname))
1493                return 7;
1494#endif
1495        int vendor;
1496        int devcount;
1497        char readid[64];
1498
1499        strcpy(readid, ifname);
1500        sscanf(readid, "ath%d", &devcount);
1501        sprintf(readid, "/proc/sys/dev/wifi%d/poweroffset", devcount);
1502        FILE *in = fopen(readid, "rb");
1503
1504        vendor = 0;
1505        if (in) {
1506                vendor = atoi(fgets(readid, sizeof(readid), in));
1507                fclose(in);
1508        }
1509        poweroffset = vendor;
1510        if (poweroffset < 0 || poweroffset > 20)
1511                poweroffset = 0;
1512#endif
1513        char *manpoweroffset;
1514        manpoweroffset = nvram_nget("%s_poweroffset", ifname);
1515        if (strlen(manpoweroffset)) {
1516                poweroffset = atoi(manpoweroffset);
1517        }
1518        return poweroffset;
1519}
1520
1521int get_wififreq(char *ifname, int freq)
1522{
1523#ifdef HAVE_NS3
1524        return -2000;
1525#endif
1526
1527        if (isEMP(ifname)) {
1528                if (nvram_nmatch("4", "%s_cardtype", ifname))
1529                        return freq - 2400;
1530        }
1531
1532        if (isDL4600(ifname))
1533                return freq - 705;
1534
1535#ifdef HAVE_ATH9K
1536        if (isFXXN_PRO(ifname) == 1) {
1537                if (nvram_nmatch("1", "%s_cardtype", ifname)) {
1538                        if (freq < 5180 || freq > 5580)
1539                                return -1;
1540                        return freq - 1830;
1541                }
1542                if (nvram_nmatch("2", "%s_cardtype", ifname)) {
1543                        if (freq < 5180 || freq > 5730)
1544                                return -1;
1545                        return freq + 720;
1546                }
1547        }
1548#endif
1549
1550        char *var = NULL;
1551        if (ifname) {
1552                char localvar[32];
1553                sprintf(localvar, "%s_offset", ifname);
1554                var = nvram_get(localvar);
1555        }
1556        if (var) {
1557                return freq + atoi(var);
1558        }
1559        int vendor;
1560        int devcount;
1561        char readid[64];
1562
1563        strcpy(readid, ifname);
1564        sscanf(readid, "ath%d", &devcount);
1565        sprintf(readid, "/proc/sys/dev/wifi%d/vendor", devcount);
1566        FILE *in = fopen(readid, "rb");
1567
1568        vendor = 0;
1569        if (in) {
1570                vendor = atoi(fgets(readid, sizeof(readid), in));
1571                fclose(in);
1572        }
1573        switch (vendor) {
1574        case 9:         // ubnt xr9
1575                if (freq < 2427 || freq > 2442)
1576                        return -1;
1577                return freq - (2427 - 907);
1578                break;
1579        case 4:         // ubnt sr9
1580                if (freq < 2422 || freq > 2437)
1581                        return -1;
1582                return (2422 + 922) - freq;
1583                break;
1584        case 13:
1585                return freq - (5540 - 3540);    // xr3 general 3,5 ghz
1586        case 1328:
1587                return freq - (5540 - 2840);    // xr3 special 2.8 ghz
1588        case 1336:
1589                if (nvram_nmatch("2", "%s_cardtype", ifname))
1590                        return freq - (5765 - 3658);    // xr3 3.7 ghz
1591                else
1592                        return freq - (5540 - 3340);    // xr3 special 3.3/3.6 ghz
1593        case 7:
1594                if (freq < 2427 || freq > 2442)
1595                        return -1;
1596                return freq - (2427 - 763);     // xr7
1597        case 14:
1598                return freq - (5540 - 4516);    // xr4
1599                // case 24:
1600                // return -(5540-4540); //sr4
1601        case 23:                // reserved for XR2.3 until spec is known
1602        case 26:                // reserved for XR2.6 until spec is known
1603
1604        default:
1605                return freq;
1606                break;
1607        }
1608        return freq;
1609}
1610
1611struct wifi_interface *wifi_getfreq(char *ifname)
1612{
1613        struct iwreq wrq;
1614
1615#ifdef HAVE_ATH9K
1616        if (has_ad(ifname)) {
1617                struct wifi_interface *interface = (struct wifi_interface *)malloc(sizeof(struct wifi_interface));
1618                memset(interface, 0, sizeof(struct wifi_interface));
1619                interface->freq = atoi(nvram_safe_get("ath2_channel"));
1620                interface->center1 = -1;
1621                interface->center2 = -1;
1622                return interface;
1623        }
1624        if (is_ath9k(ifname)) {
1625                return mac80211_get_interface(ifname);
1626        }
1627#endif
1628
1629        (void)memset(&wrq, 0, sizeof(struct iwreq));
1630        strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1631        ioctl(getsocket(), SIOCGIWFREQ, &wrq);
1632        closesocket();
1633        struct wifi_interface *interface = (struct wifi_interface *)malloc(sizeof(struct wifi_interface));
1634        memset(interface, 0, sizeof(struct wifi_interface));
1635        interface->freq = wrqfreq_to_int(&wrq);
1636        interface->center1 = -1;
1637        interface->center2 = -1;
1638        return interface;
1639}
1640
1641int wifi_getchannel(char *ifname)
1642{
1643        struct wifi_interface *interface = wifi_getfreq(ifname);
1644        if (!interface)
1645                return 0;
1646        int channel = ieee80211_mhz2ieee(interface->freq);
1647        free(interface);
1648        return channel;
1649}
1650
1651int get_radiostate(char *ifname)
1652{
1653        if (nvram_nmatch("disabled", "%s_net_mode", ifname))
1654                return 0;
1655        if (!has_ad(ifname)) {
1656#ifdef HAVE_ATH9K
1657                if (is_ath9k(ifname)) {
1658                        char debugstring[64];
1659                        FILE *fp;
1660                        int idx;
1661                        char state[11];
1662
1663                        sprintf(debugstring, "/sys/kernel/debug/ieee80211/phy%d/ath9k/diag", get_ath9k_phy_ifname(ifname));
1664                        fp = fopen(debugstring, "r");
1665                        if (fp) {
1666                                fread(state, sizeof(state) - 1, 1, fp);
1667                                fclose(fp);
1668                                state[10] = '\0';
1669                                if (!strncmp(state, "0x00000003", 10))
1670                                        return 0;
1671                        }
1672                }
1673#endif
1674        }
1675        struct ifreq ifr;
1676        int skfd = getsocket();
1677
1678        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1679        if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
1680                closesocket();
1681                return -1;
1682        }
1683        closesocket();
1684        if ((ifr.ifr_flags & IFF_UP)) {
1685                return 1;
1686        }
1687        return 0;
1688}
1689
1690static inline int iw_get_ext(int skfd,  /* Socket to the kernel */
1691                             const char *ifname,        /* Device name */
1692                             int request,       /* WE ID */
1693                             struct iwreq *pwrq)
1694{                               /* Fixed part of the
1695                                 * request */
1696        /*
1697         * Set device name
1698         */
1699        strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);
1700        /*
1701         * Do the request
1702         */
1703        return (ioctl(skfd, request, pwrq));
1704}
1705
1706int isAssociated(char *ifname)
1707{
1708        struct iwreq wrq;
1709        int i;
1710
1711        if (iw_get_ext(getsocket(), ifname, SIOCGIWAP, &wrq) >= 0) {
1712                for (i = 0; i < 6; i++)
1713                        if (wrq.u.ap_addr.sa_data[i] != 0) {
1714                                closesocket();
1715                                return 1;
1716                        }
1717        }
1718        closesocket();
1719        return 0;
1720}
1721
1722int getAssocMAC(char *ifname, char *mac)
1723{
1724        struct iwreq wrq;
1725        int i;
1726        int ret = -1;
1727
1728        if (iw_get_ext(getsocket(), ifname, SIOCGIWAP, &wrq) >= 0) {
1729                for (i = 0; i < 6; i++)
1730                        if (wrq.u.ap_addr.sa_data[i] != 0)
1731                                ret = 0;
1732        }
1733        if (!ret) {
1734                for (i = 0; i < 6; i++)
1735                        mac[i] = wrq.u.ap_addr.sa_data[i];
1736
1737        }
1738        closesocket();
1739        return ret;
1740}
1741
1742#ifdef HAVE_ATH9K
1743
1744void radio_on_off_ath9k(int idx, int on)
1745{
1746        char debugstring[64];
1747        int fp;
1748        char secmode[16];
1749        char tpt[8];
1750
1751        sprintf(debugstring, "/sys/kernel/debug/ieee80211/phy%d/ath9k/diag", get_ath9k_phy_idx(idx));
1752        fp = open(debugstring, O_WRONLY);
1753        if (fp) {
1754                if (on)
1755                        write(fp, "0", strlen("0"));
1756                else
1757                        write(fp, "3", strlen("3"));
1758                fprintf(stderr, "ath9k radio %d: phy%d ath%d\n", on, get_ath9k_phy_idx(idx), idx);
1759                close(fp);
1760        }
1761        // LED
1762#ifdef HAVE_WZRHPAG300NH
1763        if (idx == 0)
1764                sprintf(debugstring, "/sys/class/leds/wireless_generic_1/trigger");
1765        else
1766                sprintf(debugstring, "/sys/class/leds/wireless_generic_21/trigger");
1767#else
1768        sprintf(debugstring, "/sys/class/leds/ath9k-phy%d/trigger", get_ath9k_phy_idx(idx));
1769#endif
1770        fp = open(debugstring, O_WRONLY);
1771        if (fp) {
1772                if (on) {
1773                        sprintf(tpt, "phy%dtpt", get_ath9k_phy_idx(idx));
1774                        write(fp, tpt, strlen(tpt));
1775                        sprintf(secmode, "ath%d_akm", idx);
1776                        if (nvram_get(secmode) && !nvram_match(secmode, "disabled")) {
1777                                // needs refinements
1778                                if (idx == 0)
1779                                        led_control(LED_SEC0, LED_ON);
1780                                else if (idx == 1)
1781                                        led_control(LED_SEC1, LED_ON);
1782                        }
1783                } else {
1784                        write(fp, "none", strlen("none"));
1785#ifdef HAVE_WZRHPAG300NH
1786                        if (idx == 0) {
1787                                led_control(LED_SEC0, LED_OFF);
1788                        } else if (idx == 1) {
1789                                led_control(LED_SEC1, LED_OFF);
1790                        }
1791#endif
1792                }
1793                close(fp);
1794        }
1795}
1796
1797#endif
1798
1799int is_ar5008(char *prefix)
1800{
1801        char sys[64];
1802        int devnum;
1803        sscanf(prefix, "ath%d", &devnum);
1804
1805        sprintf(sys, "/proc/sys/dev/wifi%d/mimo", devnum);
1806
1807        if (f_exists(sys))
1808                return 1;
1809
1810        return 0;
1811}
1812
1813int is_ath11n(char *prefix)
1814{
1815#ifdef HAVE_ATH9K
1816        if (is_ath9k(prefix))
1817                return 1;
1818#endif
1819#ifdef HAVE_MADWIFI_MIMO
1820        if (is_ar5008(prefix))
1821                return 1;
1822#endif
1823        return 0;
1824}
1825
1826int has_athmask(int devnum, int mask)
1827{
1828        char sys[64];
1829        int modes;
1830
1831        sprintf(sys, "/proc/sys/dev/wifi%d/wirelessmodes", devnum);
1832        FILE *tmp = fopen(sys, "rb");
1833
1834        if (tmp == NULL)
1835                return 0;
1836        fscanf(tmp, "%d", &modes);
1837        fclose(tmp);
1838        if ((modes & mask) == mask)
1839                return 1;
1840        else
1841                return 0;
1842}
1843
1844static struct wifi_channels *list_channelsext(const char *ifname, int allchans)
1845{
1846        struct ieee80211req_chaninfo chans;
1847        struct ieee80211req_chaninfo achans;
1848        const struct ieee80211_channel *c;
1849        int i;
1850
1851        // fprintf (stderr, "list channels for %s\n", ifname);
1852        if (do80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) < 0) {
1853                fprintf(stderr, "unable to get channel information\n");
1854                return NULL;
1855        }
1856        if (!allchans) {
1857                uint8_t active[64];
1858                if (do80211priv(ifname, IEEE80211_IOCTL_GETCHANLIST, &active, sizeof(active)) < 0) {
1859                        fprintf(stderr, "unable to get active channel list\n");
1860                        return NULL;
1861                }
1862                memset(&achans, 0, sizeof(achans));
1863                for (i = 0; i < chans.ic_nchans; i++) {
1864                        c = &chans.ic_chans[i];
1865                        if (isset(active, c->ic_ieee) || allchans)
1866                                achans.ic_chans[achans.ic_nchans++] = *c;
1867                }
1868        } else
1869                achans = chans;
1870
1871        // fprintf(stderr,"channel number %d\n", achans.ic_nchans);
1872        struct wifi_channels *list = (struct wifi_channels *)calloc(sizeof(struct wifi_channels) * (achans.ic_nchans + 1), 1);
1873
1874        char wl_mode[16];
1875        char wl_turbo[16];
1876
1877        sprintf(wl_mode, "%s_net_mode", ifname);
1878        sprintf(wl_turbo, "%s_channelbw", ifname);
1879        int l = 0;
1880
1881        for (i = 0; i < achans.ic_nchans; i++) {
1882                // fprintf(stderr,"channel number %d of %d\n", i,achans.ic_nchans);
1883
1884                // filter out A channels if mode isnt A-Only or mixed
1885                if (IEEE80211_IS_CHAN_A(&achans.ic_chans[i])) {
1886#ifdef HAVE_WHRAG108
1887                        if (!strcmp(ifname, "ath1"))
1888                                continue;
1889#endif
1890#ifdef HAVE_TW6600
1891                        if (!strcmp(ifname, "ath1"))
1892                                continue;
1893#endif
1894                        if (nvram_invmatch(wl_mode, "a-only")
1895                            && nvram_invmatch(wl_mode, "mixed"))
1896                                continue;
1897                }
1898                // filter out B/G channels if mode isnt g-only, b-only or mixed
1899                if (IEEE80211_IS_CHAN_ANYG(&achans.ic_chans[i])
1900                    || IEEE80211_IS_CHAN_B(&achans.ic_chans[i])) {
1901#ifdef HAVE_WHRAG108
1902                        if (!strcmp(ifname, "ath0"))
1903                                continue;
1904#endif
1905#ifdef HAVE_TW6600
1906                        if (!strcmp(ifname, "ath0"))
1907                                continue;
1908#endif
1909                        if (nvram_invmatch(wl_mode, "g-only")
1910                            && nvram_invmatch(wl_mode, "mixed")
1911                            && nvram_invmatch(wl_mode, "b-only")
1912                            && nvram_invmatch(wl_mode, "bg-mixed"))
1913                                continue;
1914                }
1915                // filter out channels which are not supporting turbo mode if turbo
1916                // is enabled
1917                if (!IEEE80211_IS_CHAN_STURBO(&achans.ic_chans[i])
1918                    && !IEEE80211_IS_CHAN_DTURBO(&achans.ic_chans[i])) {
1919                        if (nvram_matchi(wl_turbo, 40))
1920                                continue;
1921                }
1922                // filter out turbo channels if turbo mode is disabled
1923                /*
1924                 * if (IEEE80211_IS_CHAN_STURBO (&achans.ic_chans[i]) ||
1925                 * IEEE80211_IS_CHAN_DTURBO (&achans.ic_chans[i])) { if (nvram_match
1926                 * (wl_turbo, "0")) continue; }
1927                 */
1928                if (IEEE80211_IS_CHAN_STURBO(&achans.ic_chans[i])) {
1929                        if (!nvram_matchi(wl_turbo, 40))
1930                                continue;
1931                }
1932
1933                list[l].channel = achans.ic_chans[i].ic_ieee;
1934                list[l].freq = achans.ic_chans[i].ic_freq;
1935                list[l].noise = -95;    // achans.ic_chans[i].ic_noise;
1936                l++;
1937        }
1938
1939        list[l].freq = -1;
1940        return list;
1941}
1942
1943struct wifi_channels *list_channels(char *devnr)
1944{
1945
1946        return list_channelsext(devnr, 1);
1947        /*
1948         * char csign[64]; char channel[64]; char ppp[64]; char freq[64]; char
1949         * dum1[64]; char dum2[64]; char dum3[64]; char dum4[64];
1950         *
1951         * char cmd[64]; sprintf (cmd, "iwlist %s chan>/tmp/.channels", devnr);
1952         * system (cmd); FILE *in = fopen ("/tmp/.channels", "rb"); if (in ==
1953         * NULL) return NULL; fscanf (in, "%s %s %s %s %s %s %s %s", csign,
1954         * channel, ppp, freq, dum1, dum2, dum3, dum4); int ch = atoi (channel);
1955         * int i; struct wifi_channels *list = (struct wifi_channels *) safe_malloc
1956         * (sizeof (struct wifi_channels) * (ch+1) ); for (i = 0; i < ch; i++) {
1957         * fscanf (in, "%s %s %s %s %s", csign, channel, ppp, freq, dum1); if
1958         * (!strcmp (csign, "Current")) break; list[i].channel = atoi (channel);
1959         * list[i].freq = strdup (freq); channelcount++; } fclose (in); return
1960         * list;
1961         */
1962}
1963
1964int getRssi(char *ifname, unsigned char *mac)
1965{
1966#ifdef HAVE_ATH9K
1967        if (is_ath9k(ifname)) {
1968                return getRssi_ath9k(ifname, mac);
1969        }
1970#endif
1971#ifdef HAVE_MADWIFI_MIMO
1972        if (is_ar5008(ifname)) {
1973                return getRssi_11n(ifname, mac);
1974        }
1975#endif
1976        unsigned char *buf = calloc(24 * 1024, 1);
1977
1978        unsigned char *cp;
1979        int len;
1980        struct iwreq iwr;
1981        int s;
1982        char nb[32];
1983        sprintf(nb, "%s_bias", ifname);
1984
1985        s = socket(AF_INET, SOCK_DGRAM, 0);
1986        if (s < 0) {
1987                fprintf(stderr, "socket(SOCK_DRAGM)\n");
1988                free(buf);
1989                return 0;
1990        }
1991        (void)memset(&iwr, 0, sizeof(iwr));
1992        (void)strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));
1993        iwr.u.data.pointer = (void *)buf;
1994        iwr.u.data.length = 1024 * 24;
1995        if (ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr) < 0) {
1996                close(s);
1997                free(buf);
1998                return 0;
1999        }
2000        len = iwr.u.data.length;
2001        if (len < sizeof(struct ieee80211req_sta_info)) {
2002                close(s);
2003                free(buf);
2004                return 0;
2005        }
2006
2007        cp = buf;
2008        char maccmp[6];
2009
2010        memset(maccmp, 0, 6);
2011        do {
2012                struct ieee80211req_sta_info *si;
2013
2014                si = (struct ieee80211req_sta_info *)cp;
2015                if (!memcmp(&si->isi_macaddr[0], mac, 6)) {
2016                        close(s);
2017                        int rssi = si->isi_noise + si->isi_rssi;
2018
2019                        free(buf);
2020
2021                        return rssi + nvram_default_geti(nb, 0);
2022                }
2023                if (!memcmp(&si->isi_macaddr[0], mac, 6))
2024                        break;
2025                cp += si->isi_len;
2026                len -= si->isi_len;
2027        }
2028        while (len >= sizeof(struct ieee80211req_sta_info));
2029        close(s);
2030        free(buf);
2031        return 0;
2032}
2033
2034int getUptime(char *ifname, unsigned char *mac)
2035{
2036#ifdef HAVE_ATH9K
2037        if (is_ath9k(ifname)) {
2038                return getUptime_ath9k(ifname, mac);
2039        }
2040#endif
2041#ifdef HAVE_MADWIFI_MIMO
2042        if (is_ar5008(ifname)) {
2043                return getUptime_11n(ifname, mac);
2044        }
2045#endif
2046        unsigned char *buf = calloc(24 * 1024, 1);
2047
2048        unsigned char *cp;
2049        int len;
2050        struct iwreq iwr;
2051        int s;
2052
2053        s = socket(AF_INET, SOCK_DGRAM, 0);
2054        if (s < 0) {
2055                fprintf(stderr, "socket(SOCK_DRAGM)\n");
2056                free(buf);
2057                return 0;
2058        }
2059        (void)memset(&iwr, 0, sizeof(iwr));
2060        (void)strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));
2061        iwr.u.data.pointer = (void *)buf;
2062        iwr.u.data.length = 24 * 1024;
2063        if (ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr) < 0) {
2064                close(s);
2065                free(buf);
2066                return 0;
2067        }
2068        len = iwr.u.data.length;
2069        if (len < sizeof(struct ieee80211req_sta_info)) {
2070                close(s);
2071                free(buf);
2072                return -1;
2073        }
2074
2075        cp = buf;
2076        char maccmp[6];
2077
2078        memset(maccmp, 0, 6);
2079        do {
2080                struct ieee80211req_sta_info *si;
2081
2082                si = (struct ieee80211req_sta_info *)cp;
2083                if (!memcmp(&si->isi_macaddr[0], mac, 6)) {
2084                        close(s);
2085                        int uptime = 0; //si->isi_uptime;
2086
2087                        free(buf);
2088                        return uptime;
2089                }
2090                if (!memcmp(&si->isi_macaddr[0], mac, 6))
2091                        break;
2092                cp += si->isi_len;
2093                len -= si->isi_len;
2094        }
2095        while (len >= sizeof(struct ieee80211req_sta_info));
2096        close(s);
2097        free(buf);
2098        return 0;
2099}
2100
2101int getNoise(char *ifname, unsigned char *mac)
2102{
2103#ifdef HAVE_ATH9K
2104        if (is_ath9k(ifname)) {
2105                return getNoise_ath9k(ifname, mac);
2106        }
2107#endif
2108#ifdef HAVE_MADWIFI_MIMO
2109        if (is_ar5008(ifname)) {
2110                return getNoise_11n(ifname, mac);
2111        }
2112#endif
2113        unsigned char *buf = calloc(24 * 1024, 1);
2114
2115        unsigned char *cp;
2116        int len;
2117        struct iwreq iwr;
2118        int s;
2119        char nb[32];
2120        sprintf(nb, "%s_bias", ifname);
2121
2122        s = socket(AF_INET, SOCK_DGRAM, 0);
2123        if (s < 0) {
2124                fprintf(stderr, "socket(SOCK_DRAGM)\n");
2125                free(buf);
2126                return 0;
2127        }
2128        (void)memset(&iwr, 0, sizeof(iwr));
2129        (void)strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));
2130        iwr.u.data.pointer = (void *)buf;
2131        iwr.u.data.length = 24 * 1024;
2132        if (ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr) < 0) {
2133                close(s);
2134                free(buf);
2135                return 0;
2136        }
2137        len = iwr.u.data.length;
2138        if (len < sizeof(struct ieee80211req_sta_info)) {
2139                close(s);
2140                free(buf);
2141                return -1;
2142        }
2143
2144        cp = buf;
2145        char maccmp[6];
2146
2147        memset(maccmp, 0, 6);
2148        do {
2149                struct ieee80211req_sta_info *si;
2150
2151                si = (struct ieee80211req_sta_info *)cp;
2152                if (!memcmp(&si->isi_macaddr[0], mac, 6)) {
2153                        close(s);
2154                        int noise = si->isi_noise;
2155
2156                        free(buf);
2157                        return noise + nvram_default_geti(nb, 0);
2158                }
2159                if (!memcmp(&si->isi_macaddr[0], mac, 6))
2160                        break;
2161                cp += si->isi_len;
2162                len -= si->isi_len;
2163        }
2164        while (len >= sizeof(struct ieee80211req_sta_info));
2165        close(s);
2166        free(buf);
2167        return 0;
2168}
2169
2170int getassoclist(char *ifname, unsigned char *list)
2171{
2172#ifdef HAVE_ATH9K
2173        if (is_ath9k(ifname)) {
2174                return getassoclist_ath9k(ifname, list);
2175        }
2176#endif
2177#ifdef HAVE_MADWIFI_MIMO
2178        if (is_ar5008(ifname)) {
2179                return getassoclist_11n(ifname, list);
2180        }
2181#endif
2182        unsigned char *buf;
2183
2184        buf = calloc(24 * 1024, 1);
2185        unsigned char *cp;
2186        int len;
2187        struct iwreq iwr;
2188        int s;
2189        unsigned int *count = (unsigned int *)list;
2190
2191        if (nvram_nmatch("disabled", "%s_net_mode", ifname)) {
2192                free(buf);
2193                return 0;
2194        }
2195        int mincount = 0;
2196
2197        if (nvram_nmatch("wdssta", "%s_mode", ifname)
2198            || nvram_nmatch("sta", "%s_mode", ifname)
2199            || nvram_nmatch("wet", "%s_mode", ifname)) {
2200                int assoc = isAssociated(ifname);
2201
2202                if (!assoc) {
2203                        free(buf);
2204                        return 0;
2205                }
2206                char mac[6];
2207
2208                getAssocMAC(ifname, mac);
2209                memcpy(&list[4], mac, 6);
2210                count[0] = 1;
2211                mincount = 1;
2212        }
2213        s = socket(AF_INET, SOCK_DGRAM, 0);
2214        if (s < 0) {
2215                fprintf(stderr, "socket(SOCK_DRAGM)\n");
2216                free(buf);
2217                mincount = 1;
2218                return mincount;
2219        }
2220        (void)memset(&iwr, 0, sizeof(iwr));
2221        (void)strncpy(iwr.ifr_name, ifname, sizeof(iwr.ifr_name));
2222        iwr.u.data.pointer = (void *)buf;
2223        iwr.u.data.length = 1024 * 24;
2224        if (ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr) < 0) {
2225                close(s);
2226                free(buf);
2227                return mincount;
2228        }
2229        len = iwr.u.data.length;
2230        if (len < sizeof(struct ieee80211req_sta_info)) {
2231                close(s);
2232                free(buf);
2233                return mincount;
2234        }
2235
2236        cp = buf;
2237        unsigned char *l = (unsigned char *)list;
2238
2239        count[0] = 0;
2240        l += 4;
2241        do {
2242                struct ieee80211req_sta_info *si;
2243
2244                si = (struct ieee80211req_sta_info *)cp;
2245                memcpy(l, &si->isi_macaddr[0], 6);
2246                if (l[0] == 0 && l[1] == 0 && l[2] == 0 && l[3] == 0 && l[4] == 0 && l[5] == 0)
2247                        break;
2248                l += 6;
2249                count[0]++;
2250                cp += si->isi_len;
2251                len -= si->isi_len;
2252        }
2253        while (len >= sizeof(struct ieee80211req_sta_info));
2254        close(s);
2255        free(buf);
2256
2257        return mincount > count[0] ? mincount : count[0];
2258}
2259
2260void radio_off(int idx)
2261{
2262#ifdef HAVE_ATH9K
2263#ifdef HAVE_MADWIFI_MIMO
2264        if (nvram_match("mimo_driver", "ath9k"))
2265#endif
2266        {
2267                if (idx == -1) {
2268                        int cc = getdevicecount();
2269                        int i;
2270                        for (i = 0; i < cc; i++) {
2271                                radio_on_off_ath9k(i, 0);
2272                        }
2273                        led_control(LED_WLAN0, LED_OFF);
2274                        led_control(LED_WLAN1, LED_OFF);
2275                } else {
2276                        radio_on_off_ath9k(idx, 0);
2277                        if (idx == 0)
2278                                led_control(LED_WLAN0, LED_OFF);
2279                        if (idx == 1)
2280                                led_control(LED_WLAN1, LED_OFF);
2281                }
2282        }
2283#endif
2284        if (idx != -1) {
2285#ifdef HAVE_MVEBU
2286
2287#else
2288                writevaproc("1", "/proc/sys/dev/wifi%d/silent", idx);
2289                writevaproc("1", "/proc/sys/dev/wifi%d/ledon", idx);    // switch off led
2290#endif
2291                if (idx == 0)
2292                        led_control(LED_WLAN0, LED_OFF);
2293                if (idx == 1)
2294                        led_control(LED_WLAN1, LED_OFF);
2295        } else {
2296                int cc = getdevicecount();
2297                int i;
2298                for (i = 0; i < cc; i++) {
2299#ifdef HAVE_MVEBU
2300
2301#else
2302                        writevaproc("1", "/proc/sys/dev/wifi%d/silent", i);
2303                        writevaproc("1", "/proc/sys/dev/wifi%d/ledon", i);      // switch off led
2304#endif
2305                }
2306                led_control(LED_WLAN0, LED_OFF);
2307                led_control(LED_WLAN1, LED_OFF);
2308        }
2309#ifdef HAVE_ATH9K
2310#endif
2311}
2312
2313void radio_on(int idx)
2314{
2315#ifdef HAVE_ATH9K
2316#ifdef HAVE_MADWIFI_MIMO
2317        if (nvram_match("mimo_driver", "ath9k"))
2318#endif
2319        {
2320                if (idx == -1) {
2321                        int cc = getdevicecount();
2322                        int i;
2323                        for (i = 0; i < cc; i++) {
2324                                radio_on_off_ath9k(i, 1);
2325                        }
2326                        led_control(LED_WLAN0, LED_ON);
2327                        led_control(LED_WLAN1, LED_ON);
2328                } else {
2329                        radio_on_off_ath9k(idx, 1);
2330                        if (idx == 0)
2331                                led_control(LED_WLAN0, LED_ON);
2332                        if (idx == 1)
2333                                led_control(LED_WLAN1, LED_ON);
2334                }
2335        }
2336#endif
2337        if (idx != -1) {
2338#ifdef HAVE_MVEBU
2339
2340#else
2341                writevaproc("0", "/proc/sys/dev/wifi%d/silent", idx);
2342#endif
2343                if (idx == 0)
2344                        led_control(LED_WLAN0, LED_ON);
2345                if (idx == 1)
2346                        led_control(LED_WLAN1, LED_ON);
2347        } else {
2348                int cc = getdevicecount();
2349                int i;
2350                for (i = 0; i < cc; i++) {
2351                        writevaproc("0", "/proc/sys/dev/wifi%d/silent", i);
2352                }
2353                led_control(LED_WLAN0, LED_ON);
2354                led_control(LED_WLAN1, LED_ON);
2355        }
2356}
2357
2358int gettxantenna(char *ifname)
2359{
2360#ifdef HAVE_ATH9K
2361        if (is_ath9k(ifname)) {
2362#ifdef HAVE_CARLSONWIRELESS
2363                if (!registered_has_cap(20))
2364                        return (1);
2365#endif
2366                return (mac80211_get_avail_tx_antenna(get_ath9k_phy_ifname(ifname)));
2367        } else
2368#endif
2369                return (7);
2370}
2371
2372int getrxantenna(char *ifname)
2373{
2374#ifdef HAVE_ATH9K
2375        if (is_ath9k(ifname)) {
2376#ifdef HAVE_CARLSONWIRELESS
2377                if (!registered_has_cap(20))
2378                        return (1);
2379#endif
2380                return (mac80211_get_avail_rx_antenna(get_ath9k_phy_ifname(ifname)));
2381        } else
2382#endif
2383                return (7);
2384}
2385
2386#endif
2387
2388#if !defined(HAVE_MADWIFI) && !defined(HAVE_RT2880) && !defined(HAVE_RT61)
2389
2390void radio_off(int idx)
2391{
2392        if (pidof("nas") > 0 || pidof("wrt-radauth") > 0) {
2393                eval("stopservice", "nas", "-f");
2394        }
2395        if (idx != -1) {
2396                fprintf(stderr, "radio_off(%d) interface: %s\n", idx, get_wl_instance_name(idx));
2397                eval("wl", "-i", get_wl_instance_name(idx), "radio", "off");
2398                if (idx == 0)
2399                        led_control(LED_WLAN0, LED_OFF);
2400                if (idx == 1)
2401                        led_control(LED_WLAN1, LED_OFF);
2402                if (idx == 2)
2403                        led_control(LED_WLAN2, LED_OFF);
2404
2405        } else {
2406
2407                int cc = get_wl_instances();
2408                int ii;
2409
2410                for (ii = 0; ii < cc; ii++) {
2411                        eval("wl", "-i", get_wl_instance_name(ii), "radio", "off");
2412                }
2413                led_control(LED_WLAN0, LED_OFF);
2414                led_control(LED_WLAN1, LED_OFF);
2415                led_control(LED_WLAN2, LED_OFF);
2416        }
2417        //fix ticket 2991
2418        eval("startservice", "nas", "-f");
2419
2420}
2421
2422void radio_on(int idx)
2423{
2424        if (pidof("nas") > 0 || pidof("wrt-radauth") > 0) {
2425                eval("stopservice", "nas", "-f");
2426        }
2427        if (idx != -1) {
2428
2429                if (!nvram_nmatch("disabled", "wl%d_net_mode", idx)) {
2430                        fprintf(stderr, "radio_on(%d) interface: %s \n", idx, get_wl_instance_name(idx));
2431                        eval("wl", "-i", get_wl_instance_name(idx), "radio", "off");
2432                        eval("wl", "-i", get_wl_instance_name(idx), "radio", "on");
2433                }
2434
2435                if (idx == 0)
2436                        led_control(LED_WLAN0, LED_ON);
2437                if (idx == 1)
2438                        led_control(LED_WLAN1, LED_ON);
2439                if (idx == 2)
2440                        led_control(LED_WLAN2, LED_ON);
2441
2442        } else {
2443                int cc = get_wl_instances();
2444                int ii;
2445                for (ii = 0; ii < cc; ii++) {
2446                        if (!nvram_nmatch("disabled", "wl%d_net_mode", ii)) {
2447                                eval("wl", "-i", get_wl_instance_name(ii), "radio", "off");
2448                                eval("wl", "-i", get_wl_instance_name(ii), "radio", "on");
2449                        }
2450                }
2451                led_control(LED_WLAN0, LED_ON);
2452                led_control(LED_WLAN1, LED_ON);
2453                led_control(LED_WLAN2, LED_ON);
2454        }
2455        eval("startservice", "nas", "-f");
2456        eval("startservice", "guest_nas", "-f");
2457}
2458
2459/*
2460 * int wl_probe (char *name) { int ret, val;
2461 *
2462 * if ((ret = wl_ioctl (name, WLC_GET_MAGIC, &val, sizeof (val)))) return
2463 * ret; if (val != WLC_IOCTL_MAGIC) return -1; if ((ret = wl_ioctl (name,
2464 * WLC_GET_VERSION, &val, sizeof (val)))) return ret; if (val >
2465 * WLC_IOCTL_VERSION) return -1;
2466 *
2467 * return ret; }
2468 */
2469// #ifndef HAVE_MSSID
2470int wl_set_val(char *name, char *var, void *val, int len)
2471{
2472        char buf[128];
2473        int buf_len;
2474
2475        /*
2476         * check for overflow
2477         */
2478        if ((buf_len = strlen(var)) + 1 + len > sizeof(buf))
2479                return -1;
2480
2481        strcpy(buf, var);
2482        buf_len += 1;
2483
2484        /*
2485         * append int value onto the end of the name string
2486         */
2487        memcpy(&buf[buf_len], val, len);
2488        buf_len += len;
2489
2490        return wl_ioctl(name, WLC_SET_VAR, buf, buf_len);
2491}
2492
2493int wl_get_val(char *name, char *var, void *val, int len)
2494{
2495        char buf[128];
2496        int ret;
2497
2498        /*
2499         * check for overflow
2500         */
2501        if (strlen(var) + 1 > sizeof(buf) || len > sizeof(buf))
2502                return -1;
2503
2504        strcpy(buf, var);
2505        if ((ret = wl_ioctl(name, WLC_GET_VAR, buf, sizeof(buf))))
2506                return ret;
2507
2508        memcpy(val, buf, len);
2509        return 0;
2510}
2511
2512int wl_set_int(char *name, char *var, int val)
2513{
2514        return wl_set_val(name, var, &val, sizeof(val));
2515}
2516
2517int wl_get_int(char *name, char *var, int *val)
2518{
2519        return wl_get_val(name, var, val, sizeof(*val));
2520}
2521
2522int wl_iovar_getbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen)
2523{
2524        int err;
2525        uint namelen;
2526        uint iolen;
2527
2528        namelen = strlen(iovar) + 1;    /* length of iovar name plus null */
2529        iolen = namelen + paramlen;
2530
2531        /* check for overflow */
2532        if (iolen > buflen)
2533                return (BCME_BUFTOOSHORT);
2534
2535        memcpy(bufptr, iovar, namelen); /* copy iovar name including null */
2536        memcpy((int8 *) bufptr + namelen, param, paramlen);
2537
2538        err = wl_ioctl(ifname, WLC_GET_VAR, bufptr, buflen);
2539
2540        return (err);
2541}
2542
2543// #else
2544int wl_iovar_setbuf(char *ifname, char *iovar, void *param, int paramlen, void *bufptr, int buflen)
2545{
2546        uint namelen;
2547        uint iolen;
2548
2549        namelen = strlen(iovar) + 1;    /* length of iovar name plus null */
2550        iolen = namelen + paramlen;
2551
2552        /* check for overflow */
2553        if (iolen > buflen)
2554                return (BCME_BUFTOOSHORT);
2555
2556        memcpy(bufptr, iovar, namelen); /* copy iovar name including null */
2557        memcpy((int8 *) bufptr + namelen, param, paramlen);
2558
2559        return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen);
2560}
2561
2562int wl_iovar_set(char *ifname, char *iovar, void *param, int paramlen)
2563{
2564        char smbuf[WLC_IOCTL_SMLEN];
2565
2566        return wl_iovar_setbuf(ifname, iovar, param, paramlen, smbuf, sizeof(smbuf));
2567}
2568
2569int wl_iovar_get(char *ifname, char *iovar, void *bufptr, int buflen)
2570{
2571        char smbuf[WLC_IOCTL_SMLEN];
2572        int ret;
2573
2574        /* use the return buffer if it is bigger than what we have on the stack */
2575        if (buflen > sizeof(smbuf)) {
2576                ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, bufptr, buflen);
2577        } else {
2578                ret = wl_iovar_getbuf(ifname, iovar, NULL, 0, smbuf, sizeof(smbuf));
2579                if (ret == 0)
2580                        memcpy(bufptr, smbuf, buflen);
2581        }
2582
2583        return ret;
2584}
2585
2586/*
2587 * set named driver variable to int value
2588 * calling example: wl_iovar_setint(ifname, "arate", rate)
2589 */
2590int wl_iovar_setint(char *ifname, char *iovar, int val)
2591{
2592        return wl_iovar_set(ifname, iovar, &val, sizeof(val));
2593}
2594
2595/*
2596 * get named driver variable to int value and return error indication
2597 * calling example: wl_iovar_getint(ifname, "arate", &rate)
2598 */
2599int wl_iovar_getint(char *ifname, char *iovar, int *val)
2600{
2601        return wl_iovar_get(ifname, iovar, val, sizeof(int));
2602}
2603
2604/*
2605 * format a bsscfg indexed iovar buffer
2606 */
2607static int wl_bssiovar_mkbuf(char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen, unsigned int *plen)
2608{
2609        char *prefix = "bsscfg:";
2610        int8 *p;
2611        uint prefixlen;
2612        uint namelen;
2613        uint iolen;
2614
2615        prefixlen = strlen(prefix);     /* length of bsscfg prefix */
2616        namelen = strlen(iovar) + 1;    /* length of iovar name + null */
2617        iolen = prefixlen + namelen + sizeof(int) + paramlen;
2618
2619        /*
2620         * check for overflow
2621         */
2622        if (buflen < 0 || iolen > (uint) buflen) {
2623                *plen = 0;
2624                return BCME_BUFTOOSHORT;
2625        }
2626
2627        p = (int8 *) bufptr;
2628
2629        /*
2630         * copy prefix, no null
2631         */
2632        memcpy(p, prefix, prefixlen);
2633        p += prefixlen;
2634
2635        /*
2636         * copy iovar name including null
2637         */
2638        memcpy(p, iovar, namelen);
2639        p += namelen;
2640
2641        /*
2642         * bss config index as first param
2643         */
2644        memcpy(p, &bssidx, sizeof(int32));
2645        p += sizeof(int32);
2646
2647        /*
2648         * parameter buffer follows
2649         */
2650        if (paramlen)
2651                memcpy(p, param, paramlen);
2652
2653        *plen = iolen;
2654        return 0;
2655}
2656
2657/*
2658 * set named & bss indexed driver variable to buffer value
2659 */
2660int wl_bssiovar_setbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen)
2661{
2662        int err;
2663        uint iolen;
2664
2665        err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen);
2666        if (err)
2667                return err;
2668
2669        return wl_ioctl(ifname, WLC_SET_VAR, bufptr, iolen);
2670}
2671
2672/*
2673 * get named & bss indexed driver variable buffer value
2674 */
2675int wl_bssiovar_getbuf(char *ifname, char *iovar, int bssidx, void *param, int paramlen, void *bufptr, int buflen)
2676{
2677        int err;
2678        uint iolen;
2679
2680        err = wl_bssiovar_mkbuf(iovar, bssidx, param, paramlen, bufptr, buflen, &iolen);
2681        if (err)
2682                return err;
2683
2684        return wl_ioctl(ifname, WLC_GET_VAR, bufptr, buflen);
2685}
2686
2687/*
2688 * set named & bss indexed driver variable to buffer value
2689 */
2690int wl_bssiovar_set(char *ifname, char *iovar, int bssidx, void *param, int paramlen)
2691{
2692        char smbuf[WLC_IOCTL_SMLEN];
2693
2694        return wl_bssiovar_setbuf(ifname, iovar, bssidx, param, paramlen, smbuf, sizeof(smbuf));
2695}
2696
2697/*
2698 * get named & bss indexed driver variable buffer value
2699 */
2700int wl_bssiovar_get(char *ifname, char *iovar, int bssidx, void *outbuf, int len)
2701{
2702        char smbuf[WLC_IOCTL_SMLEN];
2703        int err;
2704
2705        /*
2706         * use the return buffer if it is bigger than what we have on the stack
2707         */
2708        if (len > (int)sizeof(smbuf)) {
2709                err = wl_bssiovar_getbuf(ifname, iovar, bssidx, NULL, 0, outbuf, len);
2710        } else {
2711                memset(smbuf, 0, sizeof(smbuf));
2712                err = wl_bssiovar_getbuf(ifname, iovar, bssidx, NULL, 0, smbuf, sizeof(smbuf));
2713                if (err == 0)
2714                        memcpy(outbuf, smbuf, len);
2715        }
2716
2717        return err;
2718}
2719
2720/*
2721 * set named & bss indexed driver variable to int value
2722 */
2723int wl_bssiovar_setint(char *ifname, char *iovar, int bssidx, int val)
2724{
2725        return wl_bssiovar_set(ifname, iovar, bssidx, &val, sizeof(int));
2726}
2727
2728/*
2729 * void wl_printlasterror(char *name) { char err_buf[WLC_IOCTL_SMLEN];
2730 * strcpy(err_buf, "bcmerrstr");
2731 *
2732 * fprintf(stderr, "Error: "); if ( wl_ioctl(name, WLC_GET_VAR, err_buf,
2733 * sizeof (err_buf)) != 0) fprintf(stderr, "Error getting the Errorstring
2734 * from driver\n"); else fprintf(stderr, err_buf); }
2735 */
2736
2737int get_maxbssid(char *name)
2738{
2739        char cap[WLC_IOCTL_SMLEN];
2740        char caps[WLC_IOCTL_MEDLEN];
2741        char *next;
2742        if (wl_iovar_get(name, "cap", (void *)caps, sizeof(caps)))
2743                return 4;       //minimum is default
2744        foreach(cap, caps, next) {
2745                if (!strcmp(cap, "mbss16")) {
2746                        return 16;
2747                }
2748                if (!strcmp(cap, "mbss8")) {
2749                        return 8;
2750                }
2751                if (!strcmp(cap, "mbss4")) {
2752                        return 4;
2753                }
2754        }
2755        return 4;
2756}
2757
2758#endif
Note: See TracBrowser for help on using the repository browser.