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;
     63 	int errsv;
     64 	struct iovec recvmsg_iov;
     65 	struct msghdr msg;
     66 
     67 	/* Allocate buffer */
     68 	RECV_BUF_SIZE = getpagesize();
     69 	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
     70 	if (!buf) {
     71 		rc = -ENOMEM;
     72 		goto fail;
     73 	}
     74 
     75 	/* Prepare to receive message */
     76 	recvmsg_iov.iov_base = *buf;
     77 	recvmsg_iov.iov_len = RECV_BUF_SIZE;
     78 
     79 	msg.msg_name = (void *) &sk->s_peer;
     80 	msg.msg_namelen = sizeof(sk->s_peer);
     81 	msg.msg_iov = &recvmsg_iov;
     82 	msg.msg_iovlen = 1;
     83 	msg.msg_control = NULL;
     84 	msg.msg_controllen = 0;
     85 	msg.msg_flags = 0;
     86 
     87 	/* Make non blocking and then restore previous setting */
     88 	sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
     89 	fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
     90 	rc = recvmsg(sk->s_fd, &msg, 0);
     91 	errsv = errno;
     92 	fcntl(sk->s_fd, F_SETFL, sk_flags);
     93 
     94 	if (rc < 0)
     95 		rc = -errsv;
     96 
     97 fail:
     98 	return rc;
     99 }
    100 
    101 /* Receive a set of messages from a netlink socket */
    102 /* NOTE: Does not currently support callback replacements!!! */
    103 int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
    104 {
    105 	struct sockaddr_nl nla;
    106 	struct ucred *creds;
    107 
    108 	int rc, cb_rc = NL_OK, done = 0;
    109 
    110 	do {
    111 
    112 		unsigned char *buf;
    113 		int i, rem, flags;
    114 		struct nlmsghdr *nlh;
    115 		struct nlmsgerr *nlme;
    116 		struct nl_msg *msg;
    117 
    118 		done = 0;
    119 		rc = nl_recv(sk, &nla, &buf, &creds);
    120 		if (rc < 0)
    121 			break;
    122 
    123 		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
    124 
    125 			if (rc <= 0 || cb_rc == NL_STOP)
    126 				break;
    127 
    128 			/* Check for callbacks */
    129 
    130 			msg = (struct nl_msg *)malloc(sizeof(struct nl_msg));
    131 			memset(msg, 0, sizeof(*msg));
    132 			msg->nm_nlh = nlh;
    133 
    134 			/* Check netlink message type */
    135 
    136 			switch (msg->nm_nlh->nlmsg_type) {
    137 			case NLMSG_ERROR:	  /* Used for ACK too */
    138 				/* Certainly we should be doing some
    139 				 * checking here to make sure this
    140 				 * message is intended for us */
    141 				nlme = nlmsg_data(msg->nm_nlh);
    142 				if (nlme->error == 0)
    143 					msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
    144 
    145 				rc = nlme->error;
    146 				cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
    147 				nlme = NULL;
    148 				break;
    149 
    150 			case NLMSG_DONE:
    151 				done = 1;
    152 
    153 			case NLMSG_OVERRUN:
    154 			case NLMSG_NOOP:
    155 			default:
    156 				break;
    157 			};
    158 
    159 			for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
    160 
    161 				if (cb->cb_set[i]) {
    162 					switch (i) {
    163 					case NL_CB_VALID:
    164 						if (rc > 0)
    165 							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
    166 						break;
    167 
    168 					case NL_CB_FINISH:
    169 						if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
    170 							(msg->nm_nlh->nlmsg_type & NLMSG_DONE))
    171 							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
    172 
    173 						break;
    174 
    175 					case NL_CB_ACK:
    176 						if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
    177 							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
    178 
    179 						break;
    180 					default:
    181 						break;
    182 					}
    183 				}
    184 			}
    185 
    186 			free(msg);
    187 			if (done)
    188 				break;
    189 		}
    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