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