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 44 static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf"; 45 46 SoftapController::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 54 SoftapController::~SoftapController() { 55 if (mSock >= 0) 56 close(mSock); 57 } 58 59 int 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 118 int 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 146 int 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 171 int 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 216 int 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 241 bool SoftapController::isSoftapStarted() { 242 return (mPid != 0 ? true : false); 243 } 244 245 int 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 */ 268 int 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\nieee80211n=1\n", 297 iface, ssid); 298 299 if (argc > 5) { 300 if (!strcmp(argv[5], "wpa-psk")) { 301 generatePsk(ssid, argv[6], psk_str); 302 asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str); 303 } else if (!strcmp(argv[5], "wpa2-psk")) { 304 generatePsk(ssid, argv[6], psk_str); 305 asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str); 306 } else if (!strcmp(argv[5], "open")) { 307 asprintf(&fbuf, "%s", wbuf); 308 } 309 } else { 310 asprintf(&fbuf, "%s", wbuf); 311 } 312 313 fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660); 314 if (fd < 0) { 315 ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 316 free(wbuf); 317 free(fbuf); 318 return -1; 319 } 320 if (write(fd, fbuf, strlen(fbuf)) < 0) { 321 ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); 322 ret = -1; 323 } 324 close(fd); 325 free(wbuf); 326 free(fbuf); 327 328 /* Note: apparently open can fail to set permissions correctly at times */ 329 if (chmod(HOSTAPD_CONF_FILE, 0660) < 0) { 330 ALOGE("Error changing permissions of %s to 0660: %s", 331 HOSTAPD_CONF_FILE, strerror(errno)); 332 unlink(HOSTAPD_CONF_FILE); 333 return -1; 334 } 335 336 if (chown(HOSTAPD_CONF_FILE, AID_SYSTEM, AID_WIFI) < 0) { 337 ALOGE("Error changing group ownership of %s to %d: %s", 338 HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno)); 339 unlink(HOSTAPD_CONF_FILE); 340 return -1; 341 } 342 343 #else 344 /* Create command line */ 345 i = addParam(i, "ASCII_CMD", "AP_CFG"); 346 if (argc > 4) { 347 ssid = argv[4]; 348 } else { 349 ssid = (char *)"AndroidAP"; 350 } 351 i = addParam(i, "SSID", ssid); 352 if (argc > 5) { 353 i = addParam(i, "SEC", argv[5]); 354 } else { 355 i = addParam(i, "SEC", "open"); 356 } 357 if (argc > 6) { 358 generatePsk(ssid, argv[6], psk_str); 359 i = addParam(i, "KEY", psk_str); 360 } else { 361 i = addParam(i, "KEY", "12345678"); 362 } 363 if (argc > 7) { 364 i = addParam(i, "CHANNEL", argv[7]); 365 } else { 366 i = addParam(i, "CHANNEL", "6"); 367 } 368 if (argc > 8) { 369 i = addParam(i, "PREAMBLE", argv[8]); 370 } else { 371 i = addParam(i, "PREAMBLE", "0"); 372 } 373 if (argc > 9) { 374 i = addParam(i, "MAX_SCB", argv[9]); 375 } else { 376 i = addParam(i, "MAX_SCB", "8"); 377 } 378 if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) { 379 ALOGE("Softap set - command is too big"); 380 return i; 381 } 382 sprintf(&mBuf[i], "END"); 383 384 /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */ 385 ret = setCommand(iface, "AP_SET_CFG"); 386 if (ret) { 387 ALOGE("Softap set - failed: %d", ret); 388 } 389 else { 390 ALOGD("Softap set - Ok"); 391 usleep(AP_SET_CFG_DELAY); 392 } 393 #endif 394 return ret; 395 } 396 397 void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) { 398 unsigned char psk[SHA256_DIGEST_LENGTH]; 399 int j; 400 // Use the PKCS#5 PBKDF2 with 4096 iterations 401 PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase), 402 reinterpret_cast<const unsigned char *>(ssid), strlen(ssid), 403 4096, SHA256_DIGEST_LENGTH, psk); 404 for (j=0; j < SHA256_DIGEST_LENGTH; j++) { 405 sprintf(&psk_str[j<<1], "%02x", psk[j]); 406 } 407 psk_str[j<<1] = '\0'; 408 } 409 410 411 /* 412 * Arguments: 413 * argv[2] - interface name 414 * argv[3] - AP or STA 415 */ 416 int SoftapController::fwReloadSoftap(int argc, char *argv[]) 417 { 418 int ret, i = 0; 419 char *iface; 420 char *fwpath; 421 422 if (mSock < 0) { 423 ALOGE("Softap fwrealod - failed to open socket"); 424 return -1; 425 } 426 if (argc < 4) { 427 ALOGE("Softap fwreload - missing arguments"); 428 return -1; 429 } 430 431 iface = argv[2]; 432 433 if (strcmp(argv[3], "AP") == 0) { 434 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP); 435 } else if (strcmp(argv[3], "P2P") == 0) { 436 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P); 437 } else { 438 fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA); 439 } 440 if (!fwpath) 441 return -1; 442 #ifdef HAVE_HOSTAPD 443 ret = wifi_change_fw_path((const char *)fwpath); 444 #else 445 sprintf(mBuf, "FW_PATH=%s", fwpath); 446 ret = setCommand(iface, "WL_FW_RELOAD"); 447 #endif 448 if (ret) { 449 ALOGE("Softap fwReload - failed: %d", ret); 450 } 451 else { 452 ALOGD("Softap fwReload - Ok"); 453 } 454 return ret; 455 } 456 457 int SoftapController::clientsSoftap(char **retbuf) 458 { 459 int ret; 460 461 if (mSock < 0) { 462 ALOGE("Softap clients - failed to open socket"); 463 return -1; 464 } 465 *mBuf = 0; 466 ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE); 467 if (ret) { 468 ALOGE("Softap clients - failed: %d", ret); 469 } else { 470 asprintf(retbuf, "Softap clients:%s", mBuf); 471 ALOGD("Softap clients:%s", mBuf); 472 } 473 return ret; 474 } 475