blob: 9ad1e4363663320cbd7c17e777ec3c49fed812ab [file] [log] [blame]
Raj Kushwaha41027212010-10-13 00:11:12 -07001/*
Duy Truongd48aa312013-02-10 02:16:54 -08002 * Copyright (c) 2010, The Linux Foundation. All rights reserved.
Raj Kushwaha41027212010-10-13 00:11:12 -07003
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
Duy Truongd48aa312013-02-10 02:16:54 -080013 * * Neither the name of The Linux Foundation nor the names of its
Raj Kushwaha41027212010-10-13 00:11:12 -070014 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30
31#include "QWiFiSoftApCfg.h"
32
33#define UPDATE_ERROR_CODE(msg, code) \
34 { \
35 int rc; \
36 rc = snprintf(resp, sizeof(resp), "failure %s:%s",msg, code); \
37 if ( rc == sizeof(resp)) resp[sizeof(resp)-1] = 0; \
Deepthi Gowrid4c03152012-07-17 18:42:07 +053038 ALOGE("%s",resp); \
Raj Kushwaha41027212010-10-13 00:11:12 -070039 }
40
41static struct sockaddr_nl rtnl_local;
42static int rtnl_fd = -1;
43static char evt_buf[MAX_EVT_BUF_SIZE];
44static int evt_len;
45
46static void softap_handle_custom_event(char * buf, int len)
47{
48 if (strncmp(buf, "AUTO-SHUT.indication ", strlen("AUTO-SHUT.indication ")) == 0)
49 {
Deepthi Gowrid4c03152012-07-17 18:42:07 +053050 ALOGD("EVENT: Custom Event\n");
Raj Kushwaha41027212010-10-13 00:11:12 -070051 snprintf(evt_buf, sizeof(evt_buf), "105 AP Shutdown");
52 }
53}
54
55static void softap_handle_associated_event(char *mac_addr)
56{
57 snprintf(evt_buf, sizeof(evt_buf), "102 Station " HWA_FORM " Associated",
58 HWA_ARG(mac_addr));
59}
60
61static void softap_handle_disassociated_event(char *mac_addr)
62{
63 snprintf(evt_buf, sizeof(evt_buf), "103 Station " HWA_FORM " Disassociated",
64 HWA_ARG(mac_addr));
65}
66
67static void softap_handle_wireless_event(char *atr, int atrlen)
68{
69 int len = 0;
70 struct iw_event iwe;
71 char *buffer = atr + RTA_ALIGN(RTATTRLEN);
72
73 atrlen -= RTA_ALIGN(RTATTRLEN);
74
75 while ((len + (int)IW_EV_LCP_LEN) < atrlen) {
76 memcpy((char *)&iwe, buffer + len, sizeof(struct iw_event));
77
78 if (iwe.len <= IW_EV_LCP_LEN)
79 break;
80
Deepthi Gowrid4c03152012-07-17 18:42:07 +053081 ALOGD("Received Wireless Event: cmd=0x%x len=%d", iwe.cmd, iwe.len);
Raj Kushwaha41027212010-10-13 00:11:12 -070082
83 switch (iwe.cmd) {
84 case IWEVEXPIRED:
Deepthi Gowrid4c03152012-07-17 18:42:07 +053085 ALOGD("EVENT: IWEVEXPIRED\n");
Raj Kushwaha41027212010-10-13 00:11:12 -070086 softap_handle_disassociated_event(iwe.u.addr.sa_data);
87 break;
88
89 case IWEVREGISTERED:
Deepthi Gowrid4c03152012-07-17 18:42:07 +053090 ALOGD("EVENT: IWEVREGISTERED\n");
Raj Kushwaha41027212010-10-13 00:11:12 -070091 softap_handle_associated_event(iwe.u.addr.sa_data);
92 break;
93
94 case IWEVCUSTOM:
Deepthi Gowrid4c03152012-07-17 18:42:07 +053095 ALOGD("EVENT: Custom Event\n");
Raj Kushwaha41027212010-10-13 00:11:12 -070096 softap_handle_custom_event(buffer + len + IW_EV_POINT_LEN, iwe.u.data.length);
97 break;
98
99 default:
100 break;
101 }
102
103 len += iwe.len;
104 }
105
106 return;
107}
108
109void softap_handle_rtm_link_event(struct nlmsghdr *hdr)
110{
111 char *ptr = (char *)NLMSG_DATA(hdr);
112 struct rtattr *atr;
113 int atr_len;
114
115 if ((hdr->nlmsg_len - MSGHDRLEN) < IFINFOLEN) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530116 ALOGD("Message Length Problem1");
Raj Kushwaha41027212010-10-13 00:11:12 -0700117 return;
118 }
119
120 if ((atr_len = hdr->nlmsg_len - NLMSG_ALIGN(IFINFOLEN)) < 0) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530121 ALOGD("Message Length Problem2");
Raj Kushwaha41027212010-10-13 00:11:12 -0700122 return;
123 }
124
125 ptr += NLMSG_ALIGN(IFINFOLEN);
126 atr = (struct rtattr *)ptr;
127
128 while (RTA_OK(atr, atr_len)) {
129 switch (atr->rta_type) {
130 case IFLA_WIRELESS:
131 softap_handle_wireless_event((char *)atr,
132 atr->rta_len);
133 break;
134
135 default:
136 break;
137 }
138
139 atr = RTA_NEXT(atr, atr_len);
140 }
141
142 return;
143}
144
145static void softap_handle_iface_event(void)
146{
147 int cnt, mlen = 0;
148 char *ptr, buffer[MAX_RECV_BUF_SIZE];
149 socklen_t slen;
150 struct nlmsghdr * hdr;
151
152 while (1) {
153 cnt = recvfrom(rtnl_fd, buffer, sizeof(buffer),
154 MSG_DONTWAIT,
155 (struct sockaddr *)&rtnl_local, &slen);
156
157 if (cnt <= 0) {
158 buffer[0] = '\0';
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530159 ALOGD("recvfrom failed");
Raj Kushwaha41027212010-10-13 00:11:12 -0700160 return;
161 }
162
163 ptr = buffer;
164
165 while (cnt >= MSGHDRLEN) {
166 hdr = (struct nlmsghdr *)ptr;
167
168 mlen = hdr->nlmsg_len;
169
170 if ((mlen > cnt) || ((mlen - MSGHDRLEN) < 0)) {
171 break;
172 }
173
174 switch (hdr->nlmsg_type) {
175 case RTM_NEWLINK:
176 case RTM_DELLINK:
177 softap_handle_rtm_link_event(hdr);
178 break;
179 }
180
181 mlen = NLMSG_ALIGN(hdr->nlmsg_len);
182 cnt -= mlen;
183 ptr += mlen;
184 }
185 }
186
187 return;
188}
189
190static inline int softap_rtnl_wait(void)
191{
192 fd_set fds;
193 int oldfd, ret;
194
195 if (rtnl_fd < 0) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530196 ALOGD("Netlink Socket Not Available");
Raj Kushwaha41027212010-10-13 00:11:12 -0700197 return -1;
198 }
199
200 /* Initialize fds */
201 FD_ZERO(&fds);
202 FD_SET(rtnl_fd, &fds);
203 oldfd = rtnl_fd;
204
205 /* Wait for some trigger event */
206 ret = select(oldfd + 1, &fds, NULL, NULL, NULL);
207
208 if (ret < 0) {
209 /* Error Occurred */
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530210 ALOGD("Select on Netlink Socket Failed");
Raj Kushwaha41027212010-10-13 00:11:12 -0700211 return ret;
212 } else if (!ret) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530213 ALOGD("Select on Netlink Socket Timed Out");
Raj Kushwaha41027212010-10-13 00:11:12 -0700214 /* Timeout Occurred */
215 return -1;
216 }
217
218 /* Check if any event is available for us */
219 if (FD_ISSET(rtnl_fd, &fds)) {
220 softap_handle_iface_event();
221 }
222
223 return 0;
224}
225
226static void softap_rtnl_close(void)
227{
228 close(rtnl_fd);
229}
230
231static int softap_rtnl_open(void)
232{
233 int addr_len;
234
235 rtnl_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
236
237 if (rtnl_fd < 0) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530238 ALOGE("open netlink socket failed");
Raj Kushwaha41027212010-10-13 00:11:12 -0700239 return -1;
240 }
241
242 memset(&rtnl_local, 0, sizeof(rtnl_local));
243 rtnl_local.nl_family = AF_NETLINK;
244 rtnl_local.nl_groups = RTMGRP_LINK;
245
246 if (bind(rtnl_fd, (struct sockaddr*)&rtnl_local,
247 sizeof(rtnl_local)) < 0) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530248 ALOGE("bind netlink socket failed");
Raj Kushwaha41027212010-10-13 00:11:12 -0700249 return -1;
250 }
251
252 addr_len = sizeof(rtnl_local);
253
254 if (getsockname(rtnl_fd, (struct sockaddr*)&rtnl_local,
255 (socklen_t *) &addr_len) < 0) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530256 ALOGE("getsockname failed");
Raj Kushwaha41027212010-10-13 00:11:12 -0700257 return -1;
258 }
259
260 if (addr_len != sizeof(rtnl_local)) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530261 ALOGE("Wrong address length %d\n", addr_len);
Raj Kushwaha41027212010-10-13 00:11:12 -0700262 return -1;
263 }
264
265 if (rtnl_local.nl_family != AF_NETLINK) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530266 ALOGE("Wrong address family %d\n", rtnl_local.nl_family);
Raj Kushwaha41027212010-10-13 00:11:12 -0700267 return -1;
268 }
269
270 return 0;
271}
272
273JNIEXPORT void JNICALL
274 Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapCloseNetlink
275 (JNIEnv *env, jobject obj)
276{
277 softap_rtnl_close();
278 return;
279}
280
281JNIEXPORT jstring JNICALL
282 Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapWaitForEvent
283 (JNIEnv *env, jobject obj)
284{
285 int ret;
286
287 do {
288 evt_len = 0;
289 memset(evt_buf, 0, sizeof(evt_buf));
290
291 ret = softap_rtnl_wait();
292 } while (!strlen(evt_buf));
293
294 return (*env)->NewStringUTF(env, evt_buf);
295}
296
297JNIEXPORT jboolean JNICALL
298 Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapOpenNetlink
299 (JNIEnv *env, jobject obj)
300{
301 if (softap_rtnl_open() != 0) {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530302 ALOGD("Netlink Open Fail");
Raj Kushwaha41027212010-10-13 00:11:12 -0700303 return JNI_FALSE;
304 }
305
306 return JNI_TRUE;
307}
308
309JNIEXPORT jstring JNICALL
310 Java_com_qualcomm_wifi_softap_QWiFiSoftApCfg_SapSendCommand
311 (JNIEnv *env, jobject obj, jstring jcmd)
312{
313 const char *pcmd;
314 char cmd[MAX_CMD_SIZE];
315 char resp[MAX_RESP_SIZE];
santosh sajjan1a6aff92011-07-18 17:11:12 +0530316 int sock = -1;
317 int rc;
Raj Kushwaha41027212010-10-13 00:11:12 -0700318 int done = 0;
319 char code[32] = {0};
320 int connect_retry;
321
Naresh Jayaram71846202015-03-03 15:43:17 +0530322 strlcpy(cmd, "softap qccmd ", sizeof(cmd));
Raj Kushwaha41027212010-10-13 00:11:12 -0700323
324 pcmd = (char *) ((*env)->GetStringUTFChars(env, jcmd, NULL));
325
326 if ( pcmd == NULL ) {
327 UPDATE_ERROR_CODE("Command not handled","");
328 goto end;
329 }
330
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530331 ALOGD("Received Command: %s\n", pcmd);
Raj Kushwaha41027212010-10-13 00:11:12 -0700332
Naresh Jayaram71846202015-03-03 15:43:17 +0530333 if ((strlen(cmd) + strlen(pcmd)) >= sizeof(cmd)) {
Raj Kushwaha41027212010-10-13 00:11:12 -0700334 UPDATE_ERROR_CODE("Command length is larger than MAX_CMD_SIZE", "");
335 goto end;
336 }
337
Naresh Jayaram71846202015-03-03 15:43:17 +0530338 strlcat(cmd, pcmd, sizeof(cmd));
Raj Kushwaha41027212010-10-13 00:11:12 -0700339
340 connect_retry = 0;
341
342 while ( 1 ) {
343 if ((sock = socket_local_client("netd",
344 ANDROID_SOCKET_NAMESPACE_RESERVED,
345 SOCK_STREAM)) < 0) {
346 if (connect_retry > 3) {
347 UPDATE_ERROR_CODE("Error connecting",
348 strerror(errno));
349 goto end;
350 }
351
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530352 ALOGW("Unable to connect to netd, retrying ...\n");
Raj Kushwaha41027212010-10-13 00:11:12 -0700353 sleep(1);
354 } else {
355 break;
356 }
357
358 connect_retry++;
359 }
360
361 if (write(sock, cmd, strlen(cmd) + 1) < 0) {
362 UPDATE_ERROR_CODE("Error Writing to socket", strerror(errno));
363 goto end;
364 }
365
366 while (!done) {
367 int i;
368
369 if ((rc = read(sock, resp, sizeof(resp))) <= 0) {
370 if (rc == 0) {
371 UPDATE_ERROR_CODE("Lost connection to Netd",
372 strerror(errno));
373 } else {
374 UPDATE_ERROR_CODE("Error reading data",
375 strerror(errno));
376 }
377
378 done = 1;
379 } else {
380 /* skip broadcase messages */
381 i = 0;
382
383 while(resp[i] && (i<(int)(sizeof(code)-1)) &&
384 (resp[i] != ' ') && (resp[i] != '\t')) {
385 code[i] = resp[i];
386 i++;
387 }
388
389 code[i] = '\0';
390
391 if ( (!strcmp(code, "success")) ||
392 (!strcmp(code, "failure")) ) {
393 done=1;
394 } else {
Deepthi Gowrid4c03152012-07-17 18:42:07 +0530395 ALOGW("Code(%s)\n", code);
396 ALOGW("Ignore messages : %s\n", resp);
Raj Kushwaha41027212010-10-13 00:11:12 -0700397 }
398 }
399 }
400
401end:
402 (*env)->ReleaseStringUTFChars(env, jcmd, pcmd);
403
santosh sajjan1a6aff92011-07-18 17:11:12 +0530404 if( sock >= 0 ){
405 close(sock);
406 sock = -1;
407 }
408
Raj Kushwaha41027212010-10-13 00:11:12 -0700409 return (*env)->NewStringUTF(env, resp);
410}