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 <cutils/log.h> 38 #include <netutils/ifc.h> 39 #include <private/android_filesystem_config.h> 40 #include "wifi.h" 41 #include "ResponseCode.h" 42 43 #include "SoftapController.h" 44 45 static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"; 46 static const char HOSTAPD_BIN_FILE[] = "/system/bin/hostapd"; 47 48 SoftapController::SoftapController() 49 : mPid(0) {} 50 51 SoftapController::~SoftapController() { 52 } 53 54 int SoftapController::startSoftap() { 55 pid_t pid = 1; 56 57 if (mPid) { 58 ALOGE("SoftAP is already running"); 59 return ResponseCode::SoftapStatusResult; 60 } 61 62 if (ensure_entropy_file_exists() < 0) { 63 ALOGE("Wi-Fi entropy file was not created"); 64 } 65 66 if ((pid = fork()) < 0) { 67 ALOGE("fork failed (%s)", strerror(errno)); 68 return ResponseCode::ServiceStartFailed; 69 } 70 71 if (!pid) { 72 ensure_entropy_file_exists(); 73 if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE, 74 "-e", WIFI_ENTROPY_FILE, 75 HOSTAPD_CONF_FILE, (char *) NULL)) { 76 ALOGE("execl failed (%s)", strerror(errno)); 77 } 78 ALOGE("SoftAP failed to start"); 79 return ResponseCode::ServiceStartFailed; 80 } else { 81 mPid = pid; 82 ALOGD("SoftAP started successfully"); 83 usleep(AP_BSS_START_DELAY); 84 } 85 return ResponseCode::SoftapStatusResult; 86 } 87 88 int SoftapController::stopSoftap() { 89 90 if (mPid == 0) { 91 ALOGE("SoftAP is not running"); 92 return ResponseCode::SoftapStatusResult; 93 } 94 95 ALOGD("Stopping the SoftAP service..."); 96 kill(mPid, SIGTERM); 97 waitpid(mPid, NULL, 0); 98 99 mPid = 0; 100 ALOGD("SoftAP stopped successfully"); 101 usleep(AP_BSS_STOP_DELAY); 102 return ResponseCode::SoftapStatusResult; 103 } 104 105 bool SoftapController::isSoftapStarted() { 106 return (mPid != 0); 107 } 108 109 /* 110 * Arguments: 111 * argv[2] - wlan interface 112 * argv[3] - SSID 113 * argv[4] - Broadcast/Hidden 114 * argv[5] - Channel 115 * argv[6] - Security 116 * argv[7] - Key 117 */ 118 int SoftapController::setSoftap(int argc, char *argv[]) { 119 char psk_str[2*SHA256_DIGEST_LENGTH+1]; 120 int ret = ResponseCode::SoftapStatusResult; 121 int fd; 122 int hidden = 0; 123 int channel = AP_CHANNEL_DEFAULT; 124 char *wbuf = NULL; 125 char *fbuf = NULL; 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 asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface=" 143 "/data/misc/wifi/hostapd\nssid=%s\nchannel=%d\nieee80211n=1\n" 144 "hw_mode=g\nignore_broadcast_ssid=%d\nwowlan_triggers=any\n", 145 argv[2], argv[3], channel, hidden); 146 147 if (argc > 7) { 148 if (!strcmp(argv[6], "wpa-psk")) { 149 generatePsk(argv[3], argv[7], psk_str); 150 asprintf(&fbuf, "%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str); 151 } else if (!strcmp(argv[6], "wpa2-psk")) { 152 generatePsk(argv[3], argv[7], psk_str); 153 asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str); 154 } else if (!strcmp(argv[6], "open")) { 155 asprintf(&fbuf, "%s", wbuf); 156 } 157 } else if (argc > 6) { 158 if (!strcmp(argv[6], "open")) { 159 asprintf(&fbuf, "%s", wbuf); 160 } 161 } else { 162 asprintf(&fbuf, "%s", wbuf); 163 } 164 165 fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); 166 if (fd < 0) { 167 ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 168 free(wbuf); 169 free(fbuf); 170 return ResponseCode::OperationFailed; 171 } 172 if (write(fd, fbuf, strlen(fbuf)) < 0) { 173 ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 174 ret = ResponseCode::OperationFailed; 175 } 176 free(wbuf); 177 free(fbuf); 178 179 /* Note: apparently open can fail to set permissions correctly at times */ 180 if (fchmod(fd, 0660) < 0) { 181 ALOGE("Error changing permissions of %s to 0660: %s", 182 HOSTAPD_CONF_FILE, strerror(errno)); 183 close(fd); 184 unlink(HOSTAPD_CONF_FILE); 185 return ResponseCode::OperationFailed; 186 } 187 188 if (fchown(fd, AID_SYSTEM, AID_WIFI) < 0) { 189 ALOGE("Error changing group ownership of %s to %d: %s", 190 HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno)); 191 close(fd); 192 unlink(HOSTAPD_CONF_FILE); 193 return ResponseCode::OperationFailed; 194 } 195 196 close(fd); 197 return ret; 198 } 199 200 /* 201 * Arguments: 202 * argv[2] - interface name 203 * argv[3] - AP or P2P or STA 204 */ 205 int SoftapController::fwReloadSoftap(int argc, char *argv[]) 206 { 207 char *fwpath = NULL; 208 209 if (argc < 4) { 210 ALOGE("SoftAP fwreload is missing arguments. Please use: softap <wlan iface> <AP|P2P|STA>"); 211 return ResponseCode::CommandSyntaxError; 212 } 213 214 if (strcmp(argv[3], "AP") == 0) { 215 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP); 216 } else if (strcmp(argv[3], "P2P") == 0) { 217 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P); 218 } else if (strcmp(argv[3], "STA") == 0) { 219 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA); 220 } 221 if (!fwpath) 222 return ResponseCode::CommandParameterError; 223 if (wifi_change_fw_path((const char *)fwpath)) { 224 ALOGE("Softap fwReload failed"); 225 return ResponseCode::OperationFailed; 226 } 227 else { 228 ALOGD("Softap fwReload - Ok"); 229 } 230 return ResponseCode::SoftapStatusResult; 231 } 232 233 void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) { 234 unsigned char psk[SHA256_DIGEST_LENGTH]; 235 int j; 236 // Use the PKCS#5 PBKDF2 with 4096 iterations 237 PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), 238 reinterpret_cast<const unsigned char *>(ssid), strlen(ssid), 239 4096, SHA256_DIGEST_LENGTH, psk); 240 for (j=0; j < SHA256_DIGEST_LENGTH; j++) { 241 sprintf(&psk_str[j*2], "%02x", psk[j]); 242 } 243 } 244