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 public static final int HIGHEST_2G_AP_CHANNEL = 14; 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 */ convertFrequencyToChannel(int frequency)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 */ chooseApChannel(int apBand, ArrayList<Integer> allowed2GChannels, int[] allowed5GFreqList)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 */ updateApChannelConfig(WifiNative wifiNative, String countryCode, ArrayList<Integer> allowed2GChannels, WifiConfiguration config)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