SoftapController.cpp revision 0a379691e04700b3b44948450b1e3db92ef2ec01
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 42#include "SoftapController.h" 43 44static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"; 45 46SoftapController::SoftapController() { 47 mPid = 0; 48 mSock = socket(AF_INET, SOCK_DGRAM, 0); 49 if (mSock < 0) 50 ALOGE("Failed to open socket"); 51 memset(mIface, 0, sizeof(mIface)); 52} 53 54SoftapController::~SoftapController() { 55 if (mSock >= 0) 56 close(mSock); 57} 58 59int SoftapController::setCommand(char *iface, const char *fname, unsigned buflen) { 60#ifdef HAVE_HOSTAPD 61 return 0; 62#else 63 char tBuf[SOFTAP_MAX_BUFFER_SIZE]; 64 struct iwreq wrq; 65 struct iw_priv_args *priv_ptr; 66 int i, j, ret; 67 int cmd = 0, sub_cmd = 0; 68 69 strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name)); 70 wrq.u.data.pointer = tBuf; 71 wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args); 72 wrq.u.data.flags = 0; 73 if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) { 74 ALOGE("SIOCGIPRIV failed: %d", ret); 75 return ret; 76 } 77 78 priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer; 79 for(i=0; i < wrq.u.data.length;i++) { 80 if (strcmp(priv_ptr[i].name, fname) == 0) { 81 cmd = priv_ptr[i].cmd; 82 break; 83 } 84 } 85 86 if (i == wrq.u.data.length) { 87 ALOGE("iface:%s, fname: %s - function not supported", iface, fname); 88 return -1; 89 } 90 91 if (cmd < SIOCDEVPRIVATE) { 92 for(j=0; j < i; j++) { 93 if ((priv_ptr[j].set_args == priv_ptr[i].set_args) && 94 (priv_ptr[j].get_args == priv_ptr[i].get_args) && 95 (priv_ptr[j].name[0] == '\0')) 96 break; 97 } 98 if (j == i) { 99 ALOGE("iface:%s, fname: %s - invalid private ioctl", iface, fname); 100 return -1; 101 } 102 sub_cmd = cmd; 103 cmd = priv_ptr[j].cmd; 104 } 105 106 strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name)); 107 if ((buflen == 0) && (*mBuf != 0)) 108 wrq.u.data.length = strlen(mBuf) + 1; 109 else 110 wrq.u.data.length = buflen; 111 wrq.u.data.pointer = mBuf; 112 wrq.u.data.flags = sub_cmd; 113 ret = ioctl(mSock, cmd, &wrq); 114 return ret; 115#endif 116} 117 118int SoftapController::startDriver(char *iface) { 119 int ret; 120 121 if (mSock < 0) { 122 ALOGE("Softap driver start - failed to open socket"); 123 return -1; 124 } 125 if (!iface || (iface[0] == '\0')) { 126 ALOGD("Softap driver start - wrong interface"); 127 iface = mIface; 128 } 129 130 *mBuf = 0; 131 ret = setCommand(iface, "START"); 132 if (ret < 0) { 133 ALOGE("Softap driver start: %d", ret); 134 return ret; 135 } 136#ifdef HAVE_HOSTAPD 137 ifc_init(); 138 ret = ifc_up(iface); 139 ifc_close(); 140#endif 141 usleep(AP_DRIVER_START_DELAY); 142 ALOGD("Softap driver start: %d", ret); 143 return ret; 144} 145 146int SoftapController::stopDriver(char *iface) { 147 int ret; 148 149 if (mSock < 0) { 150 ALOGE("Softap driver stop - failed to open socket"); 151 return -1; 152 } 153 if (!iface || (iface[0] == '\0')) { 154 ALOGD("Softap driver stop - wrong interface"); 155 iface = mIface; 156 } 157 *mBuf = 0; 158#ifdef HAVE_HOSTAPD 159 ifc_init(); 160 ret = ifc_down(iface); 161 ifc_close(); 162 if (ret < 0) { 163 ALOGE("Softap %s down: %d", iface, ret); 164 } 165#endif 166 ret = setCommand(iface, "STOP"); 167 ALOGD("Softap driver stop: %d", ret); 168 return ret; 169} 170 171int SoftapController::startSoftap() { 172 pid_t pid = 1; 173 int ret = 0; 174 175 if (mPid) { 176 ALOGE("Softap already started"); 177 return 0; 178 } 179 if (mSock < 0) { 180 ALOGE("Softap startap - failed to open socket"); 181 return -1; 182 } 183#ifdef HAVE_HOSTAPD 184 if ((pid = fork()) < 0) { 185 ALOGE("fork failed (%s)", strerror(errno)); 186 return -1; 187 } 188#endif 189 if (!pid) { 190#ifdef HAVE_HOSTAPD 191 ensure_entropy_file_exists(); 192 if (execl("/system/bin/hostapd", "/system/bin/hostapd", 193 "-e", WIFI_ENTROPY_FILE, 194 HOSTAPD_CONF_FILE, (char *) NULL)) { 195 ALOGE("execl failed (%s)", strerror(errno)); 196 } 197#endif 198 ALOGE("Should never get here!"); 199 return -1; 200 } else { 201 *mBuf = 0; 202 ret = setCommand(mIface, "AP_BSS_START"); 203 if (ret) { 204 ALOGE("Softap startap - failed: %d", ret); 205 } 206 else { 207 mPid = pid; 208 ALOGD("Softap startap - Ok"); 209 usleep(AP_BSS_START_DELAY); 210 } 211 } 212 return ret; 213 214} 215 216int SoftapController::stopSoftap() { 217 int ret; 218 219 if (mPid == 0) { 220 ALOGE("Softap already stopped"); 221 return 0; 222 } 223 224#ifdef HAVE_HOSTAPD 225 ALOGD("Stopping Softap service"); 226 kill(mPid, SIGTERM); 227 waitpid(mPid, NULL, 0); 228#endif 229 if (mSock < 0) { 230 ALOGE("Softap stopap - failed to open socket"); 231 return -1; 232 } 233 *mBuf = 0; 234 ret = setCommand(mIface, "AP_BSS_STOP"); 235 mPid = 0; 236 ALOGD("Softap service stopped: %d", ret); 237 usleep(AP_BSS_STOP_DELAY); 238 return ret; 239} 240 241bool SoftapController::isSoftapStarted() { 242 return (mPid != 0 ? true : false); 243} 244 245int SoftapController::addParam(int pos, const char *cmd, const char *arg) 246{ 247 if (pos < 0) 248 return pos; 249 if ((unsigned)(pos + strlen(cmd) + strlen(arg) + 1) >= sizeof(mBuf)) { 250 ALOGE("Command line is too big"); 251 return -1; 252 } 253 pos += sprintf(&mBuf[pos], "%s=%s,", cmd, arg); 254 return pos; 255} 256 257/* 258 * Arguments: 259 * argv[2] - wlan interface 260 * argv[3] - softap interface 261 * argv[4] - SSID 262 * argv[5] - Security 263 * argv[6] - Key 264 * argv[7] - Channel 265 * argv[8] - Preamble 266 * argv[9] - Max SCB 267 */ 268int SoftapController::setSoftap(int argc, char *argv[]) { 269 char psk_str[2*SHA256_DIGEST_LENGTH+1]; 270 int ret = 0, i = 0, fd; 271 char *ssid, *iface; 272 273 if (mSock < 0) { 274 ALOGE("Softap set - failed to open socket"); 275 return -1; 276 } 277 if (argc < 4) { 278 ALOGE("Softap set - missing arguments"); 279 return -1; 280 } 281 282 strncpy(mIface, argv[3], sizeof(mIface)); 283 iface = argv[2]; 284 285#ifdef HAVE_HOSTAPD 286 char *wbuf = NULL; 287 char *fbuf = NULL; 288 289 if (argc > 4) { 290 ssid = argv[4]; 291 } else { 292 ssid = (char *)"AndroidAP"; 293 } 294 295 asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface=" 296 "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nwmm_enabled=1\n", iface, ssid); 297 298 if (argc > 5) { 299 if (!strcmp(argv[5], "wpa-psk")) { 300 generatePsk(ssid, argv[6], psk_str); 301 asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str); 302 } else if (!strcmp(argv[5], "wpa2-psk")) { 303 generatePsk(ssid, argv[6], psk_str); 304 asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str); 305 } else if (!strcmp(argv[5], "open")) { 306 asprintf(&fbuf, "%s", wbuf); 307 } 308 } else { 309 asprintf(&fbuf, "%s", wbuf); 310 } 311 312 fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660); 313 if (fd < 0) { 314 ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 315 free(wbuf); 316 free(fbuf); 317 return -1; 318 } 319 if (write(fd, fbuf, strlen(fbuf)) < 0) { 320 ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 321 ret = -1; 322 } 323 close(fd); 324 free(wbuf); 325 free(fbuf); 326 327 /* Note: apparently open can fail to set permissions correctly at times */ 328 if (chmod(HOSTAPD_CONF_FILE, 0660) < 0) { 329 ALOGE("Error changing permissions of %s to 0660: %s", 330 HOSTAPD_CONF_FILE, strerror(errno)); 331 unlink(HOSTAPD_CONF_FILE); 332 return -1; 333 } 334 335 if (chown(HOSTAPD_CONF_FILE, AID_SYSTEM, AID_WIFI) < 0) { 336 ALOGE("Error changing group ownership of %s to %d: %s", 337 HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno)); 338 unlink(HOSTAPD_CONF_FILE); 339 return -1; 340 } 341 342#else 343 /* Create command line */ 344 i = addParam(i, "ASCII_CMD", "AP_CFG"); 345 if (argc > 4) { 346 ssid = argv[4]; 347 } else { 348 ssid = (char *)"AndroidAP"; 349 } 350 i = addParam(i, "SSID", ssid); 351 if (argc > 5) { 352 i = addParam(i, "SEC", argv[5]); 353 } else { 354 i = addParam(i, "SEC", "open"); 355 } 356 if (argc > 6) { 357 generatePsk(ssid, argv[6], psk_str); 358 i = addParam(i, "KEY", psk_str); 359 } else { 360 i = addParam(i, "KEY", "12345678"); 361 } 362 if (argc > 7) { 363 i = addParam(i, "CHANNEL", argv[7]); 364 } else { 365 i = addParam(i, "CHANNEL", "6"); 366 } 367 if (argc > 8) { 368 i = addParam(i, "PREAMBLE", argv[8]); 369 } else { 370 i = addParam(i, "PREAMBLE", "0"); 371 } 372 if (argc > 9) { 373 i = addParam(i, "MAX_SCB", argv[9]); 374 } else { 375 i = addParam(i, "MAX_SCB", "8"); 376 } 377 if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) { 378 ALOGE("Softap set - command is too big"); 379 return i; 380 } 381 sprintf(&mBuf[i], "END"); 382 383 /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */ 384 ret = setCommand(iface, "AP_SET_CFG"); 385 if (ret) { 386 ALOGE("Softap set - failed: %d", ret); 387 } 388 else { 389 ALOGD("Softap set - Ok"); 390 usleep(AP_SET_CFG_DELAY); 391 } 392#endif 393 return ret; 394} 395 396void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) { 397 unsigned char psk[SHA256_DIGEST_LENGTH]; 398 int j; 399 // Use the PKCS#5 PBKDF2 with 4096 iterations 400 PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), 401 reinterpret_cast<const unsigned char *>(ssid), strlen(ssid), 402 4096, SHA256_DIGEST_LENGTH, psk); 403 for (j=0; j < SHA256_DIGEST_LENGTH; j++) { 404 sprintf(&psk_str[j<<1], "%02x", psk[j]); 405 } 406 psk_str[j<<1] = '\0'; 407} 408 409 410/* 411 * Arguments: 412 * argv[2] - interface name 413 * argv[3] - AP or STA 414 */ 415int SoftapController::fwReloadSoftap(int argc, char *argv[]) 416{ 417 int ret, i = 0; 418 char *iface; 419 char *fwpath; 420 421 if (mSock < 0) { 422 ALOGE("Softap fwrealod - failed to open socket"); 423 return -1; 424 } 425 if (argc < 4) { 426 ALOGE("Softap fwreload - missing arguments"); 427 return -1; 428 } 429 430 iface = argv[2]; 431 432 if (strcmp(argv[3], "AP") == 0) { 433 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP); 434 } else if (strcmp(argv[3], "P2P") == 0) { 435 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P); 436 } else { 437 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA); 438 } 439 if (!fwpath) 440 return -1; 441#ifdef HAVE_HOSTAPD 442 ret = wifi_change_fw_path((const char *)fwpath); 443#else 444 sprintf(mBuf, "FW_PATH=%s", fwpath); 445 ret = setCommand(iface, "WL_FW_RELOAD"); 446#endif 447 if (ret) { 448 ALOGE("Softap fwReload - failed: %d", ret); 449 } 450 else { 451 ALOGD("Softap fwReload - Ok"); 452 } 453 return ret; 454} 455 456int SoftapController::clientsSoftap(char **retbuf) 457{ 458 int ret; 459 460 if (mSock < 0) { 461 ALOGE("Softap clients - failed to open socket"); 462 return -1; 463 } 464 *mBuf = 0; 465 ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE); 466 if (ret) { 467 ALOGE("Softap clients - failed: %d", ret); 468 } else { 469 asprintf(retbuf, "Softap clients:%s", mBuf); 470 ALOGD("Softap clients:%s", mBuf); 471 } 472 return ret; 473} 474