OSDN Git Service

BandwidthController: hookup qtaguid for tracking closest to devices.
[android-x86/system-netd.git] / SoftapController.cpp
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     memset(mIface, 0, sizeof(mIface));
52 }
53
54 SoftapController::~SoftapController() {
55     if (mSock >= 0)
56         close(mSock);
57 }
58
59 int SoftapController::setCommand(char *iface, const char *fname, unsigned buflen) {
60 #ifdef HAVE_HOSTAPD
61     return 0;
62 #else
63     char tBuf[SOFTAP_MAX_BUFFER_SIZE];
64     struct iwreq wrq;
65     struct iw_priv_args *priv_ptr;
66     int i, j, ret;
67     int cmd = 0, sub_cmd = 0;
68
69     strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
70     wrq.u.data.pointer = tBuf;
71     wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args);
72     wrq.u.data.flags = 0;
73     if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) {
74         ALOGE("SIOCGIPRIV failed: %d", ret);
75         return ret;
76     }
77
78     priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer;
79     for(i=0; i < wrq.u.data.length;i++) {
80         if (strcmp(priv_ptr[i].name, fname) == 0) {
81             cmd = priv_ptr[i].cmd;
82             break;
83         }
84     }
85
86     if (i == wrq.u.data.length) {
87         ALOGE("iface:%s, fname: %s - function not supported", iface, fname);
88         return -1;
89     }
90
91     if (cmd < SIOCDEVPRIVATE) {
92         for(j=0; j < i; j++) {
93             if ((priv_ptr[j].set_args == priv_ptr[i].set_args) &&
94                 (priv_ptr[j].get_args == priv_ptr[i].get_args) &&
95                 (priv_ptr[j].name[0] == '\0'))
96                 break;
97         }
98         if (j == i) {
99             ALOGE("iface:%s, fname: %s - invalid private ioctl", iface, fname);
100             return -1;
101         }
102         sub_cmd = cmd;
103         cmd = priv_ptr[j].cmd;
104     }
105
106     strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
107     if ((buflen == 0) && (*mBuf != 0))
108         wrq.u.data.length = strlen(mBuf) + 1;
109     else
110         wrq.u.data.length = buflen;
111     wrq.u.data.pointer = mBuf;
112     wrq.u.data.flags = sub_cmd;
113     ret = ioctl(mSock, cmd, &wrq);
114     return ret;
115 #endif
116 }
117
118 int SoftapController::startDriver(char *iface) {
119     int ret;
120
121     if (mSock < 0) {
122         ALOGE("Softap driver start - failed to open socket");
123         return -1;
124     }
125     if (!iface || (iface[0] == '\0')) {
126         ALOGD("Softap driver start - wrong interface");
127         iface = mIface;
128     }
129
130     *mBuf = 0;
131     ret = setCommand(iface, "START");
132     if (ret < 0) {
133         ALOGE("Softap driver start: %d", ret);
134         return ret;
135     }
136 #ifdef HAVE_HOSTAPD
137     ifc_init();
138     ret = ifc_up(iface);
139     ifc_close();
140 #endif
141     usleep(AP_DRIVER_START_DELAY);
142     ALOGD("Softap driver start: %d", ret);
143     return ret;
144 }
145
146 int SoftapController::stopDriver(char *iface) {
147     int ret;
148
149     if (mSock < 0) {
150         ALOGE("Softap driver stop - failed to open socket");
151         return -1;
152     }
153     if (!iface || (iface[0] == '\0')) {
154         ALOGD("Softap driver stop - wrong interface");
155         iface = mIface;
156     }
157     *mBuf = 0;
158 #ifdef HAVE_HOSTAPD
159     ifc_init();
160     ret = ifc_down(iface);
161     ifc_close();
162     if (ret < 0) {
163         ALOGE("Softap %s down: %d", iface, ret);
164     }
165 #endif
166     ret = setCommand(iface, "STOP");
167     ALOGD("Softap driver stop: %d", ret);
168     return ret;
169 }
170
171 int SoftapController::startSoftap() {
172     pid_t pid = 1;
173     int ret = 0;
174
175     if (mPid) {
176         ALOGE("Softap already started");
177         return 0;
178     }
179     if (mSock < 0) {
180         ALOGE("Softap startap - failed to open socket");
181         return -1;
182     }
183 #ifdef HAVE_HOSTAPD
184     if ((pid = fork()) < 0) {
185         ALOGE("fork failed (%s)", strerror(errno));
186         return -1;
187     }
188 #endif
189     if (!pid) {
190 #ifdef HAVE_HOSTAPD
191         ensure_entropy_file_exists();
192         if (execl("/system/bin/hostapd", "/system/bin/hostapd",
193                   "-e", WIFI_ENTROPY_FILE,
194                   HOSTAPD_CONF_FILE, (char *) NULL)) {
195             ALOGE("execl failed (%s)", strerror(errno));
196         }
197 #endif
198         ALOGE("Should never get here!");
199         return -1;
200     } else {
201         *mBuf = 0;
202         ret = setCommand(mIface, "AP_BSS_START");
203         if (ret) {
204             ALOGE("Softap startap - failed: %d", ret);
205         }
206         else {
207            mPid = pid;
208            ALOGD("Softap startap - Ok");
209            usleep(AP_BSS_START_DELAY);
210         }
211     }
212     return ret;
213
214 }
215
216 int SoftapController::stopSoftap() {
217     int ret;
218
219     if (mPid == 0) {
220         ALOGE("Softap already stopped");
221         return 0;
222     }
223
224 #ifdef HAVE_HOSTAPD
225     ALOGD("Stopping Softap service");
226     kill(mPid, SIGTERM);
227     waitpid(mPid, NULL, 0);
228 #endif
229     if (mSock < 0) {
230         ALOGE("Softap stopap - failed to open socket");
231         return -1;
232     }
233     *mBuf = 0;
234     ret = setCommand(mIface, "AP_BSS_STOP");
235     mPid = 0;
236     ALOGD("Softap service stopped: %d", ret);
237     usleep(AP_BSS_STOP_DELAY);
238     return ret;
239 }
240
241 bool SoftapController::isSoftapStarted() {
242     return (mPid != 0 ? true : false);
243 }
244
245 int SoftapController::addParam(int pos, const char *cmd, const char *arg)
246 {
247     if (pos < 0)
248         return pos;
249     if ((unsigned)(pos + strlen(cmd) + strlen(arg) + 1) >= sizeof(mBuf)) {
250         ALOGE("Command line is too big");
251         return -1;
252     }
253     pos += sprintf(&mBuf[pos], "%s=%s,", cmd, arg);
254     return pos;
255 }
256
257 /*
258  * Arguments:
259  *      argv[2] - wlan interface
260  *      argv[3] - softap interface
261  *      argv[4] - SSID
262  *      argv[5] - Security
263  *      argv[6] - Key
264  *      argv[7] - Channel
265  *      argv[8] - Preamble
266  *      argv[9] - Max SCB
267  */
268 int SoftapController::setSoftap(int argc, char *argv[]) {
269     char psk_str[2*SHA256_DIGEST_LENGTH+1];
270     int ret = 0, i = 0, fd;
271     char *ssid, *iface;
272
273     if (mSock < 0) {
274         ALOGE("Softap set - failed to open socket");
275         return -1;
276     }
277     if (argc < 4) {
278         ALOGE("Softap set - missing arguments");
279         return -1;
280     }
281
282     strncpy(mIface, argv[3], sizeof(mIface));
283     iface = argv[2];
284
285 #ifdef HAVE_HOSTAPD
286     char *wbuf = NULL;
287     char *fbuf = NULL;
288
289     if (argc > 4) {
290         ssid = argv[4];
291     } else {
292         ssid = (char *)"AndroidAP";
293     }
294
295     asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
296             "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
297             iface, ssid);
298
299     if (argc > 5) {
300         if (!strcmp(argv[5], "wpa-psk")) {
301             generatePsk(ssid, argv[6], psk_str);
302             asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
303         } else if (!strcmp(argv[5], "wpa2-psk")) {
304             generatePsk(ssid, argv[6], psk_str);
305             asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
306         } else if (!strcmp(argv[5], "open")) {
307             asprintf(&fbuf, "%s", wbuf);
308         }
309     } else {
310         asprintf(&fbuf, "%s", wbuf);
311     }
312
313     fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660);
314     if (fd < 0) {
315         ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
316         free(wbuf);
317         free(fbuf);
318         return -1;
319     }
320     if (write(fd, fbuf, strlen(fbuf)) < 0) {
321         ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
322         ret = -1;
323     }
324     close(fd);
325     free(wbuf);
326     free(fbuf);
327
328     /* Note: apparently open can fail to set permissions correctly at times */
329     if (chmod(HOSTAPD_CONF_FILE, 0660) < 0) {
330         ALOGE("Error changing permissions of %s to 0660: %s",
331                 HOSTAPD_CONF_FILE, strerror(errno));
332         unlink(HOSTAPD_CONF_FILE);
333         return -1;
334     }
335
336     if (chown(HOSTAPD_CONF_FILE, AID_SYSTEM, AID_WIFI) < 0) {
337         ALOGE("Error changing group ownership of %s to %d: %s",
338                 HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno));
339         unlink(HOSTAPD_CONF_FILE);
340         return -1;
341     }
342
343 #else
344     /* Create command line */
345     i = addParam(i, "ASCII_CMD", "AP_CFG");
346     if (argc > 4) {
347         ssid = argv[4];
348     } else {
349         ssid = (char *)"AndroidAP";
350     }
351     i = addParam(i, "SSID", ssid);
352     if (argc > 5) {
353         i = addParam(i, "SEC", argv[5]);
354     } else {
355         i = addParam(i, "SEC", "open");
356     }
357     if (argc > 6) {
358         generatePsk(ssid, argv[6], psk_str);
359         i = addParam(i, "KEY", psk_str);
360     } else {
361         i = addParam(i, "KEY", "12345678");
362     }
363     if (argc > 7) {
364         i = addParam(i, "CHANNEL", argv[7]);
365     } else {
366         i = addParam(i, "CHANNEL", "6");
367     }
368     if (argc > 8) {
369         i = addParam(i, "PREAMBLE", argv[8]);
370     } else {
371         i = addParam(i, "PREAMBLE", "0");
372     }
373     if (argc > 9) {
374         i = addParam(i, "MAX_SCB", argv[9]);
375     } else {
376         i = addParam(i, "MAX_SCB", "8");
377     }
378     if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) {
379         ALOGE("Softap set - command is too big");
380         return i;
381     }
382     sprintf(&mBuf[i], "END");
383
384     /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */
385     ret = setCommand(iface, "AP_SET_CFG");
386     if (ret) {
387         ALOGE("Softap set - failed: %d", ret);
388     }
389     else {
390         ALOGD("Softap set - Ok");
391         usleep(AP_SET_CFG_DELAY);
392     }
393 #endif
394     return ret;
395 }
396
397 void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) {
398     unsigned char psk[SHA256_DIGEST_LENGTH];
399     int j;
400     // Use the PKCS#5 PBKDF2 with 4096 iterations
401     PKCS5_PBKDF2_HMAC_SHA1(passphrase, strlen(passphrase),
402             reinterpret_cast<const unsigned char *>(ssid), strlen(ssid),
403             4096, SHA256_DIGEST_LENGTH, psk);
404     for (j=0; j < SHA256_DIGEST_LENGTH; j++) {
405         sprintf(&psk_str[j<<1], "%02x", psk[j]);
406     }
407     psk_str[j<<1] = '\0';
408 }
409
410
411 /*
412  * Arguments:
413  *      argv[2] - interface name
414  *      argv[3] - AP or STA
415  */
416 int SoftapController::fwReloadSoftap(int argc, char *argv[])
417 {
418     int ret, i = 0;
419     char *iface;
420     char *fwpath;
421
422     if (mSock < 0) {
423         ALOGE("Softap fwrealod - failed to open socket");
424         return -1;
425     }
426     if (argc < 4) {
427         ALOGE("Softap fwreload - missing arguments");
428         return -1;
429     }
430
431     iface = argv[2];
432
433     if (strcmp(argv[3], "AP") == 0) {
434         fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP);
435     } else if (strcmp(argv[3], "P2P") == 0) {
436         fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P);
437     } else {
438         fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
439     }
440     if (!fwpath)
441         return -1;
442 #ifdef HAVE_HOSTAPD
443     ret = wifi_change_fw_path((const char *)fwpath);
444 #else
445     sprintf(mBuf, "FW_PATH=%s", fwpath);
446     ret = setCommand(iface, "WL_FW_RELOAD");
447 #endif
448     if (ret) {
449         ALOGE("Softap fwReload - failed: %d", ret);
450     }
451     else {
452         ALOGD("Softap fwReload - Ok");
453     }
454     return ret;
455 }
456
457 int SoftapController::clientsSoftap(char **retbuf)
458 {
459     int ret;
460
461     if (mSock < 0) {
462         ALOGE("Softap clients - failed to open socket");
463         return -1;
464     }
465     *mBuf = 0;
466     ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE);
467     if (ret) {
468         ALOGE("Softap clients - failed: %d", ret);
469     } else {
470         asprintf(retbuf, "Softap clients:%s", mBuf);
471         ALOGD("Softap clients:%s", mBuf);
472     }
473     return ret;
474 }