Home | History | Annotate | Download | only in cld80211-lib
      1 /*
      2  * Driver interaction with Linux nl80211/cfg80211
      3  * Copyright (c) 2002-2015, Jouni Malinen <j (at) w1.fi>
      4  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
      5  * Copyright (c) 2005-2006, Devicescape Software, Inc.
      6  * Copyright (c) 2007, Johannes Berg <johannes (at) sipsolutions.net>
      7  * Copyright (c) 2009-2010, Atheros Communications
      8  * Copyright (c) 2017, 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 <log/log.h>
     42 #include "cld80211_lib.h"
     43 
     44 #undef LOG_TAG
     45 #define LOG_TAG "CLD80211"
     46 #define SOCK_BUF_SIZE (256*1024)
     47 
     48 struct family_data {
     49 	const char *group;
     50 	int id;
     51 };
     52 
     53 
     54 static struct nl_sock * create_nl_socket(int protocol)
     55 {
     56 	struct nl_sock *sock;
     57 
     58 	sock = nl_socket_alloc();
     59 	if (sock == NULL) {
     60 		ALOGE("%s: Failed to create NL socket, err: %d",
     61 		      getprogname(), errno);
     62 		return NULL;
     63 	}
     64 
     65 	if (nl_connect(sock, protocol)) {
     66 		ALOGE("%s: Could not connect sock, err: %d",
     67 		      getprogname(), errno);
     68 		nl_socket_free(sock);
     69 		return NULL;
     70 	}
     71 
     72 	return sock;
     73 }
     74 
     75 
     76 static int init_exit_sockets(struct cld80211_ctx *ctx)
     77 {
     78 	ctx->exit_sockets[0] = -1;
     79 	ctx->exit_sockets[1] = -1;
     80 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->exit_sockets[0]) == -1) {
     81 		ALOGE("%s: Failed to create exit socket pair", getprogname());
     82 		return -1;
     83 	}
     84 	ALOGI("%s: initialized exit socket pair", getprogname());
     85 
     86 	return 0;
     87 }
     88 
     89 
     90 static void cleanup_exit_sockets(struct cld80211_ctx *ctx)
     91 {
     92 	if (ctx->exit_sockets[0] >= 0) {
     93 		close(ctx->exit_sockets[0]);
     94 		ctx->exit_sockets[0] = -1;
     95 	}
     96 
     97 	if (ctx->exit_sockets[1] >= 0) {
     98 		close(ctx->exit_sockets[1]);
     99 		ctx->exit_sockets[1] = -1;
    100 	}
    101 }
    102 
    103 
    104 void exit_cld80211_recv(struct cld80211_ctx *ctx)
    105 {
    106 	if (!ctx) {
    107 		ALOGE("%s: ctx is NULL: %s", getprogname(), __func__);
    108 		return;
    109 	}
    110 	TEMP_FAILURE_RETRY(write(ctx->exit_sockets[0], "E", 1));
    111 	ALOGI("%s: Sent msg on exit sock to unblock poll()", getprogname());
    112 }
    113 
    114 
    115 /* Event handlers */
    116 static int response_handler(struct nl_msg *msg, void *arg)
    117 {
    118 	UNUSED(msg);
    119 	UNUSED(arg);
    120 	ALOGI("%s: Received nlmsg response: no callback registered;drop it",
    121 	      getprogname());
    122 
    123 	return NL_SKIP;
    124 }
    125 
    126 
    127 static int ack_handler(struct nl_msg *msg, void *arg)
    128 {
    129 	int *err = (int *)arg;
    130 	*err = 0;
    131 	UNUSED(msg);
    132 	return NL_STOP;
    133 }
    134 
    135 
    136 static int finish_handler(struct nl_msg *msg, void *arg)
    137 {
    138 	int *ret = (int *)arg;
    139 	*ret = 0;
    140 	UNUSED(msg);
    141 	return NL_SKIP;
    142 }
    143 
    144 
    145 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
    146 			 void *arg)
    147 {
    148 	int *ret = (int *)arg;
    149 	*ret = err->error;
    150 
    151 	UNUSED(nla);
    152 	ALOGE("%s: error_handler received : %d", getprogname(), err->error);
    153 	return NL_SKIP;
    154 }
    155 
    156 
    157 static int no_seq_check(struct nl_msg *msg, void *arg)
    158 {
    159 	UNUSED(msg);
    160 	UNUSED(arg);
    161 	return NL_OK;
    162 }
    163 
    164 
    165 int cld80211_recv_msg(struct nl_sock *sock, struct nl_cb *cb)
    166 {
    167 	if (!sock || !cb) {
    168 		ALOGE("%s: %s is NULL", getprogname(), sock?"cb":"sock");
    169 		return -EINVAL;
    170 	}
    171 
    172 	int res = nl_recvmsgs(sock, cb);
    173 	if(res)
    174 		ALOGE("%s: Error :%d while reading nl msg , err: %d",
    175 		      getprogname(), res, errno);
    176 	return res;
    177 }
    178 
    179 
    180 static void cld80211_handle_event(int events, struct nl_sock *sock,
    181 				  struct nl_cb *cb)
    182 {
    183 	if (events & POLLERR) {
    184 		ALOGE("%s: Error reading from socket", getprogname());
    185 		cld80211_recv_msg(sock, cb);
    186 	} else if (events & POLLHUP) {
    187 		ALOGE("%s: Remote side hung up", getprogname());
    188 	} else if (events & POLLIN) {
    189 		cld80211_recv_msg(sock, cb);
    190 	} else {
    191 		ALOGE("%s: Unknown event - %0x", getprogname(), events);
    192 	}
    193 }
    194 
    195 
    196 static int family_handler(struct nl_msg *msg, void *arg)
    197 {
    198 	struct family_data *res = arg;
    199 	struct nlattr *tb[CTRL_ATTR_MAX + 1];
    200 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    201 	struct nlattr *mcgrp;
    202 	int i;
    203 
    204 	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
    205 			genlmsg_attrlen(gnlh, 0), NULL);
    206 	if (!tb[CTRL_ATTR_MCAST_GROUPS])
    207 		return NL_SKIP;
    208 
    209 	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
    210 		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
    211 		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
    212 				nla_len(mcgrp), NULL);
    213 
    214 		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
    215 			!tb2[CTRL_ATTR_MCAST_GRP_ID] ||
    216 			strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
    217 				   res->group,
    218 				   nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
    219 			continue;
    220 		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
    221 		break;
    222 	};
    223 
    224 	return NL_SKIP;
    225 }
    226 
    227 
    228 static int get_multicast_id(struct cld80211_ctx *ctx, const char *group)
    229 {
    230 	struct family_data res = { group, -ENOENT };
    231 	struct nl_msg *nlmsg = nlmsg_alloc();
    232 
    233 	if (!nlmsg) {
    234 		return -1;
    235 	}
    236 
    237 	genlmsg_put(nlmsg, 0, 0, ctx->nlctrl_familyid, 0, 0,
    238 	            CTRL_CMD_GETFAMILY, 0);
    239 	nla_put_string(nlmsg, CTRL_ATTR_FAMILY_NAME, "cld80211");
    240 
    241 	cld80211_send_recv_msg(ctx, nlmsg, family_handler, &res);
    242 	ALOGI("%s: nlctrl family id: %d group: %s mcast_id: %d", getprogname(),
    243 				   ctx->nlctrl_familyid, group, res.id);
    244 	nlmsg_free(nlmsg);
    245 	return res.id;
    246 }
    247 
    248 
    249 int cld80211_add_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup)
    250 {
    251 	if (!ctx || !mcgroup) {
    252 		ALOGE("%s: ctx/mcgroup is NULL: %s", getprogname(), __func__);
    253 		return 0;
    254 	}
    255 	int id = get_multicast_id(ctx, mcgroup);
    256 	if (id < 0) {
    257 		ALOGE("%s: Could not find group %s, errno: %d id: %d",
    258 		      getprogname(), mcgroup, errno, id);
    259 		return id;
    260 	}
    261 
    262 	int ret = nl_socket_add_membership(ctx->sock, id);
    263 	if (ret < 0) {
    264 		ALOGE("%s: Could not add membership to group %s, errno: %d",
    265 		      getprogname(), mcgroup, errno);
    266 	}
    267 
    268 	return ret;
    269 }
    270 
    271 
    272 int cld80211_remove_mcast_group(struct cld80211_ctx *ctx, const char* mcgroup)
    273 {
    274 	if (!ctx || !mcgroup) {
    275 		ALOGE("%s: ctx/mcgroup is NULL: %s", getprogname(), __func__);
    276 		return 0;
    277 	}
    278 	int id = get_multicast_id(ctx, mcgroup);
    279 	if (id < 0) {
    280 		ALOGE("%s: Could not find group %s, errno: %d id: %d",
    281 		      getprogname(), mcgroup, errno, id);
    282 		return id;
    283 	}
    284 
    285 	int ret = nl_socket_drop_membership(ctx->sock, id);
    286 	if (ret < 0) {
    287 		ALOGE("%s: Could not drop membership from group %s, errno: %d,"
    288 		      " ret: %d", getprogname(), mcgroup, errno, ret);
    289 		return ret;
    290 	}
    291 
    292 	return 0;
    293 }
    294 
    295 
    296 struct nl_msg *cld80211_msg_alloc(struct cld80211_ctx *ctx, int cmd,
    297 				  struct nlattr **nla_data, int pid)
    298 {
    299 	struct nl_msg *nlmsg;
    300 
    301 	if (!ctx || !nla_data) {
    302 		ALOGE("%s: ctx is null: %s", getprogname(), __func__);
    303 		return NULL;
    304 	}
    305 
    306 	nlmsg = nlmsg_alloc();
    307 	if (nlmsg == NULL) {
    308 		ALOGE("%s: Out of memory", getprogname());
    309 		return NULL;
    310 	}
    311 
    312 	genlmsg_put(nlmsg, pid, /* seq = */ 0, ctx->netlink_familyid,
    313 			0, 0, cmd, /* version = */ 0);
    314 
    315 	*nla_data = nla_nest_start(nlmsg, CLD80211_ATTR_VENDOR_DATA);
    316 	if (!nla_data)
    317 		goto cleanup;
    318 
    319 	return nlmsg;
    320 
    321 cleanup:
    322 	if (nlmsg)
    323 		nlmsg_free(nlmsg);
    324 	return NULL;
    325 }
    326 
    327 
    328 int cld80211_send_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg)
    329 {
    330 	int err;
    331 
    332 	if (!ctx || !ctx->sock || !nlmsg) {
    333 		ALOGE("%s: Invalid data from client", getprogname());
    334 		return -EINVAL;
    335 	}
    336 
    337 	err = nl_send_auto_complete(ctx->sock, nlmsg);  /* send message */
    338 	if (err < 0) {
    339 		ALOGE("%s: failed to send msg: %d", getprogname(), err);
    340 		return err;
    341 	}
    342 
    343 	return 0;
    344 }
    345 
    346 
    347 int cld80211_send_recv_msg(struct cld80211_ctx *ctx, struct nl_msg *nlmsg,
    348 			   int (*valid_handler)(struct nl_msg *, void *),
    349 			   void *valid_data)
    350 {
    351 	int err;
    352 
    353 	if (!ctx || !ctx->sock || !nlmsg) {
    354 		ALOGE("%s: Invalid data from client", getprogname());
    355 		return -EINVAL;
    356 	}
    357 
    358 	struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
    359 	if (!cb)
    360 		return -ENOMEM;
    361 
    362 	err = nl_send_auto_complete(ctx->sock, nlmsg);  /* send message */
    363 	if (err < 0)
    364 		goto out;
    365 
    366 	err = 1;
    367 
    368 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
    369 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
    370 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
    371 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
    372 
    373 	if (valid_handler)
    374 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
    375 			  valid_handler, valid_data);
    376 	else
    377 		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
    378 			  response_handler, valid_data);
    379 
    380 	while (err > 0) {    /* wait for reply */
    381 		int res = nl_recvmsgs(ctx->sock, cb);
    382 		if (res) {
    383 			ALOGE("%s: cld80211: nl_recvmsgs failed: %d",
    384 			      getprogname(), res);
    385 		}
    386 	}
    387 out:
    388 	nl_cb_put(cb);
    389 	return err;
    390 }
    391 
    392 
    393 int cld80211_recv(struct cld80211_ctx *ctx, int timeout, bool recv_multi_msg,
    394 		  int (*valid_handler)(struct nl_msg *, void *),
    395 		  void *cbctx)
    396 {
    397 	struct pollfd pfd[2];
    398 	struct nl_cb *cb;
    399 	int err;
    400 
    401 	if (!ctx || !ctx->sock || !valid_handler) {
    402 		ALOGE("%s: Invalid data from client", getprogname());
    403 		return -EINVAL;
    404 	}
    405 
    406 	cb = nl_cb_alloc(NL_CB_DEFAULT);
    407 	if (!cb)
    408 		return -ENOMEM;
    409 
    410 	memset(&pfd[0], 0, 2*sizeof(struct pollfd));
    411 
    412 	err = 1;
    413 
    414 	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
    415 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
    416 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
    417 	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
    418 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, cbctx);
    419 
    420 	pfd[0].fd = nl_socket_get_fd(ctx->sock);
    421 	pfd[0].events = POLLIN;
    422 
    423 	pfd[1].fd = ctx->exit_sockets[1];
    424 	pfd[1].events = POLLIN;
    425 
    426 	do {
    427 		pfd[0].revents = 0;
    428 		pfd[1].revents = 0;
    429 		int result = poll(pfd, 2, timeout);
    430 		if (result < 0) {
    431 			ALOGE("%s: Error polling socket", getprogname());
    432 		} else if (pfd[0].revents & (POLLIN | POLLHUP | POLLERR)) {
    433 			cld80211_handle_event(pfd[0].revents, ctx->sock, cb);
    434 			if (!recv_multi_msg)
    435 				break;
    436 		} else {
    437 			ALOGI("%s: Exiting poll", getprogname());
    438 			break;
    439 		}
    440 	} while (1);
    441 
    442 	nl_cb_put(cb);
    443 	return 0;
    444 }
    445 
    446 
    447 struct cld80211_ctx * cld80211_init()
    448 {
    449 	struct cld80211_ctx *ctx;
    450 
    451 	ctx = (struct cld80211_ctx *)malloc(sizeof(struct cld80211_ctx));
    452 	if (ctx == NULL) {
    453 		ALOGE("%s: Failed to alloc cld80211_ctx", getprogname());
    454 		return NULL;
    455 	}
    456 	memset(ctx, 0, sizeof(struct cld80211_ctx));
    457 
    458 	ctx->sock = create_nl_socket(NETLINK_GENERIC);
    459 	if (ctx->sock == NULL) {
    460 		ALOGE("%s: Failed to create socket port", getprogname());
    461 		goto cleanup;
    462 	}
    463 
    464 	/* Set the socket buffer size */
    465 	if (nl_socket_set_buffer_size(ctx->sock, SOCK_BUF_SIZE , 0) < 0) {
    466 		ALOGE("%s: Could not set nl_socket RX buffer size for sock: %s",
    467 		      getprogname(), strerror(errno));
    468 		/* continue anyway with the default (smaller) buffer */
    469 	}
    470 
    471 	ctx->netlink_familyid = genl_ctrl_resolve(ctx->sock, "cld80211");
    472 	if (ctx->netlink_familyid < 0) {
    473 		ALOGE("%s: Could not resolve cld80211 familty id",
    474 		      getprogname());
    475 		goto cleanup;
    476 	}
    477 
    478 	ctx->nlctrl_familyid = genl_ctrl_resolve(ctx->sock, "nlctrl");
    479 	if (ctx->nlctrl_familyid < 0) {
    480 		ALOGE("%s: net link family nlctrl is not present: %d err:%d",
    481 			getprogname(), ctx->nlctrl_familyid, errno);
    482 		goto cleanup;
    483 	}
    484 
    485 
    486 	if (init_exit_sockets(ctx) != 0) {
    487 		ALOGE("%s: Failed to initialize exit sockets", getprogname());
    488 		goto cleanup;
    489 	}
    490 
    491 	return ctx;
    492 cleanup:
    493 	if (ctx->sock) {
    494 		nl_socket_free(ctx->sock);
    495 	}
    496 	free (ctx);
    497 	return NULL;
    498 }
    499 
    500 
    501 void cld80211_deinit(struct cld80211_ctx *ctx)
    502 {
    503 	if (!ctx || !ctx->sock) {
    504 		ALOGE("%s: ctx/sock is NULL", getprogname());
    505 		return;
    506 	}
    507 	nl_socket_free(ctx->sock);
    508 	cleanup_exit_sockets(ctx);
    509 	free (ctx);
    510 }
    511