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