1e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu/*
2e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Copyright (C) 2016 The Android Open Source Project
3e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu *
4e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Licensed under the Apache License, Version 2.0 (the "License");
5e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * you may not use this file except in compliance with the License.
6e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * You may obtain a copy of the License at
7e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu *
8e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu *      http://www.apache.org/licenses/LICENSE-2.0
9e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu *
10e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Unless required by applicable law or agreed to in writing, software
11e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * distributed under the License is distributed on an "AS IS" BASIS,
12e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * See the License for the specific language governing permissions and
14e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * limitations under the License.
15e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */
16e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
17e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiupackage com.android.server.wifi.util;
18e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
19e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.wifi.WifiConfiguration;
20e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.net.wifi.WifiScanner;
21e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport android.util.Log;
22e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
23e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport com.android.server.wifi.WifiNative;
24e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
25e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport java.util.ArrayList;
26e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiuimport java.util.Random;
27e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
28e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu/**
29e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu * Provide utility functions for updating soft AP related configuration.
30e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu */
31e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiupublic class ApConfigUtil {
32e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    private static final String TAG = "ApConfigUtil";
33e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
34e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static final int DEFAULT_AP_BAND = WifiConfiguration.AP_BAND_2GHZ;
35e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static final int DEFAULT_AP_CHANNEL = 6;
36e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
37e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    /* Return code for updateConfiguration. */
38e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static final int SUCCESS = 0;
39e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static final int ERROR_NO_CHANNEL = 1;
40e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static final int ERROR_GENERIC = 2;
41e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
42e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    /* Random number generator used for AP channel selection. */
43e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    private static final Random sRandom = new Random();
44e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
45e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    /**
46e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * Convert frequency to channel.
47e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param frequency frequency to convert
48e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @return channel number associated with given frequency, -1 if no match
49e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     */
50e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static int convertFrequencyToChannel(int frequency) {
51e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (frequency >= 2412 && frequency <= 2472) {
52e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return (frequency - 2412) / 5 + 1;
53e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        } else if (frequency == 2484) {
54e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return 14;
55e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        } else if (frequency >= 5170  &&  frequency <= 5825) {
56e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            /* DFS is included. */
57e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return (frequency - 5170) / 5 + 34;
58e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
59e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
60e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        return -1;
61e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    }
62e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
63e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    /**
64e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * Return a channel number for AP setup based on the frequency band.
65e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param apBand 0 for 2GHz, 1 for 5GHz
66e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param allowed2GChannels list of allowed 2GHz channels
67e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param allowed5GFreqList list of allowed 5GHz frequencies
68e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @return a valid channel number on success, -1 on failure.
69e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     */
70e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static int chooseApChannel(int apBand,
71e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                                      ArrayList<Integer> allowed2GChannels,
72e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                                      int[] allowed5GFreqList) {
73e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (apBand != WifiConfiguration.AP_BAND_2GHZ
74e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                && apBand != WifiConfiguration.AP_BAND_5GHZ) {
75e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            Log.e(TAG, "Invalid band: " + apBand);
76e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return -1;
77e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
78e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
79e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (apBand == WifiConfiguration.AP_BAND_2GHZ)  {
80e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            /* Select a channel from 2GHz band. */
81e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            if (allowed2GChannels == null || allowed2GChannels.size() == 0) {
82e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                Log.d(TAG, "2GHz allowed channel list not specified");
83e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                /* Use default channel. */
84e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                return DEFAULT_AP_CHANNEL;
85e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            }
86e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
87e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            /* Pick a random channel. */
88e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            int index = sRandom.nextInt(allowed2GChannels.size());
89e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return allowed2GChannels.get(index).intValue();
90e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
91e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
92e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        /* 5G without DFS. */
93e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (allowed5GFreqList != null && allowed5GFreqList.length > 0) {
94e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            /* Pick a random channel from the list of supported channels. */
95e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return convertFrequencyToChannel(
96e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                    allowed5GFreqList[sRandom.nextInt(allowed5GFreqList.length)]);
97e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
98e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
99e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        Log.e(TAG, "No available channels on 5GHz band");
100e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        return -1;
101e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    }
102e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
103e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    /**
104e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * Update AP band and channel based on the provided country code and band.
105e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * This will also set
106e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param wifiNative reference to WifiNative
107e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param countryCode country code
108e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param allowed2GChannels list of allowed 2GHz channels
109e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @param config configuration to update
110e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     * @return an integer result code
111e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu     */
112e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    public static int updateApChannelConfig(WifiNative wifiNative,
113e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                                            String countryCode,
114e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                                            ArrayList<Integer> allowed2GChannels,
115e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                                            WifiConfiguration config) {
116e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        /* Use default band and channel for device without HAL. */
117e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (!wifiNative.isHalStarted()) {
118e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            config.apBand = DEFAULT_AP_BAND;
119e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            config.apChannel = DEFAULT_AP_CHANNEL;
120e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return SUCCESS;
121e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
122e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
123e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        /* Country code is mandatory for 5GHz band. */
124e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (config.apBand == WifiConfiguration.AP_BAND_5GHZ
125e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                && countryCode == null) {
126e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            Log.e(TAG, "5GHz band is not allowed without country code");
127e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            return ERROR_GENERIC;
128e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
129e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
130e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        /* Select a channel if it is not specified. */
131e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        if (config.apChannel == 0) {
132e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            config.apChannel = chooseApChannel(
133e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                    config.apBand, allowed2GChannels,
134e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                    wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
135e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            if (config.apChannel == -1) {
136e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                if (wifiNative.isGetChannelsForBandSupported()) {
137e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                    /* We're not able to get channel when it is supported by HAL. */
138e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                    Log.e(TAG, "Failed to get available channel.");
139e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                    return ERROR_NO_CHANNEL;
140e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                }
141e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
142e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                /* Use the default for HAL without get channel support. */
143e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                config.apBand = DEFAULT_AP_BAND;
144e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu                config.apChannel = DEFAULT_AP_CHANNEL;
145e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu            }
146e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        }
147e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu
148e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu        return SUCCESS;
149e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu    }
150e5b93fbfe451bc57c07b3f72191b52b6bd237d5bPeter Qiu}
151