1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi.scanner;
18
19import android.net.wifi.WifiScanner;
20import android.util.ArraySet;
21
22import com.android.server.wifi.WifiNative;
23
24import java.util.Set;
25
26/**
27 * ChannelHelper that offers channel manipulation utilities when the channels in a band are known.
28 * This allows more fine operations on channels than if band channels are not known.
29 */
30public class KnownBandsChannelHelper extends ChannelHelper {
31
32    private WifiScanner.ChannelSpec[][] mBandsToChannels;
33
34    protected void setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs) {
35        mBandsToChannels = new WifiScanner.ChannelSpec[8][];
36
37        mBandsToChannels[0] = NO_CHANNELS;
38
39        mBandsToChannels[1] = new WifiScanner.ChannelSpec[channels2G.length];
40        copyChannels(mBandsToChannels[1], 0, channels2G);
41
42        mBandsToChannels[2] = new WifiScanner.ChannelSpec[channels5G.length];
43        copyChannels(mBandsToChannels[2], 0, channels5G);
44
45        mBandsToChannels[3] = new WifiScanner.ChannelSpec[channels2G.length + channels5G.length];
46        copyChannels(mBandsToChannels[3], 0, channels2G);
47        copyChannels(mBandsToChannels[3], channels2G.length, channels5G);
48
49        mBandsToChannels[4] = new WifiScanner.ChannelSpec[channelsDfs.length];
50        copyChannels(mBandsToChannels[4], 0, channelsDfs);
51
52        mBandsToChannels[5] = new WifiScanner.ChannelSpec[channels2G.length + channelsDfs.length];
53        copyChannels(mBandsToChannels[5], 0, channels2G);
54        copyChannels(mBandsToChannels[5], channels2G.length, channelsDfs);
55
56        mBandsToChannels[6] = new WifiScanner.ChannelSpec[channels5G.length + channelsDfs.length];
57        copyChannels(mBandsToChannels[6], 0, channels5G);
58        copyChannels(mBandsToChannels[6], channels5G.length, channelsDfs);
59
60        mBandsToChannels[7] = new WifiScanner.ChannelSpec[
61                channels2G.length + channels5G.length + channelsDfs.length];
62        copyChannels(mBandsToChannels[7], 0, channels2G);
63        copyChannels(mBandsToChannels[7], channels2G.length, channels5G);
64        copyChannels(mBandsToChannels[7], channels2G.length + channels5G.length, channelsDfs);
65    }
66
67    private static void copyChannels(
68            WifiScanner.ChannelSpec[] channelSpec, int offset, int[] channels) {
69        for (int i = 0; i < channels.length; i++) {
70            channelSpec[offset + i] = new WifiScanner.ChannelSpec(channels[i]);
71        }
72    }
73
74    @Override
75    public WifiScanner.ChannelSpec[] getAvailableScanChannels(int band) {
76        if (band < WifiScanner.WIFI_BAND_24_GHZ || band > WifiScanner.WIFI_BAND_BOTH_WITH_DFS) {
77            // invalid value for band
78            return NO_CHANNELS;
79        } else {
80            return mBandsToChannels[band];
81        }
82    }
83
84    @Override
85    public int estimateScanDuration(WifiScanner.ScanSettings settings) {
86        if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
87            return settings.channels.length * SCAN_PERIOD_PER_CHANNEL_MS;
88        } else {
89            return getAvailableScanChannels(settings.band).length * SCAN_PERIOD_PER_CHANNEL_MS;
90        }
91    }
92
93    private boolean isDfsChannel(int frequency) {
94        for (WifiScanner.ChannelSpec dfsChannel :
95                mBandsToChannels[WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY]) {
96            if (frequency == dfsChannel.frequency) {
97                return true;
98            }
99        }
100        return false;
101    }
102
103    // TODO this should be rewritten to be based on the input data instead of hardcoded ranges
104    private int getBandFromChannel(int frequency) {
105        if (2400 <= frequency && frequency < 2500) {
106            return WifiScanner.WIFI_BAND_24_GHZ;
107        } else if (isDfsChannel(frequency)) {
108            return WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY;
109        } else if (5100 <= frequency && frequency < 6000) {
110            return WifiScanner.WIFI_BAND_5_GHZ;
111        } else {
112            return WifiScanner.WIFI_BAND_UNSPECIFIED;
113        }
114    }
115
116    @Override
117    public boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel) {
118        WifiScanner.ChannelSpec[] settingsChannels;
119        if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
120            settingsChannels = settings.channels;
121        } else {
122            settingsChannels = getAvailableScanChannels(settings.band);
123        }
124        for (int i = 0; i < settingsChannels.length; ++i) {
125            if (settingsChannels[i].frequency == channel) {
126                return true;
127            }
128        }
129        return false;
130    }
131
132    /**
133     * ChannelCollection that merges channels so that the optimal schedule will be generated.
134     * When the max channels value is satisfied this implementation will always create a channel
135     * list that includes no more than the added channels.
136     */
137    public class KnownBandsChannelCollection extends ChannelCollection {
138        /**
139         * Stores all channels, including those that belong to added bands.
140         */
141        private final ArraySet<Integer> mChannels = new ArraySet<Integer>();
142        /**
143         * Contains only the bands that were explicitly added as bands.
144         */
145        private int mExactBands = 0;
146        /**
147         * Contains all bands, including those that were added because an added channel was in that
148         * band.
149         */
150        private int mAllBands = 0;
151
152        @Override
153        public void addChannel(int frequency) {
154            mChannels.add(frequency);
155            mAllBands |= getBandFromChannel(frequency);
156        }
157
158        @Override
159        public void addBand(int band) {
160            mExactBands |= band;
161            mAllBands |= band;
162            WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
163            for (int i = 0; i < bandChannels.length; ++i) {
164                mChannels.add(bandChannels[i].frequency);
165            }
166        }
167
168        @Override
169        public boolean containsChannel(int channel) {
170            return mChannels.contains(channel);
171        }
172
173        @Override
174        public boolean containsBand(int band) {
175            WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
176            for (int i = 0; i < bandChannels.length; ++i) {
177                if (!mChannels.contains(bandChannels[i].frequency)) {
178                    return false;
179                }
180            }
181            return true;
182        }
183
184        @Override
185        public boolean partiallyContainsBand(int band) {
186            WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
187            for (int i = 0; i < bandChannels.length; ++i) {
188                if (mChannels.contains(bandChannels[i].frequency)) {
189                    return true;
190                }
191            }
192            return false;
193        }
194
195        @Override
196        public boolean isEmpty() {
197            return mChannels.isEmpty();
198        }
199
200        @Override
201        public void clear() {
202            mAllBands = 0;
203            mExactBands = 0;
204            mChannels.clear();
205        }
206
207        @Override
208        public Set<Integer> getMissingChannelsFromBand(int band) {
209            ArraySet<Integer> missingChannels = new ArraySet<>();
210            WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
211            for (int i = 0; i < bandChannels.length; ++i) {
212                if (!mChannels.contains(bandChannels[i].frequency)) {
213                    missingChannels.add(bandChannels[i].frequency);
214                }
215            }
216            return missingChannels;
217        }
218
219        @Override
220        public Set<Integer> getContainingChannelsFromBand(int band) {
221            ArraySet<Integer> containingChannels = new ArraySet<>();
222            WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
223            for (int i = 0; i < bandChannels.length; ++i) {
224                if (mChannels.contains(bandChannels[i].frequency)) {
225                    containingChannels.add(bandChannels[i].frequency);
226                }
227            }
228            return containingChannels;
229        }
230
231        @Override
232        public Set<Integer> getChannelSet() {
233            if (!isEmpty() && mAllBands != mExactBands) {
234                return mChannels;
235            } else {
236                return new ArraySet<>();
237            }
238        }
239
240        @Override
241        public void fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels) {
242            if ((mChannels.size() > maxChannels || mAllBands == mExactBands)
243                    && mAllBands != 0) {
244                bucketSettings.band = mAllBands;
245                bucketSettings.num_channels = 0;
246                bucketSettings.channels = null;
247            } else {
248                bucketSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
249                bucketSettings.num_channels = mChannels.size();
250                bucketSettings.channels = new WifiNative.ChannelSettings[mChannels.size()];
251                for (int i = 0; i < mChannels.size(); ++i) {
252                    WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings();
253                    channelSettings.frequency = mChannels.valueAt(i);
254                    bucketSettings.channels[i] = channelSettings;
255                }
256            }
257        }
258
259        @Override
260        public Set<Integer> getSupplicantScanFreqs() {
261            if (mExactBands == WifiScanner.WIFI_BAND_BOTH_WITH_DFS) {
262                return null;
263            } else {
264                return new ArraySet<Integer>(mChannels);
265            }
266        }
267
268        public Set<Integer> getAllChannels() {
269            return new ArraySet<Integer>(mChannels);
270        }
271    }
272
273    @Override
274
275    public KnownBandsChannelCollection createChannelCollection() {
276        return new KnownBandsChannelCollection();
277    }
278}
279