21 #ifndef LELY_IO2_INTERN_LINUX_RTNL_H_ 22 #define LELY_IO2_INTERN_LINUX_RTNL_H_ 34 #include <sys/socket.h> 37 #include <linux/rtnetlink.h> 44 #define RTA_TAIL(rta) \ 45 (struct rtattr *)((char *)(rta) + RTA_ALIGN((rta)->rta_len)) 57 typedef int rtnl_recv_func_t(
struct nlmsghdr *nlh,
size_t len,
void *arg);
62 static ssize_t rtnl_send(
const struct rtnl_handle *rth,
struct nlmsghdr *nlh,
63 void *data, __u32 len);
64 static ssize_t rtnl_recv(
const struct rtnl_handle *rth,
void **pbuf);
66 static int rtnl_recv_ack(
const struct rtnl_handle *rth);
68 static int rtnl_recv_type(
const struct rtnl_handle *rth, __u16 type,
69 rtnl_recv_func_t *func,
void *arg);
71 static int rtnl_send_newlink_request(
struct rtnl_handle *rth,
72 unsigned char ifi_family,
unsigned short ifi_type,
73 int ifi_index,
unsigned int ifi_flags,
void *data, __u32 len);
75 static int rtnl_send_getlink_request(
struct rtnl_handle *rth,
76 unsigned char ifi_family,
unsigned short ifi_type,
79 static struct rtattr *rta_find(
80 struct rtattr *rta,
unsigned int len,
unsigned short type);
89 rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
95 struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
96 socklen_t addrlen =
sizeof(addr);
97 if (bind(rth->fd, (
struct sockaddr *)&addr, addrlen) == -1) {
101 if (getsockname(rth->fd, (
struct sockaddr *)&addr, &addrlen) == -1) {
103 goto error_getsockname;
105 assert(addrlen ==
sizeof(addr));
106 assert(addr.nl_family == AF_NETLINK);
107 rth->pid = addr.nl_pid;
109 rth->seq = time(NULL);
132 static inline ssize_t
133 rtnl_send(
const struct rtnl_handle *rth,
struct nlmsghdr *nlh,
void *data,
139 nlh->nlmsg_pid = rth->pid;
141 struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
142 struct iovec iov[2] = {
143 { .iov_base = nlh, .iov_len = nlh->nlmsg_len - len },
144 { .iov_base = data, .iov_len = len }
146 struct msghdr msg = { .msg_name = &addr,
147 .msg_namelen =
sizeof(addr),
149 .msg_iovlen = data ? 2 : 1 };
155 result = sendmsg(rth->fd, &msg, 0);
156 }
while (result == -1 && errno == EINTR);
160 static inline ssize_t
161 rtnl_recv(
const struct rtnl_handle *rth,
void **pbuf)
166 for (;; free(buf), buf = NULL) {
172 result = recv(rth->fd, NULL, 0, MSG_PEEK | MSG_TRUNC);
173 }
while (result == -1 && errno == EINTR);
182 struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
183 socklen_t addrlen =
sizeof(addr);
186 result = recvfrom(rth->fd, buf, len, 0,
187 (
struct sockaddr *)&addr, &addrlen);
188 }
while (result == -1 && errno == EINTR);
191 assert(addrlen ==
sizeof(addr));
192 assert(addr.nl_family == AF_NETLINK);
194 struct nlmsghdr *nlh = buf;
195 if (result != (ssize_t)len || !NLMSG_OK(nlh, len)) {
200 if (addr.nl_pid || nlh->nlmsg_pid != rth->pid)
218 for (;; free(buf), buf = NULL) {
219 ssize_t len = rtnl_recv(rth, &buf);
223 for (
struct nlmsghdr *nlh = buf; NLMSG_OK(nlh, len);
224 NLMSG_NEXT(nlh, len)) {
225 if (nlh->nlmsg_seq != rth->seq)
229 if (nlh->nlmsg_type == NLMSG_ERROR) {
230 struct nlmsgerr *err = NLMSG_DATA(nlh);
231 if ((error = -err->error))
234 errno = error = EPROTO;
238 return error ? -1 : 0;
247 rtnl_recv_type(
const struct rtnl_handle *rth, __u16 type,
248 rtnl_recv_func_t *func,
void *arg)
251 for (;; free(buf), buf = NULL) {
252 ssize_t len = rtnl_recv(rth, &buf);
256 for (
struct nlmsghdr *nlh = buf; NLMSG_OK(nlh, len);
257 NLMSG_NEXT(nlh, len)) {
258 if (nlh->nlmsg_seq != rth->seq)
262 if (nlh->nlmsg_type == type) {
264 error = func(nlh, len, arg);
265 }
else if (nlh->nlmsg_type == NLMSG_ERROR) {
266 struct nlmsgerr *err = NLMSG_DATA(nlh);
267 if ((error = -err->error))
270 errno = error = EPROTO;
272 errno = error = EPROTO;
276 return error ? -1 : 0;
285 rtnl_send_newlink_request(
struct rtnl_handle *rth,
unsigned char ifi_family,
286 unsigned short ifi_type,
int ifi_index,
unsigned int ifi_flags,
287 void *data, __u32 len)
291 char buf[NLMSG_SPACE(
sizeof(
struct ifinfomsg))] = { 0 };
293 struct nlmsghdr *nlh = (
struct nlmsghdr *)buf;
294 *nlh = (
struct nlmsghdr){ .nlmsg_len =
sizeof(buf) + len,
295 .nlmsg_type = RTM_NEWLINK,
296 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
297 .nlmsg_seq = ++rth->seq };
299 struct ifinfomsg *ifi = NLMSG_DATA(nlh);
300 *ifi = (
struct ifinfomsg){ .ifi_family = ifi_family,
301 .ifi_type = ifi_type,
302 .ifi_index = ifi_index,
303 .ifi_flags = ifi_flags,
304 .ifi_change = 0xffffffffu };
306 return rtnl_send(rth, nlh, data, len) == -1 ? -1 : 0;
310 rtnl_send_getlink_request(
struct rtnl_handle *rth,
unsigned char ifi_family,
311 unsigned short ifi_type,
int ifi_index)
315 char buf[NLMSG_SPACE(
sizeof(
struct ifinfomsg))] = { 0 };
317 struct nlmsghdr *nlh = (
struct nlmsghdr *)buf;
318 *nlh = (
struct nlmsghdr){ .nlmsg_len =
sizeof(buf),
319 .nlmsg_type = RTM_GETLINK,
320 .nlmsg_flags = NLM_F_REQUEST,
321 .nlmsg_seq = ++rth->seq };
323 struct ifinfomsg *ifi = NLMSG_DATA(nlh);
324 *ifi = (
struct ifinfomsg){ .ifi_family = ifi_family,
325 .ifi_type = ifi_type,
326 .ifi_index = ifi_index,
327 .ifi_change = 0xffffffffu };
329 return rtnl_send(rth, nlh, NULL, 0) == -1 ? -1 : 0;
332 static inline struct rtattr *
333 rta_find(
struct rtattr *rta,
unsigned int len,
unsigned short type)
337 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
338 if (rta->rta_type == type)
350 #endif // !LELY_IO2_INTERN_LINUX_RTNL_H_ This header file is part of the C11 and POSIX compatibility library; it includes <string.h> and defines any missing functionality.
This is the internal header file of the Linux-specific I/O declarations.
This header file is part of the C11 and POSIX compatibility library; it includes <unistd.h>, if it exists, and defines any missing functionality.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.