Home | History | Annotate | Download | only in libnl_2
      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 <string.h>
     21 #include <unistd.h>
     22 #include <fcntl.h>
     23 #include <sys/socket.h>
     24 #include "netlink-types.h"
     25 
     26 #define NL_BUFFER_SZ (32768U)
     27 
     28 /* Checks message for completeness and sends it out */
     29 int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
     30 {
     31 	struct nlmsghdr *nlh = msg->nm_nlh;
     32 	struct timeval tv;
     33 
     34 	if (!nlh) {
     35 		int errsv = errno;
     36 		fprintf(stderr, "Netlink message header is NULL!\n");
     37 		return -errsv;
     38 	}
     39 
     40 	/* Complete the nl_msg header */
     41 	if (gettimeofday(&tv, NULL))
     42 		nlh->nlmsg_seq = 1;
     43 	else
     44 		nlh->nlmsg_seq = (int) tv.tv_sec;
     45 	nlh->nlmsg_pid = sk->s_local.nl_pid;
     46 	nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
     47 
     48 	return nl_send(sk, msg);
     49 }
     50 
     51 /* Receives a netlink message, allocates a buffer in *buf and stores
     52  * the message content. The peer's netlink address is stored in
     53  * *nla. The caller is responsible for freeing the buffer allocated in
     54  * *buf if a positive value is returned. Interrupted system calls are
     55  * handled by repeating the read. The input buffer size is determined
     56  * by peeking before the actual read is done */
     57 int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
     58 	unsigned char **buf, struct ucred **creds)
     59 {
     60 	int rc = -1;
     61 	int sk_flags;
     62 	int RECV_BUF_SIZE = getpagesize();
     63 	int errsv;
     64 	struct iovec recvmsg_iov;
     65 	struct msghdr msg;
     66 
     67 	/* Allocate buffer */
     68 	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
     69 	if (!(*buf)) {
     70 		rc = -ENOMEM;
     71 		goto fail;
     72 	}
     73 
     74 	/* Prepare to receive message */
     75 	recvmsg_iov.iov_base = *buf;
     76 	recvmsg_iov.iov_len = RECV_BUF_SIZE;
     77 
     78 	msg.msg_name = (void *) &sk->s_peer;
     79 	msg.msg_namelen = sizeof(sk->s_peer);
     80 	msg.msg_iov = &recvmsg_iov;
     81 	msg.msg_iovlen = 1;
     82 	msg.msg_control = NULL;
     83 	msg.msg_controllen = 0;
     84 	msg.msg_flags = 0;
     85 
     86 	/* Make non blocking and then restore previous setting */
     87 	sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
     88 	fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
     89 	rc = recvmsg(sk->s_fd, &msg, 0);
     90 	errsv = errno;
     91 	fcntl(sk->s_fd, F_SETFL, sk_flags);
     92 
     93 	if (rc < 0) {
     94 		rc = -errsv;
     95 		free(*buf);
     96 		*buf = NULL;
     97 	}
     98 
     99 fail:
    100 	return rc;
    101 }
    102 
    103 /* Receive a set of messages from a netlink socket */
    104 /* NOTE: Does not currently support callback replacements!!! */
    105 int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
    106 {
    107 	struct sockaddr_nl nla;
    108 	struct ucred *creds;
    109 
    110 	int rc, cb_rc = NL_OK, done = 0;
    111 
    112 	do {
    113 		unsigned char *buf;
    114 		int i, rem, flags;
    115 		struct nlmsghdr *nlh;
    116 		struct nlmsgerr *nlme;
    117 		struct nl_msg *msg;
    118 
    119 		done = 0;
    120 		rc = nl_recv(sk, &nla, &buf, &creds);
    121 		if (rc < 0)
    122 			break;
    123 
    124 		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
    125 
    126 			if (rc <= 0 || cb_rc == NL_STOP)
    127 				break;
    128 
    129 			/* Check for callbacks */
    130 
    131 			msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
    132 			memset(msg, 0, sizeof(*msg));
    133 			msg->nm_nlh = nlh;
    134 
    135 			/* Check netlink message type */
    136 
    137 			switch (msg->nm_nlh->nlmsg_type) {
    138 			case NLMSG_ERROR:	  /* Used for ACK too */
    139 				/* Certainly we should be doing some
    140 				 * checking here to make sure this
    141 				 * message is intended for us */
    142 				nlme = nlmsg_data(msg->nm_nlh);
    143 				if (nlme->error == 0)
    144 					msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
    145 
    146 				rc = nlme->error;
    147 				cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
    148 				nlme = NULL;
    149 				break;
    150 
    151 			case NLMSG_DONE:
    152 				done = 1;
    153 
    154 			case NLMSG_OVERRUN:
    155 			case NLMSG_NOOP:
    156 			default:
    157 				break;
    158 			};
    159 
    160 			for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
    161 
    162 				if (cb->cb_set[i]) {
    163 					switch (i) {
    164 					case NL_CB_VALID:
    165 						if (rc > 0)
    166 							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
    167 						break;
    168 
    169 					case NL_CB_FINISH:
    170 						if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
    171 							(msg->nm_nlh->nlmsg_type & NLMSG_DONE))
    172 							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
    173 
    174 						break;
    175 
    176 					case NL_CB_ACK:
    177 						if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
    178 							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
    179 
    180 						break;
    181 					default:
    182 						break;
    183 					}
    184 				}
    185 			}
    186 
    187 			free(msg);
    188 			if (done)
    189 				break;
    190 		}
    191 		free(buf);
    192 		buf = NULL;
    193 
    194 		if (done)
    195 			break;
    196 	} while (rc > 0 && cb_rc != NL_STOP);
    197 
    198 success:
    199 fail:
    200 	return rc;
    201 }
    202 
    203 /* Send raw data over netlink socket */
    204 int nl_send(struct nl_sock *sk, struct nl_msg *msg)
    205 {
    206 	struct nlmsghdr *nlh = nlmsg_hdr(msg);
    207 	struct iovec msg_iov;
    208 
    209 	/* Create IO vector with Netlink message */
    210 	msg_iov.iov_base = nlh;
    211 	msg_iov.iov_len = nlh->nlmsg_len;
    212 
    213 	return nl_send_iovec(sk, msg, &msg_iov, 1);
    214 }
    215 
    216 /* Send netlink message */
    217 int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
    218 		   struct iovec *iov, unsigned iovlen)
    219 {
    220 	int rc;
    221 
    222 	/* Socket message */
    223 	struct msghdr mh = {
    224 		.msg_name = (void *) &sk->s_peer,
    225 		.msg_namelen = sizeof(sk->s_peer),
    226 		.msg_iov = iov,
    227 		.msg_iovlen = iovlen,
    228 		.msg_control = NULL,
    229 		.msg_controllen = 0,
    230 		.msg_flags = 0
    231 	};
    232 
    233 	/* Send message and verify sent */
    234 	rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
    235 	if (rc < 0)
    236 		fprintf(stderr, "Error sending netlink message: %d\n", errno);
    237 	return rc;
    238 
    239 }
    240 
    241 /* Send netlink message with control over sendmsg() message header */
    242 int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
    243 {
    244 	return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
    245 }
    246 
    247 /* Create and connect netlink socket */
    248 int nl_connect(struct nl_sock *sk, int protocol)
    249 {
    250 	struct sockaddr addr;
    251 	socklen_t addrlen;
    252 	int rc;
    253 
    254 	/* Create RX socket */
    255 	sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
    256 	if (sk->s_fd < 0)
    257 		return -errno;
    258 
    259 	/* Set size of RX and TX buffers */
    260 	if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
    261 		return -errno;
    262 
    263 	/* Bind RX socket */
    264 	rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
    265 		sizeof(sk->s_local));
    266 	if (rc < 0)
    267 		return -errno;
    268 	addrlen = sizeof(addr);
    269 	getsockname(sk->s_fd, &addr, &addrlen);
    270 
    271 	return 0;
    272 
    273 }
    274