1a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* 2a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Copyright 2012 Daniel Drown 3a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 4a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Licensed under the Apache License, Version 2.0 (the "License"); 5a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * you may not use this file except in compliance with the License. 6a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * You may obtain a copy of the License at 7a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 8a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * http://www.apache.org/licenses/LICENSE-2.0 9a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 10a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * Unless required by applicable law or agreed to in writing, software 11a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * distributed under the License is distributed on an "AS IS" BASIS, 12a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * See the License for the specific language governing permissions and 14a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * limitations under the License. 15a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * 16a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * netlink_msg.c - send an ifaddrmsg/ifinfomsg/rtmsg via netlink 17a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 18a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 19a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netinet/in.h> 20a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <linux/netlink.h> 21a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <linux/rtnetlink.h> 22a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <string.h> 23a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <errno.h> 24a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 25fbef82d10366495bbd0dbb30cea015cb67c8105aColin Cross#include <netlink-local.h> 26a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink-types.h> 27a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/socket.h> 28a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/netlink.h> 29a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include <netlink/msg.h> 30a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 31a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "netlink_msg.h" 32a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown#include "netlink_callbacks.h" 33a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 34a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: family_size 35a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * returns the size of the address structure for the given family, or 0 on error 36a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * family - AF_INET or AF_INET6 37a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 38a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownsize_t inet_family_size(int family) { 39a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(family == AF_INET) { 40a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return sizeof(struct in_addr); 41a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } else if(family == AF_INET6) { 42a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return sizeof(struct in6_addr); 43a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } else { 44a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return 0; 45a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 46a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 47a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 48a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: nlmsg_alloc_generic 49a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * allocates a netlink message with the given struct inside of it. returns NULL on failure 50a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * type - netlink message type 51a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * flags - netlink message flags 52a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * payload_struct - pointer to a struct to add to netlink message 53a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * payload_len - bytelength of structure 54a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 55a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstruct nl_msg *nlmsg_alloc_generic(uint16_t type, uint16_t flags, void *payload_struct, size_t payload_len) { 56a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct nl_msg *msg; 57a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 58a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown msg = nlmsg_alloc(); 59a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!msg) { 60a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NULL; 61a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 62a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 63a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if ((sizeof(struct nl_msg) + payload_len) > msg->nm_size) { 64a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nlmsg_free(msg); 65a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return NULL; 66a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 67a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 68a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown msg->nm_nlh->nlmsg_len = NLMSG_LENGTH(payload_len); 69a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown msg->nm_nlh->nlmsg_flags = flags; 70a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown msg->nm_nlh->nlmsg_type = type; 71a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 72a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown memcpy(nlmsg_data(msg->nm_nlh), payload_struct, payload_len); 73a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 74a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return msg; 75a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 76a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 77a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: nlmsg_alloc_ifaddr 78a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * allocates a netlink message with a struct ifaddrmsg inside of it. returns NULL on failure 79a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * type - netlink message type 80a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * flags - netlink message flags 81a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ifa - ifaddrmsg to copy into the new netlink message 82a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 83a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstruct nl_msg *nlmsg_alloc_ifaddr(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa) { 84a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return nlmsg_alloc_generic(type, flags, ifa, sizeof(*ifa)); 85a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 86a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 87a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: nlmsg_alloc_ifinfo 88a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * allocates a netlink message with a struct ifinfomsg inside of it. returns NULL on failure 89a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * type - netlink message type 90a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * flags - netlink message flags 91a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ifi - ifinfomsg to copy into the new netlink message 92a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 93a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstruct nl_msg *nlmsg_alloc_ifinfo(uint16_t type, uint16_t flags, struct ifinfomsg *ifi) { 94a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return nlmsg_alloc_generic(type, flags, ifi, sizeof(*ifi)); 95a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 96a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 97a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: nlmsg_alloc_rtmsg 98a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * allocates a netlink message with a struct rtmsg inside of it. returns NULL on failure 99a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * type - netlink message type 100a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * flags - netlink message flags 101a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * rt - rtmsg to copy into the new netlink message 102a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 103a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownstruct nl_msg *nlmsg_alloc_rtmsg(uint16_t type, uint16_t flags, struct rtmsg *rt) { 104a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return nlmsg_alloc_generic(type, flags, rt, sizeof(*rt)); 105a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 106a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 1074f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti/* function: netlink_set_kernel_only 1084f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti * sets a socket to receive messages only from the kernel 1094f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti * sock - socket to connect 1104f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti */ 1114f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colittiint netlink_set_kernel_only(struct nl_sock *nl_sk) { 1124f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti struct sockaddr_nl addr = { AF_NETLINK, 0, 0, 0 }; 1134f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti 1144f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti if (!nl_sk) { 1154f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti return -EFAULT; 1164f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti } 1174f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti 1184f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti int sockfd = nl_socket_get_fd(nl_sk); 1194f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti return connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)); 1204f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti} 1214f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti 122a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: send_netlink_msg 123a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * sends a netlink message, reads a response, and hands the response(s) to the callbacks 124a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * msg - netlink message to send 125a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * callbacks - callbacks to use on responses 126a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 127a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownvoid send_netlink_msg(struct nl_msg *msg, struct nl_cb *callbacks) { 128a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct nl_sock *nl_sk; 129a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 130a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_sk = nl_socket_alloc(); 131a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!nl_sk) 132a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 133a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 134a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(nl_connect(nl_sk, NETLINK_ROUTE) != 0) 135a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 136a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 137a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(nl_send_auto_complete(nl_sk, msg) < 0) 138a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown goto cleanup; 1394f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti 1404f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti if(netlink_set_kernel_only(nl_sk) < 0) 1414f3d78640de4573ced186edd3a09b1247d981edfLorenzo Colitti goto cleanup; 142a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 143a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_recvmsgs(nl_sk, callbacks); 144a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 145a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drowncleanup: 146a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(nl_sk) 147a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_socket_free(nl_sk); 148a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 149a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 150a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: send_ifaddrmsg 151a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * sends a netlink/ifaddrmsg message and hands the responses to the callbacks 152a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * type - netlink message type 153a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * flags - netlink message flags 154a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * ifa - ifaddrmsg to send 155a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * callbacks - callbacks to use with the responses 156a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 157a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownvoid send_ifaddrmsg(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa, struct nl_cb *callbacks) { 158a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct nl_msg *msg = NULL; 159a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 160a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown msg = nlmsg_alloc_ifaddr(type, flags, ifa); 161a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!msg) 162a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return; 163a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 164a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown send_netlink_msg(msg, callbacks); 165a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 166a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nlmsg_free(msg); 167a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 168a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 169a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown/* function: netlink_sendrecv 170a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * send a nl_msg and return an int status - only supports OK/ERROR responses 171a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown * msg - msg to send 172a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown */ 173a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drownint netlink_sendrecv(struct nl_msg *msg) { 174a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown struct nl_cb *callbacks = NULL; 175a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown int retval = -EIO; 176a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 177a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown callbacks = alloc_ack_callbacks(&retval); 178a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown if(!callbacks) { 179a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return -ENOMEM; 180a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown } 181a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 182a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown send_netlink_msg(msg, callbacks); 183a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 184a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown nl_cb_put(callbacks); 185a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown 186a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown return retval; 187a45056e35c1af2a0f0a6eed258fd5fdf4846a79fDaniel Drown} 188