blob: 60397614e2d911c43fc73e545a604691f3ee769d [file] [log] [blame]
Dmitry Shmidt5af38c32010-02-10 11:10:39 -08001/*
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>
Olivier Baillyff2c0d82010-11-17 11:45:07 -080020#include <string.h>
Dmitry Shmidt5af38c32010-02-10 11:10:39 -080021
22#include <sys/socket.h>
23#include <sys/stat.h>
Olivier Baillyff2c0d82010-11-17 11:45:07 -080024#include <sys/ioctl.h>
Dmitry Shmidt5af38c32010-02-10 11:10:39 -080025#include <sys/types.h>
26#include <sys/wait.h>
27
28#include <netinet/in.h>
29#include <arpa/inet.h>
30
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080031#include <linux/wireless.h>
32
Kenny Roota2d7e3e2010-03-15 14:26:36 -070033#include <openssl/evp.h>
34#include <openssl/sha.h>
35
Dmitry Shmidt5af38c32010-02-10 11:10:39 -080036#define LOG_TAG "SoftapController"
37#include <cutils/log.h>
38
39#include "SoftapController.h"
40
41SoftapController::SoftapController() {
42 mPid = 0;
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080043 mSock = socket(AF_INET, SOCK_DGRAM, 0);
44 if (mSock < 0)
45 LOGE("Failed to open socket");
46 memset(mIface, 0, sizeof(mIface));
Dmitry Shmidt5af38c32010-02-10 11:10:39 -080047}
48
49SoftapController::~SoftapController() {
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080050 if (mSock >= 0)
51 close(mSock);
52}
53
Dmitry Shmidt666fe252011-03-08 11:01:58 -080054int SoftapController::setCommand(char *iface, const char *fname, unsigned buflen) {
Dmitry Shmidt6665fb22010-09-22 17:31:07 -070055 char tBuf[SOFTAP_MAX_BUFFER_SIZE];
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080056 struct iwreq wrq;
57 struct iw_priv_args *priv_ptr;
jmzhufbd11c42010-10-11 16:47:05 -070058 int i, j, ret;
59 int cmd = 0, sub_cmd = 0;
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080060
61 strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
Dmitry Shmidt6665fb22010-09-22 17:31:07 -070062 wrq.u.data.pointer = tBuf;
63 wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args);
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080064 wrq.u.data.flags = 0;
65 if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) {
66 LOGE("SIOCGIPRIV failed: %d", ret);
67 return ret;
68 }
jmzhufbd11c42010-10-11 16:47:05 -070069
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080070 priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer;
jmzhufbd11c42010-10-11 16:47:05 -070071 for(i=0; i < wrq.u.data.length;i++) {
72 if (strcmp(priv_ptr[i].name, fname) == 0) {
73 cmd = priv_ptr[i].cmd;
74 break;
75 }
Dmitry Shmidt84c65a62010-03-03 13:14:30 -080076 }
Dmitry Shmidt5af38c32010-02-10 11:10:39 -080077
jmzhufbd11c42010-10-11 16:47:05 -070078 if (i == wrq.u.data.length) {
79 LOGE("iface:%s, fname: %s - function not supported", iface, fname);
Dmitry Shmidt6665fb22010-09-22 17:31:07 -070080 return -1;
81 }
82
jmzhufbd11c42010-10-11 16:47:05 -070083 if (cmd < SIOCDEVPRIVATE) {
84 for(j=0; j < i; j++) {
85 if ((priv_ptr[j].set_args == priv_ptr[i].set_args) &&
86 (priv_ptr[j].get_args == priv_ptr[i].get_args) &&
87 (priv_ptr[j].name[0] == '\0'))
88 break;
89 }
90 if (j == i) {
91 LOGE("iface:%s, fname: %s - invalid private ioctl", iface, fname);
92 return -1;
93 }
94 sub_cmd = cmd;
95 cmd = priv_ptr[j].cmd;
96 }
97
Dmitry Shmidt6665fb22010-09-22 17:31:07 -070098 strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
Dmitry Shmidt666fe252011-03-08 11:01:58 -080099 if ((buflen == 0) && (*mBuf != 0))
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700100 wrq.u.data.length = strlen(mBuf) + 1;
101 else
Dmitry Shmidt666fe252011-03-08 11:01:58 -0800102 wrq.u.data.length = buflen;
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700103 wrq.u.data.pointer = mBuf;
jmzhufbd11c42010-10-11 16:47:05 -0700104 wrq.u.data.flags = sub_cmd;
105 ret = ioctl(mSock, cmd, &wrq);
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700106 return ret;
107}
108
109int SoftapController::startDriver(char *iface) {
110 int ret;
111
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800112 if (mSock < 0) {
Dmitry Shmidta1659132010-04-23 12:43:32 -0700113 LOGE("Softap driver start - failed to open socket");
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800114 return -1;
115 }
116 if (!iface || (iface[0] == '\0')) {
Dmitry Shmidta1659132010-04-23 12:43:32 -0700117 LOGD("Softap driver start - wrong interface");
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800118 iface = mIface;
119 }
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700120
121 *mBuf = 0;
122 ret = setCommand(iface, "START");
Dmitry Shmidta1659132010-04-23 12:43:32 -0700123 usleep(AP_DRIVER_START_DELAY);
124 LOGD("Softap driver start: %d", ret);
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800125 return ret;
126}
127
128int SoftapController::stopDriver(char *iface) {
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700129 int ret;
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800130
131 if (mSock < 0) {
Dmitry Shmidta1659132010-04-23 12:43:32 -0700132 LOGE("Softap driver stop - failed to open socket");
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800133 return -1;
134 }
135 if (!iface || (iface[0] == '\0')) {
Dmitry Shmidta1659132010-04-23 12:43:32 -0700136 LOGD("Softap driver stop - wrong interface");
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800137 iface = mIface;
138 }
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700139 *mBuf = 0;
140 ret = setCommand(iface, "STOP");
Dmitry Shmidta1659132010-04-23 12:43:32 -0700141 LOGD("Softap driver stop: %d", ret);
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800142 return ret;
143}
144
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800145int SoftapController::startSoftap() {
146 pid_t pid = 1;
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700147 int ret = 0;
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800148
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800149 if (mPid) {
150 LOGE("Softap already started");
Dmitry Shmidta1659132010-04-23 12:43:32 -0700151 return 0;
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800152 }
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800153 if (mSock < 0) {
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800154 LOGE("Softap startap - failed to open socket");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800155 return -1;
156 }
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800157#if 0
158 if ((pid = fork()) < 0) {
159 LOGE("fork failed (%s)", strerror(errno));
160 return -1;
161 }
162#endif
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800163 /* system("iwpriv wl0.1 AP_BSS_START"); */
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800164 if (!pid) {
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800165 /* start hostapd */
166 return ret;
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800167 } else {
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700168 *mBuf = 0;
169 ret = setCommand(mIface, "AP_BSS_START");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800170 if (ret) {
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800171 LOGE("Softap startap - failed: %d", ret);
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800172 }
173 else {
174 mPid = pid;
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800175 LOGD("Softap startap - Ok");
Dmitry Shmidt3df450a2010-03-18 13:06:47 -0700176 usleep(AP_BSS_START_DELAY);
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800177 }
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800178 }
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800179 return ret;
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800180
181}
182
183int SoftapController::stopSoftap() {
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700184 int ret;
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800185
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800186 if (mPid == 0) {
187 LOGE("Softap already stopped");
188 return 0;
189 }
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800190 if (mSock < 0) {
Dmitry Shmidtc3539e22010-03-12 14:16:46 -0800191 LOGE("Softap stopap - failed to open socket");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800192 return -1;
193 }
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700194 *mBuf = 0;
195 ret = setCommand(mIface, "AP_BSS_STOP");
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800196#if 0
197 LOGD("Stopping Softap service");
198 kill(mPid, SIGTERM);
199 waitpid(mPid, NULL, 0);
200#endif
201 mPid = 0;
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800202 LOGD("Softap service stopped: %d", ret);
Dmitry Shmidt3df450a2010-03-18 13:06:47 -0700203 usleep(AP_BSS_STOP_DELAY);
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800204 return ret;
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800205}
206
207bool SoftapController::isSoftapStarted() {
208 return (mPid != 0 ? true : false);
209}
210
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800211int SoftapController::addParam(int pos, const char *cmd, const char *arg)
212{
213 if (pos < 0)
214 return pos;
215 if ((unsigned)(pos + strlen(cmd) + strlen(arg) + 1) >= sizeof(mBuf)) {
216 LOGE("Command line is too big");
217 return -1;
218 }
219 pos += sprintf(&mBuf[pos], "%s=%s,", cmd, arg);
220 return pos;
221}
222
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800223/*
224 * Arguments:
225 * argv[2] - wlan interface
226 * argv[3] - softap interface
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800227 * argv[4] - SSID
228 * argv[5] - Security
229 * argv[6] - Key
230 * argv[7] - Channel
231 * argv[8] - Preamble
232 * argv[9] - Max SCB
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800233 */
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800234int SoftapController::setSoftap(int argc, char *argv[]) {
Kenny Roota2d7e3e2010-03-15 14:26:36 -0700235 unsigned char psk[SHA256_DIGEST_LENGTH];
236 char psk_str[2*SHA256_DIGEST_LENGTH+1];
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700237 int ret, i = 0;
238 char *ssid, *iface;
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800239
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800240 if (mSock < 0) {
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800241 LOGE("Softap set - failed to open socket");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800242 return -1;
243 }
244 if (argc < 4) {
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800245 LOGE("Softap set - missing arguments");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800246 return -1;
247 }
248
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800249 strncpy(mIface, argv[3], sizeof(mIface));
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700250 iface = argv[2];
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800251
252 /* Create command line */
253 i = addParam(i, "ASCII_CMD", "AP_CFG");
254 if (argc > 4) {
Dmitry Shmidt321f95a2010-03-09 15:46:34 -0800255 ssid = argv[4];
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800256 } else {
Dmitry Shmidt321f95a2010-03-09 15:46:34 -0800257 ssid = (char *)"AndroidAP";
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800258 }
Dmitry Shmidt321f95a2010-03-09 15:46:34 -0800259 i = addParam(i, "SSID", ssid);
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800260 if (argc > 5) {
261 i = addParam(i, "SEC", argv[5]);
262 } else {
263 i = addParam(i, "SEC", "open");
264 }
265 if (argc > 6) {
Dmitry Shmidt321f95a2010-03-09 15:46:34 -0800266 int j;
Kenny Roota2d7e3e2010-03-15 14:26:36 -0700267 // Use the PKCS#5 PBKDF2 with 4096 iterations
268 PKCS5_PBKDF2_HMAC_SHA1(argv[6], strlen(argv[6]),
269 reinterpret_cast<const unsigned char *>(ssid), strlen(ssid),
270 4096, SHA256_DIGEST_LENGTH, psk);
271 for (j=0; j < SHA256_DIGEST_LENGTH; j++) {
Dmitry Shmidt321f95a2010-03-09 15:46:34 -0800272 sprintf(&psk_str[j<<1], "%02x", psk[j]);
273 }
274 psk_str[j<<1] = '\0';
275 i = addParam(i, "KEY", psk_str);
Dmitry Shmidt7977d672010-03-09 10:57:59 -0800276 } else {
277 i = addParam(i, "KEY", "12345678");
278 }
279 if (argc > 7) {
280 i = addParam(i, "CHANNEL", argv[7]);
281 } else {
282 i = addParam(i, "CHANNEL", "6");
283 }
284 if (argc > 8) {
285 i = addParam(i, "PREAMBLE", argv[8]);
286 } else {
287 i = addParam(i, "PREAMBLE", "0");
288 }
289 if (argc > 9) {
290 i = addParam(i, "MAX_SCB", argv[9]);
291 } else {
292 i = addParam(i, "MAX_SCB", "8");
293 }
294 if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) {
295 LOGE("Softap set - command is too big");
296 return i;
297 }
298 sprintf(&mBuf[i], "END");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800299
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800300 /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700301 ret = setCommand(iface, "AP_SET_CFG");
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800302 if (ret) {
303 LOGE("Softap set - failed: %d", ret);
304 }
305 else {
306 LOGD("Softap set - Ok");
Dmitry Shmidt3df450a2010-03-18 13:06:47 -0700307 usleep(AP_SET_CFG_DELAY);
Dmitry Shmidt84c65a62010-03-03 13:14:30 -0800308 }
309 return ret;
Dmitry Shmidt5af38c32010-02-10 11:10:39 -0800310}
Dmitry Shmidt31fd6c52010-03-12 10:01:58 -0800311
312/*
313 * Arguments:
314 * argv[2] - interface name
315 * argv[3] - AP or STA
316 */
317int SoftapController::fwReloadSoftap(int argc, char *argv[])
318{
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700319 int ret, i = 0;
Dmitry Shmidt31fd6c52010-03-12 10:01:58 -0800320 char *iface;
321
322 if (mSock < 0) {
323 LOGE("Softap fwrealod - failed to open socket");
324 return -1;
325 }
326 if (argc < 4) {
327 LOGE("Softap fwreload - missing arguments");
328 return -1;
329 }
330
331 iface = argv[2];
Dmitry Shmidt31fd6c52010-03-12 10:01:58 -0800332
333 if (strcmp(argv[3], "AP") == 0) {
334#ifdef WIFI_DRIVER_FW_AP_PATH
335 sprintf(mBuf, "FW_PATH=%s", WIFI_DRIVER_FW_AP_PATH);
336#endif
337 } else {
338#ifdef WIFI_DRIVER_FW_STA_PATH
339 sprintf(mBuf, "FW_PATH=%s", WIFI_DRIVER_FW_STA_PATH);
340#endif
341 }
Dmitry Shmidt6665fb22010-09-22 17:31:07 -0700342 ret = setCommand(iface, "WL_FW_RELOAD");
Dmitry Shmidt31fd6c52010-03-12 10:01:58 -0800343 if (ret) {
344 LOGE("Softap fwReload - failed: %d", ret);
345 }
346 else {
347 LOGD("Softap fwReload - Ok");
348 }
349 return ret;
350}
Dmitry Shmidt666fe252011-03-08 11:01:58 -0800351
352int SoftapController::clientsSoftap(char **retbuf)
353{
354 int ret;
355
356 if (mSock < 0) {
357 LOGE("Softap clients - failed to open socket");
358 return -1;
359 }
360 *mBuf = 0;
361 ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE);
362 if (ret) {
363 LOGE("Softap clients - failed: %d", ret);
364 } else {
365 asprintf(retbuf, "Softap clients:%s", mBuf);
366 LOGD("Softap clients:%s", mBuf);
367 }
368 return ret;
369}