Home | History | Annotate | Download | only in genl
      1 /*
      2  * Copyright (C) 2011 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 /* NOTICE: This is a clean room re-implementation of libnl */
     18 
     19 #include <errno.h>
     20 #include <unistd.h>
     21 #include <stdio.h>
     22 #include <sys/time.h>
     23 #include <linux/netlink.h>
     24 #include "netlink-types.h"
     25 
     26 /* Get head of attribute data. */
     27 struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
     28 {
     29 	return (struct nlattr *) \
     30 		((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
     31 
     32 }
     33 
     34 /* Get length of attribute data. */
     35 int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
     36 {
     37 	struct nlattr *nla;
     38 	struct nlmsghdr *nlh;
     39 
     40 	nla = genlmsg_attrdata(gnlh, hdrlen);
     41 	nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
     42 	return (char *) nlmsg_tail(nlh) - (char *) nla;
     43 }
     44 
     45 /* Add generic netlink header to netlink message. */
     46 void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
     47 		int hdrlen, int flags, uint8_t cmd, uint8_t version)
     48 {
     49 	int new_size;
     50 	struct nlmsghdr *nlh;
     51 	struct timeval tv;
     52 	struct genlmsghdr *gmh;
     53 
     54 	/* Make sure nl_msg has enough space */
     55 	new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
     56 	if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
     57 		goto fail;
     58 
     59 	/* Fill in netlink header */
     60 	nlh = msg->nm_nlh;
     61 	nlh->nlmsg_len = new_size;
     62 	nlh->nlmsg_type = family;
     63 	nlh->nlmsg_pid = getpid();
     64 	nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
     65 
     66 	/* Get current time for sequence number */
     67 	if (gettimeofday(&tv, NULL))
     68 		nlh->nlmsg_seq = 1;
     69 	else
     70 		nlh->nlmsg_seq = (int) tv.tv_sec;
     71 
     72 	/* Setup genlmsghdr in new message */
     73 	gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
     74 	gmh->cmd = (__u8) cmd;
     75 	gmh->version = version;
     76 
     77 	return gmh;
     78 fail:
     79 	return NULL;
     80 
     81 }
     82 
     83 /* Socket has already been alloced to connect it to kernel? */
     84 int genl_connect(struct nl_sock *sk)
     85 {
     86 	return nl_connect(sk, NETLINK_GENERIC);
     87 
     88 }
     89 
     90 int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
     91 {
     92 	int rc = -1;
     93 	int nl80211_genl_id = -1;
     94 	char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
     95 	struct nlmsghdr nlmhdr;
     96 	struct genlmsghdr gmhhdr;
     97 	struct iovec sendmsg_iov;
     98 	struct msghdr msg;
     99 	int num_char;
    100 	const int RECV_BUF_SIZE = getpagesize();
    101 	char *recvbuf;
    102 	struct iovec recvmsg_iov;
    103 	int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
    104 	struct nlmsghdr *nlh;
    105 
    106 	/* REQUEST GENERIC NETLINK FAMILY ID */
    107 	/* Message buffer */
    108 	nlmhdr.nlmsg_len = sizeof(sendbuf);
    109 	nlmhdr.nlmsg_type = NETLINK_GENERIC;
    110 	nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
    111 	nlmhdr.nlmsg_seq = sock->s_seq_next;
    112 	nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
    113 
    114 	/* Generic netlink header */
    115 	memset(&gmhhdr, 0, sizeof(gmhhdr));
    116 	gmhhdr.cmd = CTRL_CMD_GETFAMILY;
    117 	gmhhdr.version = CTRL_ATTR_FAMILY_ID;
    118 
    119 	/* Combine netlink and generic netlink headers */
    120 	memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
    121 	memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
    122 
    123 	/* Create IO vector with Netlink message */
    124 	sendmsg_iov.iov_base = &sendbuf;
    125 	sendmsg_iov.iov_len = sizeof(sendbuf);
    126 
    127 	/* Socket message */
    128 	msg.msg_name = (void *) &sock->s_peer;
    129 	msg.msg_namelen = sizeof(sock->s_peer);
    130 	msg.msg_iov = &sendmsg_iov;
    131 	msg.msg_iovlen = 1; /* Only sending one iov */
    132 	msg.msg_control = NULL;
    133 	msg.msg_controllen = 0;
    134 	msg.msg_flags = 0;
    135 
    136 	/* Send message and verify sent */
    137 	num_char = sendmsg(sock->s_fd, &msg, 0);
    138 	if (num_char == -1)
    139 		return -errno;
    140 
    141 	/* RECEIVE GENL CMD RESPONSE */
    142 
    143 	/* Create receive iov buffer */
    144 	recvbuf = (char *) malloc(RECV_BUF_SIZE);
    145 
    146 	/* Attach to iov */
    147 	recvmsg_iov.iov_base = recvbuf;
    148 	recvmsg_iov.iov_len = RECV_BUF_SIZE;
    149 
    150 	msg.msg_iov = &recvmsg_iov;
    151 	msg.msg_iovlen = 1;
    152 
    153 	/***************************************************************/
    154 	/* Receive message. If multipart message, keep receiving until */
    155 	/* message type is NLMSG_DONE				       */
    156 	/***************************************************************/
    157 
    158 	do {
    159 
    160 		int recvmsg_len, nlmsg_rem;
    161 
    162 		/* Receive message */
    163 		memset(recvbuf, 0, RECV_BUF_SIZE);
    164 		recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
    165 
    166 		/* Make sure receive successful */
    167 		if (recvmsg_len < 0) {
    168 			rc = -errno;
    169 			goto error_recvbuf;
    170 		}
    171 
    172 		/* Parse nlmsghdr */
    173 		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
    174 				recvmsg_len, nlmsg_rem) {
    175 			struct nlattr *nla;
    176 			int nla_rem;
    177 
    178 			/* Check type */
    179 			switch (nlh->nlmsg_type) {
    180 			case NLMSG_DONE:
    181 				goto return_genl_id;
    182 				break;
    183 			case NLMSG_ERROR:
    184 
    185 				/* Should check nlmsgerr struct received */
    186 				fprintf(stderr, "Receive message error\n");
    187 				goto error_recvbuf;
    188 			case NLMSG_OVERRUN:
    189 				fprintf(stderr, "Receive data partly lost\n");
    190 				goto error_recvbuf;
    191 			case NLMSG_MIN_TYPE:
    192 			case NLMSG_NOOP:
    193 				break;
    194 			default:
    195 				break;
    196 			}
    197 
    198 
    199 
    200 			/* Check flags */
    201 			if (nlh->nlmsg_flags & NLM_F_MULTI)
    202 				nlm_f_multi = 1;
    203 			else
    204 				nlm_f_multi = 0;
    205 
    206 			if (nlh->nlmsg_type & NLMSG_DONE)
    207 				nlmsg_done = 1;
    208 			else
    209 				nlmsg_done = 0;
    210 
    211 			/* Iteratve over attributes */
    212 			nla_for_each_attr(nla,
    213 					nlmsg_attrdata(nlh, GENL_HDRLEN),
    214 					nlmsg_attrlen(nlh, GENL_HDRLEN),
    215 					nla_rem){
    216 
    217 				/* If this family is nl80211 */
    218 				if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
    219 					!strcmp((char *)nla_data(nla),
    220 						"nl80211"))
    221 					nl80211_flag = 1;
    222 
    223 				/* Save the family id */
    224 				else if (nl80211_flag &&
    225 					nla->nla_type == CTRL_ATTR_FAMILY_ID) {
    226 					nl80211_genl_id =
    227 						*((int *)nla_data(nla));
    228 					nl80211_flag = 0;
    229 				}
    230 
    231 			}
    232 
    233 		}
    234 
    235 	} while (nlm_f_multi && !nlmsg_done);
    236 
    237 return_genl_id:
    238 	/* Return family id as cache pointer */
    239 	*result = (struct nl_cache *) nl80211_genl_id;
    240 	rc = 0;
    241 error_recvbuf:
    242 	free(recvbuf);
    243 error:
    244 	return rc;
    245 }
    246 
    247 /* Checks the netlink cache to find family reference by name string */
    248 /* NOTE: Caller needs to call genl_family_put() when done with *
    249  * returned object */
    250 struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
    251 					const char *name)
    252 {
    253 	/* TODO: When will we release this memory ? */
    254 	struct genl_family *gf = (struct genl_family *) \
    255 		malloc(sizeof(struct genl_family));
    256 	if (!gf)
    257 		goto fail;
    258 	memset(gf, 0, sizeof(*gf));
    259 
    260 	/* Add ref */
    261 	gf->ce_refcnt++;
    262 
    263 	/* Overriding cache pointer as family id for now */
    264 	gf->gf_id = (uint16_t) ((uint32_t) cache);
    265 	strcpy(gf->gf_name, "nl80211");
    266 
    267 	return gf;
    268 fail:
    269 	return NULL;
    270 
    271 }
    272 
    273 int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
    274 {
    275 	/* Hack to support wpa_supplicant */
    276 	if (strcmp(name, "nlctrl") == 0)
    277 		return NETLINK_GENERIC;
    278 	else {
    279 		int errsv = errno;
    280 		fprintf(stderr, \
    281 			"Only nlctrl supported by genl_ctrl_resolve!\n");
    282 		return -errsv;
    283 	}
    284 
    285 }
    286 
    287