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