Home | History | Annotate | Download | only in netd
      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 }
     52 
     53 SoftapController::~SoftapController() {
     54     if (mSock >= 0)
     55         close(mSock);
     56 }
     57 
     58 int SoftapController::startSoftap() {
     59     pid_t pid = 1;
     60     int ret = 0;
     61 
     62     if (mPid) {
     63         ALOGE("Softap already started");
     64         return 0;
     65     }
     66     if (mSock < 0) {
     67         ALOGE("Softap startap - failed to open socket");
     68         return -1;
     69     }
     70 
     71     if ((pid = fork()) < 0) {
     72         ALOGE("fork failed (%s)", strerror(errno));
     73         return -1;
     74     }
     75 
     76     if (!pid) {
     77         ensure_entropy_file_exists();
     78         if (execl("/system/bin/hostapd", "/system/bin/hostapd",
     79                   "-e", WIFI_ENTROPY_FILE,
     80                   HOSTAPD_CONF_FILE, (char *) NULL)) {
     81             ALOGE("execl failed (%s)", strerror(errno));
     82         }
     83         ALOGE("Should never get here!");
     84         return -1;
     85     } else {
     86         mPid = pid;
     87         ALOGD("Softap startap - Ok");
     88         usleep(AP_BSS_START_DELAY);
     89     }
     90     return ret;
     91 
     92 }
     93 
     94 int SoftapController::stopSoftap() {
     95 
     96     if (mPid == 0) {
     97         ALOGE("Softap already stopped");
     98         return 0;
     99     }
    100 
    101     ALOGD("Stopping Softap service");
    102     kill(mPid, SIGTERM);
    103     waitpid(mPid, NULL, 0);
    104 
    105     if (mSock < 0) {
    106         ALOGE("Softap stopap - failed to open socket");
    107         return -1;
    108     }
    109     mPid = 0;
    110     ALOGD("Softap service stopped");
    111     usleep(AP_BSS_STOP_DELAY);
    112     return 0;
    113 }
    114 
    115 bool SoftapController::isSoftapStarted() {
    116     return (mPid != 0 ? true : false);
    117 }
    118 
    119 /*
    120  * Arguments:
    121  *      argv[2] - wlan interface
    122  *      argv[3] - SSID
    123  *	argv[4] - Security
    124  *	argv[5] - Key
    125  *	argv[6] - Channel
    126  *	argv[7] - Preamble
    127  *	argv[8] - Max SCB
    128  */
    129 int SoftapController::setSoftap(int argc, char *argv[]) {
    130     char psk_str[2*SHA256_DIGEST_LENGTH+1];
    131     int ret = 0, i = 0, fd;
    132     char *ssid, *iface;
    133 
    134     if (mSock < 0) {
    135         ALOGE("Softap set - failed to open socket");
    136         return -1;
    137     }
    138     if (argc < 4) {
    139         ALOGE("Softap set - missing arguments");
    140         return -1;
    141     }
    142 
    143     iface = argv[2];
    144 
    145     char *wbuf = NULL;
    146     char *fbuf = NULL;
    147 
    148     if (argc > 3) {
    149         ssid = argv[3];
    150     } else {
    151         ssid = (char *)"AndroidAP";
    152     }
    153 
    154     asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
    155             "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
    156             iface, ssid);
    157 
    158     if (argc > 4) {
    159         if (!strcmp(argv[4], "wpa-psk")) {
    160             generatePsk(ssid, argv[5], psk_str);
    161             asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
    162         } else if (!strcmp(argv[4], "wpa2-psk")) {
    163             generatePsk(ssid, argv[5], psk_str);
    164             asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
    165         } else if (!strcmp(argv[4], "open")) {
    166             asprintf(&fbuf, "%s", wbuf);
    167         }
    168     } else {
    169         asprintf(&fbuf, "%s", wbuf);
    170     }
    171 
    172     fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660);
    173     if (fd < 0) {
    174         ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
    175         free(wbuf);
    176         free(fbuf);
    177         return -1;
    178     }
    179     if (write(fd, fbuf, strlen(fbuf)) < 0) {
    180         ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
    181         ret = -1;
    182     }
    183     close(fd);
    184     free(wbuf);
    185     free(fbuf);
    186 
    187     /* Note: apparently open can fail to set permissions correctly at times */
    188     if (chmod(HOSTAPD_CONF_FILE, 0660) < 0) {
    189         ALOGE("Error changing permissions of %s to 0660: %s",
    190                 HOSTAPD_CONF_FILE, strerror(errno));
    191         unlink(HOSTAPD_CONF_FILE);
    192         return -1;
    193     }
    194 
    195     if (chown(HOSTAPD_CONF_FILE, AID_SYSTEM, AID_WIFI) < 0) {
    196         ALOGE("Error changing group ownership of %s to %d: %s",
    197                 HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno));
    198         unlink(HOSTAPD_CONF_FILE);
    199         return -1;
    200     }
    201 
    202     return ret;
    203 }
    204 
    205 void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) {
    206     unsigned char psk[SHA256_DIGEST_LENGTH];
    207     int j;
    208     // Use the PKCS#5 PBKDF2 with 4096 iterations
    209     PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase),
    210             reinterpret_cast<const unsigned char *>(ssid), strlen(ssid),
    211             4096, SHA256_DIGEST_LENGTH, psk);
    212     for (j=0; j < SHA256_DIGEST_LENGTH; j++) {
    213         sprintf(&psk_str[j<<1], "%02x", psk[j]);
    214     }
    215     psk_str[j<<1] = '\0';
    216 }
    217 
    218 
    219 /*
    220  * Arguments:
    221  *	argv[2] - interface name
    222  *	argv[3] - AP or STA
    223  */
    224 int SoftapController::fwReloadSoftap(int argc, char *argv[])
    225 {
    226     int ret, i = 0;
    227     char *iface;
    228     char *fwpath;
    229 
    230     if (mSock < 0) {
    231         ALOGE("Softap fwrealod - failed to open socket");
    232         return -1;
    233     }
    234     if (argc < 4) {
    235         ALOGE("Softap fwreload - missing arguments");
    236         return -1;
    237     }
    238 
    239     iface = argv[2];
    240 
    241     if (strcmp(argv[3], "AP") == 0) {
    242         fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP);
    243     } else if (strcmp(argv[3], "P2P") == 0) {
    244         fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P);
    245     } else {
    246         fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
    247     }
    248     if (!fwpath)
    249         return -1;
    250     ret = wifi_change_fw_path((const char *)fwpath);
    251     if (ret) {
    252         ALOGE("Softap fwReload - failed: %d", ret);
    253     }
    254     else {
    255         ALOGD("Softap fwReload - Ok");
    256     }
    257     return ret;
    258 }
    259 
    260 int SoftapController::clientsSoftap(char **retbuf)
    261 {
    262     /* TODO: implement over hostapd */
    263     return 0;
    264 }
    265