Home | History | Annotate | Download | only in util
      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 
     17 package com.android.server.wifi.util;
     18 
     19 import android.net.wifi.WifiConfiguration;
     20 import android.net.wifi.WifiScanner;
     21 import android.util.Log;
     22 
     23 import com.android.server.wifi.WifiNative;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Random;
     27 
     28 /**
     29  * Provide utility functions for updating soft AP related configuration.
     30  */
     31 public class ApConfigUtil {
     32     private static final String TAG = "ApConfigUtil";
     33 
     34     public static final int DEFAULT_AP_BAND = WifiConfiguration.AP_BAND_2GHZ;
     35     public static final int DEFAULT_AP_CHANNEL = 6;
     36 
     37     /* Return code for updateConfiguration. */
     38     public static final int SUCCESS = 0;
     39     public static final int ERROR_NO_CHANNEL = 1;
     40     public static final int ERROR_GENERIC = 2;
     41 
     42     /* Random number generator used for AP channel selection. */
     43     private static final Random sRandom = new Random();
     44 
     45     /**
     46      * Convert frequency to channel.
     47      * @param frequency frequency to convert
     48      * @return channel number associated with given frequency, -1 if no match
     49      */
     50     public static int convertFrequencyToChannel(int frequency) {
     51         if (frequency >= 2412 && frequency <= 2472) {
     52             return (frequency - 2412) / 5 + 1;
     53         } else if (frequency == 2484) {
     54             return 14;
     55         } else if (frequency >= 5170  &&  frequency <= 5825) {
     56             /* DFS is included. */
     57             return (frequency - 5170) / 5 + 34;
     58         }
     59 
     60         return -1;
     61     }
     62 
     63     /**
     64      * Return a channel number for AP setup based on the frequency band.
     65      * @param apBand one of the value of WifiConfiguration.AP_BAND_*.
     66      * @param allowed2GChannels list of allowed 2GHz channels
     67      * @param allowed5GFreqList list of allowed 5GHz frequencies
     68      * @return a valid channel number on success, -1 on failure.
     69      */
     70     public static int chooseApChannel(int apBand,
     71                                       ArrayList<Integer> allowed2GChannels,
     72                                       int[] allowed5GFreqList) {
     73         if (apBand != WifiConfiguration.AP_BAND_2GHZ
     74                 && apBand != WifiConfiguration.AP_BAND_5GHZ
     75                         && apBand != WifiConfiguration.AP_BAND_ANY) {
     76             Log.e(TAG, "Invalid band: " + apBand);
     77             return -1;
     78         }
     79 
     80         // TODO(b/72120668): Create channel selection logic for AP_BAND_ANY.
     81         if (apBand == WifiConfiguration.AP_BAND_2GHZ
     82                 || apBand == WifiConfiguration.AP_BAND_ANY)  {
     83             /* Select a channel from 2GHz band. */
     84             if (allowed2GChannels == null || allowed2GChannels.size() == 0) {
     85                 Log.d(TAG, "2GHz allowed channel list not specified");
     86                 /* Use default channel. */
     87                 return DEFAULT_AP_CHANNEL;
     88             }
     89 
     90             /* Pick a random channel. */
     91             int index = sRandom.nextInt(allowed2GChannels.size());
     92             return allowed2GChannels.get(index).intValue();
     93         }
     94 
     95         /* 5G without DFS. */
     96         if (allowed5GFreqList != null && allowed5GFreqList.length > 0) {
     97             /* Pick a random channel from the list of supported channels. */
     98             return convertFrequencyToChannel(
     99                     allowed5GFreqList[sRandom.nextInt(allowed5GFreqList.length)]);
    100         }
    101 
    102         Log.e(TAG, "No available channels on 5GHz band");
    103         return -1;
    104     }
    105 
    106     /**
    107      * Update AP band and channel based on the provided country code and band.
    108      * This will also set
    109      * @param wifiNative reference to WifiNative
    110      * @param countryCode country code
    111      * @param allowed2GChannels list of allowed 2GHz channels
    112      * @param config configuration to update
    113      * @return an integer result code
    114      */
    115     public static int updateApChannelConfig(WifiNative wifiNative,
    116                                             String countryCode,
    117                                             ArrayList<Integer> allowed2GChannels,
    118                                             WifiConfiguration config) {
    119         /* Use default band and channel for device without HAL. */
    120         if (!wifiNative.isHalStarted()) {
    121             config.apBand = DEFAULT_AP_BAND;
    122             config.apChannel = DEFAULT_AP_CHANNEL;
    123             return SUCCESS;
    124         }
    125 
    126         /* Country code is mandatory for 5GHz band. */
    127         if (config.apBand == WifiConfiguration.AP_BAND_5GHZ
    128                 && countryCode == null) {
    129             Log.e(TAG, "5GHz band is not allowed without country code");
    130             return ERROR_GENERIC;
    131         }
    132 
    133         /* Select a channel if it is not specified. */
    134         if (config.apChannel == 0) {
    135             config.apChannel = chooseApChannel(
    136                     config.apBand, allowed2GChannels,
    137                     wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
    138             if (config.apChannel == -1) {
    139                 /* We're not able to get channel from wificond. */
    140                 Log.e(TAG, "Failed to get available channel.");
    141                 return ERROR_NO_CHANNEL;
    142             }
    143         }
    144 
    145         return SUCCESS;
    146     }
    147 }
    148