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