RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / shared / bcm_app_utils.c
blobda9a6063e51164f3e62c719514533f4ebd14b25b
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.
6 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
15 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
17 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * $Id: bcm_app_utils.c,v 1.5 2009-12-03 23:24:26 Exp $
22 #include <typedefs.h>
24 #ifdef BCMDRIVER
25 #include <osl.h>
26 #include <bcmutils.h>
27 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
28 #define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
29 #else /* BCMDRIVER */
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #ifndef ASSERT
34 #define ASSERT(exp)
35 #endif
36 #endif /* BCMDRIVER */
37 #include <bcmwifi.h>
39 #if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
40 #include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
41 #endif
43 #include <bcmutils.h>
44 #include <wlioctl.h>
46 cca_congest_channel_req_t *
47 cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg,
48 bool percent);
50 int
51 cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer);
53 /* Take an array of measurments representing a single channel over time and return
54 a summary. Currently implemented as a simple average but could easily evolve
55 into more cpomplex alogrithms.
57 cca_congest_channel_req_t *
58 cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, bool percent)
60 int sec;
61 cca_congest_t totals;
63 totals.duration = 0;
64 totals.congest_ibss = 0;
65 totals.congest_obss = 0;
66 totals.interference = 0;
67 avg->num_secs = 0;
69 for (sec = 0; sec < input->num_secs; sec++) {
70 if (input->secs[sec].duration) {
71 totals.duration += input->secs[sec].duration;
72 totals.congest_ibss += input->secs[sec].congest_ibss;
73 totals.congest_obss += input->secs[sec].congest_obss;
74 totals.interference += input->secs[sec].interference;
75 avg->num_secs++;
78 avg->chanspec = input->chanspec;
80 if (!avg->num_secs || !totals.duration)
81 return (avg);
83 if (percent) {
84 avg->secs[0].duration = totals.duration / avg->num_secs;
85 avg->secs[0].congest_ibss = totals.congest_ibss * 100/totals.duration;
86 avg->secs[0].congest_obss = totals.congest_obss * 100/totals.duration;
87 avg->secs[0].interference = totals.interference * 100/totals.duration;
88 } else {
89 avg->secs[0].duration = totals.duration / avg->num_secs;
90 avg->secs[0].congest_ibss = totals.congest_ibss / avg->num_secs;
91 avg->secs[0].congest_obss = totals.congest_obss / avg->num_secs;
92 avg->secs[0].interference = totals.interference / avg->num_secs;
95 return (avg);
98 static void
99 cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos)
101 int i;
102 for (*left = 0, i = 0; i < num_bits; i++) {
103 if (isset(bitmap, i)) {
104 (*left)++;
105 *bit_pos = i;
110 static uint8
111 spec_to_chan(chanspec_t chspec)
113 switch (CHSPEC_CTL_SB(chspec)) {
114 case WL_CHANSPEC_CTL_SB_NONE:
115 return CHSPEC_CHANNEL(chspec);
116 case WL_CHANSPEC_CTL_SB_UPPER:
117 return UPPER_20_SB(CHSPEC_CHANNEL(chspec));
118 case WL_CHANSPEC_CTL_SB_LOWER:
119 return LOWER_20_SB(CHSPEC_CHANNEL(chspec));
120 default:
121 return 0;
125 #define CCA_THRESH_MILLI 14
126 #define CCA_THRESH_INTERFERE 6
129 Take an array of measumrements representing summaries of different channels.
130 Return a recomended channel.
131 Interference is evil, get rid of that first.
132 Then hunt for lowest Other bss traffic.
133 Don't forget that channels with low duration times may not have accurate readings.
134 For the moment, do not overwrite input array.
137 cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer)
139 uint8 bitmap[CEIL(MAX_CCA_CHANNELS, NBBY)]; /* 38 Max channels needs 5 bytes = 40 */
140 int i, left, winner;
141 uint32 min_obss = 1 << 30;
143 ASSERT(num_chans < MAX_CCA_CHANNELS);
144 for (i = 0; i < (int)sizeof(bitmap); i++)
145 bitmap[i] = 0;
147 /* Initially, all channels are up for consideration */
148 for (i = 0; i < num_chans; i++) {
149 if (input[i]->chanspec)
150 setbit(bitmap, i);
152 cca_info(bitmap, num_chans, &left, &i);
153 if (!left)
154 return CCA_ERRNO_TOO_FEW;
156 /* Filter for 2.4 GHz Band */
157 if (flags & CCA_FLAG_2G_ONLY) {
158 for (i = 0; i < num_chans; i++) {
159 if (!CHSPEC_IS2G(input[i]->chanspec))
160 clrbit(bitmap, i);
163 cca_info(bitmap, num_chans, &left, &i);
164 if (!left)
165 return CCA_ERRNO_BAND;
167 /* Filter for 5 GHz Band */
168 if (flags & CCA_FLAG_5G_ONLY) {
169 for (i = 0; i < num_chans; i++) {
170 if (!CHSPEC_IS5G(input[i]->chanspec))
171 clrbit(bitmap, i);
174 cca_info(bitmap, num_chans, &left, &i);
175 if (!left)
176 return CCA_ERRNO_BAND;
178 /* Filter for Duration */
179 if (!(flags & CCA_FLAG_IGNORE_DURATION)) {
180 for (i = 0; i < num_chans; i++) {
181 if (input[i]->secs[0].duration < CCA_THRESH_MILLI)
182 clrbit(bitmap, i);
185 cca_info(bitmap, num_chans, &left, &i);
186 if (!left)
187 return CCA_ERRNO_DURATION;
189 /* Filter for 1 6 11 on 2.4 Band */
190 if (flags & CCA_FLAGS_PREFER_1_6_11) {
191 int tmp_channel = spec_to_chan(input[i]->chanspec);
192 int is2g = CHSPEC_IS2G(input[i]->chanspec);
193 for (i = 0; i < num_chans; i++) {
194 if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11)
195 clrbit(bitmap, i);
198 cca_info(bitmap, num_chans, &left, &i);
199 if (!left)
200 return CCA_ERRNO_PREF_CHAN;
202 /* Toss high interference interference */
203 if (!(flags & CCA_FLAG_IGNORE_INTERFER)) {
204 for (i = 0; i < num_chans; i++) {
205 if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE)
206 clrbit(bitmap, i);
208 cca_info(bitmap, num_chans, &left, &i);
209 if (!left)
210 return CCA_ERRNO_INTERFER;
213 /* Now find lowest obss */
214 winner = 0;
215 for (i = 0; i < num_chans; i++) {
216 if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) {
217 winner = i;
218 min_obss = input[i]->secs[0].congest_obss;
221 *answer = input[winner]->chanspec;
223 return 0;