1 /* 2 * Copyright (C) 2008 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 #include <stdlib.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <string.h> 21 22 #include <sys/socket.h> 23 #include <sys/stat.h> 24 #include <sys/ioctl.h> 25 #include <sys/types.h> 26 #include <sys/wait.h> 27 28 #include <netinet/in.h> 29 #include <arpa/inet.h> 30 31 #include <linux/wireless.h> 32 33 #include <openssl/evp.h> 34 #include <openssl/sha.h> 35 36 #define LOG_TAG "SoftapController" 37 #include <android-base/file.h> 38 #include <android-base/stringprintf.h> 39 #include <cutils/log.h> 40 #include <netutils/ifc.h> 41 #include <private/android_filesystem_config.h> 42 #include "wifi.h" 43 #include "ResponseCode.h" 44 45 #include "SoftapController.h" 46 47 using android::base::StringPrintf; 48 using android::base::WriteStringToFile; 49 50 static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"; 51 static const char HOSTAPD_BIN_FILE[] = "/system/bin/hostapd"; 52 53 SoftapController::SoftapController() 54 : mPid(0) {} 55 56 SoftapController::~SoftapController() { 57 } 58 59 int SoftapController::startSoftap() { 60 pid_t pid = 1; 61 62 if (mPid) { 63 ALOGE("SoftAP is already running"); 64 return ResponseCode::SoftapStatusResult; 65 } 66 67 if (ensure_entropy_file_exists() < 0) { 68 ALOGE("Wi-Fi entropy file was not created"); 69 } 70 71 if ((pid = fork()) < 0) { 72 ALOGE("fork failed (%s)", strerror(errno)); 73 return ResponseCode::ServiceStartFailed; 74 } 75 76 if (!pid) { 77 ensure_entropy_file_exists(); 78 if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE, 79 "-e", WIFI_ENTROPY_FILE, 80 HOSTAPD_CONF_FILE, (char *) NULL)) { 81 ALOGE("execl failed (%s)", strerror(errno)); 82 } 83 ALOGE("SoftAP failed to start"); 84 return ResponseCode::ServiceStartFailed; 85 } else { 86 mPid = pid; 87 ALOGD("SoftAP started successfully"); 88 usleep(AP_BSS_START_DELAY); 89 } 90 return ResponseCode::SoftapStatusResult; 91 } 92 93 int SoftapController::stopSoftap() { 94 95 if (mPid == 0) { 96 ALOGE("SoftAP is not running"); 97 return ResponseCode::SoftapStatusResult; 98 } 99 100 ALOGD("Stopping the SoftAP service..."); 101 kill(mPid, SIGTERM); 102 waitpid(mPid, NULL, 0); 103 104 mPid = 0; 105 ALOGD("SoftAP stopped successfully"); 106 usleep(AP_BSS_STOP_DELAY); 107 return ResponseCode::SoftapStatusResult; 108 } 109 110 bool SoftapController::isSoftapStarted() { 111 return (mPid != 0); 112 } 113 114 /* 115 * Arguments: 116 * argv[2] - wlan interface 117 * argv[3] - SSID 118 * argv[4] - Broadcast/Hidden 119 * argv[5] - Channel 120 * argv[6] - Security 121 * argv[7] - Key 122 */ 123 int SoftapController::setSoftap(int argc, char *argv[]) { 124 int hidden = 0; 125 int channel = AP_CHANNEL_DEFAULT; 126 127 if (argc < 5) { 128 ALOGE("Softap set is missing arguments. Please use:"); 129 ALOGE("softap <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>"); 130 return ResponseCode::CommandSyntaxError; 131 } 132 133 if (!strcasecmp(argv[4], "hidden")) 134 hidden = 1; 135 136 if (argc >= 5) { 137 channel = atoi(argv[5]); 138 if (channel <= 0) 139 channel = AP_CHANNEL_DEFAULT; 140 } 141 142 std::string wbuf(StringPrintf("interface=%s\n" 143 "driver=nl80211\n" 144 "ctrl_interface=/data/misc/wifi/hostapd\n" 145 "ssid=%s\n" 146 "channel=%d\n" 147 "ieee80211n=1\n" 148 "hw_mode=%c\n" 149 "ignore_broadcast_ssid=%d\n" 150 "wowlan_triggers=any\n", 151 argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden)); 152 153 std::string fbuf; 154 if (argc > 7) { 155 char psk_str[2*SHA256_DIGEST_LENGTH+1]; 156 if (!strcmp(argv[6], "wpa-psk")) { 157 if (!generatePsk(argv[3], argv[7], psk_str)) { 158 return ResponseCode::OperationFailed; 159 } 160 fbuf = StringPrintf("%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str); 161 } else if (!strcmp(argv[6], "wpa2-psk")) { 162 if (!generatePsk(argv[3], argv[7], psk_str)) { 163 return ResponseCode::OperationFailed; 164 } 165 fbuf = StringPrintf("%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str); 166 } else if (!strcmp(argv[6], "open")) { 167 fbuf = wbuf; 168 } 169 } else if (argc > 6) { 170 if (!strcmp(argv[6], "open")) { 171 fbuf = wbuf; 172 } 173 } else { 174 fbuf = wbuf; 175 } 176 177 if (!WriteStringToFile(fbuf, HOSTAPD_CONF_FILE, 0660, AID_SYSTEM, AID_WIFI)) { 178 ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 179 return ResponseCode::OperationFailed; 180 } 181 return ResponseCode::SoftapStatusResult; 182 } 183 184 /* 185 * Arguments: 186 * argv[2] - interface name 187 * argv[3] - AP or P2P or STA 188 */ 189 int SoftapController::fwReloadSoftap(int argc, char *argv[]) 190 { 191 char *fwpath = NULL; 192 193 if (argc < 4) { 194 ALOGE("SoftAP fwreload is missing arguments. Please use: softap <wlan iface> <AP|P2P|STA>"); 195 return ResponseCode::CommandSyntaxError; 196 } 197 198 if (strcmp(argv[3], "AP") == 0) { 199 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP); 200 } else if (strcmp(argv[3], "P2P") == 0) { 201 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P); 202 } else if (strcmp(argv[3], "STA") == 0) { 203 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA); 204 } else { 205 return ResponseCode::CommandParameterError; 206 } 207 if (!fwpath) { 208 ALOGE("Softap fwReload - NULL path for %s", argv[3]); 209 return ResponseCode::SoftapStatusResult; 210 } 211 if (wifi_change_fw_path((const char *)fwpath)) { 212 ALOGE("Softap fwReload failed"); 213 return ResponseCode::OperationFailed; 214 } 215 else { 216 ALOGD("Softap fwReload - Ok"); 217 } 218 return ResponseCode::SoftapStatusResult; 219 } 220 221 bool SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) { 222 unsigned char psk[SHA256_DIGEST_LENGTH]; 223 224 // Use the PKCS#5 PBKDF2 with 4096 iterations 225 if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), 226 reinterpret_cast<const unsigned char *>(ssid), 227 strlen(ssid), 4096, SHA256_DIGEST_LENGTH, 228 psk) != 1) { 229 ALOGE("Cannot generate PSK using PKCS#5 PBKDF2"); 230 return false; 231 } 232 233 for (int j=0; j < SHA256_DIGEST_LENGTH; j++) { 234 sprintf(&psk_str[j*2], "%02x", psk[j]); 235 } 236 237 return true; 238 } 239