1 /*
2  * Driver interaction with Linux nl80211/cfg80211
3  * Copyright (c) 2002-2015, Jouni Malinen <[email protected]>
4  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5  * Copyright (c) 2005-2006, Devicescape Software, Inc.
6  * Copyright (c) 2007, Johannes Berg <[email protected]>
7  * Copyright (c) 2009-2010, Atheros Communications
8  * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are
12  * met:
13  *     * Redistributions of source code must retain the above copyright
14  *     * Redistributions in binary form must reproduce the above
15  *       copyright notice, this list of conditions and the following
16  *       disclaimer in the documentation and/or other materials provided
17  *       with the distribution.
18  *     * Neither the name of The Linux Foundation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
33  *
34  */
35 
36 #include <errno.h>
37 #include <netlink/genl/family.h>
38 #include <netlink/genl/ctrl.h>
39 #include <linux/pkt_sched.h>
40 #include <unistd.h>
41 #include "cld80211_lib.h"
42 
43 #ifndef LE_BUILD
44  #include <log/log.h>
45  #undef LOG_TAG
46  #define LOG_TAG "CLD80211"
47 #else
48  #include <stdlib.h>
49  #include <syslog.h>
50  #include <unistd.h>
51  #define ALOGI(fmt, args...) syslog(LOG_INFO, fmt, ## args)
52  #define ALOGE(fmt, args...) syslog(LOG_ERR, fmt, ## args)
53  extern const char *__progname;
getprogname()54  const char *getprogname() { return (__progname); }
55 #endif
56 
57 #define SOCK_BUF_SIZE (256*1024)
58 
59 struct family_data {
60 	const char *group;
61 	int id;
62 };
63 
64 
create_nl_socket(int protocol)65 static struct nl_sock * create_nl_socket(int protocol)
66 {
67 	struct nl_sock *sock;
68 
69 	sock = nl_socket_alloc();
70 	if (sock == NULL) {
71 		ALOGE("%s: Failed to create NL socket, err: %d",
72 		      getprogname(), errno);
73 		return NULL;
74 	}
75 
76 	if (nl_connect(sock, protocol)) {
77 		ALOGE("%s: Could not connect sock, err: %d",
78 		      getprogname(), errno);
79 		nl_socket_free(sock);
80 		return NULL;
81 	}
82 
83 	return sock;
84 }
85 
86 
init_exit_sockets(struct cld80211_ctx * ctx)87 static int init_exit_sockets(struct cld80211_ctx *ctx)
88 {
89 	ctx->exit_sockets[0] = -1;
90 	ctx->exit_sockets[1] = -1;
91 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->exit_sockets[0]) == -1) {
92 		ALOGE("%s: Failed to create exit socket pair", getprogname());
93 		return -1;
94 	}
95 	ALOGI("%s: initialized exit socket pair", getprogname());
96 
97 	return 0;
98 }
99 
100 
cleanup_exit_sockets(struct cld80211_ctx * ctx)101 static void cleanup_exit_sockets(struct cld80211_ctx *ctx)
102 {
103 	if (ctx->exit_sockets[0] >= 0) {
104 		close(ctx->exit_sockets[0]);
105 		ctx->exit_sockets[0] = -1;
106 	}
107 
108 	if (ctx->exit_sockets[1] >= 0) {
109 		close(ctx->exit_sockets[1]);
110 		ctx->exit_sockets[1] = -1;
111 	}
112 }
113 
114 
exit_cld80211_recv(struct cld80211_ctx * ctx)115 void exit_cld80211_recv(struct cld80211_ctx *ctx)
116 {
117 	if (!ctx) {
118 		ALOGE("%s: ctx is NULL: %s", getprogname(), __func__);
119 		return;
120 	}
121 	TEMP_FAILURE_RETRY(write(ctx->exit_sockets[0], "E", 1));
122 	ALOGI("%s: Sent msg on exit sock to unblock poll()", getprogname());
123 }
124 
125 
126 /* Event handlers */
response_handler(struct nl_msg * msg,void * arg)127 static int response_handler(struct nl_msg *msg, void *arg)
128 {
129 	UNUSED(msg);
130 	UNUSED(arg);
131 	ALOGI("%s: Received nlmsg response: no callback registered;drop it",
132 	      getprogname());
133 
134 	return NL_SKIP;
135 }
136 
137 
ack_handler(struct nl_msg * msg,void * arg)138 static int ack_handler(struct nl_msg *msg, void *arg)
139 {
140 	int *err = (int *)arg;
141 	*err = 0;
142 	UNUSED(msg);
143 	return NL_STOP;
144 }
145 
146 
finish_handler(struct nl_msg * msg,void * arg)147 static int finish_handler(struct nl_msg *msg, void *arg)
148 {
149 	int *ret = (int *)arg;
150 	*ret = 0;
151 	UNUSED(msg);
152 	return NL_SKIP;
153 }
154 
155 
error_handler(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)156 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
157 			 void *arg)
158 {
159 	int *ret = (int *)arg;
160 	*ret = err->error;
161 
162 	UNUSED(nla);
163 	ALOGE("%s: error_handler received : %d", getprogname(), err->error);
164 	return NL_SKIP;
165 }
166 
167 
no_seq_check(struct nl_msg * msg,void * arg)168 static int no_seq_check(struct nl_msg *msg, void *arg)
169 {
170 	UNUSED(msg);
171 	UNUSED(arg);
172 	return NL_OK;
173 }
174 
175 
cld80211_recv_msg(struct nl_sock * sock,struct nl_cb * cb)176 int cld80211_recv_msg(struct nl_sock *sock, struct nl_cb *cb)
177 {
178 	if (!sock || !cb) {
179 		ALOGE("%s: %s is NULL", getprogname(), sock?"cb":"sock");
180 		return -EINVAL;
181 	}
182 
183 	int res = nl_recvmsgs(sock, cb);
184 	if(res)
185 		ALOGE("%s: Error :%d while reading nl msg , err: %d",
186 		      getprogname(), res, errno);
187 	return res;
188 }
189 
190 
cld80211_handle_event(int events,struct nl_sock * sock,struct nl_cb * cb)191 static void cld80211_handle_event(int events, struct nl_sock *sock,
192 				  struct nl_cb *cb)
193 {
194 	if (events & POLLERR) {
195 		ALOGE("%s: Error reading from socket", getprogname());
196 		cld80211_recv_msg(sock, cb);
197 	} else if (events & POLLHUP) {
198 		ALOGE("%s: Remote side hung up", getprogname());
199 	} else if (events & POLLIN) {
200 		cld80211_recv_msg(sock, cb);
201 	} else {
202 		ALOGE("%s: Unknown event - %0x", getprogname(), events);
203 	}
204 }
205 
206 
family_handler(struct nl_msg * msg,void * arg)207 static int family_handler(struct nl_msg *msg, void *arg)
208 {
209 	struct family_data *res = arg;
210 	struct nlattr *tb[CTRL_ATTR_MAX + 1];
211 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
212 	struct nlattr *mcgrp;
213 	int i;
214 
215 	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
216 			genlmsg_attrlen(gnlh, 0), NULL);
217 	if (!tb[CTRL_ATTR_MCAST_GROUPS])
218 		return NL_SKIP;
219 
220 	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
221 		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
222 		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
223 				nla_len(mcgrp), NULL);
224 
225 		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
226 			!tb2[CTRL_ATTR_MCAST_GRP_ID] ||
227 			strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
228 				   res->group,
229 				   nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
230 			continue;
231 		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
232 		break;
233 	};
234 
235 	return NL_SKIP;
236 }
237 
238 
get_multicast_id(struct cld80211_ctx * ctx,const char * group)239 static int get_multicast_id(struct cld80211_ctx *ctx, const char *group)
240 {
241 	struct family_data res = { group, -ENOENT };
242 	struct nl_msg *nlmsg = nlmsg_alloc();
243 
244 	if (!nlmsg) {
245 		return -1;
246 	}
247 
248 	genlmsg_put(nlmsg, 0, 0, ctx->nlctrl_familyid, 0, 0,
249 	            CTRL_CMD_GETFAMILY, 0);
250 	nla_put_string(nlmsg, CTRL_ATTR_FAMILY_NAME, "cld80211");
251 
252 	cld80211_send_recv_msg(ctx, nlmsg, family_handler, &res);
253 	ALOGI("%s: nlctrl family id: %d group: %s mcast_id: %d", getprogname(),
254 				   ctx->nlctrl_familyid, group, res.id);
255 	nlmsg_free(nlmsg);
256 	return res.id;
257 }
258 
259 
cld80211_add_mcast_group(struct cld80211_ctx * ctx,const char * mcgroup)260 int cld80211_add_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup)
261 {
262 	if (!ctx || !mcgroup) {
263 		ALOGE("%s: ctx/mcgroup is NULL: %s", getprogname(), __func__);
264 		return 0;
265 	}
266 	int id = get_multicast_id(ctx, mcgroup);
267 	if (id < 0) {
268 		ALOGE("%s: Could not find group %s, errno: %d id: %d",
269 		      getprogname(), mcgroup, errno, id);
270 		return id;
271 	}
272 
273 	int ret = nl_socket_add_membership(ctx->sock, id);
274 	if (ret < 0) {
275 		ALOGE("%s: Could not add membership to group %s, errno: %d",
276 		      getprogname(), mcgroup, errno);
277 	}
278 
279 	return ret;
280 }
281 
282 
cld80211_remove_mcast_group(struct cld80211_ctx * ctx,const char * mcgroup)283 int cld80211_remove_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup)
284 {
285 	// Drop membership is not a necessary cleanup action so comment it out.
286 #if 0
287 	if (!ctx || !mcgroup) {
288 		ALOGE("%s: ctx/mcgroup is NULL: %s", getprogname(), __func__);
289 		return 0;
290 	}
291 	int id = get_multicast_id(ctx, mcgroup);
292 	if (id < 0) {
293 		ALOGE("%s: Could not find group %s, errno: %d id: %d",
294 		      getprogname(), mcgroup, errno, id);
295 		return id;
296 	}
297 
298 	int ret = nl_socket_drop_membership(ctx->sock, id);
299 	if (ret < 0) {
300 		ALOGE("%s: Could not drop membership from group %s, errno: %d,"
301 		      " ret: %d", getprogname(), mcgroup, errno, ret);
302 		return ret;
303 	}
304 #endif
305 	return 0;
306 }
307 
308 
cld80211_msg_alloc(struct cld80211_ctx * ctx,int cmd,struct nlattr ** nla_data,int pid)309 struct nl_msg *cld80211_msg_alloc(struct cld80211_ctx *ctx, int cmd,
310 				  struct nlattr **nla_data, int pid)
311 {
312 	struct nl_msg *nlmsg;
313 
314 	if (!ctx || !nla_data) {
315 		ALOGE("%s: ctx is null: %s", getprogname(), __func__);
316 		return NULL;
317 	}
318 
319 	nlmsg = nlmsg_alloc();
320 	if (nlmsg == NULL) {
321 		ALOGE("%s: Out of memory", getprogname());
322 		return NULL;
323 	}
324 
325 	genlmsg_put(nlmsg, pid, /* seq = */ 0, ctx->netlink_familyid,
326 			0, 0, cmd, /* version = */ 0);
327 
328 	*nla_data = nla_nest_start(nlmsg, CLD80211_ATTR_VENDOR_DATA);
329 	if (!*nla_data)
330 		goto cleanup;
331 
332 	return nlmsg;
333 
334 cleanup:
335 	if (nlmsg)
336 		nlmsg_free(nlmsg);
337 	return NULL;
338 }
339 
340 
cld80211_send_msg(struct cld80211_ctx * ctx,struct nl_msg * nlmsg)341 int cld80211_send_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg)
342 {
343 	int err;
344 
345 	if (!ctx || !ctx->sock || !nlmsg) {
346 		ALOGE("%s: Invalid data from client", getprogname());
347 		return -EINVAL;
348 	}
349 
350 	err = nl_send_auto_complete(ctx->sock, nlmsg);  /* send message */
351 	if (err < 0) {
352 		ALOGE("%s: failed to send msg: %d", getprogname(), err);
353 		return err;
354 	}
355 
356 	return 0;
357 }
358 
359 
cld80211_send_recv_msg(struct cld80211_ctx * ctx,struct nl_msg * nlmsg,int (* valid_handler)(struct nl_msg *,void *),void * valid_data)360 int cld80211_send_recv_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg,
361 			   int (*valid_handler)(struct nl_msg *, void *),
362 			   void *valid_data)
363 {
364 	int err;
365 
366 	if (!ctx || !ctx->sock || !nlmsg) {
367 		ALOGE("%s: Invalid data from client", getprogname());
368 		return -EINVAL;
369 	}
370 
371 	struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
372 	if (!cb)
373 		return -ENOMEM;
374 
375 	err = nl_send_auto_complete(ctx->sock, nlmsg);  /* send message */
376 	if (err < 0)
377 		goto out;
378 
379 	err = 1;
380 
381 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
382 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
383 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
384 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
385 
386 	if (valid_handler)
387 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
388 			  valid_handler, valid_data);
389 	else
390 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
391 			  response_handler, valid_data);
392 
393 	while (err > 0) {    /* wait for reply */
394 		int res = nl_recvmsgs(ctx->sock, cb);
395 		if (res) {
396 			ALOGE("%s: cld80211: nl_recvmsgs failed: %d",
397 			      getprogname(), res);
398 		}
399 	}
400 out:
401 	nl_cb_put(cb);
402 	return err;
403 }
404 
405 
cld80211_recv(struct cld80211_ctx * ctx,int timeout,bool recv_multi_msg,int (* valid_handler)(struct nl_msg *,void *),void * cbctx)406 int cld80211_recv(struct cld80211_ctx *ctx, int timeout, bool recv_multi_msg,
407 		  int (*valid_handler)(struct nl_msg *, void *),
408 		  void *cbctx)
409 {
410 	struct pollfd pfd[2];
411 	struct nl_cb *cb;
412 	int err;
413 
414 	if (!ctx || !ctx->sock || !valid_handler) {
415 		ALOGE("%s: Invalid data from client", getprogname());
416 		return -EINVAL;
417 	}
418 
419 	cb = nl_cb_alloc(NL_CB_DEFAULT);
420 	if (!cb)
421 		return -ENOMEM;
422 
423 	memset(&pfd[0], 0, 2*sizeof(struct pollfd));
424 
425 	err = 1;
426 
427 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
428 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
429 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
430 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
431 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, cbctx);
432 
433 	pfd[0].fd = nl_socket_get_fd(ctx->sock);
434 	pfd[0].events = POLLIN;
435 
436 	pfd[1].fd = ctx->exit_sockets[1];
437 	pfd[1].events = POLLIN;
438 
439 	do {
440 		pfd[0].revents = 0;
441 		pfd[1].revents = 0;
442 		int result = poll(pfd, 2, timeout);
443 		if (result < 0) {
444 			ALOGE("%s: Error polling socket", getprogname());
445 		} else if (pfd[0].revents & (POLLIN | POLLHUP | POLLERR)) {
446 			cld80211_handle_event(pfd[0].revents, ctx->sock, cb);
447 			if (!recv_multi_msg)
448 				break;
449 		} else {
450 			ALOGI("%s: Exiting poll", getprogname());
451 			break;
452 		}
453 	} while (1);
454 
455 	nl_cb_put(cb);
456 	return 0;
457 }
458 
459 
cld80211_init(void)460 struct cld80211_ctx * cld80211_init(void)
461 {
462 	struct cld80211_ctx *ctx;
463 
464 	ctx = (struct cld80211_ctx *)malloc(sizeof(struct cld80211_ctx));
465 	if (ctx == NULL) {
466 		ALOGE("%s: Failed to alloc cld80211_ctx", getprogname());
467 		return NULL;
468 	}
469 	memset(ctx, 0, sizeof(struct cld80211_ctx));
470 
471 	ctx->sock = create_nl_socket(NETLINK_GENERIC);
472 	if (ctx->sock == NULL) {
473 		ALOGE("%s: Failed to create socket port", getprogname());
474 		goto cleanup;
475 	}
476 
477 	/* Set the socket buffer size */
478 	if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE , 0) < 0) {
479 		ALOGE("%s: Could not set nl_socket RX buffer size for sock: %s",
480 		      getprogname(), strerror(errno));
481 		/* continue anyway with the default (smaller) buffer */
482 	}
483 
484 	ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "cld80211");
485 	if (ctx->netlink_familyid < 0) {
486 		ALOGE("%s: Could not resolve cld80211 familty id",
487 		      getprogname());
488 		goto cleanup;
489 	}
490 
491 	ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
492 	if (ctx->nlctrl_familyid < 0) {
493 		ALOGE("%s: net link family nlctrl is not present: %d err:%d",
494 			getprogname(), ctx->nlctrl_familyid, errno);
495 		goto cleanup;
496 	}
497 
498 
499 	if (init_exit_sockets(ctx) != 0) {
500 		ALOGE("%s: Failed to initialize exit sockets", getprogname());
501 		goto cleanup;
502 	}
503 
504 	return ctx;
505 cleanup:
506 	if (ctx->sock) {
507 		nl_socket_free(ctx->sock);
508 	}
509 	free (ctx);
510 	return NULL;
511 }
512 
513 
cld80211_deinit(struct cld80211_ctx * ctx)514 void cld80211_deinit(struct cld80211_ctx *ctx)
515 {
516 	if (!ctx || !ctx->sock) {
517 		ALOGE("%s: ctx/sock is NULL", getprogname());
518 		return;
519 	}
520 	nl_socket_free(ctx->sock);
521 	cleanup_exit_sockets(ctx);
522 	free (ctx);
523 }
524