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