├── docs └── csi_demo.gif ├── nexmon_compiled ├── mcp ├── dhd.ko ├── nexutil └── tcpdump ├── env.yaml ├── Makefile ├── utils ├── makecsiparams │ ├── Makefile │ ├── types.h │ ├── README.md │ ├── bcm_cfg.h │ ├── typedefs.h │ ├── bcmdefs.h │ ├── makecsiparams.c │ ├── bcmwifi_channels.h │ ├── bcmutils.h │ └── bcmwifi_channels.c └── matlab │ └── unpack_float_py.c ├── csi_params.py ├── README.md ├── main.py ├── csi_reader.py └── LICENSE /docs/csi_demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConnectedSystemsLab/nexmon_csi_gui/HEAD/docs/csi_demo.gif -------------------------------------------------------------------------------- /nexmon_compiled/mcp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConnectedSystemsLab/nexmon_csi_gui/HEAD/nexmon_compiled/mcp -------------------------------------------------------------------------------- /nexmon_compiled/dhd.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConnectedSystemsLab/nexmon_csi_gui/HEAD/nexmon_compiled/dhd.ko -------------------------------------------------------------------------------- /nexmon_compiled/nexutil: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConnectedSystemsLab/nexmon_csi_gui/HEAD/nexmon_compiled/nexutil -------------------------------------------------------------------------------- /nexmon_compiled/tcpdump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ConnectedSystemsLab/nexmon_csi_gui/HEAD/nexmon_compiled/tcpdump -------------------------------------------------------------------------------- /env.yaml: -------------------------------------------------------------------------------- 1 | name: csi_visualizer 2 | channels: 3 | - conda-forge 4 | - defaults 5 | dependencies: 6 | - python==3.8.12 7 | - pip 8 | - absl-py 9 | - tqdm 10 | - numpy 11 | - matplotlib 12 | - paramiko 13 | - dpkt 14 | - pyqtgraph==0.13.1 15 | - pyqt 16 | - pyyaml 17 | 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | TARGETS=makecsiparams unpack_float_py.so 3 | 4 | all: $(TARGETS) 5 | 6 | makecsiparams: utils/makecsiparams/makecsiparams.c utils/makecsiparams/bcmwifi_channels.c 7 | $(CC) -o $@ $^ -I./utils/makecsiparams/ 8 | 9 | unpack_float_py.so: utils/matlab/unpack_float_py.c 10 | $(CC) -o $@ $^ -shared 11 | 12 | .PHONY: clean 13 | 14 | clean: 15 | rm -rf $(TARGETS) 16 | -------------------------------------------------------------------------------- /utils/makecsiparams/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-I./ 3 | SRCS=makecsiparams.c bcmwifi_channels.c 4 | OBJS=$(SRCS:.c=.o) 5 | DEPS=types.h typedefs.h bcmwifi_channels.h bcmutils.h bcmdefs.h bcm_cfg.h 6 | 7 | $(ODIR)/%.o: $(SRCS) $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | makecsiparams: $(OBJS) 11 | $(CC) -o $@ $^ $(CFLAGS) 12 | 13 | .PHONY: clean 14 | 15 | clean: 16 | rm -rf $(OBJS) 17 | -------------------------------------------------------------------------------- /utils/makecsiparams/types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | typedef unsigned char byte; 5 | typedef unsigned short word; 6 | typedef unsigned int dword; 7 | typedef unsigned char bool; 8 | typedef signed char int8_t; 9 | typedef unsigned char uint8_t; 10 | typedef signed short int int16_t; 11 | typedef unsigned short int uint16_t; 12 | typedef signed int int32_t; 13 | typedef unsigned int uint32_t; 14 | typedef int8_t int8; 15 | typedef uint8_t uint8; 16 | typedef int16_t int16; 17 | typedef uint16_t uint16; 18 | typedef int32_t int32; 19 | typedef uint32_t uint32; 20 | typedef unsigned char uchar_t; 21 | typedef uint32_t addr_t; 22 | typedef int32_t pid_t; 23 | typedef uint32_t uint; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /utils/makecsiparams/README.md: -------------------------------------------------------------------------------- 1 | Tool for generating base64 encoded strings that can be used for configurating the [Nexmon Channel State Information Extractor](https://nexmon.org/csi). 2 | You can build it by running `make`. Parameters are: 3 | ``` 4 | Usage: makecsiparams [OPTION...] 5 | 6 | -h print this message 7 | -e on/off enable/disable CSI collection (0 = disable, default is 1) 8 | -c chanspec Channel specification / 9 | -C coremask bitmask with cores where to activate capture 10 | (e.g., 0x5 = 0b0101 set core 0 and 2) 11 | -N nssmask bitmask with spatial streams to capture 12 | (e.g., 0x7 = 0b0111 capture first 3 ss) 13 | -m addr filter on this source mac address (up to four, comma separated) 14 | -b byte filter frames starting with byte 15 | -d delay delay in us after each CSI operation 16 | (really needed for 3x4, 4x3 and 4x4 configurations, 17 | without it is enforced automatically) 18 | -r generate raw output (no base64) 19 | ``` 20 | -------------------------------------------------------------------------------- /utils/makecsiparams/bcm_cfg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BCM common config options 3 | * 4 | * Copyright (C) 1999-2013, Broadcom Corporation 5 | * 6 | * Unless you and Broadcom execute a separate written software license 7 | * agreement governing use of this software, this software is licensed to you 8 | * under the terms of the GNU General Public License version 2 (the "GPL"), 9 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 | * following added to such license: 11 | * 12 | * As a special exception, the copyright holders of this software give you 13 | * permission to link this software with independent modules, and to copy and 14 | * distribute the resulting executable under terms of your choice, provided that 15 | * you also meet, for each linked independent module, the terms and conditions of 16 | * the license of that module. An independent module is a module which is not 17 | * derived from this software. The special exception does not apply to any 18 | * modifications of the software. 19 | * 20 | * Notwithstanding the above, under no circumstances may you combine this 21 | * software in any way with any other Broadcom software provided under a license 22 | * other than the GPL, without Broadcom's express prior written consent. 23 | * 24 | * $Id: bcm_cfg.h 351867 2012-08-21 18:46:16Z $ 25 | */ 26 | 27 | #ifndef _bcm_cfg_h_ 28 | #define _bcm_cfg_h_ 29 | #endif /* _bcm_cfg_h_ */ 30 | -------------------------------------------------------------------------------- /csi_params.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import subprocess 3 | import os 4 | 5 | # 20Mhz -> n_fft = 64 6 | # 40Mhz -> n_fft = 128 7 | # 80Mhz -> n_fft = 256 8 | def _subcarriers(n_fft): 9 | return np.array([x for x in range(-(n_fft//2),(n_fft//2))]) 10 | 11 | subcarriers = { 12 | 64 : _subcarriers(64), 13 | 128 : _subcarriers(128), 14 | 256 : _subcarriers(256), 15 | } 16 | 17 | 18 | guard_bins = { 19 | 64 : np.array([x+32 for x in [-32,-31,-30,-29,-28,-27,0,27,28,29,30,31]]), 20 | 128 : np.array([x+64 for x in [-64,-63,-62,-61,-60,-59,-1,0,1,59,60,61,62,63]]), 21 | 256 : np.array([x+128 for x in [-128,-127,-126,-125,-124,-123,-1,0,1,123,124,125,126,127]]), 22 | } 23 | 24 | pilot_bins = { 25 | 64 : np.array([x+32 for x in [-21,-7,7,21]]), 26 | 128 : np.array([x+64 for x in [-53,-25,-11,11,25,53]]), 27 | 256 : np.array([x+128 for x in [-103,-75,-39,-11,11,39,75,103]]), 28 | } 29 | 30 | data_bins = { 31 | 64 : np.array([x for x in range(64) 32 | if x not in guard_bins[64] and x not in pilot_bins[64]]), 33 | 128 : np.array([x for x in range(128) 34 | if x not in guard_bins[128] and x not in pilot_bins[128]]), 35 | 256 : np.array([x for x in range(256) 36 | if x not in guard_bins[256] and x not in pilot_bins[256]]), 37 | } 38 | 39 | def get_bitmask_positions(bitmask): 40 | """Return list of enabled bitmask indices in sorted order. 41 | 42 | Args: 43 | bitmask: Bitmask (0-15) 44 | 45 | Returns: 46 | Sorted list of indices. 47 | """ 48 | 49 | return [i for i in range(4) if bitmask & (1 << i) > 0] 50 | 51 | def get_subc(chan_spec): 52 | """Returns number of subcarriers in a channel spec. 53 | 54 | Args: 55 | chan_spec: Channel specification. 56 | 57 | Returns: 58 | Number of subcarriers. 59 | """ 60 | _, bw = chan_spec.split('/') 61 | if bw == "20": 62 | return 64 63 | elif bw == "40": 64 | return 128 65 | elif bw == "80": 66 | return 256 67 | else: 68 | raise ValueError('Invalid channel.') 69 | 70 | def get_csi_params(chan_spec, core_mask, stream_mask, clients): 71 | """Get CSI parameter string from makecsiparams. 72 | 73 | Args: 74 | chan_spec: Channel specification. 75 | core_mask: Bitmask for which cores to use (0-15). 76 | stream_mask: Bitmask for which streams to use (0-15). 77 | clients: List of client MAC addresses. 78 | 79 | Returns: 80 | CSI parameter string from makecsiparams. 81 | """ 82 | path = os.path.dirname(os.path.abspath(__file__)) + '/makecsiparams' 83 | args = [] 84 | if chan_spec: 85 | args.append(f"-c{chan_spec}") 86 | if core_mask: 87 | args.append(f"-C{core_mask}") 88 | if stream_mask: 89 | args.append(f"-N{stream_mask}") 90 | if clients: 91 | clients = ','.join(clients) 92 | args.append(f"-m{clients}") 93 | out = subprocess.run([path] + args, stdout=subprocess.PIPE) 94 | return out.stdout.decode('utf-8')[:-1] 95 | -------------------------------------------------------------------------------- /utils/matlab/unpack_float_py.c: -------------------------------------------------------------------------------- 1 | /* #include "mex.h" */ 2 | /* #include "matrix.h" */ 3 | #include 4 | 5 | 6 | #define k_tof_unpack_sgn_mask (1<<31) 7 | 8 | void unpack_float_acphy(int nbits, int autoscale, int shft, 9 | int fmt, int nman, int nexp, int nfft, 10 | uint32_t *H, int32_t *Hout) 11 | { 12 | int e_p, maxbit, e, i, pwr_shft = 0, e_zero, sgn; 13 | int n_out, e_shift; 14 | int8_t He[256]; 15 | int32_t vi, vq, *pOut; 16 | uint32_t x, iq_mask, e_mask, sgnr_mask, sgni_mask; 17 | 18 | iq_mask = (1<<(nman-1))- 1; 19 | e_mask = (1<> nman); 23 | e_zero = -nman; 24 | pOut = (int32_t*)Hout; 25 | n_out = (nfft << 1); 26 | e_shift = 1; 27 | maxbit = -e_p; 28 | for (i = 0; i < nfft; i++) { 29 | vi = (int32_t)((H[i] >> (nexp + nman)) & iq_mask); 30 | vq = (int32_t)((H[i] >> nexp) & iq_mask); 31 | e = (int)(H[i] & e_mask); 32 | if (e >= e_p) 33 | e -= (e_p << 1); 34 | He[i] = (int8_t)e; 35 | x = (uint32_t)vi | (uint32_t)vq; 36 | if (autoscale && x) { 37 | uint32_t m = 0xffff0000, b = 0xffff; 38 | int s = 16; 39 | while (s > 0) { 40 | if (x & m) { 41 | e += s; 42 | x >>= s; 43 | } 44 | s >>= 1; 45 | m = (m >> s) & b; 46 | b >>= s; 47 | } 48 | if (e > maxbit) 49 | maxbit = e; 50 | } 51 | if (H[i] & sgnr_mask) 52 | vi |= k_tof_unpack_sgn_mask; 53 | if (H[i] & sgni_mask) 54 | vq |= k_tof_unpack_sgn_mask; 55 | Hout[i<<1] = vi; 56 | Hout[(i<<1)+1] = vq; 57 | } 58 | shft = nbits - maxbit; 59 | for (i = 0; i < n_out; i++) { 60 | e = He[(i >> e_shift)] + shft; 61 | vi = *pOut; 62 | sgn = 1; 63 | if (vi & k_tof_unpack_sgn_mask) { 64 | sgn = -1; 65 | vi &= ~k_tof_unpack_sgn_mask; 66 | } 67 | if (e < e_zero) { 68 | vi = 0; 69 | } else if (e < 0) { 70 | e = -e; 71 | vi = (vi >> e); 72 | } else { 73 | vi = (vi << e); 74 | } 75 | *pOut++ = (int32_t)sgn*vi; 76 | } 77 | } 78 | 79 | /* void mexFunction(int nlhs, mxArray *plhs[], */ 80 | /* int nrhs, const mxArray *prhs[]) */ 81 | /* { */ 82 | /* int *nfftp, *formatp; */ 83 | /* uint32_t *H; */ 84 | /* int32_t *Hout; */ 85 | /* mwSize Hsize; */ 86 | /* if(nrhs != 3) { */ 87 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:nrhs", */ 88 | /* "Three inputs expected: unpack_float(int32 format, int32 nfft, uint32 H[](nfftx1))"); */ 89 | /* } */ 90 | /* if(!mxIsInt32(prhs[0])) { */ 91 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:formatNotInt32", */ 92 | /* "Input format must be Int32."); */ 93 | /* } */ 94 | /* if(!mxIsInt32(prhs[1])) { */ 95 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:nfftNotInt32", */ 96 | /* "Input nfft must be Int32."); */ 97 | /* } */ 98 | /* if(!mxIsUint32(prhs[2])) { */ 99 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:HNotInt32", */ 100 | /* "Input H must be Uint32."); */ 101 | /* } */ 102 | /* if(nlhs != 1) { */ 103 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:nlhs", */ 104 | /* "One output required."); */ 105 | /* } */ 106 | 107 | /* formatp = (int*)mxGetData(prhs[0]); */ 108 | /* nfftp = (int*)mxGetData(prhs[1]); */ 109 | /* Hsize = mxGetNumberOfElements(prhs[2]); */ 110 | /* if(Hsize < *nfftp) { */ 111 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:Hsize", */ 112 | /* "Length of H must be at least nfft."); */ 113 | /* } */ 114 | /* H = (uint32_t*)mxGetData(prhs[2]); */ 115 | /* plhs[0] = mxCreateNumericMatrix((*nfftp)<<1, 1, mxINT32_CLASS, mxREAL); */ 116 | /* Hout = (int32_t*)mxGetPr(plhs[0]); */ 117 | /* if (*formatp == 0) { */ 118 | /* unpack_float_acphy(10, 1, 0, 1, 9, 5, *nfftp, H, Hout); */ 119 | /* } else if (*formatp == 1) { */ 120 | /* unpack_float_acphy(10, 1, 0, 1, 12, 6, *nfftp, H, Hout); */ 121 | /* } else { */ 122 | /* mexErrMsgIdAndTxt("NexmonCSI:unpack_float:format", */ 123 | /* "format can only be 0 or 1."); */ 124 | /* } */ 125 | /* } */ 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Realtime Nexmon CSI Visualizer 2 | 3 | This repo contains the data collection tool used in the following paper:
4 | > **[Exploring Practical Vulnerabilities of Machine Learning-based Wireless Systems](https://www.usenix.org/conference/nsdi23/presentation/liu-zikun)** 5 | > Zikun Liu, Changming Xu, Emerson Sie, Gagandeep Singh, Deepak Vasisht 6 | > *USENIX Networked Systems Design and Implementation (**NSDI**), 2023* 7 | > 8 | 9 | [Nexmon Channel State Information Extractor](https://github.com/seemoo-lab/nexmon_csi) can be used to extract CSI of OFDM-modulated WIFI frames (802.11a/(g)/n/ac) on a per frame basis with up to 80 MHz bandwidth on Broadcom WiFi Chips. 10 | 11 | This repo contains an convenient Python utility for decoding and displaying CSI from a Nexmon device (e.g. ASUS RT-AC86U) in real time (up to ~100 Hz on a typical desktop CPU). It is ideal for real time applications such as on-the-fly debugging, gesture sensing, etc. 12 | 13 | https://github.com/ConnectedSystemsLab/nexmon_csi_gui/assets/14133352/cd7fd630-2d26-43c5-a940-2369cedbb9a2 14 | 15 | ### Features 16 | 17 | - Primarily for ASUS RT-AC86U, but works for other devices (RPi4b+, Nexus 6P) with a little modification. 18 | - Supports 4 x 4 cores and spatial streams simultaneously at ~100 Hz on typical desktop CPU. 19 | - Includes per-core RSSI [issue #93](https://github.com/seemoo-lab/nexmon_csi/issues/93) to deal with AGC. 20 | - Shows relative phase difference to first core [issue #219](https://github.com/seemoo-lab/nexmon_csi/issues/219) 21 | 22 | ### Requirements 23 | 24 | - **Host**, where you wish to receive CSI data (tested on Ubuntu 18.04). 25 | - **Monitor** (RT-AC86U AP), where CSI data collection occurs. 26 | - This router contains bcm4366c0 WIFI Chip. bcm4366e is a updated version and it also works. 27 | - Set the username of the router to be `admin` in the login page. 28 | - Setup SSH keys 29 | - Run `ssh-keygen -t ed25519` and generate a SSH Key. You can use the default settings. 30 | - Login to the router Web interface. 31 | - In Advanced > Administration > System: 32 | - Enable SSH 33 | - Copy paste the key from ~/.ssh/id_ed25519.pub 34 | - Ensure that the router login name is admin. The makefiles need this. 35 | - Test that the VM is able to ssh into the router 36 | - `ssh admin@` this should happen without asking for a password. 37 | - **Client**, whose transmissions we want to monitor. 38 | 39 | ### Basic Setup 40 | 41 | Connect a host (desktop/laptop) to the AP through an Ethernet port. Connect a client to some other WIFI network, e.g., your home WLAN (NOT the AP). 42 | 43 | ### Host Setup 44 | 45 | - Setup the conda environment `conda env create -f env.yaml` and activate the environment with `conda activate csi_visualizer`. 46 | - Make the binaries under `utils/` folder by running `make`. This should create an executable `makecsiparams` and library `unpack_float_py.so`. 47 | 48 | ### Monitor Setup 49 | 50 | - For convenience, we have precompiled binaries under the `nexmon_compiled/` folder. 51 | - This folder contains the nexmon core firmware `dhd.ko`, `nexutil`, `makecsiparams` and `tcpdump`. 52 | - The vanilla Nexmon from official repo doesn't support RSSI extraction which makes the CSI amplitude meaningless. We use the workaround detailed in [issue #126](https://github.com/seemoo-lab/nexmon_csi/issues/126). 53 | - Copy the contents to the `/jffs/` partition of your router: `scp ./nexmon_compiled/* admin@:/jffs/` 54 | - Make `nexutil`, `makecsiparams`, and `tcpdump` executable: `ssh admin@ "/bin/chmod +x /jffs/nexutil /jffs/mcp /jffs/tcpdump "` 55 | 56 | ### Run CSI Collection 57 | 58 | - Take note of the monitor IP, client MAC, and channel in which the client is transmitting (this can usually be found using `iwlist` on the client). 59 | - Generate traffic on your client device somehow, for example using: 60 | ``` 61 | sudo ping -i 0.1 62 | ``` 63 | - Run `main.py` with the appropriate arguments. For example 64 | ```bash 65 | ./main.py --monitor_ip=192.168.10.1 --clients=b0:7d:64:af:ea:ec --chan_spec=40/20 66 | ``` 67 | 68 | and you will get the real-time CSI collection like this: 69 | 70 | ![](docs/csi_demo.gif) 71 | 72 | - Each row corresponds to a different core (antenna) and column to a different spatial stream. CSI amplitudes are in red, phases are in blue, and RSSI (dBm) is in green. 73 | 74 | ## Citation 75 | 76 | If you find this work and/or dataset useful in your research, please cite: 77 | 78 | ```bibtex 79 | @inproceedings {liu2023exploiting, 80 | author = {Zikun Liu and Changming Xu and Emerson Sie and Gagandeep Singh and Deepak Vasisht}, 81 | title = {Exploring Practical Vulnerabilities of Machine Learning-based Wireless Systems}, 82 | booktitle = {20th USENIX Symposium on Networked Systems Design and Implementation (NSDI 23)}, 83 | year = {2023}, 84 | isbn = {978-1-939133-33-5}, 85 | address = {Boston, MA}, 86 | pages = {1801--1817}, 87 | url = {https://www.usenix.org/conference/nsdi23/presentation/liu-zikun}, 88 | publisher = {USENIX Association}, 89 | month = apr,} 90 | ``` 91 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import time 5 | from csi_reader import * 6 | from csi_params import * 7 | from multiprocessing import Process, Queue 8 | from PyQt5 import QtWidgets, QtCore 9 | from pyqtgraph import PlotWidget, plot 10 | import pyqtgraph as pg 11 | from absl import app 12 | from absl import flags 13 | import numpy as np 14 | 15 | FLAGS = flags.FLAGS 16 | flags.DEFINE_string('monitor_ip', '192.168.10.1', 'IP address of monitor to read packets from.') 17 | flags.DEFINE_string('monitor_user', 'admin', 'Username for monitor.') 18 | flags.DEFINE_string('monitor_pwd', 'admin', 'Password for monitor.') 19 | flags.DEFINE_enum('chip', '4366c0', ['4358', '43455c0', '4366c0'], 'Wifi card. Possible options are 4358 for Nexus 6P, 43455c0 for Raspberry Pi 4, 4366c0 for ASUS RT-AC86U') 20 | flags.DEFINE_string('chan_spec', '40/20', 'Channel specification.') 21 | flags.DEFINE_integer('core_mask', 15, 'Bitmask for cores to use.', lower_bound=0, upper_bound=15) 22 | flags.DEFINE_integer('stream_mask', 15, 'Bitmask for streams to use.', lower_bound=0, upper_bound=15) 23 | flags.DEFINE_multi_string('clients', None, 'List of client MAC addresses.') 24 | flags.DEFINE_integer('queue_size', 100, 'Max number of CSI to buffer', lower_bound=0) 25 | 26 | flags.mark_flag_as_required('clients') 27 | 28 | class MainWindow(QtWidgets.QMainWindow): 29 | 30 | def __init__(self, queue, *args, **kwargs): 31 | super(MainWindow, self).__init__(*args, **kwargs) 32 | 33 | # Process flags. 34 | self.cores = get_bitmask_positions(FLAGS.core_mask) 35 | self.streams = get_bitmask_positions(FLAGS.stream_mask) 36 | self.n_subc = get_subc(FLAGS.chan_spec) 37 | self.csi_antenna = [np.ones(self.n_subc, dtype=complex) for _ in enumerate(self.cores)] 38 | self.rssi_antenna = [[] for _ in enumerate(self.cores)] 39 | 40 | # Data feed. 41 | self.queue = queue 42 | 43 | # Subplots. 44 | self.canvas = pg.GraphicsLayoutWidget() 45 | self.setCentralWidget(self.canvas) 46 | 47 | # CSI Abs subplots. 48 | self.csi_plots = [[self.canvas.addPlot(row=i,col=2*j) 49 | for j,_ in enumerate(self.streams)] 50 | for i,_ in enumerate(self.cores)] 51 | 52 | # CSI Phase subplots. 53 | self.csi_phase_plots = [[self.canvas.addPlot(row=i, col=2*j+1) 54 | for j, _ in enumerate(self.streams)] 55 | for i, _ in enumerate(self.cores)] 56 | # RSSI subplots. 57 | self.rssi_plots = [self.canvas.addPlot(row=i,col=2*len(self.streams)) 58 | for i,_ in enumerate(self.cores)] 59 | 60 | # Fill subplots. 61 | 62 | # Abs plots 63 | self.canvas.setBackground('w') 64 | pen = pg.mkPen(color=(255, 0, 0), width=3) 65 | x = subcarriers[self.n_subc][data_bins[self.n_subc]] 66 | y = [0 for _ in range(len(x))] 67 | self.csi_lines_abs = [[self.csi_plots[i][j].plot(x, y, pen=pen) 68 | for j, _ in enumerate(self.streams)] 69 | for i, _ in enumerate(self.cores)] 70 | [self.csi_plots[i][j].setXRange(min(x),max(x)) 71 | for i,_ in enumerate(self.cores) 72 | for j,_ in enumerate(self.streams)] 73 | [self.csi_plots[i][j].setYRange(0, 3) 74 | for i,_ in enumerate(self.cores) 75 | for j,_ in enumerate(self.streams)] 76 | [self.csi_plots[i][j].setTitle(f"[Abs] Core {core}, Stream {stream}", **{'size': '22pt'}) 77 | for i,core in enumerate(self.cores) 78 | for j,stream in enumerate(self.streams)] 79 | 80 | # RSSI plots 81 | pen = pg.mkPen(color=(0, 255, 0), width=3) 82 | self.rssi = [[-100 for _ in range(100)] for _ in self.cores] 83 | self.rssi_lines = [self.rssi_plots[i].plot(self.rssi[i],pen=pen) 84 | for i,_ in enumerate(self.cores)] 85 | [self.rssi_plots[i].setXRange(0,100) for i,_ in enumerate(self.cores)] 86 | [self.rssi_plots[i].setYRange(-100,0) for i,_ in enumerate(self.cores)] 87 | [self.rssi_plots[i].setTitle(f"[RSSI] Core {i}", **{'size': '22pt'}) 88 | for i,_ in enumerate(self.cores)] 89 | 90 | # Phase plots 91 | pen = pg.mkPen(color=(0, 0, 255), width=3) 92 | x = subcarriers[self.n_subc][data_bins[self.n_subc]] 93 | y = [0 for _ in range(len(x))] 94 | self.csi_lines_phase = [[self.csi_phase_plots[i][j].plot(x, y, pen=pen) 95 | for j, _ in enumerate(self.streams)] 96 | for i, _ in enumerate(self.cores)] 97 | [self.csi_phase_plots[i][j].setXRange(min(x), max(x)) 98 | for i, _ in enumerate(self.cores) 99 | for j, _ in enumerate(self.streams)] 100 | [self.csi_phase_plots[i][j].setYRange(-20, 20) 101 | for i, _ in enumerate(self.cores) 102 | for j, _ in enumerate(self.streams)] 103 | [self.csi_phase_plots[i][j].setTitle(f"[Phase] Core {core}, Stream {stream}", **{'size': '22pt'}) 104 | for i, core in enumerate(self.cores) 105 | for j, stream in enumerate(self.streams)] 106 | 107 | # Set timer. 108 | self.timer = QtCore.QTimer() 109 | self.timer.setInterval(1) 110 | self.timer.timeout.connect(self.update_plot_data) 111 | self.timer.start() 112 | 113 | self.fps = None 114 | self.lastTime = time.perf_counter() 115 | 116 | 117 | def update_plot_data(self): 118 | 119 | # Dequeue new CSI 120 | if self.queue.empty(): 121 | return 122 | elif self.queue.full(): 123 | print('Warning: Queue is full.') 124 | new_csi = self.queue.get() 125 | 126 | # Find core and stream idx. 127 | core_idx = self.cores.index(new_csi["core"]) 128 | stream_idx = self.streams.index(new_csi["stream"]) 129 | 130 | # Get CSI data. 131 | n_subc = len(new_csi["data"]) 132 | csi_data = new_csi["data"][data_bins[n_subc]] 133 | rssi = new_csi["rssi"] 134 | 135 | # Store per-core CSI and RSSI. 136 | self.csi_antenna[core_idx] = csi_data 137 | self.rssi_antenna[core_idx] = rssi 138 | 139 | # Get scaled CSI. 140 | x = subcarriers[n_subc][data_bins[n_subc]] 141 | y = np.abs(csi_data) 142 | 143 | # Update CSI Abs. 144 | self.csi_lines_abs[core_idx][stream_idx].setData(x, y) 145 | 146 | # Update RSSI. 147 | self.rssi[core_idx] = self.rssi[core_idx][1:] + [new_csi["rssi"]] 148 | self.rssi_lines[core_idx].setData(self.rssi[core_idx]) 149 | 150 | # Update CSI Phase Ratio. 151 | y = np.unwrap(np.angle(csi_data/self.csi_antenna[0])) 152 | self.csi_lines_phase[core_idx][stream_idx].setData(x, y) 153 | 154 | # Update FPS. 155 | self.fps = 1.0/(time.perf_counter() - self.lastTime) 156 | self.lastTime = time.perf_counter() 157 | 158 | self.setWindowTitle(f"FPS: {self.fps}") 159 | 160 | def listen_csi(queue): 161 | monitor = CSIMonitor(FLAGS.monitor_ip, 162 | FLAGS.monitor_user, 163 | FLAGS.monitor_pwd, 164 | FLAGS.chip, 165 | FLAGS.chan_spec, 166 | FLAGS.core_mask, 167 | FLAGS.stream_mask, 168 | FLAGS.clients) 169 | monitor.monitor_csi(queue) 170 | 171 | def main(_): 172 | try: 173 | # Init queue to store incoming data. 174 | queue = Queue(FLAGS.queue_size) 175 | 176 | # Init the GUI. 177 | gui_thread = QtWidgets.QApplication(sys.argv) 178 | window = MainWindow(queue) 179 | window.resize(900, 600) 180 | window.show() 181 | 182 | # Start listening for CSI and adding it to the queue. 183 | monitor_thread = Process(target=listen_csi, args=(queue,)) 184 | monitor_thread.start() 185 | 186 | # Run the GUI on current thread. 187 | gui_thread.exec_() 188 | finally: 189 | monitor_thread.join() 190 | 191 | if __name__ == '__main__': 192 | app.run(main) 193 | -------------------------------------------------------------------------------- /utils/makecsiparams/typedefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1999-2013, Broadcom Corporation 3 | * 4 | * Unless you and Broadcom execute a separate written software license 5 | * agreement governing use of this software, this software is licensed to you 6 | * under the terms of the GNU General Public License version 2 (the "GPL"), 7 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the 8 | * following added to such license: 9 | * 10 | * As a special exception, the copyright holders of this software give you 11 | * permission to link this software with independent modules, and to copy and 12 | * distribute the resulting executable under terms of your choice, provided that 13 | * you also meet, for each linked independent module, the terms and conditions of 14 | * the license of that module. An independent module is a module which is not 15 | * derived from this software. The special exception does not apply to any 16 | * modifications of the software. 17 | * 18 | * Notwithstanding the above, under no circumstances may you combine this 19 | * software in any way with any other Broadcom software provided under a license 20 | * other than the GPL, without Broadcom's express prior written consent. 21 | * $Id: typedefs.h 397286 2013-04-18 01:42:19Z $ 22 | */ 23 | 24 | #ifndef _TYPEDEFS_H_ 25 | #define _TYPEDEFS_H_ 26 | 27 | #ifdef SITE_TYPEDEFS 28 | 29 | /* 30 | * Define SITE_TYPEDEFS in the compile to include a site-specific 31 | * typedef file "site_typedefs.h". 32 | * 33 | * If SITE_TYPEDEFS is not defined, then the code section below makes 34 | * inferences about the compile environment based on defined symbols and 35 | * possibly compiler pragmas. 36 | * 37 | * Following these two sections is the Default Typedefs section. 38 | * This section is only processed if USE_TYPEDEF_DEFAULTS is 39 | * defined. This section has a default set of typedefs and a few 40 | * preprocessor symbols (TRUE, FALSE, NULL, ...). 41 | */ 42 | 43 | #include "site_typedefs.h" 44 | 45 | #else 46 | 47 | /* 48 | * Infer the compile environment based on preprocessor symbols and pragmas. 49 | * Override type definitions as needed, and include configuration-dependent 50 | * header files to define types. 51 | */ 52 | 53 | #ifdef __cplusplus 54 | 55 | #define TYPEDEF_BOOL 56 | #ifndef FALSE 57 | #define FALSE false 58 | #endif 59 | #ifndef TRUE 60 | #define TRUE true 61 | #endif 62 | 63 | #else /* ! __cplusplus */ 64 | 65 | 66 | #endif /* ! __cplusplus */ 67 | 68 | #if defined(__x86_64__) 69 | #define TYPEDEF_UINTPTR 70 | typedef unsigned long long int uintptr; 71 | #endif 72 | 73 | 74 | 75 | 76 | 77 | #if defined(_NEED_SIZE_T_) 78 | typedef long unsigned int size_t; 79 | #endif 80 | 81 | 82 | 83 | 84 | 85 | #if defined(__sparc__) 86 | #define TYPEDEF_ULONG 87 | #endif 88 | 89 | 90 | /* 91 | * If this is either a Linux hybrid build or the per-port code of a hybrid build 92 | * then use the Linux header files to get some of the typedefs. Otherwise, define 93 | * them entirely in this file. We can't always define the types because we get 94 | * a duplicate typedef error; there is no way to "undefine" a typedef. 95 | * We know when it's per-port code because each file defines LINUX_PORT at the top. 96 | */ 97 | #if !defined(LINUX_HYBRID) || defined(LINUX_PORT) 98 | #define TYPEDEF_UINT 99 | #ifndef TARGETENV_android 100 | #define TYPEDEF_USHORT 101 | #define TYPEDEF_ULONG 102 | #endif /* TARGETENV_android */ 103 | #ifdef __KERNEL__ 104 | #include 105 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) 106 | #define TYPEDEF_BOOL 107 | #endif /* >= 2.6.19 */ 108 | /* special detection for 2.6.18-128.7.1.0.1.el5 */ 109 | #if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18)) 110 | #include 111 | #ifdef noinline_for_stack 112 | #define TYPEDEF_BOOL 113 | #endif 114 | #endif /* == 2.6.18 */ 115 | #endif /* __KERNEL__ */ 116 | #endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ 117 | 118 | 119 | 120 | 121 | /* Do not support the (u)int64 types with strict ansi for GNU C */ 122 | #if defined(__GNUC__) && defined(__STRICT_ANSI__) 123 | #define TYPEDEF_INT64 124 | #define TYPEDEF_UINT64 125 | #endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ 126 | 127 | /* ICL accepts unsigned 64 bit type only, and complains in ANSI mode 128 | * for signed or unsigned 129 | */ 130 | #if defined(__ICL) 131 | 132 | #define TYPEDEF_INT64 133 | 134 | #if defined(__STDC__) 135 | #define TYPEDEF_UINT64 136 | #endif 137 | 138 | #endif /* __ICL */ 139 | 140 | #if !defined(__DJGPP__) 141 | 142 | /* pick up ushort & uint from standard types.h */ 143 | #if defined(__KERNEL__) 144 | 145 | /* See note above */ 146 | #if !defined(LINUX_HYBRID) || defined(LINUX_PORT) 147 | #include /* sys/types.h and linux/types.h are oil and water */ 148 | #endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */ 149 | 150 | #else 151 | 152 | 153 | #include 154 | 155 | #endif /* linux && __KERNEL__ */ 156 | 157 | #endif 158 | 159 | 160 | 161 | /* use the default typedefs in the next section of this file */ 162 | #define USE_TYPEDEF_DEFAULTS 163 | 164 | #endif /* SITE_TYPEDEFS */ 165 | 166 | 167 | /* 168 | * Default Typedefs 169 | */ 170 | 171 | #ifdef USE_TYPEDEF_DEFAULTS 172 | #undef USE_TYPEDEF_DEFAULTS 173 | 174 | #ifndef TYPEDEF_BOOL 175 | typedef /* @abstract@ */ unsigned char bool; 176 | #endif 177 | 178 | /* define uchar, ushort, uint, ulong */ 179 | 180 | #ifndef TYPEDEF_UCHAR 181 | typedef unsigned char uchar; 182 | #endif 183 | 184 | #ifndef TYPEDEF_USHORT 185 | typedef unsigned short ushort; 186 | #endif 187 | 188 | #ifndef TYPEDEF_UINT 189 | typedef unsigned int uint; 190 | #endif 191 | 192 | #ifndef TYPEDEF_ULONG 193 | typedef unsigned long ulong; 194 | #endif 195 | 196 | /* define [u]int8/16/32/64, uintptr */ 197 | 198 | #ifndef TYPEDEF_UINT8 199 | typedef unsigned char uint8; 200 | #endif 201 | 202 | #ifndef TYPEDEF_UINT16 203 | typedef unsigned short uint16; 204 | #endif 205 | 206 | #ifndef TYPEDEF_UINT32 207 | typedef unsigned int uint32; 208 | #endif 209 | 210 | #ifndef TYPEDEF_UINT64 211 | typedef unsigned long long uint64; 212 | #endif 213 | 214 | #ifndef TYPEDEF_UINTPTR 215 | typedef unsigned int uintptr; 216 | #endif 217 | 218 | #ifndef TYPEDEF_INT8 219 | typedef signed char int8; 220 | #endif 221 | 222 | #ifndef TYPEDEF_INT16 223 | typedef signed short int16; 224 | #endif 225 | 226 | #ifndef TYPEDEF_INT32 227 | typedef signed int int32; 228 | #endif 229 | 230 | #ifndef TYPEDEF_INT64 231 | typedef signed long long int64; 232 | #endif 233 | 234 | /* define float32/64, float_t */ 235 | 236 | #ifndef TYPEDEF_FLOAT32 237 | typedef float float32; 238 | #endif 239 | 240 | #ifndef TYPEDEF_FLOAT64 241 | typedef double float64; 242 | #endif 243 | 244 | /* 245 | * abstracted floating point type allows for compile time selection of 246 | * single or double precision arithmetic. Compiling with -DFLOAT32 247 | * selects single precision; the default is double precision. 248 | */ 249 | 250 | #ifndef TYPEDEF_FLOAT_T 251 | 252 | #if defined(FLOAT32) 253 | typedef float32 float_t; 254 | #else /* default to double precision floating point */ 255 | typedef float64 float_t; 256 | #endif 257 | 258 | #endif /* TYPEDEF_FLOAT_T */ 259 | 260 | /* define macro values */ 261 | 262 | #ifndef FALSE 263 | #define FALSE 0 264 | #endif 265 | 266 | #ifndef TRUE 267 | #define TRUE 1 /* TRUE */ 268 | #endif 269 | 270 | #ifndef NULL 271 | #define NULL 0 272 | #endif 273 | 274 | #ifndef OFF 275 | #define OFF 0 276 | #endif 277 | 278 | #ifndef ON 279 | #define ON 1 /* ON = 1 */ 280 | #endif 281 | 282 | #define AUTO (-1) /* Auto = -1 */ 283 | 284 | /* define PTRSZ, INLINE */ 285 | 286 | #ifndef PTRSZ 287 | #define PTRSZ sizeof(char*) 288 | #endif 289 | 290 | 291 | /* Detect compiler type. */ 292 | #if defined(__GNUC__) || defined(__lint) 293 | #define BWL_COMPILER_GNU 294 | #elif defined(__CC_ARM) && __CC_ARM 295 | #define BWL_COMPILER_ARMCC 296 | #else 297 | #error "Unknown compiler!" 298 | #endif 299 | 300 | 301 | #ifndef INLINE 302 | #if defined(BWL_COMPILER_MICROSOFT) 303 | #define INLINE __inline 304 | #elif defined(BWL_COMPILER_GNU) 305 | #define INLINE __inline__ 306 | #elif defined(BWL_COMPILER_ARMCC) 307 | #define INLINE __inline 308 | #else 309 | #define INLINE 310 | #endif 311 | #endif /* INLINE */ 312 | 313 | #undef TYPEDEF_BOOL 314 | #undef TYPEDEF_UCHAR 315 | #undef TYPEDEF_USHORT 316 | #undef TYPEDEF_UINT 317 | #undef TYPEDEF_ULONG 318 | #undef TYPEDEF_UINT8 319 | #undef TYPEDEF_UINT16 320 | #undef TYPEDEF_UINT32 321 | #undef TYPEDEF_UINT64 322 | #undef TYPEDEF_UINTPTR 323 | #undef TYPEDEF_INT8 324 | #undef TYPEDEF_INT16 325 | #undef TYPEDEF_INT32 326 | #undef TYPEDEF_INT64 327 | #undef TYPEDEF_FLOAT32 328 | #undef TYPEDEF_FLOAT64 329 | #undef TYPEDEF_FLOAT_T 330 | 331 | #endif /* USE_TYPEDEF_DEFAULTS */ 332 | 333 | /* Suppress unused parameter warning */ 334 | #define UNUSED_PARAMETER(x) (void)(x) 335 | 336 | /* Avoid warning for discarded const or volatile qualifier in special cases (-Wcast-qual) */ 337 | #define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) 338 | 339 | /* 340 | * Including the bcmdefs.h here, to make sure everyone including typedefs.h 341 | * gets this automatically 342 | */ 343 | #include 344 | #endif /* _TYPEDEFS_H_ */ 345 | -------------------------------------------------------------------------------- /utils/makecsiparams/bcmdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Misc system wide definitions 3 | * 4 | * Copyright (C) 1999-2013, Broadcom Corporation 5 | * 6 | * Unless you and Broadcom execute a separate written software license 7 | * agreement governing use of this software, this software is licensed to you 8 | * under the terms of the GNU General Public License version 2 (the "GPL"), 9 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 | * following added to such license: 11 | * 12 | * As a special exception, the copyright holders of this software give you 13 | * permission to link this software with independent modules, and to copy and 14 | * distribute the resulting executable under terms of your choice, provided that 15 | * you also meet, for each linked independent module, the terms and conditions of 16 | * the license of that module. An independent module is a module which is not 17 | * derived from this software. The special exception does not apply to any 18 | * modifications of the software. 19 | * 20 | * Notwithstanding the above, under no circumstances may you combine this 21 | * software in any way with any other Broadcom software provided under a license 22 | * other than the GPL, without Broadcom's express prior written consent. 23 | * 24 | * $Id: bcmdefs.h 416231 2013-08-02 07:38:34Z $ 25 | */ 26 | 27 | #ifndef _bcmdefs_h_ 28 | #define _bcmdefs_h_ 29 | 30 | /* 31 | * One doesn't need to include this file explicitly, gets included automatically if 32 | * typedefs.h is included. 33 | */ 34 | 35 | /* Use BCM_REFERENCE to suppress warnings about intentionally-unused function 36 | * arguments or local variables. 37 | */ 38 | #define BCM_REFERENCE(data) ((void)(data)) 39 | 40 | /* Compile-time assert can be used in place of ASSERT if the expression evaluates 41 | * to a constant at compile time. 42 | */ 43 | #define STATIC_ASSERT(expr) { \ 44 | /* Make sure the expression is constant. */ \ 45 | typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e; \ 46 | /* Make sure the expression is true. */ \ 47 | typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1]; \ 48 | } 49 | 50 | /* Reclaiming text and data : 51 | * The following macros specify special linker sections that can be reclaimed 52 | * after a system is considered 'up'. 53 | * BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN, 54 | * as in most cases, the attach function calls the detach function to clean up on error). 55 | */ 56 | 57 | #define bcmreclaimed 0 58 | #define _data _data 59 | #define _fn _fn 60 | #define BCMPREATTACHDATA(_data) _data 61 | #define BCMPREATTACHFN(_fn) _fn 62 | #define _data _data 63 | #define _fn _fn 64 | #define _fn _fn 65 | #define BCMNMIATTACHFN(_fn) _fn 66 | #define BCMNMIATTACHDATA(_data) _data 67 | #define CONST const 68 | 69 | /* Do not put BCM47XX and __ARM_ARCH_7A__ to the same line. 70 | * DHD build has problem because the BCM47XX will be excluded in DHD release. 71 | */ 72 | #undef BCM47XX_CA9 73 | #ifdef __ARM_ARCH_7A__ 74 | #define BCM47XX_CA9 75 | #endif /* __ARM_ARCH_7A__ */ 76 | #ifndef BCMFASTPATH 77 | #if defined(BCM47XX_CA9) 78 | #define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath"))) 79 | #define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host"))) 80 | #else 81 | #define BCMFASTPATH 82 | #define BCMFASTPATH_HOST 83 | #endif 84 | #endif /* BCMFASTPATH */ 85 | 86 | 87 | /* Put some library data/code into ROM to reduce RAM requirements */ 88 | #define _data _data 89 | #define BCMROMDAT_NAME(_data) _data 90 | #define _fn _fn 91 | #define _fn _fn 92 | #define STATIC static 93 | #define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) 94 | #define BCMROMDAT_SIZEOF(data) sizeof(data) 95 | #define BCMROMDAT_APATCH(data) 96 | #define BCMROMDAT_SPATCH(data) 97 | 98 | /* Bus types */ 99 | #define SI_BUS 0 /* SOC Interconnect */ 100 | #define PCI_BUS 1 /* PCI target */ 101 | #define PCMCIA_BUS 2 /* PCMCIA target */ 102 | #define SDIO_BUS 3 /* SDIO target */ 103 | #define JTAG_BUS 4 /* JTAG */ 104 | #define USB_BUS 5 /* USB (does not support R/W REG) */ 105 | #define SPI_BUS 6 /* gSPI target */ 106 | #define RPC_BUS 7 /* RPC target */ 107 | 108 | /* Allows size optimization for single-bus image */ 109 | #ifdef BCMBUSTYPE 110 | #define BUSTYPE(bus) (BCMBUSTYPE) 111 | #else 112 | #define BUSTYPE(bus) (bus) 113 | #endif 114 | 115 | /* Allows size optimization for single-backplane image */ 116 | #ifdef BCMCHIPTYPE 117 | #define CHIPTYPE(bus) (BCMCHIPTYPE) 118 | #else 119 | #define CHIPTYPE(bus) (bus) 120 | #endif 121 | 122 | 123 | /* Allows size optimization for SPROM support */ 124 | #if defined(BCMSPROMBUS) 125 | #define SPROMBUS (BCMSPROMBUS) 126 | #elif defined(SI_PCMCIA_SROM) 127 | #define SPROMBUS (PCMCIA_BUS) 128 | #else 129 | #define SPROMBUS (PCI_BUS) 130 | #endif 131 | 132 | /* Allows size optimization for single-chip image */ 133 | #ifdef BCMCHIPID 134 | #define CHIPID(chip) (BCMCHIPID) 135 | #else 136 | #define CHIPID(chip) (chip) 137 | #endif 138 | 139 | #ifdef BCMCHIPREV 140 | #define CHIPREV(rev) (BCMCHIPREV) 141 | #else 142 | #define CHIPREV(rev) (rev) 143 | #endif 144 | 145 | /* Defines for DMA Address Width - Shared between OSL and HNDDMA */ 146 | #define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */ 147 | #define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */ 148 | #define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */ 149 | 150 | #define DMADDRWIDTH_30 30 /* 30-bit addressing capability */ 151 | #define DMADDRWIDTH_32 32 /* 32-bit addressing capability */ 152 | #define DMADDRWIDTH_63 63 /* 64-bit addressing capability */ 153 | #define DMADDRWIDTH_64 64 /* 64-bit addressing capability */ 154 | 155 | #ifdef BCMDMA64OSL 156 | typedef struct { 157 | uint32 loaddr; 158 | uint32 hiaddr; 159 | } dma64addr_t; 160 | 161 | typedef dma64addr_t dmaaddr_t; 162 | #define PHYSADDRHI(_pa) ((_pa).hiaddr) 163 | #define PHYSADDRHISET(_pa, _val) \ 164 | do { \ 165 | (_pa).hiaddr = (_val); \ 166 | } while (0) 167 | #define PHYSADDRLO(_pa) ((_pa).loaddr) 168 | #define PHYSADDRLOSET(_pa, _val) \ 169 | do { \ 170 | (_pa).loaddr = (_val); \ 171 | } while (0) 172 | 173 | #else 174 | typedef unsigned long dmaaddr_t; 175 | #define PHYSADDRHI(_pa) (0) 176 | #define PHYSADDRHISET(_pa, _val) 177 | #define PHYSADDRLO(_pa) ((_pa)) 178 | #define PHYSADDRLOSET(_pa, _val) \ 179 | do { \ 180 | (_pa) = (_val); \ 181 | } while (0) 182 | #endif /* BCMDMA64OSL */ 183 | 184 | /* One physical DMA segment */ 185 | typedef struct { 186 | dmaaddr_t addr; 187 | uint32 length; 188 | } hnddma_seg_t; 189 | 190 | #define MAX_DMA_SEGS 4 191 | 192 | 193 | typedef struct { 194 | void *oshdmah; /* Opaque handle for OSL to store its information */ 195 | uint origsize; /* Size of the virtual packet */ 196 | uint nsegs; 197 | hnddma_seg_t segs[MAX_DMA_SEGS]; 198 | } hnddma_seg_map_t; 199 | 200 | 201 | /* packet headroom necessary to accommodate the largest header in the system, (i.e TXOFF). 202 | * By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL. 203 | * There is a compile time check in wlc.c which ensure that this value is at least as big 204 | * as TXOFF. This value is used in dma_rxfill (hnddma.c). 205 | */ 206 | 207 | #if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY) 208 | /* add 40 bytes to allow for extra RPC header and info */ 209 | #define BCMEXTRAHDROOM 260 210 | #else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ 211 | #if defined(BCM47XX_CA9) 212 | #define BCMEXTRAHDROOM 224 213 | #else 214 | #define BCMEXTRAHDROOM 204 215 | #endif /* linux && BCM47XX_CA9 */ 216 | #endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */ 217 | 218 | /* Packet alignment for most efficient SDIO (can change based on platform) */ 219 | #ifndef SDALIGN 220 | #define SDALIGN 32 221 | #endif 222 | 223 | /* Headroom required for dongle-to-host communication. Packets allocated 224 | * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should 225 | * leave this much room in front for low-level message headers which may 226 | * be needed to get across the dongle bus to the host. (These messages 227 | * don't go over the network, so room for the full WL header above would 228 | * be a waste.). 229 | */ 230 | #define BCMDONGLEHDRSZ 12 231 | #define BCMDONGLEPADSZ 16 232 | 233 | #define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ) 234 | 235 | 236 | #if defined(NO_BCMDBG_ASSERT) 237 | # undef BCMDBG_ASSERT 238 | # undef BCMASSERT_LOG 239 | #endif 240 | 241 | #if defined(BCMASSERT_LOG) 242 | #define BCMASSERT_SUPPORT 243 | #endif 244 | 245 | /* Macros for doing definition and get/set of bitfields 246 | * Usage example, e.g. a three-bit field (bits 4-6): 247 | * #define _M BITFIELD_MASK(3) 248 | * #define _S 4 249 | * ... 250 | * regval = R_REG(osh, ®s->regfoo); 251 | * field = GFIELD(regval, ); 252 | * regval = SFIELD(regval, , 1); 253 | * W_REG(osh, ®s->regfoo, regval); 254 | */ 255 | #define BITFIELD_MASK(width) \ 256 | (((unsigned)1 << (width)) - 1) 257 | #define GFIELD(val, field) \ 258 | (((val) >> field ## _S) & field ## _M) 259 | #define SFIELD(val, field, bits) \ 260 | (((val) & (~(field ## _M << field ## _S))) | \ 261 | ((unsigned)(bits) << field ## _S)) 262 | 263 | /* define BCMSMALL to remove misc features for memory-constrained environments */ 264 | #ifdef BCMSMALL 265 | #undef BCMSPACE 266 | #define bcmspace FALSE /* if (bcmspace) code is discarded */ 267 | #else 268 | #define BCMSPACE 269 | #define bcmspace TRUE /* if (bcmspace) code is retained */ 270 | #endif 271 | 272 | /* Max. nvram variable table size */ 273 | #define MAXSZ_NVRAM_VARS 4096 274 | 275 | 276 | /* Max size for reclaimable NVRAM array */ 277 | #ifdef DL_NVRAM 278 | #define NVRAM_ARRAY_MAXSIZE DL_NVRAM 279 | #else 280 | #define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS 281 | #endif /* DL_NVRAM */ 282 | 283 | #ifdef BCMUSBDEV_ENABLED 284 | extern uint32 gFWID; 285 | #endif 286 | 287 | #endif /* _bcmdefs_h_ */ 288 | -------------------------------------------------------------------------------- /utils/makecsiparams/makecsiparams.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | /* 9 | #include 10 | #include 11 | #include 12 | */ 13 | #include "bcmwifi_channels.h" 14 | 15 | void st16le (uint16_t value, uint16_t *addr) 16 | { 17 | uint8_t *_addr = (uint8_t *) addr; 18 | _addr[0] = value & 0xff; 19 | _addr[1] = (value >> 8) & 0xff; 20 | } 21 | 22 | void st16be (uint16_t value, uint16_t *addr) 23 | { 24 | uint8_t *_addr = (uint8_t *) addr; 25 | _addr[1] = value & 0xff; 26 | _addr[0] = (value >> 8) & 0xff; 27 | } 28 | 29 | #define VALID_CORE_MASK 0xf 30 | #define VALID_NSS_MASK 0xf 31 | #define MAX_MAC_ADDRESS 4 32 | #define DEFAULT_DELAY_US 50 33 | 34 | int countbit (uint32_t val) 35 | { 36 | int counter = 0; 37 | while (val != 0) { 38 | if (val & 1) counter ++; 39 | val = val >> 1; 40 | } 41 | return counter; 42 | } 43 | 44 | struct csi_params { 45 | uint16_t chanspec; // chanspec to tune to 46 | uint8_t csi_collect; // trigger csi collect (1: on, 0: off) 47 | uint8_t core_nss_mask; // coremask and spatialstreammask./iperf -u -c 192.168.2.59 -i 1 -b 10M 48 | uint8_t use_pkt_filter; // trigger first packet byte filter (1: on, 0: off) 49 | uint8_t first_pkt_byte; // first packet byte to filter for 50 | uint16_t n_mac_addr; // number of mac addresses to filter for (0: off, 1-4: on,use src_mac_0-3) 51 | uint16_t cmp_src_mac_0_0; // filter src mac 0 52 | uint16_t cmp_src_mac_0_1; 53 | uint16_t cmp_src_mac_0_2; 54 | uint16_t cmp_src_mac_1_0; // filter src mac 1 55 | uint16_t cmp_src_mac_1_1; 56 | uint16_t cmp_src_mac_1_2; 57 | uint16_t cmp_src_mac_2_0; // filter src mac 2 58 | uint16_t cmp_src_mac_2_1; 59 | uint16_t cmp_src_mac_2_2; 60 | uint16_t cmp_src_mac_3_0; // filter src mac 3 61 | uint16_t cmp_src_mac_3_1; 62 | uint16_t cmp_src_mac_3_2; 63 | uint16_t delay; 64 | }; 65 | 66 | void usage () 67 | { 68 | char *usage_str = 69 | "Usage: makecsiparams [OPTION...]\n" 70 | "\n" 71 | " -h print this message\n" 72 | " -e on/off enable/disable CSI collection (0 = disable, default is 1)\n" 73 | " -c chanspec Channel specification /\n" 74 | " -C coremask bitmask with cores where to activate capture\n" 75 | " (e.g., 0x5 = 0b0101 set core 0 and 2)\n" 76 | " -N nssmask bitmask with spatial streams to capture\n" 77 | " (e.g., 0x7 = 0b0111 capture first 3 ss)\n" 78 | " -m addr filter on this source mac address (up to four, comma separated)\n" 79 | " -b byte filter frames starting with byte\n" 80 | " -d delay delay in us after each CSI operation\n" 81 | " (really needed for 3x4, 4x3 and 4x4 configurations,\n" 82 | " without it is enforced automatically)\n" 83 | " -r generate raw output (no base64)\n" 84 | ""; 85 | fprintf (stdout, "%s\n", usage_str); 86 | } 87 | 88 | char base64(uint32_t val) 89 | { 90 | char ch = '/'; 91 | if (val < 26) 92 | ch = 'A' + val; 93 | else if (val < 52) 94 | ch = 'a' + (val - 26); 95 | else if (val < 62) 96 | ch = '0' + (val - 52); 97 | else if (val == 62) 98 | ch = '+'; 99 | return ch; 100 | } 101 | 102 | int main (int argc, char *argv[]) { 103 | struct csi_params p; 104 | memset (&p, 0, sizeof(p)); 105 | int c; 106 | int retval = 0; 107 | 108 | int enable = 1; 109 | int coremask = 0; 110 | int nssmask = 0; 111 | int force_delay = 0; 112 | int delay; 113 | int nmac = 0; 114 | int byte = 0; 115 | //int chanspec = 0; 116 | uint16_t chanspec = 0; 117 | char *endptr = NULL; 118 | int doraw = 0; 119 | 120 | if(argc < 2) { 121 | usage (); 122 | goto finish; 123 | } 124 | 125 | while ((c = getopt(argc, argv, "hre:m:b:c:C:N:d:")) != EOF) { 126 | switch (c) { 127 | case 'h': 128 | usage (); 129 | goto finish; 130 | 131 | case 'r': 132 | doraw = 1; 133 | break; 134 | 135 | case 'e': 136 | enable = (int) strtol (optarg, &endptr, 0); 137 | if (*endptr != 0) { 138 | fprintf (stderr, "Invalid enable value\n"); 139 | goto finish_error; 140 | } 141 | break; 142 | 143 | case 'm': 144 | { 145 | char *split; 146 | split = strtok(optarg, ","); 147 | struct ether_addr *ea; 148 | while (split != NULL) { 149 | if (nmac >= MAX_MAC_ADDRESS) { 150 | fprintf (stderr, "Only %d mac addresses can be given\n", MAX_MAC_ADDRESS); 151 | goto finish_error; 152 | } 153 | 154 | ea = ether_aton (split); 155 | if (ea == NULL) { 156 | fprintf (stderr, "Invalid mac address\n"); 157 | goto finish_error; 158 | } 159 | 160 | // assuming mac addresses are packed 161 | memcpy (((void *) &p.cmp_src_mac_0_0) + nmac * 6, 162 | ea->ether_addr_octet /* ea->octet */, 6); 163 | nmac ++; 164 | st16le(nmac, &p.n_mac_addr); 165 | split = strtok(NULL, ","); 166 | } 167 | break; 168 | } 169 | 170 | case 'b': 171 | byte = strtol (optarg, &endptr, 0); 172 | if (*endptr != 0 || byte < 0 || byte > 255) { 173 | fprintf (stderr, "Invalid byte filter\n"); 174 | goto finish_error; 175 | } 176 | p.use_pkt_filter = 0x01; 177 | p.first_pkt_byte = (uint8_t) byte; 178 | break; 179 | 180 | case 'c': 181 | //chanspec = strtol (optarg, &endptr, 0); 182 | //if (*endptr != 0) { 183 | // fprintf (stderr, "Invalid chanspec string\n"); 184 | // goto finish_error; 185 | //} 186 | // 187 | //st16le ((uint16_t) chanspec, &p.chanspec); 188 | chanspec = wf_chspec_aton(optarg); 189 | if (chanspec == 0) { 190 | fprintf (stderr, "Invalid chanspec\n"); 191 | goto finish_error; 192 | } 193 | p.chanspec = chanspec; 194 | break; 195 | 196 | case 'C': 197 | coremask = (int) strtol (optarg, &endptr, 0); 198 | if (*endptr != 0 || (coremask & ~VALID_CORE_MASK)) { 199 | fprintf (stderr, "Invalid core mask\n"); 200 | goto finish_error; 201 | } 202 | p.core_nss_mask = (p.core_nss_mask & 0xf0) | coremask; 203 | //fprintf (stdout, "mask core: %04x\n", p.core_nss_mask); 204 | break; 205 | 206 | case 'N': 207 | nssmask = (int) strtol (optarg, &endptr, 0); 208 | if (*endptr != 0 || (nssmask & ~VALID_NSS_MASK)) { 209 | fprintf (stderr, "Invalid nss mask\n"); 210 | goto finish_error; 211 | } 212 | p.core_nss_mask = (p.core_nss_mask & 0x0f) | (nssmask << 4); 213 | //fprintf (stdout, "mask nss: %04x\n", p.core_nss_mask); 214 | break; 215 | 216 | case 'd': 217 | delay = (int) strtol (optarg, &endptr, 0); 218 | if (*endptr != 0 || delay < 0) { 219 | fprintf (stderr, "Invalid delay\n"); 220 | goto finish_error; 221 | } 222 | force_delay = 1; 223 | st16le(delay, &p.delay); 224 | break; 225 | 226 | default: 227 | fprintf (stderr, "Invalid option\n"); 228 | goto finish_error; 229 | } 230 | } 231 | 232 | p.csi_collect = enable; 233 | 234 | if (enable != 0) { 235 | if (chanspec == 0) { 236 | fprintf (stderr, "No channel given\n"); 237 | goto finish_error; 238 | } 239 | 240 | if (nssmask == 0 || coremask == 0) { 241 | fprintf (stderr, "No nssmask and/or coremask given\n"); 242 | goto finish_error; 243 | } 244 | } 245 | 246 | if (force_delay == 0) { 247 | int csi_to_capture = countbit (nssmask) * countbit (coremask); 248 | if (csi_to_capture >= 12) { 249 | delay = DEFAULT_DELAY_US; 250 | st16le(delay, &p.delay); 251 | } 252 | } 253 | 254 | uint8_t *base64p = (uint8_t *) &p; 255 | 256 | if (doraw) { 257 | fwrite (base64p, sizeof(p), 1, stdout); 258 | goto finish; 259 | } 260 | 261 | int jj, kk; 262 | int len = sizeof(p); 263 | for (jj = 0; jj < len; jj += 3) { 264 | uint32_t val = 0; 265 | int parts = (len - jj); 266 | if (parts >= 3) { 267 | parts = 3; 268 | val = base64p[jj + 0] << 16 | base64p[jj + 1] << 8 | base64p[jj + 2]; 269 | } 270 | else { 271 | for (kk = 0; kk < parts; kk ++) { 272 | val |= (base64p[jj + kk] << (8 * (2 - kk))); 273 | } 274 | } 275 | int bits = parts * 8; 276 | for (kk = 0; kk < 24; kk += 6) { 277 | uint32_t ch = (val >> 18) & 0x3f; 278 | if (kk > bits) fprintf (stdout, "="); 279 | else fprintf (stdout, "%c", base64(ch)); 280 | val = val << 6; 281 | } 282 | } 283 | fprintf (stdout, "\n"); 284 | goto finish; 285 | 286 | finish_error: 287 | retval = 1; 288 | 289 | finish: 290 | return 0; 291 | } 292 | // printf ${string} | xxd -r -p | base64 293 | -------------------------------------------------------------------------------- /csi_reader.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import io 4 | import struct 5 | import ctypes 6 | import dpkt 7 | import numpy as np 8 | import paramiko 9 | import time 10 | from csi_params import * 11 | 12 | _LIB = ctypes.CDLL(os.path.dirname(os.path.abspath(__file__)) + 13 | '/unpack_float_py.so') 14 | _C_UNPACK_FLOAT = _LIB.unpack_float_acphy 15 | _C_UNPACK_FLOAT.argtypes = [ 16 | ctypes.c_int, # int nbits 17 | ctypes.c_int, # int autoscale 18 | ctypes.c_int, # int shft 19 | ctypes.c_int, # int fmt 20 | ctypes.c_int, # int nman 21 | ctypes.c_int, # int nexp 22 | ctypes.c_int, # int nfft 23 | ctypes.POINTER(ctypes.c_uint32), # uint32_t* H 24 | ctypes.POINTER(ctypes.c_uint32) # uint32_t* Hout 25 | ] 26 | _C_UNPACK_FLOAT.restype = None 27 | 28 | def unpack_csi(payload, chip): 29 | """Unpacks a raw CSI packet. 30 | 31 | Args: 32 | payload: Raw packet data to unpack. 33 | chip: Monitor chip. 34 | 35 | Returns: 36 | Unpacked packet data as dict. 37 | 'src_mac' - Source MAC address of frame. 38 | 'seq_num' - Sequence numbe of frame. 39 | 'core' - Antenna number. 40 | 'stream' - Spatial stream. 41 | 'chan_spec'- Channel spec. 42 | 'chip_ver' - Chip version. 43 | 'rssi' - RSSI value. 44 | 45 | """ 46 | unpacked_csi = {} 47 | 48 | if chip == '4366c0': 49 | header_fmt = '> 8) & 0x7) # uint16 59 | unpacked_csi['stream'] = ((unpacked[8] >> 11) & 0x7) # uint16 60 | unpacked_csi['chan_spec'] = unpacked[9] # uint16 61 | unpacked_csi['chip_ver'] = unpacked[10] # uint16 62 | unpacked_csi['rssi'] = unpacked[11] # int16 63 | 64 | data = unpacked[12:] # uint32[BW*3.2] 65 | H = (ctypes.c_uint32*len(data))(*data) 66 | Hout = (ctypes.c_uint32*(2*len(data)))() 67 | _C_UNPACK_FLOAT(10, 1, 0, 1, 12, 6, len(data), H, Hout) 68 | 69 | # Scale CSI by RSSI factor. 70 | data = np.fft.fftshift(np.frombuffer(Hout, dtype=np.int32).astype(np.float32).view(np.complex64)) 71 | data_subc = data[data_bins[nfft]] 72 | # scale_factor = np.sqrt((unpacked_csi["rssi"]+100)/np.sum(np.vdot(data_subc,data_subc))) 73 | scale_factor = np.power(10, unpacked_csi['rssi']/20)/np.sqrt(np.sum(np.vdot(data_subc,data_subc)))*1000 # times 1000 to scale it into roughly 0~3 74 | 75 | unpacked_csi['data'] = data*scale_factor 76 | 77 | elif chip == '4358': 78 | header_fmt = '> 8) & 0x7) # uint16 88 | unpacked_csi['stream'] = ((unpacked[8] >> 11) & 0x7) # uint16 89 | unpacked_csi['chan_spec'] = unpacked[9] # uint16 90 | unpacked_csi['chip_ver'] = unpacked[10] # uint16 91 | 92 | data = unpacked[11:] # uint32[BW*3.2] 93 | H = (ctypes.c_uint32*len(data))(*data) 94 | Hout = (ctypes.c_uint32*(2*len(data)))() 95 | _C_UNPACK_FLOAT(10, 1, 0, 1, 9, 5, len(data), H, Hout) 96 | 97 | unpacked_csi['data'] = \ 98 | np.fft.fftshift(np.frombuffer(Hout, dtype=np.int32).astype(np.float32).view(np.complex64)) 99 | 100 | elif chip == '43455c0' or chip == '4339': 101 | header_fmt = '> 8) & 0x7) # uint16 111 | unpacked_csi['stream'] = ((unpacked[8] >> 11) & 0x7) # uint16 112 | unpacked_csi['chan_spec'] = unpacked[9] # uint16 113 | unpacked_csi['chip_ver'] = unpacked[10] # uint16 114 | data = unpacked[11:] # uint16[2*BW*3.2] 115 | 116 | unpacked_csi['data'] = \ 117 | np.fft.fftshift(np.array(data,dtype=np.int16).astype(np.float32).view(np.complex64)) 118 | 119 | else: 120 | raise ValueError('Invalid chip.') 121 | 122 | return unpacked_csi 123 | 124 | class CSIMonitor: 125 | def __init__(self, monitor_ip, monitor_user, monitor_pwd, 126 | chip, chan_spec, core_mask, stream_mask, clients): 127 | """Interface to Nexmon CSI collection device. 128 | 129 | Args: 130 | monitor_ip: IP address of monitor. 131 | monitor_user: SSH username of monitor. 132 | monitor_pwd: SSH password of monitor. 133 | chip: Chip of monitor. 134 | chan_spec: Chanspec (channel + bandwidth). 135 | core_mask: Cores (antennas). 136 | stream_mask: Spatial streams. 137 | clients: List of client MAC addresses to filter by. 138 | """ 139 | 140 | self.monitor_ip = monitor_ip 141 | self.monitor_user = monitor_user 142 | self.monitor_pwd = monitor_pwd 143 | self.chip = chip 144 | self.chan_spec = chan_spec 145 | self.core_mask = core_mask 146 | self.cores = get_bitmask_positions(self.core_mask) 147 | self.stream_mask = stream_mask 148 | self.streams = get_bitmask_positions(self.stream_mask) 149 | self.clients = clients 150 | self.csi_params = get_csi_params(chan_spec, core_mask, stream_mask, clients) 151 | 152 | self.ssh = paramiko.SSHClient() 153 | self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 154 | self.ssh.connect(monitor_ip, username=monitor_user, password=monitor_pwd) 155 | 156 | if self.chip == '43455c0': 157 | self.ssh.exec_command('modprobe -r brcmfmac') 158 | time.sleep(1) 159 | self.ssh.exec_command('modprobe brcmfmac') 160 | time.sleep(1) 161 | self.ssh.exec_command('ifconfig wlan0 up') 162 | self.ssh.exec_command('nexutil -Iwlan0 -s500 -b -l34 -v' + self.csi_params) 163 | self.ssh.exec_command('nexutil -m1') 164 | 165 | elif chip == '4358': 166 | self.ssh.exec_command('ifconfig wlan0 up') 167 | self.ssh.exec_command('nexutil -Iwlan0 -s500 -b -l34 -v' + self.csi_params) 168 | self.ssh.exec_command('nexutil -m1') 169 | 170 | elif chip == '4366c0': 171 | self.ssh.exec_command('/sbin/rmmod dhd.ko') 172 | time.sleep(1) 173 | print('rmmod dhd.ko') 174 | self.ssh.exec_command('/sbin/insmod /jffs/dhd.ko') 175 | time.sleep(3) 176 | print('insmod dhd.ko') 177 | self.ssh.exec_command('wl -i eth6 up') 178 | self.ssh.exec_command('wl -i eth6 radio on') 179 | self.ssh.exec_command('wl -i eth6 country US') 180 | self.ssh.exec_command('ifconfig eth6 up') 181 | time.sleep(3) 182 | print('eth6 up') 183 | self.ssh.exec_command('/jffs/nexutil -Ieth6 -s500 -b -l34 -v' + self.csi_params) 184 | time.sleep(1) 185 | print('nexutil configured') 186 | self.ssh.exec_command('/usr/sbin/wl -i eth6 monitor 1') 187 | 188 | _,stdout,_ = self.ssh.exec_command('/jffs/nexutil -Ieth6 -k') 189 | print('/jffs/nexutil -Ieth6 -k', stdout.read()) 190 | _,stdout,_ = self.ssh.exec_command('/jffs/nexutil -Ieth6 -m') 191 | print('/jffs/nexutil -Ieth6 -m', stdout.read()) 192 | 193 | else: 194 | raise ValueError('Invalid chip.') 195 | 196 | def dump_pcap(self, n_frames): 197 | """Retrieves n_frames of CSI data. 198 | 199 | Args: 200 | n_frames: Number of CSI frames to extract. 201 | 202 | Returns: 203 | n_frames of raw CSI data in .pcap format. 204 | """ 205 | 206 | if self.chip == '4366c0': 207 | cmd = '/jffs/tcpdump -i eth6 dst port 5500 -U -w - -c '\ 208 | + str(n_frames) \ 209 | + ' 2>/dev/null' 210 | elif self.chip == '43455c0' or self.chip == '4358' or self.chip == '4339': 211 | cmd = 'tcpdump -i wlan0 dst port 5500 -U -w - -c '\ 212 | + str(n_frames) \ 213 | + ' 2>/dev/null' 214 | else: 215 | raise ValueError('Invalid chip.') 216 | 217 | _,stdout,_ = self.ssh.exec_command(cmd) 218 | pcap = stdout.read() 219 | 220 | return pcap 221 | 222 | def dump_csi(self, n_samples): 223 | 224 | # Initialize counters. 225 | count = np.zeros((len(self.clients),len(self.cores),len(self.streams))) 226 | 227 | # Initialize empty lists to hold result. 228 | csi = [[[[] for _ in self.streams] for _ in self.cores] for _ in self.clients] 229 | 230 | if self.chip == '4366c0': 231 | cmd = '/jffs/tcpdump -i eth6 dst port 5500 -U -w - 2>/dev/null' 232 | else: 233 | cmd = 'tcpdump -i wlan0 dst port 5500 -U -w - 2>/dev/null' 234 | 235 | _, stdout, _ = self.ssh.exec_command(cmd) 236 | _ = stdout.read(24) # global pcap header 237 | 238 | while not np.all(count >= n_samples): 239 | packet_header = stdout.read(16) 240 | pkt_len = int.from_bytes(packet_header[12:16], 'little') 241 | packet = stdout.read(pkt_len) 242 | payload = packet[42:] 243 | unpacked_csi = unpack_csi(payload,self.chip) 244 | 245 | client_idx = self.clients.index(unpacked_csi['src_mac']) 246 | core_idx = self.cores.index(unpacked_csi['core']) 247 | stream_idx = self.streams.index(unpacked_csi['stream']) 248 | 249 | if count[client_idx,core_idx,stream_idx] >= n_samples: 250 | continue 251 | 252 | count[client_idx,core_idx,stream_idx] += 1 253 | csi[client_idx][core_idx][stream_idx].append(unpacked_csi['data']) 254 | 255 | stdout.channel.close() 256 | self.ssh.exec_command('killall tcpdump') 257 | 258 | csi = np.array(csi) 259 | return csi 260 | 261 | def monitor_csi(self, queue): 262 | """Start CSI collection on device, feeding CSI to queue. 263 | 264 | Args: 265 | queue: Multiprocessing queue to feed CSI to. 266 | """ 267 | if self.chip == '4366c0': 268 | cmd = '/jffs/tcpdump -i eth6 dst port 5500 -U -w - 2>/dev/null' 269 | else: 270 | cmd = 'tcpdump -i wlan0 dst port 5500 -U -w - 2>/dev/null' 271 | 272 | _,stdout,_ = self.ssh.exec_command(cmd) 273 | _ = stdout.read(24) # global pcap header 274 | 275 | while True: 276 | if not queue.full(): 277 | packet_header = stdout.read(16) 278 | pkt_len = int.from_bytes(packet_header[12:16], 'little') 279 | packet = stdout.read(pkt_len) 280 | payload = packet[42:] 281 | unpacked_csi = unpack_csi(payload,self.chip) 282 | queue.put(unpacked_csi) 283 | 284 | def __del__(self): 285 | if self.chip == '4366c0': 286 | self.ssh.exec_command('/jffs/nexutil -Ieth6 -m0') 287 | self.ssh.close() 288 | else: 289 | self.ssh.exec_command('nexutil -m0') 290 | self.ssh.close() 291 | 292 | -------------------------------------------------------------------------------- /utils/makecsiparams/bcmwifi_channels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Misc utility routines for WL and Apps 3 | * This header file housing the define and function prototype use by 4 | * both the wl driver, tools & Apps. 5 | * 6 | * Copyright (C) 1999-2013, Broadcom Corporation 7 | * 8 | * Unless you and Broadcom execute a separate written software license 9 | * agreement governing use of this software, this software is licensed to you 10 | * under the terms of the GNU General Public License version 2 (the "GPL"), 11 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the 12 | * following added to such license: 13 | * 14 | * As a special exception, the copyright holders of this software give you 15 | * permission to link this software with independent modules, and to copy and 16 | * distribute the resulting executable under terms of your choice, provided that 17 | * you also meet, for each linked independent module, the terms and conditions of 18 | * the license of that module. An independent module is a module which is not 19 | * derived from this software. The special exception does not apply to any 20 | * modifications of the software. 21 | * 22 | * Notwithstanding the above, under no circumstances may you combine this 23 | * software in any way with any other Broadcom software provided under a license 24 | * other than the GPL, without Broadcom's express prior written consent. 25 | * 26 | * $Id: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $ 27 | */ 28 | 29 | #include "types.h" 30 | 31 | #ifndef _bcmwifi_channels_h_ 32 | #define _bcmwifi_channels_h_ 33 | 34 | 35 | /* A chanspec holds the channel number, band, bandwidth and control sideband */ 36 | typedef uint16 chanspec_t; 37 | 38 | /* channel defines */ 39 | #define CH_UPPER_SB 0x01 40 | #define CH_LOWER_SB 0x02 41 | #define CH_EWA_VALID 0x04 42 | #define CH_80MHZ_APART 16 43 | #define CH_40MHZ_APART 8 44 | #define CH_20MHZ_APART 4 45 | #define CH_10MHZ_APART 2 46 | #define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ 47 | #define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ 48 | #define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216, 49 | * this is that + 1 rounded up to a multiple of NBBY (8). 50 | * DO NOT MAKE it > 255: channels are uint8's all over 51 | */ 52 | #define CHSPEC_CTLOVLP(sp1, sp2, sep) (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < \ 53 | (sep)) 54 | 55 | /* All builds use the new 11ac ratespec/chanspec */ 56 | #undef D11AC_IOTYPES 57 | #define D11AC_IOTYPES 58 | 59 | #ifndef D11AC_IOTYPES 60 | 61 | #define WL_CHANSPEC_CHAN_MASK 0x00ff 62 | #define WL_CHANSPEC_CHAN_SHIFT 0 63 | 64 | #define WL_CHANSPEC_CTL_SB_MASK 0x0300 65 | #define WL_CHANSPEC_CTL_SB_SHIFT 8 66 | #define WL_CHANSPEC_CTL_SB_LOWER 0x0100 67 | #define WL_CHANSPEC_CTL_SB_UPPER 0x0200 68 | #define WL_CHANSPEC_CTL_SB_NONE 0x0300 69 | 70 | #define WL_CHANSPEC_BW_MASK 0x0C00 71 | #define WL_CHANSPEC_BW_SHIFT 10 72 | #define WL_CHANSPEC_BW_10 0x0400 73 | #define WL_CHANSPEC_BW_20 0x0800 74 | #define WL_CHANSPEC_BW_40 0x0C00 75 | 76 | #define WL_CHANSPEC_BAND_MASK 0xf000 77 | #define WL_CHANSPEC_BAND_SHIFT 12 78 | #ifdef WL_CHANSPEC_BAND_5G 79 | #undef WL_CHANSPEC_BAND_5G 80 | #endif 81 | #ifdef WL_CHANSPEC_BAND_2G 82 | #undef WL_CHANSPEC_BAND_2G 83 | #endif 84 | #define WL_CHANSPEC_BAND_5G 0x1000 85 | #define WL_CHANSPEC_BAND_2G 0x2000 86 | #define INVCHANSPEC 255 87 | 88 | /* channel defines */ 89 | #define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0) 90 | #define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ 91 | ((channel) + CH_10MHZ_APART) : 0) 92 | 93 | #define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) 94 | #define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ 95 | ((channel) + 3 * CH_10MHZ_APART) : 0) 96 | #define LU_20_SB(channel) LOWER_20_SB(channel) 97 | #define UL_20_SB(channel) UPPER_20_SB(channel) 98 | 99 | #define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) 100 | #define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ 101 | WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ 102 | WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) 103 | #define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ 104 | ((channel) + CH_20MHZ_APART) : 0) 105 | #define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ 106 | ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ 107 | ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ 108 | WL_CHANSPEC_BAND_5G)) 109 | #define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) 110 | #define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) 111 | 112 | /* chanspec stores radio channel & flags to indicate control channel location, i.e. upper/lower */ 113 | #define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) 114 | #define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) 115 | 116 | #ifdef WL11N_20MHZONLY 117 | 118 | #define CHSPEC_IS10(chspec) 0 119 | #define CHSPEC_IS20(chspec) 1 120 | #ifndef CHSPEC_IS40 121 | #define CHSPEC_IS40(chspec) 0 122 | #endif 123 | 124 | #else /* !WL11N_20MHZONLY */ 125 | 126 | #define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) 127 | #define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) 128 | #ifndef CHSPEC_IS40 129 | #define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) 130 | #endif 131 | 132 | #endif /* !WL11N_20MHZONLY */ 133 | 134 | #define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) 135 | #define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) 136 | #define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) 137 | #define CHSPEC_SB_UPPER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) 138 | #define CHSPEC_SB_LOWER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) 139 | #define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \ 140 | (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ 141 | (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK)))) 142 | #define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) 143 | 144 | #define CHANSPEC_STR_LEN 8 145 | 146 | #else /* D11AC_IOTYPES */ 147 | 148 | #define WL_CHANSPEC_CHAN_MASK 0x00ff 149 | #define WL_CHANSPEC_CHAN_SHIFT 0 150 | #define WL_CHANSPEC_CHAN1_MASK 0x000f 151 | #define WL_CHANSPEC_CHAN1_SHIFT 0 152 | #define WL_CHANSPEC_CHAN2_MASK 0x00f0 153 | #define WL_CHANSPEC_CHAN2_SHIFT 4 154 | 155 | #define WL_CHANSPEC_CTL_SB_MASK 0x0700 156 | #define WL_CHANSPEC_CTL_SB_SHIFT 8 157 | #define WL_CHANSPEC_CTL_SB_LLL 0x0000 158 | #define WL_CHANSPEC_CTL_SB_LLU 0x0100 159 | #define WL_CHANSPEC_CTL_SB_LUL 0x0200 160 | #define WL_CHANSPEC_CTL_SB_LUU 0x0300 161 | #define WL_CHANSPEC_CTL_SB_ULL 0x0400 162 | #define WL_CHANSPEC_CTL_SB_ULU 0x0500 163 | #define WL_CHANSPEC_CTL_SB_UUL 0x0600 164 | #define WL_CHANSPEC_CTL_SB_UUU 0x0700 165 | #define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL 166 | #define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU 167 | #define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL 168 | #define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU 169 | #define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL 170 | #define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU 171 | #define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL 172 | #define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU 173 | 174 | #define WL_CHANSPEC_BW_MASK 0x3800 175 | #define WL_CHANSPEC_BW_SHIFT 11 176 | #define WL_CHANSPEC_BW_5 0x0000 177 | #define WL_CHANSPEC_BW_10 0x0800 178 | #define WL_CHANSPEC_BW_20 0x1000 179 | #define WL_CHANSPEC_BW_40 0x1800 180 | #define WL_CHANSPEC_BW_80 0x2000 181 | #define WL_CHANSPEC_BW_160 0x2800 182 | #define WL_CHANSPEC_BW_8080 0x3000 183 | 184 | #define WL_CHANSPEC_BAND_MASK 0xc000 185 | #define WL_CHANSPEC_BAND_SHIFT 14 186 | #define WL_CHANSPEC_BAND_2G 0x0000 187 | #define WL_CHANSPEC_BAND_3G 0x4000 188 | #define WL_CHANSPEC_BAND_4G 0x8000 189 | #define WL_CHANSPEC_BAND_5G 0xc000 190 | #define INVCHANSPEC 255 191 | 192 | /* channel defines */ 193 | #define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ 194 | ((channel) - CH_10MHZ_APART) : 0) 195 | #define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ 196 | ((channel) + CH_10MHZ_APART) : 0) 197 | 198 | #define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) 199 | #define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ 200 | ((channel) + 3 * CH_10MHZ_APART) : 0) 201 | #define LU_20_SB(channel) LOWER_20_SB(channel) 202 | #define UL_20_SB(channel) UPPER_20_SB(channel) 203 | 204 | #define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) 205 | #define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) 206 | #define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) 207 | #define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ 208 | (((channel) <= CH_MAX_2G_CHANNEL) ? \ 209 | WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) 210 | #define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ 211 | ((channel) + CH_20MHZ_APART) : 0) 212 | #define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ 213 | ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ 214 | ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ 215 | WL_CHANSPEC_BAND_5G)) 216 | #define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ 217 | ((channel) | (ctlsb) | \ 218 | WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) 219 | #define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ 220 | ((channel) | (ctlsb) | \ 221 | WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) 222 | 223 | /* simple MACROs to get different fields of chanspec */ 224 | #define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) 225 | #define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) 226 | #define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) 227 | #define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) 228 | #define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) 229 | #define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) 230 | 231 | #ifdef WL11N_20MHZONLY 232 | 233 | #define CHSPEC_IS10(chspec) 0 234 | #define CHSPEC_IS20(chspec) 1 235 | #ifndef CHSPEC_IS40 236 | #define CHSPEC_IS40(chspec) 0 237 | #endif 238 | #ifndef CHSPEC_IS80 239 | #define CHSPEC_IS80(chspec) 0 240 | #endif 241 | #ifndef CHSPEC_IS160 242 | #define CHSPEC_IS160(chspec) 0 243 | #endif 244 | #ifndef CHSPEC_IS8080 245 | #define CHSPEC_IS8080(chspec) 0 246 | #endif 247 | 248 | #else /* !WL11N_20MHZONLY */ 249 | 250 | #define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) 251 | #define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) 252 | #ifndef CHSPEC_IS40 253 | #define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) 254 | #endif 255 | #ifndef CHSPEC_IS80 256 | #define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) 257 | #endif 258 | #ifndef CHSPEC_IS160 259 | #define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) 260 | #endif 261 | #ifndef CHSPEC_IS8080 262 | #define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) 263 | #endif 264 | 265 | #endif /* !WL11N_20MHZONLY */ 266 | 267 | #define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) 268 | #define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) 269 | #define CHSPEC_SB_UPPER(chspec) \ 270 | ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ 271 | (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) 272 | #define CHSPEC_SB_LOWER(chspec) \ 273 | ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ 274 | (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) 275 | #define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) 276 | 277 | /** 278 | * Number of chars needed for wf_chspec_ntoa() destination character buffer. 279 | */ 280 | #define CHANSPEC_STR_LEN 20 281 | 282 | 283 | /* Legacy Chanspec defines 284 | * These are the defines for the previous format of the chanspec_t 285 | */ 286 | #define WL_LCHANSPEC_CHAN_MASK 0x00ff 287 | #define WL_LCHANSPEC_CHAN_SHIFT 0 288 | 289 | #define WL_LCHANSPEC_CTL_SB_MASK 0x0300 290 | #define WL_LCHANSPEC_CTL_SB_SHIFT 8 291 | #define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 292 | #define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 293 | #define WL_LCHANSPEC_CTL_SB_NONE 0x0300 294 | 295 | #define WL_LCHANSPEC_BW_MASK 0x0C00 296 | #define WL_LCHANSPEC_BW_SHIFT 10 297 | #define WL_LCHANSPEC_BW_10 0x0400 298 | #define WL_LCHANSPEC_BW_20 0x0800 299 | #define WL_LCHANSPEC_BW_40 0x0C00 300 | 301 | #define WL_LCHANSPEC_BAND_MASK 0xf000 302 | #define WL_LCHANSPEC_BAND_SHIFT 12 303 | #define WL_LCHANSPEC_BAND_5G 0x1000 304 | #define WL_LCHANSPEC_BAND_2G 0x2000 305 | 306 | #define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) 307 | #define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) 308 | #define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) 309 | #define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) 310 | #define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) 311 | #define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) 312 | #define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) 313 | #define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) 314 | #define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) 315 | 316 | #define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) 317 | 318 | #define CH20MHZ_LCHSPEC(channel) \ 319 | (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ 320 | WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ 321 | WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) 322 | 323 | #endif /* D11AC_IOTYPES */ 324 | 325 | /* 326 | * WF_CHAN_FACTOR_* constants are used to calculate channel frequency 327 | * given a channel number. 328 | * chan_freq = chan_factor * 500Mhz + chan_number * 5 329 | */ 330 | 331 | /** 332 | * Channel Factor for the starting frequence of 2.4 GHz channels. 333 | * The value corresponds to 2407 MHz. 334 | */ 335 | #define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ 336 | 337 | /** 338 | * Channel Factor for the starting frequence of 5 GHz channels. 339 | * The value corresponds to 5000 MHz. 340 | */ 341 | #define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ 342 | 343 | /** 344 | * Channel Factor for the starting frequence of 4.9 GHz channels. 345 | * The value corresponds to 4000 MHz. 346 | */ 347 | #define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ 348 | 349 | #define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ 350 | 351 | /** 352 | * Convert chanspec to ascii string 353 | * 354 | * @param chspec chanspec format 355 | * @param buf ascii string of chanspec 356 | * 357 | * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes 358 | * 359 | * @see CHANSPEC_STR_LEN 360 | */ 361 | extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); 362 | 363 | /** 364 | * Convert ascii string to chanspec 365 | * 366 | * @param a pointer to input string 367 | * 368 | * @return >= 0 if successful or 0 otherwise 369 | */ 370 | extern chanspec_t wf_chspec_aton(const char *a); 371 | 372 | /** 373 | * Verify the chanspec fields are valid. 374 | * 375 | * Verify the chanspec is using a legal set field values, i.e. that the chanspec 376 | * specified a band, bw, ctl_sb and channel and that the combination could be 377 | * legal given some set of circumstances. 378 | * 379 | * @param chanspec input chanspec to verify 380 | * 381 | * @return TRUE if the chanspec is malformed, FALSE if it looks good. 382 | */ 383 | extern bool wf_chspec_malformed(chanspec_t chanspec); 384 | 385 | /** 386 | * Verify the chanspec specifies a valid channel according to 802.11. 387 | * 388 | * @param chanspec input chanspec to verify 389 | * 390 | * @return TRUE if the chanspec is a valid 802.11 channel 391 | */ 392 | extern bool wf_chspec_valid(chanspec_t chanspec); 393 | 394 | /** 395 | * Return the primary (control) channel. 396 | * 397 | * This function returns the channel number of the primary 20MHz channel. For 398 | * 20MHz channels this is just the channel number. For 40MHz or wider channels 399 | * it is the primary 20MHz channel specified by the chanspec. 400 | * 401 | * @param chspec input chanspec 402 | * 403 | * @return Returns the channel number of the primary 20MHz channel 404 | */ 405 | extern uint8 wf_chspec_ctlchan(chanspec_t chspec); 406 | 407 | /** 408 | * Return the primary (control) chanspec. 409 | * 410 | * This function returns the chanspec of the primary 20MHz channel. For 20MHz 411 | * channels this is just the chanspec. For 40MHz or wider channels it is the 412 | * chanspec of the primary 20MHZ channel specified by the chanspec. 413 | * 414 | * @param chspec input chanspec 415 | * 416 | * @return Returns the chanspec of the primary 20MHz channel 417 | */ 418 | extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); 419 | 420 | /** 421 | * Return a channel number corresponding to a frequency. 422 | * 423 | * This function returns the chanspec for the primary 40MHz of an 80MHz channel. 424 | * The control sideband specifies the same 20MHz channel that the 80MHz channel is using 425 | * as the primary 20MHz channel. 426 | */ 427 | extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); 428 | 429 | /* 430 | * Return the channel number for a given frequency and base frequency. 431 | * The returned channel number is relative to the given base frequency. 432 | * If the given base frequency is zero, a base frequency of 5 GHz is assumed for 433 | * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. 434 | * 435 | * Frequency is specified in MHz. 436 | * The base frequency is specified as (start_factor * 500 kHz). 437 | * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for 438 | * 2.4 GHz and 5 GHz bands. 439 | * 440 | * The returned channel will be in the range [1, 14] in the 2.4 GHz band 441 | * and [0, 200] otherwise. 442 | * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the 443 | * frequency is not a 2.4 GHz channel, or if the frequency is not and even 444 | * multiple of 5 MHz from the base frequency to the base plus 1 GHz. 445 | * 446 | * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 447 | * 448 | * @param freq frequency in MHz 449 | * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz 450 | * 451 | * @return Returns a channel number 452 | * 453 | * @see WF_CHAN_FACTOR_2_4_G 454 | * @see WF_CHAN_FACTOR_5_G 455 | */ 456 | extern int wf_mhz2channel(uint freq, uint start_factor); 457 | 458 | /** 459 | * Return the center frequency in MHz of the given channel and base frequency. 460 | * 461 | * Return the center frequency in MHz of the given channel and base frequency. 462 | * The channel number is interpreted relative to the given base frequency. 463 | * 464 | * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. 465 | * The base frequency is specified as (start_factor * 500 kHz). 466 | * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for 467 | * 2.4 GHz and 5 GHz bands. 468 | * The channel range of [1, 14] is only checked for a start_factor of 469 | * WF_CHAN_FACTOR_2_4_G (4814). 470 | * Odd start_factors produce channels on .5 MHz boundaries, in which case 471 | * the answer is rounded down to an integral MHz. 472 | * -1 is returned for an out of range channel. 473 | * 474 | * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 475 | * 476 | * @param channel input channel number 477 | * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz 478 | * 479 | * @return Returns a frequency in MHz 480 | * 481 | * @see WF_CHAN_FACTOR_2_4_G 482 | * @see WF_CHAN_FACTOR_5_G 483 | */ 484 | extern int wf_channel2mhz(uint channel, uint start_factor); 485 | 486 | /** 487 | * Convert ctl chan and bw to chanspec 488 | * 489 | * @param ctl_ch channel 490 | * @param bw bandwidth 491 | * 492 | * @return > 0 if successful or 0 otherwise 493 | * 494 | */ 495 | extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); 496 | 497 | extern uint wf_channel2freq(uint channel); 498 | extern uint wf_freq2channel(uint freq); 499 | 500 | 501 | #endif /* _bcmwifi_channels_h_ */ 502 | -------------------------------------------------------------------------------- /utils/makecsiparams/bcmutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Misc useful os-independent macros and functions. 3 | * 4 | * Copyright (C) 1999-2013, Broadcom Corporation 5 | * 6 | * Unless you and Broadcom execute a separate written software license 7 | * agreement governing use of this software, this software is licensed to you 8 | * under the terms of the GNU General Public License version 2 (the "GPL"), 9 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 | * following added to such license: 11 | * 12 | * As a special exception, the copyright holders of this software give you 13 | * permission to link this software with independent modules, and to copy and 14 | * distribute the resulting executable under terms of your choice, provided that 15 | * you also meet, for each linked independent module, the terms and conditions of 16 | * the license of that module. An independent module is a module which is not 17 | * derived from this software. The special exception does not apply to any 18 | * modifications of the software. 19 | * 20 | * Notwithstanding the above, under no circumstances may you combine this 21 | * software in any way with any other Broadcom software provided under a license 22 | * other than the GPL, without Broadcom's express prior written consent. 23 | * 24 | * $Id: bcmutils.h 412804 2013-07-16 16:26:39Z $ 25 | */ 26 | 27 | #ifndef _bcmutils_h_ 28 | #define _bcmutils_h_ 29 | 30 | #define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src)) 31 | #define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count)) 32 | #define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src)) 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #ifdef PKTQ_LOG 39 | #include 40 | #endif 41 | 42 | /* ctype replacement */ 43 | #define _BCM_U 0x01 /* upper */ 44 | #define _BCM_L 0x02 /* lower */ 45 | #define _BCM_D 0x04 /* digit */ 46 | #define _BCM_C 0x08 /* cntrl */ 47 | #define _BCM_P 0x10 /* punct */ 48 | #define _BCM_S 0x20 /* white space (space/lf/tab) */ 49 | #define _BCM_X 0x40 /* hex digit */ 50 | #define _BCM_SP 0x80 /* hard space (0x20) */ 51 | 52 | extern const unsigned char bcm_ctype[]; 53 | #define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)]) 54 | 55 | #define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0) 56 | #define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0) 57 | #define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0) 58 | #define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0) 59 | #define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0) 60 | #define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0) 61 | #define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0) 62 | #define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0) 63 | #define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0) 64 | #define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0) 65 | #define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0) 66 | #define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) 67 | #define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c)) 68 | 69 | /* Buffer structure for collecting string-formatted data 70 | * using bcm_bprintf() API. 71 | * Use bcm_binit() to initialize before use 72 | */ 73 | 74 | struct bcmstrbuf { 75 | char *buf; /* pointer to current position in origbuf */ 76 | unsigned int size; /* current (residual) size in bytes */ 77 | char *origbuf; /* unmodified pointer to orignal buffer */ 78 | unsigned int origsize; /* unmodified orignal buffer size in bytes */ 79 | }; 80 | 81 | /* ** driver-only section ** */ 82 | #ifdef BCMDRIVER 83 | #include 84 | 85 | #define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */ 86 | 87 | /* 88 | * Spin at most 'us' microseconds while 'exp' is true. 89 | * Caller should explicitly test 'exp' when this completes 90 | * and take appropriate error action if 'exp' is still true. 91 | */ 92 | #define SPINWAIT(exp, us) { \ 93 | uint countdown = (us) + 9; \ 94 | while ((exp) && (countdown >= 10)) {\ 95 | OSL_DELAY(10); \ 96 | countdown -= 10; \ 97 | } \ 98 | } 99 | 100 | /* osl multi-precedence packet queue */ 101 | #ifndef PKTQ_LEN_DEFAULT 102 | #define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ 103 | #endif 104 | #ifndef PKTQ_MAX_PREC 105 | #define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ 106 | #endif 107 | 108 | typedef struct pktq_prec { 109 | void *head; /* first packet to dequeue */ 110 | void *tail; /* last packet to dequeue */ 111 | uint16 len; /* number of queued packets */ 112 | uint16 max; /* maximum number of queued packets */ 113 | } pktq_prec_t; 114 | 115 | #ifdef PKTQ_LOG 116 | typedef struct { 117 | uint32 requested; /* packets requested to be stored */ 118 | uint32 stored; /* packets stored */ 119 | uint32 saved; /* packets saved, 120 | because a lowest priority queue has given away one packet 121 | */ 122 | uint32 selfsaved; /* packets saved, 123 | because an older packet from the same queue has been dropped 124 | */ 125 | uint32 full_dropped; /* packets dropped, 126 | because pktq is full with higher precedence packets 127 | */ 128 | uint32 dropped; /* packets dropped because pktq per that precedence is full */ 129 | uint32 sacrificed; /* packets dropped, 130 | in order to save one from a queue of a highest priority 131 | */ 132 | uint32 busy; /* packets droped because of hardware/transmission error */ 133 | uint32 retry; /* packets re-sent because they were not received */ 134 | uint32 ps_retry; /* packets retried again prior to moving power save mode */ 135 | uint32 retry_drop; /* packets finally dropped after retry limit */ 136 | uint32 max_avail; /* the high-water mark of the queue capacity for packets - 137 | goes to zero as queue fills 138 | */ 139 | uint32 max_used; /* the high-water mark of the queue utilisation for packets - 140 | increases with use ('inverse' of max_avail) 141 | */ 142 | uint32 queue_capacity; /* the maximum capacity of the queue */ 143 | uint32 rtsfail; /* count of rts attempts that failed to receive cts */ 144 | uint32 acked; /* count of packets sent (acked) successfully */ 145 | } pktq_counters_t; 146 | #endif /* PKTQ_LOG */ 147 | 148 | 149 | #define PKTQ_COMMON \ 150 | uint16 num_prec; /* number of precedences in use */ \ 151 | uint16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ \ 152 | uint16 max; /* total max packets */ \ 153 | uint16 len; /* total number of packets */ 154 | 155 | /* multi-priority pkt queue */ 156 | struct pktq { 157 | PKTQ_COMMON 158 | /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ 159 | struct pktq_prec q[PKTQ_MAX_PREC]; 160 | #ifdef PKTQ_LOG 161 | pktq_counters_t _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */ 162 | pktq_counters_t _prec_bytes[PKTQ_MAX_PREC]; /* Byte count per queue */ 163 | uint32 _logtime; /* timestamp of last counter clear */ 164 | #endif 165 | }; 166 | 167 | /* simple, non-priority pkt queue */ 168 | struct spktq { 169 | PKTQ_COMMON 170 | /* q array must be last since # of elements can be either PKTQ_MAX_PREC or 1 */ 171 | struct pktq_prec q[1]; 172 | }; 173 | 174 | #define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--) 175 | 176 | /* fn(pkt, arg). return true if pkt belongs to if */ 177 | typedef bool (*ifpkt_cb_t)(void*, int); 178 | 179 | #ifdef BCMPKTPOOL 180 | #define POOL_ENAB(pool) ((pool) && (pool)->inited) 181 | #define SHARED_POOL (pktpool_shared) 182 | #else /* BCMPKTPOOL */ 183 | #define POOL_ENAB(bus) 0 184 | #define SHARED_POOL ((struct pktpool *)NULL) 185 | #endif /* BCMPKTPOOL */ 186 | 187 | #ifndef PKTPOOL_LEN_MAX 188 | #define PKTPOOL_LEN_MAX 40 189 | #endif /* PKTPOOL_LEN_MAX */ 190 | #define PKTPOOL_CB_MAX 3 191 | 192 | struct pktpool; 193 | typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg); 194 | typedef struct { 195 | pktpool_cb_t cb; 196 | void *arg; 197 | } pktpool_cbinfo_t; 198 | 199 | #ifdef BCMDBG_POOL 200 | /* pkt pool debug states */ 201 | #define POOL_IDLE 0 202 | #define POOL_RXFILL 1 203 | #define POOL_RXDH 2 204 | #define POOL_RXD11 3 205 | #define POOL_TXDH 4 206 | #define POOL_TXD11 5 207 | #define POOL_AMPDU 6 208 | #define POOL_TXENQ 7 209 | 210 | typedef struct { 211 | void *p; 212 | uint32 cycles; 213 | uint32 dur; 214 | } pktpool_dbg_t; 215 | 216 | typedef struct { 217 | uint8 txdh; /* tx to host */ 218 | uint8 txd11; /* tx to d11 */ 219 | uint8 enq; /* waiting in q */ 220 | uint8 rxdh; /* rx from host */ 221 | uint8 rxd11; /* rx from d11 */ 222 | uint8 rxfill; /* dma_rxfill */ 223 | uint8 idle; /* avail in pool */ 224 | } pktpool_stats_t; 225 | #endif /* BCMDBG_POOL */ 226 | 227 | typedef struct pktpool { 228 | bool inited; 229 | uint16 r; 230 | uint16 w; 231 | uint16 len; 232 | uint16 maxlen; 233 | uint16 plen; 234 | bool istx; 235 | bool empty; 236 | uint8 cbtoggle; 237 | uint8 cbcnt; 238 | uint8 ecbcnt; 239 | bool emptycb_disable; 240 | pktpool_cbinfo_t *availcb_excl; 241 | pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX]; 242 | pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX]; 243 | void *q[PKTPOOL_LEN_MAX + 1]; 244 | 245 | #ifdef BCMDBG_POOL 246 | uint8 dbg_cbcnt; 247 | pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX]; 248 | uint16 dbg_qlen; 249 | pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1]; 250 | #endif 251 | } pktpool_t; 252 | 253 | extern pktpool_t *pktpool_shared; 254 | 255 | extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx); 256 | extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp); 257 | extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal); 258 | extern void* pktpool_get(pktpool_t *pktp); 259 | extern void pktpool_free(pktpool_t *pktp, void *p); 260 | extern int pktpool_add(pktpool_t *pktp, void *p); 261 | extern uint16 pktpool_avail(pktpool_t *pktp); 262 | extern int pktpool_avail_notify_normal(osl_t *osh, pktpool_t *pktp); 263 | extern int pktpool_avail_notify_exclusive(osl_t *osh, pktpool_t *pktp, pktpool_cb_t cb); 264 | extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); 265 | extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); 266 | extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); 267 | extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); 268 | extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); 269 | extern bool pktpool_emptycb_disabled(pktpool_t *pktp); 270 | 271 | #define POOLPTR(pp) ((pktpool_t *)(pp)) 272 | #define pktpool_len(pp) (POOLPTR(pp)->len - 1) 273 | #define pktpool_plen(pp) (POOLPTR(pp)->plen) 274 | #define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen) 275 | 276 | #ifdef BCMDBG_POOL 277 | extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); 278 | extern int pktpool_start_trigger(pktpool_t *pktp, void *p); 279 | extern int pktpool_dbg_dump(pktpool_t *pktp); 280 | extern int pktpool_dbg_notify(pktpool_t *pktp); 281 | extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats); 282 | #endif /* BCMDBG_POOL */ 283 | 284 | /* forward definition of ether_addr structure used by some function prototypes */ 285 | 286 | struct ether_addr; 287 | 288 | extern int ether_isbcast(const void *ea); 289 | extern int ether_isnulladdr(const void *ea); 290 | 291 | /* operations on a specific precedence in packet queue */ 292 | 293 | #define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max)) 294 | #define pktq_pmax(pq, prec) ((pq)->q[prec].max) 295 | #define pktq_plen(pq, prec) ((pq)->q[prec].len) 296 | #define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len) 297 | #define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max) 298 | #define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0) 299 | 300 | #define pktq_ppeek(pq, prec) ((pq)->q[prec].head) 301 | #define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail) 302 | 303 | extern void *pktq_penq(struct pktq *pq, int prec, void *p); 304 | extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); 305 | extern void *pktq_pdeq(struct pktq *pq, int prec); 306 | extern void *pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p); 307 | extern void *pktq_pdeq_with_fn(struct pktq *pq, int prec, ifpkt_cb_t fn, int arg); 308 | extern void *pktq_pdeq_tail(struct pktq *pq, int prec); 309 | /* Empty the queue at particular precedence level */ 310 | extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, 311 | ifpkt_cb_t fn, int arg); 312 | /* Remove a specified packet from its queue */ 313 | extern bool pktq_pdel(struct pktq *pq, void *p, int prec); 314 | 315 | /* operations on a set of precedences in packet queue */ 316 | 317 | extern int pktq_mlen(struct pktq *pq, uint prec_bmp); 318 | extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out); 319 | extern void *pktq_mpeek(struct pktq *pq, uint prec_bmp, int *prec_out); 320 | 321 | /* operations on packet queue as a whole */ 322 | 323 | #define pktq_len(pq) ((int)(pq)->len) 324 | #define pktq_max(pq) ((int)(pq)->max) 325 | #define pktq_avail(pq) ((int)((pq)->max - (pq)->len)) 326 | #define pktq_full(pq) ((pq)->len >= (pq)->max) 327 | #define pktq_empty(pq) ((pq)->len == 0) 328 | 329 | /* operations for single precedence queues */ 330 | #define pktenq(pq, p) pktq_penq(((struct pktq *)(void *)pq), 0, (p)) 331 | #define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)(void *)pq), 0, (p)) 332 | #define pktdeq(pq) pktq_pdeq(((struct pktq *)(void *)pq), 0) 333 | #define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)(void *)pq), 0) 334 | #define pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len) 335 | 336 | extern void pktq_init(struct pktq *pq, int num_prec, int max_len); 337 | extern void pktq_set_max_plen(struct pktq *pq, int prec, int max_len); 338 | 339 | /* prec_out may be NULL if caller is not interested in return value */ 340 | extern void *pktq_deq(struct pktq *pq, int *prec_out); 341 | extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); 342 | extern void *pktq_peek(struct pktq *pq, int *prec_out); 343 | extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); 344 | extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg); 345 | 346 | /* externs */ 347 | /* packet */ 348 | extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); 349 | extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); 350 | extern uint pkttotlen(osl_t *osh, void *p); 351 | extern void *pktlast(osl_t *osh, void *p); 352 | extern uint pktsegcnt(osl_t *osh, void *p); 353 | extern uint pktsegcnt_war(osl_t *osh, void *p); 354 | extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset); 355 | extern void *pktoffset(osl_t *osh, void *p, uint offset); 356 | 357 | /* Get priority from a packet and pass it back in scb (or equiv) */ 358 | #define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ 359 | #define PKTPRIO_VLAN 0x200 /* VLAN prio found */ 360 | #define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ 361 | #define PKTPRIO_DSCP 0x800 /* DSCP prio found */ 362 | 363 | /* DSCP type definitions (RFC4594) */ 364 | /* AF1x: High-Throughput Data (RFC2597) */ 365 | #define DSCP_AF11 0x0A 366 | #define DSCP_AF12 0x0C 367 | #define DSCP_AF13 0x0E 368 | /* AF2x: Low-Latency Data (RFC2597) */ 369 | #define DSCP_AF21 0x12 370 | #define DSCP_AF22 0x14 371 | #define DSCP_AF23 0x16 372 | /* AF3x: Multimedia Streaming (RFC2597) */ 373 | #define DSCP_AF31 0x1A 374 | #define DSCP_AF32 0x1C 375 | #define DSCP_AF33 0x1E 376 | /* EF: Telephony (RFC3246) */ 377 | #define DSCP_EF 0x2E 378 | 379 | extern uint pktsetprio(void *pkt, bool update_vtag); 380 | 381 | /* string */ 382 | extern int bcm_atoi(const char *s); 383 | extern ulong bcm_strtoul(const char *cp, char **endp, uint base); 384 | extern char *bcmstrstr(const char *haystack, const char *needle); 385 | extern char *bcmstrcat(char *dest, const char *src); 386 | extern char *bcmstrncat(char *dest, const char *src, uint size); 387 | extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); 388 | char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); 389 | int bcmstricmp(const char *s1, const char *s2); 390 | int bcmstrnicmp(const char* s1, const char* s2, int cnt); 391 | 392 | 393 | /* ethernet address */ 394 | extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); 395 | extern int bcm_ether_atoe(const char *p, struct ether_addr *ea); 396 | 397 | /* ip address */ 398 | struct ipv4_addr; 399 | extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); 400 | 401 | /* delay */ 402 | extern void bcm_mdelay(uint ms); 403 | /* variable access */ 404 | #define NVRAM_RECLAIM_CHECK(name) 405 | 406 | extern char *getvar(char *vars, const char *name); 407 | extern int getintvar(char *vars, const char *name); 408 | extern int getintvararray(char *vars, const char *name, int index); 409 | extern int getintvararraysize(char *vars, const char *name); 410 | extern uint getgpiopin(char *vars, char *pin_name, uint def_pin); 411 | #define bcm_perf_enable() 412 | #define bcmstats(fmt) 413 | #define bcmlog(fmt, a1, a2) 414 | #define bcmdumplog(buf, size) *buf = '\0' 415 | #define bcmdumplogent(buf, idx) -1 416 | 417 | #define bcmtslog(tstamp, fmt, a1, a2) 418 | #define bcmprinttslogs() 419 | #define bcmprinttstamp(us) 420 | #define bcmdumptslog(buf, size) 421 | 422 | extern char *bcm_nvram_vars(uint *length); 423 | extern int bcm_nvram_cache(void *sih); 424 | 425 | /* Support for sharing code across in-driver iovar implementations. 426 | * The intent is that a driver use this structure to map iovar names 427 | * to its (private) iovar identifiers, and the lookup function to 428 | * find the entry. Macros are provided to map ids and get/set actions 429 | * into a single number space for a switch statement. 430 | */ 431 | 432 | /* iovar structure */ 433 | typedef struct bcm_iovar { 434 | const char *name; /* name for lookup and display */ 435 | uint16 varid; /* id for switch */ 436 | uint16 flags; /* driver-specific flag bits */ 437 | uint16 type; /* base type of argument */ 438 | uint16 minlen; /* min length for buffer vars */ 439 | } bcm_iovar_t; 440 | 441 | /* varid definitions are per-driver, may use these get/set bits */ 442 | 443 | /* IOVar action bits for id mapping */ 444 | #define IOV_GET 0 /* Get an iovar */ 445 | #define IOV_SET 1 /* Set an iovar */ 446 | 447 | /* Varid to actionid mapping */ 448 | #define IOV_GVAL(id) ((id) * 2) 449 | #define IOV_SVAL(id) ((id) * 2 + IOV_SET) 450 | #define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET) 451 | #define IOV_ID(actionid) (actionid >> 1) 452 | 453 | /* flags are per-driver based on driver attributes */ 454 | 455 | extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); 456 | extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set); 457 | #if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \ 458 | defined(WLMSG_PRPKT) || defined(WLMSG_WSEC) 459 | extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); 460 | #endif 461 | #endif /* BCMDRIVER */ 462 | 463 | /* Base type definitions */ 464 | #define IOVT_VOID 0 /* no value (implictly set only) */ 465 | #define IOVT_BOOL 1 /* any value ok (zero/nonzero) */ 466 | #define IOVT_INT8 2 /* integer values are range-checked */ 467 | #define IOVT_UINT8 3 /* unsigned int 8 bits */ 468 | #define IOVT_INT16 4 /* int 16 bits */ 469 | #define IOVT_UINT16 5 /* unsigned int 16 bits */ 470 | #define IOVT_INT32 6 /* int 32 bits */ 471 | #define IOVT_UINT32 7 /* unsigned int 32 bits */ 472 | #define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */ 473 | #define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER) 474 | 475 | /* Initializer for IOV type strings */ 476 | #define BCM_IOV_TYPE_INIT { \ 477 | "void", \ 478 | "bool", \ 479 | "int8", \ 480 | "uint8", \ 481 | "int16", \ 482 | "uint16", \ 483 | "int32", \ 484 | "uint32", \ 485 | "buffer", \ 486 | "" } 487 | 488 | #define BCM_IOVT_IS_INT(type) (\ 489 | (type == IOVT_BOOL) || \ 490 | (type == IOVT_INT8) || \ 491 | (type == IOVT_UINT8) || \ 492 | (type == IOVT_INT16) || \ 493 | (type == IOVT_UINT16) || \ 494 | (type == IOVT_INT32) || \ 495 | (type == IOVT_UINT32)) 496 | 497 | /* ** driver/apps-shared section ** */ 498 | 499 | #define BCME_STRLEN 64 /* Max string length for BCM errors */ 500 | #define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST)) 501 | 502 | 503 | /* 504 | * error codes could be added but the defined ones shouldn't be changed/deleted 505 | * these error codes are exposed to the user code 506 | * when ever a new error code is added to this list 507 | * please update errorstring table with the related error string and 508 | * update osl files with os specific errorcode map 509 | */ 510 | 511 | #define BCME_OK 0 /* Success */ 512 | #define BCME_ERROR -1 /* Error generic */ 513 | #define BCME_BADARG -2 /* Bad Argument */ 514 | #define BCME_BADOPTION -3 /* Bad option */ 515 | #define BCME_NOTUP -4 /* Not up */ 516 | #define BCME_NOTDOWN -5 /* Not down */ 517 | #define BCME_NOTAP -6 /* Not AP */ 518 | #define BCME_NOTSTA -7 /* Not STA */ 519 | #define BCME_BADKEYIDX -8 /* BAD Key Index */ 520 | #define BCME_RADIOOFF -9 /* Radio Off */ 521 | #define BCME_NOTBANDLOCKED -10 /* Not band locked */ 522 | #define BCME_NOCLK -11 /* No Clock */ 523 | #define BCME_BADRATESET -12 /* BAD Rate valueset */ 524 | #define BCME_BADBAND -13 /* BAD Band */ 525 | #define BCME_BUFTOOSHORT -14 /* Buffer too short */ 526 | #define BCME_BUFTOOLONG -15 /* Buffer too long */ 527 | #define BCME_BUSY -16 /* Busy */ 528 | #define BCME_NOTASSOCIATED -17 /* Not Associated */ 529 | #define BCME_BADSSIDLEN -18 /* Bad SSID len */ 530 | #define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */ 531 | #define BCME_BADCHAN -20 /* Bad Channel */ 532 | #define BCME_BADADDR -21 /* Bad Address */ 533 | #define BCME_NORESOURCE -22 /* Not Enough Resources */ 534 | #define BCME_UNSUPPORTED -23 /* Unsupported */ 535 | #define BCME_BADLEN -24 /* Bad length */ 536 | #define BCME_NOTREADY -25 /* Not Ready */ 537 | #define BCME_EPERM -26 /* Not Permitted */ 538 | #define BCME_NOMEM -27 /* No Memory */ 539 | #define BCME_ASSOCIATED -28 /* Associated */ 540 | #define BCME_RANGE -29 /* Not In Range */ 541 | #define BCME_NOTFOUND -30 /* Not Found */ 542 | #define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */ 543 | #define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */ 544 | #define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */ 545 | #define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */ 546 | #define BCME_SDIO_ERROR -35 /* SDIO Bus Error */ 547 | #define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */ 548 | #define BCME_VERSION -37 /* Incorrect version */ 549 | #define BCME_TXFAIL -38 /* TX failure */ 550 | #define BCME_RXFAIL -39 /* RX failure */ 551 | #define BCME_NODEVICE -40 /* Device not present */ 552 | #define BCME_NMODE_DISABLED -41 /* NMODE disabled */ 553 | #define BCME_NONRESIDENT -42 /* access to nonresident overlay */ 554 | #define BCME_SCANREJECT -43 /* reject scan request */ 555 | #define BCME_USAGE_ERROR -44 /* WLCMD usage error */ 556 | #define BCME_IOCTL_ERROR -45 /* WLCMD ioctl error */ 557 | #define BCME_SERIAL_PORT_ERR -46 /* RWL serial port error */ 558 | #define BCME_LAST BCME_SERIAL_PORT_ERR 559 | 560 | /* These are collection of BCME Error strings */ 561 | #define BCMERRSTRINGTABLE { \ 562 | "OK", \ 563 | "Undefined error", \ 564 | "Bad Argument", \ 565 | "Bad Option", \ 566 | "Not up", \ 567 | "Not down", \ 568 | "Not AP", \ 569 | "Not STA", \ 570 | "Bad Key Index", \ 571 | "Radio Off", \ 572 | "Not band locked", \ 573 | "No clock", \ 574 | "Bad Rate valueset", \ 575 | "Bad Band", \ 576 | "Buffer too short", \ 577 | "Buffer too long", \ 578 | "Busy", \ 579 | "Not Associated", \ 580 | "Bad SSID len", \ 581 | "Out of Range Channel", \ 582 | "Bad Channel", \ 583 | "Bad Address", \ 584 | "Not Enough Resources", \ 585 | "Unsupported", \ 586 | "Bad length", \ 587 | "Not Ready", \ 588 | "Not Permitted", \ 589 | "No Memory", \ 590 | "Associated", \ 591 | "Not In Range", \ 592 | "Not Found", \ 593 | "WME Not Enabled", \ 594 | "TSPEC Not Found", \ 595 | "ACM Not Supported", \ 596 | "Not WME Association", \ 597 | "SDIO Bus Error", \ 598 | "Dongle Not Accessible", \ 599 | "Incorrect version", \ 600 | "TX Failure", \ 601 | "RX Failure", \ 602 | "Device Not Present", \ 603 | "NMODE Disabled", \ 604 | "Nonresident overlay access", \ 605 | "Scan Rejected", \ 606 | "WLCMD usage error", \ 607 | "WLCMD ioctl error", \ 608 | "RWL serial port error", \ 609 | } 610 | 611 | #ifndef ABS 612 | #define ABS(a) (((a) < 0) ? -(a) : (a)) 613 | #endif /* ABS */ 614 | 615 | #ifndef MIN 616 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 617 | #endif /* MIN */ 618 | 619 | #ifndef MAX 620 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 621 | #endif /* MAX */ 622 | 623 | /* limit to [min, max] */ 624 | #ifndef LIMIT_TO_RANGE 625 | #define LIMIT_TO_RANGE(x, min, max) \ 626 | ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) 627 | #endif /* LIMIT_TO_RANGE */ 628 | 629 | /* limit to max */ 630 | #ifndef LIMIT_TO_MAX 631 | #define LIMIT_TO_MAX(x, max) \ 632 | (((x) > (max) ? (max) : (x))) 633 | #endif /* LIMIT_TO_MAX */ 634 | 635 | /* limit to min */ 636 | #ifndef LIMIT_TO_MIN 637 | #define LIMIT_TO_MIN(x, min) \ 638 | (((x) < (min) ? (min) : (x))) 639 | #endif /* LIMIT_TO_MIN */ 640 | 641 | #define CEIL(x, y) (((x) + ((y) - 1)) / (y)) 642 | #define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) 643 | #define ISALIGNED(a, x) (((uintptr)(a) & ((x) - 1)) == 0) 644 | #define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \ 645 | & ~((boundary) - 1)) 646 | #define ALIGN_SIZE(size, boundary) (((size) + (boundary) - 1) \ 647 | & ~((boundary) - 1)) 648 | #define ISPOWEROF2(x) ((((x) - 1) & (x)) == 0) 649 | #define VALID_MASK(mask) !((mask) & ((mask) + 1)) 650 | 651 | #ifndef OFFSETOF 652 | #ifdef __ARMCC_VERSION 653 | /* 654 | * The ARM RVCT compiler complains when using OFFSETOF where a constant 655 | * expression is expected, such as an initializer for a static object. 656 | * offsetof from the runtime library doesn't have that problem. 657 | */ 658 | #include 659 | #define OFFSETOF(type, member) offsetof(type, member) 660 | #else 661 | #define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) 662 | #endif /* __ARMCC_VERSION */ 663 | #endif /* OFFSETOF */ 664 | 665 | #ifndef ARRAYSIZE 666 | #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) 667 | #endif 668 | 669 | #ifndef ARRAYLAST /* returns pointer to last array element */ 670 | #define ARRAYLAST(a) (&a[ARRAYSIZE(a)-1]) 671 | #endif 672 | 673 | /* Reference a function; used to prevent a static function from being optimized out */ 674 | extern void *_bcmutils_dummy_fn; 675 | #define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f)) 676 | 677 | /* bit map related macros */ 678 | #ifndef setbit 679 | #ifndef NBBY /* the BSD family defines NBBY */ 680 | #define NBBY 8 /* 8 bits per byte */ 681 | #endif /* #ifndef NBBY */ 682 | #ifdef BCMUTILS_BIT_MACROS_USE_FUNCS 683 | extern void setbit(void *array, uint bit); 684 | extern void clrbit(void *array, uint bit); 685 | extern bool isset(const void *array, uint bit); 686 | extern bool isclr(const void *array, uint bit); 687 | #else 688 | #define setbit(a, i) (((uint8 *)a)[(i) / NBBY] |= 1 << ((i) % NBBY)) 689 | #define clrbit(a, i) (((uint8 *)a)[(i) / NBBY] &= ~(1 << ((i) % NBBY))) 690 | #define isset(a, i) (((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) 691 | #define isclr(a, i) ((((const uint8 *)a)[(i) / NBBY] & (1 << ((i) % NBBY))) == 0) 692 | #endif 693 | #endif /* setbit */ 694 | 695 | #define isbitset(a, i) (((a) & (1 << (i))) != 0) 696 | 697 | #define NBITS(type) (sizeof(type) * 8) 698 | #define NBITVAL(nbits) (1 << (nbits)) 699 | #define MAXBITVAL(nbits) ((1 << (nbits)) - 1) 700 | #define NBITMASK(nbits) MAXBITVAL(nbits) 701 | #define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) 702 | 703 | /* basic mux operation - can be optimized on several architectures */ 704 | #define MUX(pred, true, false) ((pred) ? (true) : (false)) 705 | 706 | /* modulo inc/dec - assumes x E [0, bound - 1] */ 707 | #define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1) 708 | #define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) 709 | 710 | /* modulo inc/dec, bound = 2^k */ 711 | #define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) 712 | #define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) 713 | 714 | /* modulo add/sub - assumes x, y E [0, bound - 1] */ 715 | #define MODADD(x, y, bound) \ 716 | MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y)) 717 | #define MODSUB(x, y, bound) \ 718 | MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y)) 719 | 720 | /* module add/sub, bound = 2^k */ 721 | #define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) 722 | #define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) 723 | 724 | /* crc defines */ 725 | #define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */ 726 | #define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */ 727 | #define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ 728 | #define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ 729 | #define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */ 730 | #define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */ 731 | 732 | /* use for direct output of MAC address in printf etc */ 733 | #define MACF "%02x:%02x:%02x:%02x:%02x:%02x" 734 | #define ETHERP_TO_MACF(ea) ((struct ether_addr *) (ea))->octet[0], \ 735 | ((struct ether_addr *) (ea))->octet[1], \ 736 | ((struct ether_addr *) (ea))->octet[2], \ 737 | ((struct ether_addr *) (ea))->octet[3], \ 738 | ((struct ether_addr *) (ea))->octet[4], \ 739 | ((struct ether_addr *) (ea))->octet[5] 740 | 741 | #define ETHER_TO_MACF(ea) (ea).octet[0], \ 742 | (ea).octet[1], \ 743 | (ea).octet[2], \ 744 | (ea).octet[3], \ 745 | (ea).octet[4], \ 746 | (ea).octet[5] 747 | #if !defined(SIMPLE_MAC_PRINT) 748 | #define MACDBG "%02x:%02x:%02x:%02x:%02x:%02x" 749 | #define MAC2STRDBG(ea) (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] 750 | #else 751 | #define MACDBG "%02x:%02x:%02x" 752 | #define MAC2STRDBG(ea) (ea)[0], (ea)[4], (ea)[5] 753 | #endif /* SIMPLE_MAC_PRINT */ 754 | 755 | /* bcm_format_flags() bit description structure */ 756 | typedef struct bcm_bit_desc { 757 | uint32 bit; 758 | const char* name; 759 | } bcm_bit_desc_t; 760 | 761 | /* bcm_format_field */ 762 | typedef struct bcm_bit_desc_ex { 763 | uint32 mask; 764 | const bcm_bit_desc_t *bitfield; 765 | } bcm_bit_desc_ex_t; 766 | 767 | 768 | /* tag_ID/length/value_buffer tuple */ 769 | typedef struct bcm_tlv { 770 | uint8 id; 771 | uint8 len; 772 | uint8 data[1]; 773 | } bcm_tlv_t; 774 | 775 | /* Check that bcm_tlv_t fits into the given buflen */ 776 | #define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len)) 777 | 778 | /* buffer length for ethernet address from bcm_ether_ntoa() */ 779 | #define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */ 780 | 781 | /* crypto utility function */ 782 | /* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */ 783 | static INLINE void 784 | xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst) 785 | { 786 | if ( 787 | #ifdef __i386__ 788 | 1 || 789 | #endif 790 | (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) { 791 | /* ARM CM3 rel time: 1229 (727 if alignment check could be omitted) */ 792 | /* x86 supports unaligned. This version runs 6x-9x faster on x86. */ 793 | ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0]; 794 | ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1]; 795 | ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2]; 796 | ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3]; 797 | } else { 798 | /* ARM CM3 rel time: 4668 (4191 if alignment check could be omitted) */ 799 | int k; 800 | for (k = 0; k < 16; k++) 801 | dst[k] = src1[k] ^ src2[k]; 802 | } 803 | } 804 | 805 | /* externs */ 806 | /* crc */ 807 | extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); 808 | extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); 809 | extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); 810 | 811 | /* format/print */ 812 | #if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ 813 | defined(WLMSG_ASSOC) 814 | /* print out the value a field has: fields may have 1-32 bits and may hold any value */ 815 | extern int bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 field, char* buf, int len); 816 | /* print out which bits in flags are set */ 817 | extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); 818 | #endif 819 | 820 | #if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ 821 | defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE) 822 | extern int bcm_format_hex(char *str, const void *bytes, int len); 823 | #endif 824 | 825 | extern const char *bcm_crypto_algo_name(uint algo); 826 | extern char *bcm_chipname(uint chipid, char *buf, uint len); 827 | extern char *bcm_brev_str(uint32 brev, char *buf); 828 | extern void printbig(char *buf); 829 | extern void prhex(const char *msg, uchar *buf, uint len); 830 | 831 | /* IE parsing */ 832 | extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); 833 | extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); 834 | extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); 835 | 836 | /* bcmerror */ 837 | extern const char *bcmerrorstr(int bcmerror); 838 | /* extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); */ 839 | 840 | /* multi-bool data type: set of bools, mbool is true if any is set */ 841 | typedef uint32 mbool; 842 | #define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */ 843 | #define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */ 844 | #define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* TRUE if one bool is set */ 845 | #define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) 846 | 847 | /* generic datastruct to help dump routines */ 848 | struct fielddesc { 849 | const char *nameandfmt; 850 | uint32 offset; 851 | uint32 len; 852 | }; 853 | 854 | extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); 855 | extern void bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, uint8 *buf, int len); 856 | 857 | extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); 858 | extern int bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes); 859 | extern void bcm_print_bytes(const char *name, const uchar *cdata, int len); 860 | 861 | typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); 862 | extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, 863 | char *buf, uint32 bufsize); 864 | extern uint bcm_bitcount(uint8 *bitmap, uint bytelength); 865 | 866 | extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); 867 | 868 | /* power conversion */ 869 | extern uint16 bcm_qdbm_to_mw(uint8 qdbm); 870 | extern uint8 bcm_mw_to_qdbm(uint16 mw); 871 | extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); 872 | 873 | unsigned int process_nvram_vars(char *varbuf, unsigned int len); 874 | extern bcm_tlv_t *find_vendor_ie(void *tlvs, int tlvs_len, 875 | const char *voui, uint8 *type, int type_len); 876 | 877 | /* calculate a * b + c */ 878 | extern void bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c); 879 | /* calculate a / b */ 880 | extern void bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b); 881 | 882 | #ifdef __cplusplus 883 | } 884 | #endif 885 | 886 | #endif /* _bcmutils_h_ */ 887 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /utils/makecsiparams/bcmwifi_channels.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Misc utility routines used by kernel or app-level. 3 | * Contents are wifi-specific, used by any kernel or app-level 4 | * software that might want wifi things as it grows. 5 | * 6 | * Copyright (C) 1999-2013, Broadcom Corporation 7 | * 8 | * Unless you and Broadcom execute a separate written software license 9 | * agreement governing use of this software, this software is licensed to you 10 | * under the terms of the GNU General Public License version 2 (the "GPL"), 11 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the 12 | * following added to such license: 13 | * 14 | * As a special exception, the copyright holders of this software give you 15 | * permission to link this software with independent modules, and to copy and 16 | * distribute the resulting executable under terms of your choice, provided that 17 | * you also meet, for each linked independent module, the terms and conditions of 18 | * the license of that module. An independent module is a module which is not 19 | * derived from this software. The special exception does not apply to any 20 | * modifications of the software. 21 | * 22 | * Notwithstanding the above, under no circumstances may you combine this 23 | * software in any way with any other Broadcom software provided under a license 24 | * other than the GPL, without Broadcom's express prior written consent. 25 | * $Id: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $ 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef BCMDRIVER 33 | #include 34 | #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) 35 | #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) 36 | #else 37 | #include 38 | #include 39 | #include 40 | #ifndef ASSERT 41 | #define ASSERT(exp) 42 | #endif 43 | #endif /* BCMDRIVER */ 44 | 45 | #ifdef _bcmwifi_c_ 46 | /* temporary for transitional compatibility */ 47 | #include 48 | #else 49 | #include 50 | #endif 51 | 52 | #if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) 53 | #include /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ 54 | #endif 55 | 56 | #ifndef D11AC_IOTYPES 57 | 58 | /* Definitions for legacy Chanspec type */ 59 | 60 | /* Chanspec ASCII representation: 61 | * 62 | * digit [AB] [N] [UL] 63 | * 64 | * : channel number of the 10MHz or 20MHz channel, 65 | * or control sideband channel of 40MHz channel. 66 | * : A for 5GHz, B for 2.4GHz 67 | * : N for 10MHz, nothing for 20MHz or 40MHz 68 | * (ctl-sideband spec implies 40MHz) 69 | * : U for upper, L for lower 70 | * 71 | * may be omitted on input, and will be assumed to be 72 | * 2.4GHz if channel number <= 14. 73 | * 74 | * Examples: 75 | * 8 -> 2.4GHz channel 8, 20MHz 76 | * 8b -> 2.4GHz channel 8, 20MHz 77 | * 8l -> 2.4GHz channel 8, 40MHz, lower ctl sideband 78 | * 8a -> 5GHz channel 8 (low 5 GHz band), 20MHz 79 | * 36 -> 5GHz channel 36, 20MHz 80 | * 36l -> 5GHz channel 36, 40MHz, lower ctl sideband 81 | * 40u -> 5GHz channel 40, 40MHz, upper ctl sideband 82 | * 180n -> channel 180, 10MHz 83 | */ 84 | 85 | 86 | /* given a chanspec and a string buffer, format the chanspec as a 87 | * string, and return the original pointer a. 88 | * Min buffer length must be CHANSPEC_STR_LEN. 89 | * On error return NULL 90 | */ 91 | char * 92 | wf_chspec_ntoa(chanspec_t chspec, char *buf) 93 | { 94 | const char *band, *bw, *sb; 95 | uint channel; 96 | 97 | band = ""; 98 | bw = ""; 99 | sb = ""; 100 | channel = CHSPEC_CHANNEL(chspec); 101 | /* check for non-default band spec */ 102 | if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) || 103 | (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL)) 104 | band = (CHSPEC_IS2G(chspec)) ? "b" : "a"; 105 | if (CHSPEC_IS40(chspec)) { 106 | if (CHSPEC_SB_UPPER(chspec)) { 107 | sb = "u"; 108 | channel += CH_10MHZ_APART; 109 | } else { 110 | sb = "l"; 111 | channel -= CH_10MHZ_APART; 112 | } 113 | } else if (CHSPEC_IS10(chspec)) { 114 | bw = "n"; 115 | } 116 | 117 | /* Outputs a max of 6 chars including '\0' */ 118 | snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb); 119 | return (buf); 120 | } 121 | 122 | /* given a chanspec string, convert to a chanspec. 123 | * On error return 0 124 | */ 125 | chanspec_t 126 | wf_chspec_aton(const char *a) 127 | { 128 | char *endp = NULL; 129 | uint channel, band, bw, ctl_sb; 130 | char c; 131 | 132 | channel = strtoul(a, &endp, 10); 133 | 134 | /* check for no digits parsed */ 135 | if (endp == a) 136 | return 0; 137 | 138 | if (channel > MAXCHANNEL) 139 | return 0; 140 | 141 | band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); 142 | bw = WL_CHANSPEC_BW_20; 143 | ctl_sb = WL_CHANSPEC_CTL_SB_NONE; 144 | 145 | a = endp; 146 | 147 | c = tolower(a[0]); 148 | if (c == '\0') 149 | goto done; 150 | 151 | /* parse the optional ['A' | 'B'] band spec */ 152 | if (c == 'a' || c == 'b') { 153 | band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G; 154 | a++; 155 | c = tolower(a[0]); 156 | if (c == '\0') 157 | goto done; 158 | } 159 | 160 | /* parse bandwidth 'N' (10MHz) or 40MHz ctl sideband ['L' | 'U'] */ 161 | if (c == 'n') { 162 | bw = WL_CHANSPEC_BW_10; 163 | } else if (c == 'l') { 164 | bw = WL_CHANSPEC_BW_40; 165 | ctl_sb = WL_CHANSPEC_CTL_SB_LOWER; 166 | /* adjust channel to center of 40MHz band */ 167 | if (channel <= (MAXCHANNEL - CH_20MHZ_APART)) 168 | channel += CH_10MHZ_APART; 169 | else 170 | return 0; 171 | } else if (c == 'u') { 172 | bw = WL_CHANSPEC_BW_40; 173 | ctl_sb = WL_CHANSPEC_CTL_SB_UPPER; 174 | /* adjust channel to center of 40MHz band */ 175 | if (channel > CH_20MHZ_APART) 176 | channel -= CH_10MHZ_APART; 177 | else 178 | return 0; 179 | } else { 180 | return 0; 181 | } 182 | 183 | done: 184 | return (channel | band | bw | ctl_sb); 185 | } 186 | 187 | /* 188 | * Verify the chanspec is using a legal set of parameters, i.e. that the 189 | * chanspec specified a band, bw, ctl_sb and channel and that the 190 | * combination could be legal given any set of circumstances. 191 | * RETURNS: TRUE is the chanspec is malformed, false if it looks good. 192 | */ 193 | bool 194 | wf_chspec_malformed(chanspec_t chanspec) 195 | { 196 | /* must be 2G or 5G band */ 197 | if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec)) 198 | return TRUE; 199 | /* must be 20 or 40 bandwidth */ 200 | if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec)) 201 | return TRUE; 202 | 203 | /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */ 204 | if (CHSPEC_IS20(chanspec)) { 205 | if (!CHSPEC_SB_NONE(chanspec)) 206 | return TRUE; 207 | } else { 208 | if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) 209 | return TRUE; 210 | } 211 | 212 | return FALSE; 213 | } 214 | 215 | /* 216 | * This function returns the channel number that control traffic is being sent on, for legacy 217 | * channels this is just the channel number, for 40MHZ channels it is the upper or lower 20MHZ 218 | * sideband depending on the chanspec selected 219 | */ 220 | uint8 221 | wf_chspec_ctlchan(chanspec_t chspec) 222 | { 223 | uint8 ctl_chan; 224 | 225 | /* Is there a sideband ? */ 226 | if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { 227 | return CHSPEC_CHANNEL(chspec); 228 | } else { 229 | /* we only support 40MHZ with sidebands */ 230 | ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40); 231 | /* chanspec channel holds the centre frequency, use that and the 232 | * side band information to reconstruct the control channel number 233 | */ 234 | if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { 235 | /* control chan is the upper 20 MHZ SB of the 40MHZ channel */ 236 | ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); 237 | } else { 238 | ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER); 239 | /* control chan is the lower 20 MHZ SB of the 40MHZ channel */ 240 | ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); 241 | } 242 | } 243 | 244 | return ctl_chan; 245 | } 246 | 247 | chanspec_t 248 | wf_chspec_ctlchspec(chanspec_t chspec) 249 | { 250 | chanspec_t ctl_chspec = 0; 251 | uint8 channel; 252 | 253 | ASSERT(!wf_chspec_malformed(chspec)); 254 | 255 | /* Is there a sideband ? */ 256 | if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) { 257 | return chspec; 258 | } else { 259 | if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) { 260 | channel = UPPER_20_SB(CHSPEC_CHANNEL(chspec)); 261 | } else { 262 | channel = LOWER_20_SB(CHSPEC_CHANNEL(chspec)); 263 | } 264 | ctl_chspec = channel | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; 265 | ctl_chspec |= CHSPEC_BAND(chspec); 266 | } 267 | return ctl_chspec; 268 | } 269 | 270 | #else /* D11AC_IOTYPES */ 271 | 272 | /* Definitions for D11AC capable Chanspec type */ 273 | 274 | /* Chanspec ASCII representation with 802.11ac capability: 275 | * [ 'g'] ['/' []['/'<1st80channel>'-'<2nd80channel>]] 276 | * 277 | * : 278 | * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. 279 | * Default value is 2g if channel <= 14, otherwise 5g. 280 | * : 281 | * channel number of the 5MHz, 10MHz, 20MHz channel, 282 | * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. 283 | * : 284 | * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. 285 | * : 286 | * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. 287 | * 288 | * For 2.4GHz band 40MHz channels, the same primary channel may be the 289 | * upper sideband for one 40MHz channel, and the lower sideband for an 290 | * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel 291 | * is being specified. 292 | * 293 | * For 40MHz in the 5GHz band and all channel bandwidths greater than 294 | * 40MHz, the U/L specificaion is not allowed since the channels are 295 | * non-overlapping and the primary sub-band is derived from its 296 | * position in the wide bandwidth channel. 297 | * 298 | * <1st80Channel>: 299 | * <2nd80Channel>: 300 | * Required for 80+80, otherwise not allowed. 301 | * Specifies the center channel of the first and second 80MHz band. 302 | * 303 | * In its simplest form, it is a 20MHz channel number, with the implied band 304 | * of 2.4GHz if channel number <= 14, and 5GHz otherwise. 305 | * 306 | * To allow for backward compatibility with scripts, the old form for 307 | * 40MHz channels is also allowed: 308 | * 309 | * : 310 | * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz 311 | * : 312 | * "U" for upper, "L" for lower (or lower case "u" "l") 313 | * 314 | * 5 GHz Examples: 315 | * Chanspec BW Center Ch Channel Range Primary Ch 316 | * 5g8 20MHz 8 - - 317 | * 52 20MHz 52 - - 318 | * 52/40 40MHz 54 52-56 52 319 | * 56/40 40MHz 54 52-56 56 320 | * 52/80 80MHz 58 52-64 52 321 | * 56/80 80MHz 58 52-64 56 322 | * 60/80 80MHz 58 52-64 60 323 | * 64/80 80MHz 58 52-64 64 324 | * 52/160 160MHz 50 36-64 52 325 | * 36/160 160MGz 50 36-64 36 326 | * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 327 | * 328 | * 2 GHz Examples: 329 | * Chanspec BW Center Ch Channel Range Primary Ch 330 | * 2g8 20MHz 8 - - 331 | * 8 20MHz 8 - - 332 | * 6 20MHz 6 - - 333 | * 6/40l 40MHz 8 6-10 6 334 | * 6l 40MHz 8 6-10 6 335 | * 6/40u 40MHz 4 2-6 6 336 | * 6u 40MHz 4 2-6 6 337 | */ 338 | 339 | /* bandwidth ASCII string */ 340 | static const char *wf_chspec_bw_str[] = 341 | { 342 | "5", 343 | "10", 344 | "20", 345 | "40", 346 | "80", 347 | "160", 348 | "80+80", 349 | "na" 350 | }; 351 | 352 | static const uint8 wf_chspec_bw_mhz[] = 353 | {5, 10, 20, 40, 80, 160, 160}; 354 | 355 | #define WF_NUM_BW \ 356 | (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) 357 | 358 | /* 40MHz channels in 5GHz band */ 359 | static const uint8 wf_5g_40m_chans[] = 360 | {38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; 361 | #define WF_NUM_5G_40M_CHANS \ 362 | (sizeof(wf_5g_40m_chans)/sizeof(uint8)) 363 | 364 | /* 80MHz channels in 5GHz band */ 365 | static const uint8 wf_5g_80m_chans[] = 366 | {42, 58, 106, 122, 138, 155}; 367 | #define WF_NUM_5G_80M_CHANS \ 368 | (sizeof(wf_5g_80m_chans)/sizeof(uint8)) 369 | 370 | /* 160MHz channels in 5GHz band */ 371 | static const uint8 wf_5g_160m_chans[] = 372 | {50, 114}; 373 | #define WF_NUM_5G_160M_CHANS \ 374 | (sizeof(wf_5g_160m_chans)/sizeof(uint8)) 375 | 376 | 377 | /* convert bandwidth from chanspec to MHz */ 378 | static uint 379 | bw_chspec_to_mhz(chanspec_t chspec) 380 | { 381 | uint bw; 382 | 383 | bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; 384 | return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); 385 | } 386 | 387 | /* bw in MHz, return the channel count from the center channel to the 388 | * the channel at the edge of the band 389 | */ 390 | static uint8 391 | center_chan_to_edge(uint bw) 392 | { 393 | /* edge channels separated by BW - 10MHz on each side 394 | * delta from cf to edge is half of that, 395 | * MHz to channel num conversion is 5MHz/channel 396 | */ 397 | return (uint8)(((bw - 20) / 2) / 5); 398 | } 399 | 400 | /* return channel number of the low edge of the band 401 | * given the center channel and BW 402 | */ 403 | static uint8 404 | channel_low_edge(uint center_ch, uint bw) 405 | { 406 | return (uint8)(center_ch - center_chan_to_edge(bw)); 407 | } 408 | 409 | /* return side band number given center channel and control channel 410 | * return -1 on error 411 | */ 412 | static int 413 | channel_to_sb(uint center_ch, uint ctl_ch, uint bw) 414 | { 415 | uint lowest = channel_low_edge(center_ch, bw); 416 | uint sb; 417 | 418 | if ((ctl_ch - lowest) % 4) { 419 | /* bad ctl channel, not mult 4 */ 420 | return -1; 421 | } 422 | 423 | sb = ((ctl_ch - lowest) / 4); 424 | 425 | /* sb must be a index to a 20MHz channel in range */ 426 | if (sb >= (bw / 20)) { 427 | /* ctl_ch must have been too high for the center_ch */ 428 | return -1; 429 | } 430 | 431 | return sb; 432 | } 433 | 434 | /* return control channel given center channel and side band */ 435 | static uint8 436 | channel_to_ctl_chan(uint center_ch, uint bw, uint sb) 437 | { 438 | return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); 439 | } 440 | 441 | /* return index of 80MHz channel from channel number 442 | * return -1 on error 443 | */ 444 | static int 445 | channel_80mhz_to_id(uint ch) 446 | { 447 | uint i; 448 | for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { 449 | if (ch == wf_5g_80m_chans[i]) 450 | return i; 451 | } 452 | 453 | return -1; 454 | } 455 | 456 | /* given a chanspec and a string buffer, format the chanspec as a 457 | * string, and return the original pointer a. 458 | * Min buffer length must be CHANSPEC_STR_LEN. 459 | * On error return NULL 460 | */ 461 | char * 462 | wf_chspec_ntoa(chanspec_t chspec, char *buf) 463 | { 464 | const char *band; 465 | uint ctl_chan; 466 | 467 | //if (wf_chspec_malformed(chspec)) 468 | // return NULL; 469 | 470 | band = ""; 471 | 472 | /* check for non-default band spec */ 473 | if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || 474 | (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) 475 | band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; 476 | 477 | /* ctl channel */ 478 | ctl_chan = wf_chspec_ctlchan(chspec); 479 | 480 | /* bandwidth and ctl sideband */ 481 | if (CHSPEC_IS20(chspec)) { 482 | snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); 483 | } else if (!CHSPEC_IS8080(chspec)) { 484 | const char *bw; 485 | const char *sb = ""; 486 | 487 | bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; 488 | 489 | #ifdef CHANSPEC_NEW_40MHZ_FORMAT 490 | /* ctl sideband string if needed for 2g 40MHz */ 491 | if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { 492 | sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; 493 | } 494 | 495 | snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); 496 | #else 497 | /* ctl sideband string instead of BW for 40MHz */ 498 | if (CHSPEC_IS40(chspec)) { 499 | sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; 500 | snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); 501 | } else { 502 | snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); 503 | } 504 | #endif /* CHANSPEC_NEW_40MHZ_FORMAT */ 505 | 506 | } else { 507 | /* 80+80 */ 508 | uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; 509 | uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; 510 | 511 | /* convert to channel number */ 512 | chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; 513 | chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; 514 | 515 | /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ 516 | snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); 517 | } 518 | 519 | return (buf); 520 | } 521 | 522 | static int 523 | read_uint(const char **p, unsigned int *num) 524 | { 525 | unsigned long val; 526 | char *endp = NULL; 527 | 528 | val = strtoul(*p, &endp, 10); 529 | /* if endp is the initial pointer value, then a number was not read */ 530 | if (endp == *p) 531 | return 0; 532 | 533 | /* advance the buffer pointer to the end of the integer string */ 534 | *p = endp; 535 | /* return the parsed integer */ 536 | *num = (unsigned int)val; 537 | 538 | return 1; 539 | } 540 | 541 | /* given a chanspec string, convert to a chanspec. 542 | * On error return 0 543 | */ 544 | chanspec_t 545 | wf_chspec_aton(const char *a) 546 | { 547 | chanspec_t chspec; 548 | uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; 549 | uint num, ctl_ch; 550 | uint ch1, ch2; 551 | char c, sb_ul = '\0'; 552 | int i; 553 | 554 | bw = 20; 555 | chspec_sb = 0; 556 | chspec_ch = ch1 = ch2 = 0; 557 | 558 | /* parse channel num or band */ 559 | if (!read_uint(&a, &num)) 560 | return 0; 561 | 562 | /* if we are looking at a 'g', then the first number was a band */ 563 | c = tolower((int)a[0]); 564 | if (c == 'g') { 565 | a ++; /* consume the char */ 566 | 567 | /* band must be "2" or "5" */ 568 | if (num == 2) 569 | chspec_band = WL_CHANSPEC_BAND_2G; 570 | else if (num == 5) 571 | chspec_band = WL_CHANSPEC_BAND_5G; 572 | else 573 | return 0; 574 | 575 | /* read the channel number */ 576 | if (!read_uint(&a, &ctl_ch)) 577 | return 0; 578 | 579 | c = tolower((int)a[0]); 580 | } 581 | else { 582 | /* first number is channel, use default for band */ 583 | ctl_ch = num; 584 | chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? 585 | WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); 586 | } 587 | 588 | if (c == '\0') { 589 | /* default BW of 20MHz */ 590 | chspec_bw = WL_CHANSPEC_BW_20; 591 | goto done_read; 592 | } 593 | 594 | a ++; /* consume the 'u','l', or '/' */ 595 | 596 | /* check 'u'/'l' */ 597 | if (c == 'u' || c == 'l') { 598 | sb_ul = c; 599 | chspec_bw = WL_CHANSPEC_BW_40; 600 | goto done_read; 601 | } 602 | 603 | /* next letter must be '/' */ 604 | if (c != '/') 605 | return 0; 606 | 607 | /* read bandwidth */ 608 | if (!read_uint(&a, &bw)) 609 | return 0; 610 | 611 | /* convert to chspec value */ 612 | if (bw == 20) { 613 | chspec_bw = WL_CHANSPEC_BW_20; 614 | } else if (bw == 40) { 615 | chspec_bw = WL_CHANSPEC_BW_40; 616 | } else if (bw == 80) { 617 | chspec_bw = WL_CHANSPEC_BW_80; 618 | } else if (bw == 160) { 619 | chspec_bw = WL_CHANSPEC_BW_160; 620 | } else { 621 | return 0; 622 | } 623 | 624 | /* So far we have g/ 625 | * Can now be followed by u/l if bw = 40, 626 | * or '+80' if bw = 80, to make '80+80' bw. 627 | */ 628 | 629 | c = tolower((int)a[0]); 630 | 631 | /* if we have a 2g/40 channel, we should have a l/u spec now */ 632 | if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { 633 | if (c == 'u' || c == 'l') { 634 | a ++; /* consume the u/l char */ 635 | sb_ul = c; 636 | goto done_read; 637 | } 638 | } 639 | 640 | /* check for 80+80 */ 641 | if (c == '+') { 642 | /* 80+80 */ 643 | static const char *plus80 = "80/"; 644 | 645 | /* must be looking at '+80/' 646 | * check and consume this string. 647 | */ 648 | chspec_bw = WL_CHANSPEC_BW_8080; 649 | 650 | a ++; /* consume the char '+' */ 651 | 652 | /* consume the '80/' string */ 653 | for (i = 0; i < 3; i++) { 654 | if (*a++ != *plus80++) { 655 | return 0; 656 | } 657 | } 658 | 659 | /* read primary 80MHz channel */ 660 | if (!read_uint(&a, &ch1)) 661 | return 0; 662 | 663 | /* must followed by '-' */ 664 | if (a[0] != '-') 665 | return 0; 666 | a ++; /* consume the char */ 667 | 668 | /* read secondary 80MHz channel */ 669 | if (!read_uint(&a, &ch2)) 670 | return 0; 671 | } 672 | 673 | done_read: 674 | /* skip trailing white space */ 675 | while (a[0] == ' ') { 676 | a ++; 677 | } 678 | 679 | /* must be end of string */ 680 | if (a[0] != '\0') 681 | return 0; 682 | 683 | /* Now have all the chanspec string parts read; 684 | * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. 685 | * chspec_band and chspec_bw are chanspec values. 686 | * Need to convert ctl_ch, sb_ul, and ch1,ch2 into 687 | * a center channel (or two) and sideband. 688 | */ 689 | 690 | /* if a sb u/l string was given, just use that, 691 | * guaranteed to be bw = 40 by sting parse. 692 | */ 693 | if (sb_ul != '\0') { 694 | if (sb_ul == 'l') { 695 | chspec_ch = UPPER_20_SB(ctl_ch); 696 | chspec_sb = WL_CHANSPEC_CTL_SB_LLL; 697 | } else if (sb_ul == 'u') { 698 | chspec_ch = LOWER_20_SB(ctl_ch); 699 | chspec_sb = WL_CHANSPEC_CTL_SB_LLU; 700 | } 701 | } 702 | /* if the bw is 20, center and sideband are trivial */ 703 | else if (chspec_bw == WL_CHANSPEC_BW_20) { 704 | chspec_ch = ctl_ch; 705 | chspec_sb = 0; 706 | } 707 | /* if the bw is 40/80/160, not 80+80, a single method 708 | * can be used to to find the center and sideband 709 | */ 710 | else if (chspec_bw != WL_CHANSPEC_BW_8080) { 711 | /* figure out ctl sideband based on ctl channel and bandwidth */ 712 | const uint8 *center_ch = NULL; 713 | int num_ch = 0; 714 | int sb = -1; 715 | 716 | if (chspec_bw == WL_CHANSPEC_BW_40) { 717 | center_ch = wf_5g_40m_chans; 718 | num_ch = WF_NUM_5G_40M_CHANS; 719 | } else if (chspec_bw == WL_CHANSPEC_BW_80) { 720 | center_ch = wf_5g_80m_chans; 721 | num_ch = WF_NUM_5G_80M_CHANS; 722 | } else if (chspec_bw == WL_CHANSPEC_BW_160) { 723 | center_ch = wf_5g_160m_chans; 724 | num_ch = WF_NUM_5G_160M_CHANS; 725 | } else { 726 | return 0; 727 | } 728 | 729 | for (i = 0; i < num_ch; i ++) { 730 | sb = channel_to_sb(center_ch[i], ctl_ch, bw); 731 | if (sb >= 0) { 732 | chspec_ch = center_ch[i]; 733 | chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; 734 | break; 735 | } 736 | } 737 | 738 | /* check for no matching sb/center */ 739 | if (sb < 0) { 740 | return 0; 741 | } 742 | } 743 | /* Otherwise, bw is 80+80. Figure out channel pair and sb */ 744 | else { 745 | int ch1_id = 0, ch2_id = 0; 746 | int sb; 747 | 748 | ch1_id = channel_80mhz_to_id(ch1); 749 | ch2_id = channel_80mhz_to_id(ch2); 750 | 751 | /* validate channels */ 752 | if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0) 753 | return 0; 754 | 755 | /* combined channel in chspec */ 756 | chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | 757 | ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); 758 | 759 | /* figure out ctl sideband */ 760 | 761 | /* does the primary channel fit with the 1st 80MHz channel ? */ 762 | sb = channel_to_sb(ch1, ctl_ch, bw); 763 | if (sb < 0) { 764 | /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ 765 | sb = channel_to_sb(ch2, ctl_ch, bw); 766 | if (sb < 0) { 767 | /* no match for ctl_ch to either 80MHz center channel */ 768 | return 0; 769 | } 770 | /* sb index is 0-3 for the low 80MHz channel, and 4-7 for 771 | * the high 80MHz channel. Add 4 to to shift to high set. 772 | */ 773 | sb += 4; 774 | } 775 | 776 | chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; 777 | } 778 | 779 | chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); 780 | 781 | if (wf_chspec_malformed(chspec)) 782 | return 0; 783 | 784 | return chspec; 785 | } 786 | 787 | /* 788 | * Verify the chanspec is using a legal set of parameters, i.e. that the 789 | * chanspec specified a band, bw, ctl_sb and channel and that the 790 | * combination could be legal given any set of circumstances. 791 | * RETURNS: TRUE is the chanspec is malformed, false if it looks good. 792 | */ 793 | bool 794 | wf_chspec_malformed(chanspec_t chanspec) 795 | { 796 | uint chspec_bw = CHSPEC_BW(chanspec); 797 | uint chspec_ch = CHSPEC_CHANNEL(chanspec); 798 | 799 | /* must be 2G or 5G band */ 800 | if (CHSPEC_IS2G(chanspec)) { 801 | /* must be valid bandwidth */ 802 | if (chspec_bw != WL_CHANSPEC_BW_20 && 803 | chspec_bw != WL_CHANSPEC_BW_40) { 804 | return TRUE; 805 | } 806 | } else if (CHSPEC_IS5G(chanspec)) { 807 | if (chspec_bw == WL_CHANSPEC_BW_8080) { 808 | uint ch1_id, ch2_id; 809 | 810 | /* channel number in 80+80 must be in range */ 811 | ch1_id = CHSPEC_CHAN1(chanspec); 812 | ch2_id = CHSPEC_CHAN2(chanspec); 813 | if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) 814 | return TRUE; 815 | 816 | /* ch2 must be above ch1 for the chanspec */ 817 | if (ch2_id <= ch1_id) 818 | return TRUE; 819 | } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 || 820 | chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) { 821 | 822 | if (chspec_ch > MAXCHANNEL) { 823 | return TRUE; 824 | } 825 | } else { 826 | /* invalid bandwidth */ 827 | return TRUE; 828 | } 829 | } else { 830 | /* must be 2G or 5G band */ 831 | return TRUE; 832 | } 833 | 834 | /* side band needs to be consistent with bandwidth */ 835 | if (chspec_bw == WL_CHANSPEC_BW_20) { 836 | if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) 837 | return TRUE; 838 | } else if (chspec_bw == WL_CHANSPEC_BW_40) { 839 | if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) 840 | return TRUE; 841 | } else if (chspec_bw == WL_CHANSPEC_BW_80) { 842 | if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) 843 | return TRUE; 844 | } 845 | 846 | return FALSE; 847 | } 848 | 849 | /* 850 | * Verify the chanspec specifies a valid channel according to 802.11. 851 | * RETURNS: TRUE if the chanspec is a valid 802.11 channel 852 | */ 853 | bool 854 | wf_chspec_valid(chanspec_t chanspec) 855 | { 856 | uint chspec_bw = CHSPEC_BW(chanspec); 857 | uint chspec_ch = CHSPEC_CHANNEL(chanspec); 858 | 859 | if (wf_chspec_malformed(chanspec)) 860 | return FALSE; 861 | 862 | if (CHSPEC_IS2G(chanspec)) { 863 | /* must be valid bandwidth and channel range */ 864 | if (chspec_bw == WL_CHANSPEC_BW_20) { 865 | if (chspec_ch >= 1 && chspec_ch <= 14) 866 | return TRUE; 867 | } else if (chspec_bw == WL_CHANSPEC_BW_40) { 868 | if (chspec_ch >= 3 && chspec_ch <= 11) 869 | return TRUE; 870 | } 871 | } else if (CHSPEC_IS5G(chanspec)) { 872 | if (chspec_bw == WL_CHANSPEC_BW_8080) { 873 | uint16 ch1, ch2; 874 | 875 | ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; 876 | ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; 877 | 878 | /* the two channels must be separated by more than 80MHz by VHT req, 879 | * and ch2 above ch1 for the chanspec 880 | */ 881 | if (ch2 > ch1 + CH_80MHZ_APART) 882 | return TRUE; 883 | } else { 884 | const uint8 *center_ch; 885 | uint num_ch, i; 886 | 887 | if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40) { 888 | center_ch = wf_5g_40m_chans; 889 | num_ch = WF_NUM_5G_40M_CHANS; 890 | } else if (chspec_bw == WL_CHANSPEC_BW_80) { 891 | center_ch = wf_5g_80m_chans; 892 | num_ch = WF_NUM_5G_80M_CHANS; 893 | } else if (chspec_bw == WL_CHANSPEC_BW_160) { 894 | center_ch = wf_5g_160m_chans; 895 | num_ch = WF_NUM_5G_160M_CHANS; 896 | } else { 897 | /* invalid bandwidth */ 898 | return FALSE; 899 | } 900 | 901 | /* check for a valid center channel */ 902 | if (chspec_bw == WL_CHANSPEC_BW_20) { 903 | /* We don't have an array of legal 20MHz 5G channels, but they are 904 | * each side of the legal 40MHz channels. Check the chanspec 905 | * channel against either side of the 40MHz channels. 906 | */ 907 | for (i = 0; i < num_ch; i ++) { 908 | if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || 909 | chspec_ch == (uint)UPPER_20_SB(center_ch[i])) 910 | break; /* match found */ 911 | } 912 | 913 | if (i == num_ch) { 914 | /* check for channel 165 which is not the side band 915 | * of 40MHz 5G channel 916 | */ 917 | if (chspec_ch == 165) 918 | i = 0; 919 | 920 | /* check for legacy JP channels on failure */ 921 | if (chspec_ch == 34 || chspec_ch == 38 || 922 | chspec_ch == 42 || chspec_ch == 46) 923 | i = 0; 924 | } 925 | } else { 926 | /* check the chanspec channel to each legal channel */ 927 | for (i = 0; i < num_ch; i ++) { 928 | if (chspec_ch == center_ch[i]) 929 | break; /* match found */ 930 | } 931 | } 932 | 933 | if (i < num_ch) { 934 | /* match found */ 935 | return TRUE; 936 | } 937 | } 938 | } 939 | 940 | return FALSE; 941 | } 942 | 943 | /* 944 | * This function returns the channel number that control traffic is being sent on, for 20MHz 945 | * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ 946 | * sideband depending on the chanspec selected 947 | */ 948 | uint8 949 | wf_chspec_ctlchan(chanspec_t chspec) 950 | { 951 | uint center_chan; 952 | uint bw_mhz; 953 | uint sb; 954 | 955 | ASSERT(!wf_chspec_malformed(chspec)); 956 | 957 | /* Is there a sideband ? */ 958 | if (CHSPEC_IS20(chspec)) { 959 | return CHSPEC_CHANNEL(chspec); 960 | } else { 961 | sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; 962 | 963 | if (CHSPEC_IS8080(chspec)) { 964 | bw_mhz = 80; 965 | 966 | if (sb < 4) { 967 | center_chan = CHSPEC_CHAN1(chspec); 968 | } 969 | else { 970 | center_chan = CHSPEC_CHAN2(chspec); 971 | sb -= 4; 972 | } 973 | 974 | /* convert from channel index to channel number */ 975 | center_chan = wf_5g_80m_chans[center_chan]; 976 | } 977 | else { 978 | bw_mhz = bw_chspec_to_mhz(chspec); 979 | center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; 980 | } 981 | 982 | return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); 983 | } 984 | } 985 | 986 | /* 987 | * This function returns the chanspec of the control channel of a given chanspec 988 | */ 989 | chanspec_t 990 | wf_chspec_ctlchspec(chanspec_t chspec) 991 | { 992 | chanspec_t ctl_chspec = chspec; 993 | uint8 ctl_chan; 994 | 995 | ASSERT(!wf_chspec_malformed(chspec)); 996 | 997 | /* Is there a sideband ? */ 998 | if (!CHSPEC_IS20(chspec)) { 999 | ctl_chan = wf_chspec_ctlchan(chspec); 1000 | ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; 1001 | ctl_chspec |= CHSPEC_BAND(chspec); 1002 | } 1003 | return ctl_chspec; 1004 | } 1005 | 1006 | /* return chanspec given control channel and bandwidth 1007 | * return 0 on error 1008 | */ 1009 | uint16 1010 | wf_channel2chspec(uint ctl_ch, uint bw) 1011 | { 1012 | uint16 chspec; 1013 | const uint8 *center_ch = NULL; 1014 | int num_ch = 0; 1015 | int sb = -1; 1016 | int i = 0; 1017 | 1018 | chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); 1019 | 1020 | chspec |= bw; 1021 | 1022 | if (bw == WL_CHANSPEC_BW_40) { 1023 | center_ch = wf_5g_40m_chans; 1024 | num_ch = WF_NUM_5G_40M_CHANS; 1025 | bw = 40; 1026 | } else if (bw == WL_CHANSPEC_BW_80) { 1027 | center_ch = wf_5g_80m_chans; 1028 | num_ch = WF_NUM_5G_80M_CHANS; 1029 | bw = 80; 1030 | } else if (bw == WL_CHANSPEC_BW_160) { 1031 | center_ch = wf_5g_160m_chans; 1032 | num_ch = WF_NUM_5G_160M_CHANS; 1033 | bw = 160; 1034 | } else if (bw == WL_CHANSPEC_BW_20) { 1035 | chspec |= ctl_ch; 1036 | return chspec; 1037 | } else { 1038 | return 0; 1039 | } 1040 | 1041 | for (i = 0; i < num_ch; i ++) { 1042 | sb = channel_to_sb(center_ch[i], ctl_ch, bw); 1043 | if (sb >= 0) { 1044 | chspec |= center_ch[i]; 1045 | chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); 1046 | break; 1047 | } 1048 | } 1049 | 1050 | /* check for no matching sb/center */ 1051 | if (sb < 0) { 1052 | return 0; 1053 | } 1054 | 1055 | return chspec; 1056 | } 1057 | 1058 | #endif /* D11AC_IOTYPES */ 1059 | 1060 | /* 1061 | * This function returns the chanspec for the primary 40MHz of an 80MHz channel. 1062 | * The control sideband specifies the same 20MHz channel that the 80MHz channel is using 1063 | * as the primary 20MHz channel. 1064 | */ 1065 | extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) 1066 | { 1067 | chanspec_t chspec40 = chspec; 1068 | uint center_chan; 1069 | uint sb; 1070 | 1071 | ASSERT(!wf_chspec_malformed(chspec)); 1072 | 1073 | if (CHSPEC_IS80(chspec)) { 1074 | center_chan = CHSPEC_CHANNEL(chspec); 1075 | sb = CHSPEC_CTL_SB(chspec); 1076 | 1077 | if (sb == WL_CHANSPEC_CTL_SB_UL) { 1078 | /* Primary 40MHz is on upper side */ 1079 | sb = WL_CHANSPEC_CTL_SB_L; 1080 | center_chan += CH_20MHZ_APART; 1081 | } else if (sb == WL_CHANSPEC_CTL_SB_UU) { 1082 | /* Primary 40MHz is on upper side */ 1083 | sb = WL_CHANSPEC_CTL_SB_U; 1084 | center_chan += CH_20MHZ_APART; 1085 | } else { 1086 | /* Primary 40MHz is on lower side */ 1087 | /* sideband bits are the same for LL/LU and L/U */ 1088 | center_chan -= CH_20MHZ_APART; 1089 | } 1090 | 1091 | /* Create primary 40MHz chanspec */ 1092 | chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | 1093 | sb | center_chan); 1094 | } 1095 | 1096 | return chspec40; 1097 | } 1098 | 1099 | /* 1100 | * Return the channel number for a given frequency and base frequency. 1101 | * The returned channel number is relative to the given base frequency. 1102 | * If the given base frequency is zero, a base frequency of 5 GHz is assumed for 1103 | * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. 1104 | * 1105 | * Frequency is specified in MHz. 1106 | * The base frequency is specified as (start_factor * 500 kHz). 1107 | * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for 1108 | * 2.4 GHz and 5 GHz bands. 1109 | * 1110 | * The returned channel will be in the range [1, 14] in the 2.4 GHz band 1111 | * and [0, 200] otherwise. 1112 | * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the 1113 | * frequency is not a 2.4 GHz channel, or if the frequency is not and even 1114 | * multiple of 5 MHz from the base frequency to the base plus 1 GHz. 1115 | * 1116 | * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 1117 | */ 1118 | int 1119 | wf_mhz2channel(uint freq, uint start_factor) 1120 | { 1121 | int ch = -1; 1122 | uint base; 1123 | int offset; 1124 | 1125 | /* take the default channel start frequency */ 1126 | if (start_factor == 0) { 1127 | if (freq >= 2400 && freq <= 2500) 1128 | start_factor = WF_CHAN_FACTOR_2_4_G; 1129 | else if (freq >= 5000 && freq <= 6000) 1130 | start_factor = WF_CHAN_FACTOR_5_G; 1131 | } 1132 | 1133 | if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) 1134 | return 14; 1135 | 1136 | base = start_factor / 2; 1137 | 1138 | /* check that the frequency is in 1GHz range of the base */ 1139 | if ((freq < base) || (freq > base + 1000)) 1140 | return -1; 1141 | 1142 | offset = freq - base; 1143 | ch = offset / 5; 1144 | 1145 | /* check that frequency is a 5MHz multiple from the base */ 1146 | if (offset != (ch * 5)) 1147 | return -1; 1148 | 1149 | /* restricted channel range check for 2.4G */ 1150 | if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) 1151 | return -1; 1152 | 1153 | return ch; 1154 | } 1155 | 1156 | /* 1157 | * Return the center frequency in MHz of the given channel and base frequency. 1158 | * The channel number is interpreted relative to the given base frequency. 1159 | * 1160 | * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. 1161 | * The base frequency is specified as (start_factor * 500 kHz). 1162 | * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_4_G, and WF_CHAN_FACTOR_5_G 1163 | * are defined for 2.4 GHz, 4 GHz, and 5 GHz bands. 1164 | * The channel range of [1, 14] is only checked for a start_factor of 1165 | * WF_CHAN_FACTOR_2_4_G (4814 = 2407 * 2). 1166 | * Odd start_factors produce channels on .5 MHz boundaries, in which case 1167 | * the answer is rounded down to an integral MHz. 1168 | * -1 is returned for an out of range channel. 1169 | * 1170 | * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 1171 | */ 1172 | int 1173 | wf_channel2mhz(uint ch, uint start_factor) 1174 | { 1175 | int freq; 1176 | 1177 | if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || 1178 | (ch > 200)) 1179 | freq = -1; 1180 | else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) 1181 | freq = 2484; 1182 | else 1183 | freq = ch * 5 + start_factor / 2; 1184 | 1185 | return freq; 1186 | } 1187 | 1188 | /* These chan_info[] & lookup routines replicate those from wlc_phy.c because of BMAC split */ 1189 | static const struct chan_info { 1190 | uint16 chan; /* channel number */ 1191 | uint16 freq; /* in MHz */ 1192 | } chan_info[] = { 1193 | /* 11b/11g */ 1194 | /* 0 */ {1, 2412}, 1195 | /* 1 */ {2, 2417}, 1196 | /* 2 */ {3, 2422}, 1197 | /* 3 */ {4, 2427}, 1198 | /* 4 */ {5, 2432}, 1199 | /* 5 */ {6, 2437}, 1200 | /* 6 */ {7, 2442}, 1201 | /* 7 */ {8, 2447}, 1202 | /* 8 */ {9, 2452}, 1203 | /* 9 */ {10, 2457}, 1204 | /* 10 */ {11, 2462}, 1205 | /* 11 */ {12, 2467}, 1206 | /* 12 */ {13, 2472}, 1207 | /* 13 */ {14, 2484}, 1208 | 1209 | #ifdef BAND5G 1210 | /* 11a japan high */ 1211 | /* 14 */ {34, 5170}, 1212 | /* 15 */ {38, 5190}, 1213 | /* 16 */ {42, 5210}, 1214 | /* 17 */ {46, 5230}, 1215 | 1216 | /* 11a usa low */ 1217 | /* 18 */ {36, 5180}, 1218 | /* 19 */ {40, 5200}, 1219 | /* 20 */ {44, 5220}, 1220 | /* 21 */ {48, 5240}, 1221 | /* 22 */ {52, 5260}, 1222 | /* 23 */ {56, 5280}, 1223 | /* 24 */ {60, 5300}, 1224 | /* 25 */ {64, 5320}, 1225 | 1226 | /* 11a Europe */ 1227 | /* 26 */ {100, 5500}, 1228 | /* 27 */ {104, 5520}, 1229 | /* 28 */ {108, 5540}, 1230 | /* 29 */ {112, 5560}, 1231 | /* 30 */ {116, 5580}, 1232 | /* 31 */ {120, 5600}, 1233 | /* 32 */ {124, 5620}, 1234 | /* 33 */ {128, 5640}, 1235 | /* 34 */ {132, 5660}, 1236 | /* 35 */ {136, 5680}, 1237 | /* 36 */ {140, 5700}, 1238 | 1239 | /* 11a usa high, ref5 only */ 1240 | /* 37 */ {149, 5745}, 1241 | /* 38 */ {153, 5765}, 1242 | /* 39 */ {157, 5785}, 1243 | /* 40 */ {161, 5805}, 1244 | /* 41 */ {165, 5825}, 1245 | 1246 | /* 11a japan */ 1247 | /* 42 */ {184, 4920}, 1248 | /* 43 */ {188, 4940}, 1249 | /* 44 */ {192, 4960}, 1250 | /* 45 */ {196, 4980}, 1251 | /* 46 */ {200, 5000}, 1252 | /* 47 */ {204, 5020}, 1253 | /* 48 */ {208, 5040}, 1254 | /* 49 */ {212, 5060}, 1255 | /* 50 */ {216, 5080} 1256 | #endif /* BAND5G */ 1257 | }; 1258 | 1259 | /* 1260 | * Converts channel frequency to channel number. 1261 | * Returns 0 if the frequency does not match any channel definition. 1262 | */ 1263 | uint 1264 | wf_freq2channel(uint freq) 1265 | { 1266 | uint i; 1267 | 1268 | for (i = 0; i < ARRAYSIZE(chan_info); i++) { 1269 | if (chan_info[i].freq == freq) 1270 | return (chan_info[i].chan); 1271 | } 1272 | return (0); 1273 | } 1274 | 1275 | /* 1276 | * Converts channel number to channel frequency. 1277 | * Returns 0 if the channel is out of range. 1278 | * Also used by some code in wlc_iw.c 1279 | */ 1280 | uint 1281 | wf_channel2freq(uint channel) 1282 | { 1283 | uint i; 1284 | 1285 | for (i = 0; i < ARRAYSIZE(chan_info); i++) 1286 | if (chan_info[i].chan == channel) 1287 | return (chan_info[i].freq); 1288 | return (0); 1289 | } 1290 | --------------------------------------------------------------------------------