X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-rtnl%2Frtnl-message.c;h=c0a38e148b1ee6c8a1cb20349cee82f33f1f7c7f;hp=9558e112af62ce673123a9495569dc6addcf1958;hb=ca4e095ab9e970cb8fa472ae69ea1f0648041722;hpb=26349add97c8e9bfd26f2f16d61dd80a324f504e diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index 9558e112a..c0a38e148 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -786,7 +786,7 @@ int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **d return RTA_PAYLOAD(rta); } -int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) { +int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) { int r; void *attr_data; @@ -800,7 +800,7 @@ int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char ** else if (strnlen(attr_data, r) >= (size_t) r) return -EIO; - *data = (char *) attr_data; + *data = (const char *) attr_data; return 0; } @@ -962,7 +962,7 @@ int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) { return r; } else if (nl_type->type == NLA_UNION) { const NLTypeSystemUnion *type_system_union; - char *key; + const char *key; r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, @@ -1098,8 +1098,9 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) { return k; } -static int socket_recv_message(int fd, struct iovec *iov, bool peek) { - uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))]; +static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) { + uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(struct nl_pktinfo))]; struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1, @@ -1107,6 +1108,7 @@ static int socket_recv_message(int fd, struct iovec *iov, bool peek) { .msg_controllen = sizeof(cred_buffer), }; struct cmsghdr *cmsg; + uint32_t group = 0; bool auth = false; int r; @@ -1128,10 +1130,15 @@ static int socket_recv_message(int fd, struct iovec *iov, bool peek) { struct ucred *ucred = (void *)CMSG_DATA(cmsg); /* from the kernel */ - if (ucred->uid == 0 && ucred->pid == 0) { + if (ucred->uid == 0 && ucred->pid == 0) auth = true; - break; - } + } else if (cmsg->cmsg_level == SOL_NETLINK && + cmsg->cmsg_type == NETLINK_PKTINFO && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) { + struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg); + + /* multi-cast group */ + group = pktinfo->group; } } @@ -1139,6 +1146,9 @@ static int socket_recv_message(int fd, struct iovec *iov, bool peek) { /* not from the kernel, ignore */ return 0; + if (group) + *_group = group; + return r; } @@ -1150,6 +1160,7 @@ static int socket_recv_message(int fd, struct iovec *iov, bool peek) { int socket_read_message(sd_rtnl *rtnl) { _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL; struct iovec iov = {}; + uint32_t group = 0; bool multi_part = false, done = false; struct nlmsghdr *new_msg; size_t len; @@ -1161,7 +1172,7 @@ int socket_read_message(sd_rtnl *rtnl) { assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr)); /* read nothing, just get the pending message size */ - r = socket_recv_message(rtnl->fd, &iov, true); + r = socket_recv_message(rtnl->fd, &iov, &group, true); if (r <= 0) return r; else @@ -1177,7 +1188,7 @@ int socket_read_message(sd_rtnl *rtnl) { iov.iov_len = rtnl->rbuffer_allocated; /* read the pending message */ - r = socket_recv_message(rtnl->fd, &iov, false); + r = socket_recv_message(rtnl->fd, &iov, &group, false); if (r <= 0) return r; else @@ -1203,7 +1214,7 @@ int socket_read_message(sd_rtnl *rtnl) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; const NLType *nl_type; - if (new_msg->nlmsg_pid && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid) + if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid) /* not broadcast and not for us */ continue;