1 /* 2 * Copyright 2012 Daniel Drown 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 * netlink_msg.c - send an ifaddrmsg/ifinfomsg/rtmsg via netlink 17 */ 18 19 #include <netinet/in.h> 20 #include <linux/netlink.h> 21 #include <linux/rtnetlink.h> 22 #include <string.h> 23 #include <errno.h> 24 25 #include <netlink-local.h> 26 #include <netlink-types.h> 27 #include <netlink/socket.h> 28 #include <netlink/netlink.h> 29 #include <netlink/msg.h> 30 31 #include "netlink_msg.h" 32 #include "netlink_callbacks.h" 33 34 /* function: family_size 35 * returns the size of the address structure for the given family, or 0 on error 36 * family - AF_INET or AF_INET6 37 */ 38 size_t inet_family_size(int family) { 39 if(family == AF_INET) { 40 return sizeof(struct in_addr); 41 } else if(family == AF_INET6) { 42 return sizeof(struct in6_addr); 43 } else { 44 return 0; 45 } 46 } 47 48 /* function: nlmsg_alloc_generic 49 * allocates a netlink message with the given struct inside of it. returns NULL on failure 50 * type - netlink message type 51 * flags - netlink message flags 52 * payload_struct - pointer to a struct to add to netlink message 53 * payload_len - bytelength of structure 54 */ 55 struct nl_msg *nlmsg_alloc_generic(uint16_t type, uint16_t flags, void *payload_struct, size_t payload_len) { 56 struct nl_msg *msg; 57 58 msg = nlmsg_alloc(); 59 if(!msg) { 60 return NULL; 61 } 62 63 if ((sizeof(struct nl_msg) + payload_len) > msg->nm_size) { 64 nlmsg_free(msg); 65 return NULL; 66 } 67 68 msg->nm_nlh->nlmsg_len = NLMSG_LENGTH(payload_len); 69 msg->nm_nlh->nlmsg_flags = flags; 70 msg->nm_nlh->nlmsg_type = type; 71 72 memcpy(nlmsg_data(msg->nm_nlh), payload_struct, payload_len); 73 74 return msg; 75 } 76 77 /* function: nlmsg_alloc_ifaddr 78 * allocates a netlink message with a struct ifaddrmsg inside of it. returns NULL on failure 79 * type - netlink message type 80 * flags - netlink message flags 81 * ifa - ifaddrmsg to copy into the new netlink message 82 */ 83 struct nl_msg *nlmsg_alloc_ifaddr(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa) { 84 return nlmsg_alloc_generic(type, flags, ifa, sizeof(*ifa)); 85 } 86 87 /* function: nlmsg_alloc_ifinfo 88 * allocates a netlink message with a struct ifinfomsg inside of it. returns NULL on failure 89 * type - netlink message type 90 * flags - netlink message flags 91 * ifi - ifinfomsg to copy into the new netlink message 92 */ 93 struct nl_msg *nlmsg_alloc_ifinfo(uint16_t type, uint16_t flags, struct ifinfomsg *ifi) { 94 return nlmsg_alloc_generic(type, flags, ifi, sizeof(*ifi)); 95 } 96 97 /* function: nlmsg_alloc_rtmsg 98 * allocates a netlink message with a struct rtmsg inside of it. returns NULL on failure 99 * type - netlink message type 100 * flags - netlink message flags 101 * rt - rtmsg to copy into the new netlink message 102 */ 103 struct nl_msg *nlmsg_alloc_rtmsg(uint16_t type, uint16_t flags, struct rtmsg *rt) { 104 return nlmsg_alloc_generic(type, flags, rt, sizeof(*rt)); 105 } 106 107 /* function: netlink_set_kernel_only 108 * sets a socket to receive messages only from the kernel 109 * sock - socket to connect 110 */ 111 int netlink_set_kernel_only(struct nl_sock *nl_sk) { 112 struct sockaddr_nl addr = { AF_NETLINK, 0, 0, 0 }; 113 114 if (!nl_sk) { 115 return -EFAULT; 116 } 117 118 int sockfd = nl_socket_get_fd(nl_sk); 119 return connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)); 120 } 121 122 /* function: send_netlink_msg 123 * sends a netlink message, reads a response, and hands the response(s) to the callbacks 124 * msg - netlink message to send 125 * callbacks - callbacks to use on responses 126 */ 127 void send_netlink_msg(struct nl_msg *msg, struct nl_cb *callbacks) { 128 struct nl_sock *nl_sk; 129 130 nl_sk = nl_socket_alloc(); 131 if(!nl_sk) 132 goto cleanup; 133 134 if(nl_connect(nl_sk, NETLINK_ROUTE) != 0) 135 goto cleanup; 136 137 if(nl_send_auto_complete(nl_sk, msg) < 0) 138 goto cleanup; 139 140 if(netlink_set_kernel_only(nl_sk) < 0) 141 goto cleanup; 142 143 nl_recvmsgs(nl_sk, callbacks); 144 145 cleanup: 146 if(nl_sk) 147 nl_socket_free(nl_sk); 148 } 149 150 /* function: send_ifaddrmsg 151 * sends a netlink/ifaddrmsg message and hands the responses to the callbacks 152 * type - netlink message type 153 * flags - netlink message flags 154 * ifa - ifaddrmsg to send 155 * callbacks - callbacks to use with the responses 156 */ 157 void send_ifaddrmsg(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa, struct nl_cb *callbacks) { 158 struct nl_msg *msg = NULL; 159 160 msg = nlmsg_alloc_ifaddr(type, flags, ifa); 161 if(!msg) 162 return; 163 164 send_netlink_msg(msg, callbacks); 165 166 nlmsg_free(msg); 167 } 168 169 /* function: netlink_sendrecv 170 * send a nl_msg and return an int status - only supports OK/ERROR responses 171 * msg - msg to send 172 */ 173 int netlink_sendrecv(struct nl_msg *msg) { 174 struct nl_cb *callbacks = NULL; 175 int retval = -EIO; 176 177 callbacks = alloc_ack_callbacks(&retval); 178 if(!callbacks) { 179 return -ENOMEM; 180 } 181 182 send_netlink_msg(msg, callbacks); 183 184 nl_cb_put(callbacks); 185 186 return retval; 187 } 188