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