Home | History | Annotate | Download | only in server
      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