Use netlink for setting link flags instead of ioctl.
This commit is contained in:
parent
cce93139d0
commit
50d6284fee
244
ndhc/ifset.c
244
ndhc/ifset.c
@ -57,40 +57,6 @@
|
||||
|
||||
static uint32_t ifset_nl_seq = 1;
|
||||
|
||||
static int set_if_flag(short flag)
|
||||
{
|
||||
int fd, ret = -1;
|
||||
struct ifreq ifrt;
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
log_line("%s: (set_if_flag) failed to open interface socket: %s",
|
||||
client_config.interface, strerror(errno));
|
||||
goto out0;
|
||||
}
|
||||
|
||||
strnkcpy(ifrt.ifr_name, client_config.interface, IFNAMSIZ);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) {
|
||||
log_line("%s: unknown interface: %s", client_config.interface, strerror(errno));
|
||||
goto out1;
|
||||
}
|
||||
if (((ifrt.ifr_flags & flag ) ^ flag) & flag) {
|
||||
strnkcpy(ifrt.ifr_name, client_config.interface, IFNAMSIZ);
|
||||
ifrt.ifr_flags |= flag;
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) {
|
||||
log_line("%s: failed to set interface flags: %s",
|
||||
client_config.interface, strerror(errno));
|
||||
goto out1;
|
||||
}
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
out1:
|
||||
close(fd);
|
||||
out0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 32-bit position values are relatively prime to 37, so the residue mod37
|
||||
// gives a unique mapping for each value. Gives correct result for v=0.
|
||||
static int trailz(uint32_t v)
|
||||
@ -125,18 +91,85 @@ static int rtattr_assign(struct rtattr *attr, int type, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rtnl_do_send(int fd, uint8_t *sbuf, size_t slen,
|
||||
const char *fnname)
|
||||
{
|
||||
uint8_t response[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 64];
|
||||
struct sockaddr_nl nl_addr;
|
||||
ssize_t r;
|
||||
|
||||
memset(&nl_addr, 0, sizeof nl_addr);
|
||||
nl_addr.nl_family = AF_NETLINK;
|
||||
|
||||
retry_sendto:
|
||||
r = sendto(fd, sbuf, slen, 0, (struct sockaddr *)&nl_addr,
|
||||
sizeof nl_addr);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
goto retry_sendto;
|
||||
else {
|
||||
log_line("%s: (%s) netlink sendto failed: %s",
|
||||
client_config.interface, fnname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
retry_recv:
|
||||
r = recv(fd, response, sizeof response, 0);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
goto retry_recv;
|
||||
else {
|
||||
log_line("%s: (%s) netlink recv failed: %s",
|
||||
client_config.interface, fnname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ((size_t)r < sizeof(struct nlmsghdr)) {
|
||||
log_line("%s: (%s) netlink recv returned a headerless response",
|
||||
client_config.interface, fnname);
|
||||
return -1;
|
||||
}
|
||||
uint32_t nr_type;
|
||||
memcpy(&nr_type, response + 4, 2);
|
||||
if (nr_type == NLMSG_ERROR) {
|
||||
log_line("%s: (%s) netlink sendto returned NLMSG_ERROR",
|
||||
client_config.interface, fnname);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t rtnl_if_flags_send(int fd, int type, int ifi_flags)
|
||||
{
|
||||
uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
|
||||
NLMSG_ALIGN(sizeof(struct ifinfomsg))];
|
||||
struct nlmsghdr *header;
|
||||
struct ifinfomsg *ifinfomsg;
|
||||
|
||||
memset(&request, 0, sizeof request);
|
||||
header = (struct nlmsghdr *)request;
|
||||
header->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
||||
header->nlmsg_type = type;
|
||||
header->nlmsg_flags = NLM_F_REPLACE | NLM_F_ACK | NLM_F_REQUEST;
|
||||
header->nlmsg_seq = ifset_nl_seq++;
|
||||
|
||||
ifinfomsg = NLMSG_DATA(header);
|
||||
ifinfomsg->ifi_flags = ifi_flags;
|
||||
ifinfomsg->ifi_index = client_config.ifindex;
|
||||
ifinfomsg->ifi_change = 0xffffffff;
|
||||
|
||||
return rtnl_do_send(fd, request, header->nlmsg_len, __func__);
|
||||
}
|
||||
|
||||
static ssize_t rtnl_addr_broadcast_send(int fd, int type, int ifa_flags,
|
||||
int ifa_scope, uint32_t *ipaddr,
|
||||
uint32_t *bcast, uint8_t prefixlen)
|
||||
{
|
||||
uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
|
||||
NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
|
||||
RTA_LENGTH(sizeof(struct in6_addr))];
|
||||
uint8_t response[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 64];
|
||||
2 * RTA_LENGTH(sizeof(struct in6_addr))];
|
||||
struct nlmsghdr *header;
|
||||
struct ifaddrmsg *ifaddrmsg;
|
||||
struct sockaddr_nl nl_addr;
|
||||
ssize_t r;
|
||||
|
||||
if (!ipaddr && !bcast) {
|
||||
log_warning("%s: (%s) no ipaddr or bcast!",
|
||||
@ -175,47 +208,88 @@ static ssize_t rtnl_addr_broadcast_send(int fd, int type, int ifa_flags,
|
||||
}
|
||||
}
|
||||
|
||||
memset(&nl_addr, 0, sizeof nl_addr);
|
||||
nl_addr.nl_family = AF_NETLINK;
|
||||
|
||||
retry_sendto:
|
||||
r = sendto(fd, request, header->nlmsg_len, 0,
|
||||
(struct sockaddr *)&nl_addr, sizeof nl_addr);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
goto retry_sendto;
|
||||
else {
|
||||
log_line("%s: (%s) netlink sendto failed: %s",
|
||||
client_config.interface, __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
retry_recv:
|
||||
r = recv(fd, response, sizeof response, 0);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
goto retry_recv;
|
||||
else {
|
||||
log_line("%s: (%s) netlink recv failed: %s",
|
||||
client_config.interface, __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ((size_t)r < sizeof(struct nlmsghdr)) {
|
||||
log_line("%s: (%s) netlink recv returned a headerless response",
|
||||
client_config.interface, __func__);
|
||||
return -1;
|
||||
}
|
||||
uint32_t nr_type;
|
||||
memcpy(&nr_type, response + 4, 2);
|
||||
if (nr_type == NLMSG_ERROR) {
|
||||
log_line("%s: (%s) netlink sendto returned NLMSG_ERROR",
|
||||
client_config.interface, __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return rtnl_do_send(fd, request, header->nlmsg_len, __func__);
|
||||
}
|
||||
|
||||
struct link_flag_data {
|
||||
int fd;
|
||||
uint32_t flags;
|
||||
bool got_flags;
|
||||
};
|
||||
|
||||
static void link_flags_get_do(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct ifinfomsg *ifm = nlmsg_get_data(nlh);
|
||||
struct link_flag_data *ifd = data;
|
||||
|
||||
switch(nlh->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
if (ifm->ifi_index != client_config.ifindex)
|
||||
break;
|
||||
ifd->flags = ifm->ifi_flags;
|
||||
ifd->got_flags = true;
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
log_line("%s: got RTM_DELLINK", __func__);
|
||||
break;
|
||||
default:
|
||||
log_line("%s: got %u", __func__, nlh->nlmsg_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int link_flags_get(int fd, uint32_t *flags)
|
||||
{
|
||||
char nlbuf[8192];
|
||||
struct link_flag_data ipx = { .fd = fd, .flags = 0, .got_flags = false };
|
||||
ssize_t ret;
|
||||
uint32_t seq = ifset_nl_seq++;
|
||||
if (nl_sendgetlink(fd, seq, client_config.ifindex) < 0)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
ret = nl_recv_buf(fd, nlbuf, sizeof nlbuf);
|
||||
if (ret == -1)
|
||||
return -2;
|
||||
if (nl_foreach_nlmsg(nlbuf, ret, seq, 0, link_flags_get_do,
|
||||
&ipx) == -1)
|
||||
return -3;
|
||||
} while (ret > 0);
|
||||
if (ipx.got_flags) {
|
||||
*flags = ipx.flags;
|
||||
return 0;
|
||||
}
|
||||
return -4;
|
||||
}
|
||||
|
||||
static int link_set_flags(int fd, uint32_t flags)
|
||||
{
|
||||
uint32_t oldflags;
|
||||
|
||||
int r = link_flags_get(fd, &oldflags);
|
||||
if (r < 0) {
|
||||
log_line("%s: (%s) failed to get old link flags: %u",
|
||||
client_config.interface, __func__, r);
|
||||
return -1;
|
||||
}
|
||||
return (int)rtnl_if_flags_send(fd, RTM_SETLINK, flags | oldflags);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int link_unset_flags(int fd, uint32_t flags)
|
||||
{
|
||||
uint32_t oldflags;
|
||||
|
||||
int r = link_flags_get(fd, &oldflags);
|
||||
if (r < 0) {
|
||||
log_line("%s: (%s) failed to get old link flags: %u",
|
||||
client_config.interface, __func__, r);
|
||||
return -1;
|
||||
}
|
||||
return (int)rtnl_if_flags_send(fd, RTM_SETLINK, oldflags & ~flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ipbcpfx_clear_others_do(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct rtattr *tb[IFA_MAX] = {0};
|
||||
@ -277,8 +351,7 @@ static int ipbcpfx_clear_others(int fd, uint32_t ipaddr, uint32_t bcast,
|
||||
.prefixlen = prefixlen, .already_ok = false };
|
||||
ssize_t ret;
|
||||
uint32_t seq = ifset_nl_seq++;
|
||||
ret = nl_sendgetaddr(fd, seq, client_config.ifindex);
|
||||
if (ret < 0)
|
||||
if (nl_sendgetaddr(fd, seq, client_config.ifindex) < 0)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
@ -356,10 +429,10 @@ void perform_ip_subnet_bcast(const char *str_ipaddr,
|
||||
r = rtnl_addr_broadcast_send(fd, RTM_NEWADDR, IFA_F_PERMANENT,
|
||||
RT_SCOPE_UNIVERSE, &ipaddr.s_addr, &bcast.s_addr,
|
||||
prefixlen);
|
||||
|
||||
close(fd); // XXX: Move this when we also set the link flags.
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
log_line("Interface IP set to: '%s'", str_ipaddr);
|
||||
log_line("Interface subnet set to: '%s'", str_subnet);
|
||||
@ -368,9 +441,10 @@ void perform_ip_subnet_bcast(const char *str_ipaddr,
|
||||
} else
|
||||
log_line("Interface IP, subnet, and broadcast were already OK.");
|
||||
|
||||
// XXX: Would be nice to do this via netlink, too.
|
||||
if (set_if_flag(IFF_UP | IFF_RUNNING))
|
||||
return;
|
||||
if (link_set_flags(fd, IFF_UP | IFF_RUNNING) < 0)
|
||||
log_line("%s: (%s) Failed to set link to be up and running.",
|
||||
client_config.interface, __func__);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,7 +139,7 @@ void handle_nl_message(struct client_state_t *cs)
|
||||
|
||||
int nl_getifdata(struct client_state_t *cs)
|
||||
{
|
||||
if (nl_sendgetlink(cs->nlFd, time(NULL)))
|
||||
if (nl_sendgetlinks(cs->nlFd, time(NULL)))
|
||||
return -1;
|
||||
|
||||
for (int pr = 0; !pr;) {
|
||||
|
18
ndhc/nl.c
18
ndhc/nl.c
@ -164,10 +164,11 @@ int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t seq, uint32_t portid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nl_sendgetlink(int fd, int seq)
|
||||
static int nl_sendgetlink_do(int fd, int seq, int ifindex, int by_ifindex)
|
||||
{
|
||||
char nlbuf[512];
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *)nlbuf;
|
||||
struct ifinfomsg *ifinfomsg;
|
||||
ssize_t r;
|
||||
|
||||
memset(nlbuf, 0, sizeof nlbuf);
|
||||
@ -176,6 +177,11 @@ int nl_sendgetlink(int fd, int seq)
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
nlh->nlmsg_seq = seq;
|
||||
|
||||
if (by_ifindex) {
|
||||
ifinfomsg = NLMSG_DATA(nlh);
|
||||
ifinfomsg->ifi_index = ifindex;
|
||||
}
|
||||
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
};
|
||||
@ -194,6 +200,16 @@ retry_sendto:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nl_sendgetlinks(int fd, int seq)
|
||||
{
|
||||
return nl_sendgetlink_do(fd, seq, 0, 0);
|
||||
}
|
||||
|
||||
int nl_sendgetlink(int fd, int seq, int ifindex)
|
||||
{
|
||||
return nl_sendgetlink_do(fd, seq, ifindex, 1);
|
||||
}
|
||||
|
||||
int nl_sendgetaddr(int fd, int seq, int ifindex)
|
||||
{
|
||||
char nlbuf[512];
|
||||
|
@ -92,7 +92,8 @@ typedef void (*nlmsg_foreach_fn)(const struct nlmsghdr *, void *);
|
||||
extern int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t seq,
|
||||
uint32_t portid,
|
||||
nlmsg_foreach_fn pfn, void *fnarg);
|
||||
extern int nl_sendgetlink(int fd, int seq);
|
||||
extern int nl_sendgetlinks(int fd, int seq);
|
||||
extern int nl_sendgetlink(int fd, int seq, int ifindex);
|
||||
extern int nl_sendgetaddr(int fd, int seq, int ifindex);
|
||||
|
||||
extern int nl_open(int nltype, int nlgroup, int *nlportid);
|
||||
|
Loading…
Reference in New Issue
Block a user