SoftapController.cpp revision 6665fb2adf78beddde21f7f3088a695646ca8c57
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
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25
26#include <netinet/in.h>
27#include <arpa/inet.h>
28
29#include <linux/wireless.h>
30
31#include <openssl/evp.h>
32#include <openssl/sha.h>
33
34#define LOG_TAG "SoftapController"
35#include <cutils/log.h>
36
37#include "SoftapController.h"
38
39SoftapController::SoftapController() {
40    mPid = 0;
41    mSock = socket(AF_INET, SOCK_DGRAM, 0);
42    if (mSock < 0)
43        LOGE("Failed to open socket");
44    memset(mIface, 0, sizeof(mIface));
45}
46
47SoftapController::~SoftapController() {
48    if (mSock >= 0)
49        close(mSock);
50}
51
52int SoftapController::getPrivFuncNum(char *iface, const char *fname) {
53    char tBuf[SOFTAP_MAX_BUFFER_SIZE];
54    struct iwreq wrq;
55    struct iw_priv_args *priv_ptr;
56    int i, ret;
57
58    strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
59    wrq.u.data.pointer = tBuf;
60    wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args);
61    wrq.u.data.flags = 0;
62    if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) {
63        LOGE("SIOCGIPRIV failed: %d", ret);
64        return ret;
65    }
66    priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer;
67    for(i=0;(i < wrq.u.data.length);i++) {
68        if (strcmp(priv_ptr[i].name, fname) == 0)
69            return priv_ptr[i].cmd;
70    }
71    return -1;
72}
73
74int SoftapController::setCommand(char *iface, const char *fname)
75{
76    struct iwreq wrq;
77    int fnum, ret;
78
79    fnum = getPrivFuncNum(iface, fname);
80    if (fnum < 0) {
81        LOGE("Softap %s - function not supported", fname);
82        return -1;
83    }
84
85    strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
86    if (*mBuf != 0)
87        wrq.u.data.length = strlen(mBuf) + 1;
88    else
89        wrq.u.data.length = 0;
90    wrq.u.data.pointer = mBuf;
91    wrq.u.data.flags = 0;
92    ret = ioctl(mSock, fnum, &wrq);
93    return ret;
94}
95
96int SoftapController::startDriver(char *iface) {
97    int ret;
98
99    if (mSock < 0) {
100        LOGE("Softap driver start - failed to open socket");
101        return -1;
102    }
103    if (!iface || (iface[0] == '\0')) {
104        LOGD("Softap driver start - wrong interface");
105        iface = mIface;
106    }
107
108    *mBuf = 0;
109    ret = setCommand(iface, "START");
110    usleep(AP_DRIVER_START_DELAY);
111    LOGD("Softap driver start: %d", ret);
112    return ret;
113}
114
115int SoftapController::stopDriver(char *iface) {
116    int ret;
117
118    if (mSock < 0) {
119        LOGE("Softap driver stop - failed to open socket");
120        return -1;
121    }
122    if (!iface || (iface[0] == '\0')) {
123        LOGD("Softap driver stop - wrong interface");
124        iface = mIface;
125    }
126    *mBuf = 0;
127    ret = setCommand(iface, "STOP");
128    LOGD("Softap driver stop: %d", ret);
129    return ret;
130}
131
132int SoftapController::startSoftap() {
133    pid_t pid = 1;
134    int ret = 0;
135
136    if (mPid) {
137        LOGE("Softap already started");
138        return 0;
139    }
140    if (mSock < 0) {
141        LOGE("Softap startap - failed to open socket");
142        return -1;
143    }
144#if 0
145   if ((pid = fork()) < 0) {
146        LOGE("fork failed (%s)", strerror(errno));
147        return -1;
148    }
149#endif
150    /* system("iwpriv wl0.1 AP_BSS_START"); */
151    if (!pid) {
152        /* start hostapd */
153        return ret;
154    } else {
155        *mBuf = 0;
156        ret = setCommand(mIface, "AP_BSS_START");
157        if (ret) {
158            LOGE("Softap startap - failed: %d", ret);
159        }
160        else {
161           mPid = pid;
162           LOGD("Softap startap - Ok");
163           usleep(AP_BSS_START_DELAY);
164        }
165    }
166    return ret;
167
168}
169
170int SoftapController::stopSoftap() {
171    int ret;
172
173    if (mPid == 0) {
174        LOGE("Softap already stopped");
175        return 0;
176    }
177    if (mSock < 0) {
178        LOGE("Softap stopap - failed to open socket");
179        return -1;
180    }
181    *mBuf = 0;
182    ret = setCommand(mIface, "AP_BSS_STOP");
183#if 0
184    LOGD("Stopping Softap service");
185    kill(mPid, SIGTERM);
186    waitpid(mPid, NULL, 0);
187#endif
188    mPid = 0;
189    LOGD("Softap service stopped: %d", ret);
190    usleep(AP_BSS_STOP_DELAY);
191    return ret;
192}
193
194bool SoftapController::isSoftapStarted() {
195    return (mPid != 0 ? true : false);
196}
197
198int SoftapController::addParam(int pos, const char *cmd, const char *arg)
199{
200    if (pos < 0)
201        return pos;
202    if ((unsigned)(pos + strlen(cmd) + strlen(arg) + 1) >= sizeof(mBuf)) {
203        LOGE("Command line is too big");
204        return -1;
205    }
206    pos += sprintf(&mBuf[pos], "%s=%s,", cmd, arg);
207    return pos;
208}
209
210/*
211 * Arguments:
212 *      argv[2] - wlan interface
213 *      argv[3] - softap interface
214 *      argv[4] - SSID
215 *	argv[5] - Security
216 *	argv[6] - Key
217 *	argv[7] - Channel
218 *	argv[8] - Preamble
219 *	argv[9] - Max SCB
220 */
221int SoftapController::setSoftap(int argc, char *argv[]) {
222    unsigned char psk[SHA256_DIGEST_LENGTH];
223    char psk_str[2*SHA256_DIGEST_LENGTH+1];
224    int ret, i = 0;
225    char *ssid, *iface;
226
227    if (mSock < 0) {
228        LOGE("Softap set - failed to open socket");
229        return -1;
230    }
231    if (argc < 4) {
232        LOGE("Softap set - missing arguments");
233        return -1;
234    }
235
236    strncpy(mIface, argv[3], sizeof(mIface));
237    iface = argv[2];
238
239    /* Create command line */
240    i = addParam(i, "ASCII_CMD", "AP_CFG");
241    if (argc > 4) {
242        ssid = argv[4];
243    } else {
244        ssid = (char *)"AndroidAP";
245    }
246    i = addParam(i, "SSID", ssid);
247    if (argc > 5) {
248        i = addParam(i, "SEC", argv[5]);
249    } else {
250        i = addParam(i, "SEC", "open");
251    }
252    if (argc > 6) {
253        int j;
254        // Use the PKCS#5 PBKDF2 with 4096 iterations
255        PKCS5_PBKDF2_HMAC_SHA1(argv[6], strlen(argv[6]),
256                reinterpret_cast<const unsigned char *>(ssid), strlen(ssid),
257                4096, SHA256_DIGEST_LENGTH, psk);
258        for (j=0; j < SHA256_DIGEST_LENGTH; j++) {
259            sprintf(&psk_str[j<<1], "%02x", psk[j]);
260        }
261        psk_str[j<<1] = '\0';
262        i = addParam(i, "KEY", psk_str);
263    } else {
264        i = addParam(i, "KEY", "12345678");
265    }
266    if (argc > 7) {
267        i = addParam(i, "CHANNEL", argv[7]);
268    } else {
269        i = addParam(i, "CHANNEL", "6");
270    }
271    if (argc > 8) {
272        i = addParam(i, "PREAMBLE", argv[8]);
273    } else {
274        i = addParam(i, "PREAMBLE", "0");
275    }
276    if (argc > 9) {
277        i = addParam(i, "MAX_SCB", argv[9]);
278    } else {
279        i = addParam(i, "MAX_SCB", "8");
280    }
281    if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) {
282        LOGE("Softap set - command is too big");
283        return i;
284    }
285    sprintf(&mBuf[i], "END");
286
287    /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */
288    ret = setCommand(iface, "AP_SET_CFG");
289    if (ret) {
290        LOGE("Softap set - failed: %d", ret);
291    }
292    else {
293        LOGD("Softap set - Ok");
294        usleep(AP_SET_CFG_DELAY);
295    }
296    return ret;
297}
298
299/*
300 * Arguments:
301 *	argv[2] - interface name
302 *	argv[3] - AP or STA
303 */
304int SoftapController::fwReloadSoftap(int argc, char *argv[])
305{
306    int ret, i = 0;
307    char *iface;
308
309    if (mSock < 0) {
310        LOGE("Softap fwrealod - failed to open socket");
311        return -1;
312    }
313    if (argc < 4) {
314        LOGE("Softap fwreload - missing arguments");
315        return -1;
316    }
317
318    iface = argv[2];
319
320    if (strcmp(argv[3], "AP") == 0) {
321#ifdef WIFI_DRIVER_FW_AP_PATH
322        sprintf(mBuf, "FW_PATH=%s", WIFI_DRIVER_FW_AP_PATH);
323#endif
324    } else {
325#ifdef WIFI_DRIVER_FW_STA_PATH
326        sprintf(mBuf, "FW_PATH=%s", WIFI_DRIVER_FW_STA_PATH);
327#endif
328    }
329    ret = setCommand(iface, "WL_FW_RELOAD");
330    if (ret) {
331        LOGE("Softap fwReload - failed: %d", ret);
332    }
333    else {
334        LOGD("Softap fwReload - Ok");
335    }
336    return ret;
337}
338