12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
- */
- #define _GNU_SOURCE
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netlink/msg.h>
- #include <netlink/attr.h>
- #include <netlink/socket.h>
- #include <linux/rtnetlink.h>
- #include "unetd.h"
- static struct nl_sock *rtnl;
- bool rtnl_ignore_errors;
- static int
- unetd_nl_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err,
- void *arg)
- {
- struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1;
- struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
- struct nlattr *attrs;
- int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
- int len = nlh->nlmsg_len;
- const char *errstr = "(unknown)";
- if (rtnl_ignore_errors)
- return NL_STOP;
- if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
- return NL_STOP;
- if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
- ack_len += err->msg.nlmsg_len - sizeof(*nlh);
- attrs = (void *) ((unsigned char *) nlh + ack_len);
- len -= ack_len;
- nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
- if (tb[NLMSGERR_ATTR_MSG])
- errstr = nla_data(tb[NLMSGERR_ATTR_MSG]);
- D("Netlink error(%d): %s\n", err->error, errstr);
- return NL_STOP;
- }
- int rtnl_call(struct nl_msg *msg)
- {
- int ret;
- ret = nl_send_auto_complete(rtnl, msg);
- nlmsg_free(msg);
- if (ret < 0)
- return ret;
- return nl_wait_for_ack(rtnl);
- }
- int rtnl_init(void)
- {
- int fd, opt;
- if (rtnl)
- return 0;
- rtnl = nl_socket_alloc();
- if (!rtnl)
- return -1;
- if (nl_connect(rtnl, NETLINK_ROUTE))
- goto free;
- nl_socket_disable_seq_check(rtnl);
- nl_socket_set_buffer_size(rtnl, 65536, 0);
- nl_cb_err(nl_socket_get_cb(rtnl), NL_CB_CUSTOM, unetd_nl_error_cb, NULL);
- fd = nl_socket_get_fd(rtnl);
- opt = 1;
- setsockopt(fd, SOL_NETLINK, NETLINK_EXT_ACK, &opt, sizeof(opt));
- opt = 1;
- setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &opt, sizeof(opt));
- return 0;
- free:
- nl_socket_free(rtnl);
- rtnl = NULL;
- return -1;
- }
|