SoftapController.cpp revision 389f8d1550880f3bc67ade3e93f2ddb767e64092
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 {
367        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
368    }
369    if (!fwpath)
370        return -1;
371#ifdef HAVE_HOSTAPD
372    ret = wifi_change_fw_path((const char *)fwpath);
373#else
374    sprintf(mBuf, "FW_PATH=%s", fwpath);
375    ret = setCommand(iface, "WL_FW_RELOAD");
376#endif
377    if (ret) {
378        LOGE("Softap fwReload - failed: %d", ret);
379    }
380    else {
381        LOGD("Softap fwReload - Ok");
382    }
383    return ret;
384}
385
386int SoftapController::clientsSoftap(char **retbuf)
387{
388    int ret;
389
390    if (mSock < 0) {
391        LOGE("Softap clients - failed to open socket");
392        return -1;
393    }
394    *mBuf = 0;
395    ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE);
396    if (ret) {
397        LOGE("Softap clients - failed: %d", ret);
398    } else {
399        asprintf(retbuf, "Softap clients:%s", mBuf);
400        LOGD("Softap clients:%s", mBuf);
401    }
402    return ret;
403}
404