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