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