X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Fsd-rtnl.c;h=c7a36b9efbcbf68252dd89f54efa1a289ccb2004;hb=3f42446d286a12292f1693d5cf9cb3ec3844e1a4;hp=7f1ec308a8e79a4d739d76684db3b5c8751f193c;hpb=233ba5c3a0f73e01fe6149fd8c377826a83c2a0a;p=elogind.git diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c index 7f1ec308a..c7a36b9ef 100644 --- a/src/libsystemd/sd-rtnl/sd-rtnl.c +++ b/src/libsystemd/sd-rtnl/sd-rtnl.c @@ -61,6 +61,36 @@ static int sd_rtnl_new(sd_rtnl **ret) { sizeof(struct nlmsghdr), sizeof(uint8_t))) return -ENOMEM; + /* Change notification responses have sequence 0, so we must + * start our request sequence numbers at 1, or we may confuse our + * responses with notifications from the kernel */ + rtnl->serial = 1; + + *ret = rtnl; + rtnl = NULL; + + return 0; +} + +int sd_rtnl_new_from_netlink(sd_rtnl **ret, int fd) { + _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL; + socklen_t addrlen; + int r; + + assert_return(ret, -EINVAL); + + r = sd_rtnl_new(&rtnl); + if (r < 0) + return r; + + addrlen = sizeof(rtnl->sockaddr); + + r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen); + if (r < 0) + return -errno; + + rtnl->fd = fd; + *ret = rtnl; rtnl = NULL; @@ -121,12 +151,13 @@ static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) addrlen = sizeof(rtnl->sockaddr); r = bind(fd, &rtnl->sockaddr.sa, addrlen); - if (r < 0) + /* ignore EINVAL to allow opening an already bound socket */ + if (r < 0 && errno != EINVAL) return -errno; r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen); if (r < 0) - return r; + return -errno; rtnl->fd = fd; @@ -231,7 +262,9 @@ static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) { assert(m); assert(m->hdr); - m->hdr->nlmsg_seq = rtnl->serial++; + /* don't use seq == 0, as that is used for broadcasts, so we + would get confused by replies to such messages */ + m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++; rtnl_message_seal(m); @@ -967,7 +1000,7 @@ int sd_rtnl_add_match(sd_rtnl *rtnl, assert_return(!rtnl_pid_changed(rtnl), -ECHILD); assert_return(rtnl_message_type_is_link(type) || rtnl_message_type_is_addr(type) || - rtnl_message_type_is_route(type), -ENOTSUP); + rtnl_message_type_is_route(type), -EOPNOTSUPP); c = new0(struct match_callback, 1); if (!c)