Home | History | Annotate | Download | only in dhdutil
      1 /*
      2  * nl80211 linux driver interface.
      3  *
      4  * Copyright (C) 1999-2013, Broadcom Corporation
      5  *
      6  * Permission to use, copy, modify, and/or distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     13  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     15  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     16  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  *
     18  * $Id: $
     19  */
     20 #include <errno.h>
     21 #include <linux/nl80211.h>
     22 #include <dhdioctl.h>
     23 #include "dhdu_nl80211.h"
     24 
     25 /* libnl 1.x compatibility code */
     26 #if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
     27 static inline struct nl_handle *nl_socket_alloc(void)
     28 {
     29 	return nl_handle_alloc();
     30 }
     31 
     32 static inline void nl_socket_free(struct nl_sock *h)
     33 {
     34 	nl_handle_destroy(h);
     35 }
     36 #endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */
     37 
     38 static int dhd_nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
     39 {
     40 	int *ret = arg;
     41 	*ret = err->error;
     42 	return NL_STOP;
     43 }
     44 
     45 static int dhd_nl_finish_handler(struct nl_msg *msg, void *arg)
     46 {
     47 	int *ret = arg;
     48 	*ret = 0;
     49 	return NL_SKIP;
     50 }
     51 
     52 static int dhd_nl_ack_handler(struct nl_msg *msg, void *arg)
     53 {
     54 	int *ret = arg;
     55 	*ret = 0;
     56 	return NL_STOP;
     57 }
     58 
     59 static int dhd_nl_valid_handler(struct nl_msg *msg, void *arg)
     60 {
     61 	return NL_SKIP;
     62 }
     63 
     64 int dhd_nl_sock_connect(struct dhd_netlink_info *dhd_nli)
     65 {
     66 	dhd_nli->nl = nl_socket_alloc();
     67 	if (dhd_nli->nl == NULL)
     68 		return -1;
     69 
     70 	if (genl_connect(dhd_nli->nl) < 0) {
     71 		fprintf(stderr, "netlink connection failed\n");
     72 		goto err;
     73 	}
     74 
     75 	dhd_nli->nl_id = genl_ctrl_resolve(dhd_nli->nl, "nl80211");
     76 	if (dhd_nli->nl_id < 0) {
     77 		fprintf(stderr, "'nl80211' netlink not found\n");
     78 		goto err;
     79 	}
     80 
     81 	dhd_nli->cb = nl_cb_alloc(NL_CB_DEBUG);
     82 	if (dhd_nli->cb == NULL)
     83 		goto err;
     84 
     85 	nl_socket_set_cb(dhd_nli->nl, dhd_nli->cb);
     86 	return 0;
     87 
     88 err:
     89 	nl_cb_put(dhd_nli->cb);
     90 	nl_socket_free(dhd_nli->nl);
     91 	fprintf(stderr, "nl80211 connection failed\n");
     92 	return -1;
     93 }
     94 
     95 void dhd_nl_sock_disconnect(struct dhd_netlink_info *dhd_nli)
     96 {
     97 	nl_cb_put(dhd_nli->cb);
     98 	nl_socket_free(dhd_nli->nl);
     99 }
    100 
    101 int dhd_nl_do_testmode(struct dhd_netlink_info *dhd_nli, dhd_ioctl_t *ioc)
    102 {
    103 	struct nl_msg *msg;
    104 	int err;
    105 
    106 	msg = nlmsg_alloc();
    107 	if (msg == NULL)
    108 		return -ENOMEM;
    109 
    110 	/* fill testmode message */
    111 	genlmsg_put(msg, 0, 0, dhd_nli->nl_id, 0, 0,
    112 		NL80211_CMD_TESTMODE, 0);
    113 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dhd_nli->ifidx);
    114 	NLA_PUT(msg, NL80211_ATTR_TESTDATA, sizeof(*ioc), ioc);
    115 
    116 	err = nl_send_auto_complete(dhd_nli->nl, msg);
    117 	if (err < 0)
    118 		goto out;
    119 
    120 	err = 1;
    121 	nl_cb_err(dhd_nli->cb, NL_CB_CUSTOM, dhd_nl_error_handler, &err);
    122 	nl_cb_set(dhd_nli->cb, NL_CB_ACK, NL_CB_CUSTOM,
    123 		dhd_nl_ack_handler, &err);
    124 	nl_cb_set(dhd_nli->cb, NL_CB_FINISH, NL_CB_CUSTOM,
    125 		dhd_nl_finish_handler, &err);
    126 	nl_cb_set(dhd_nli->cb, NL_CB_VALID, NL_CB_CUSTOM,
    127 		dhd_nl_valid_handler, &err);
    128 	while (err > 0)
    129 		nl_recvmsgs(dhd_nli->nl, dhd_nli->cb);
    130 out:
    131 	nlmsg_free(msg);
    132 	return err;
    133 
    134 nla_put_failure:
    135 	fprintf(stderr, "setting netlink attribute failed\n");
    136 	err = -EFAULT;
    137 	goto out;
    138 }
    139