/** Receive message from netlink and update interface table * * \param nlif_handle A pointer to a ::nlif_handle created * \return 0 if OK */ int nlif_catch(struct nlif_handle *nlif_handle) { assert(nlif_handle != NULL); if (nlif_handle->rtnl_handle) return rtnl_receive(nlif_handle->rtnl_handle); return -1; }
/* rtnl_receive - receive netlink packets from rtnetlink socket */ int rtnl_receive(struct rtnl_handle *rtnl_handle) { int status; char buf[8192]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; struct nlmsghdr *h; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0); if (status < 0) { if (errno == EINTR) return 0; rtnl_log(LOG_NOTICE, "OVERRUN on rtnl socket"); return -1; } if (status == 0) { rtnl_log(LOG_ERROR, "EOF on rtnl socket"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { rtnl_log(LOG_ERROR, "invalid address size"); return -1; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, status)) { #if 0 if (h->nlmsg_pid != rtnl_local.nl_pid || h->nlmsg_seq != rtnl_dump) { goto skip; } #endif if (h->nlmsg_type == NLMSG_DONE) { rtnl_log(LOG_NOTICE, "NLMSG_DONE"); return 0; } if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = NLMSG_DATA(h); if (h->nlmsg_len>=NLMSG_LENGTH(sizeof(struct nlmsgerr))) errno = -err->error; rtnl_log(LOG_ERROR, "NLMSG_ERROR, errnp=%d", errno); return -1; } if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0) rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u", h->nlmsg_type); h = NLMSG_NEXT(h, status); } return 1; } int rtnl_receive_multi(struct rtnl_handle *rtnl_handle) { while (1) { if (rtnl_receive(rtnl_handle) <= 0) break; } return 1; } /* rtnl_open - constructor of rtnetlink module */ struct rtnl_handle *rtnl_open(void) { socklen_t addrlen; struct rtnl_handle *h; h = calloc(1, sizeof(struct rtnl_handle)); if (!h) return NULL; addrlen = sizeof(h->rtnl_local); h->rtnl_local.nl_pid = getpid(); h->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (h->rtnl_fd < 0) { rtnl_log(LOG_ERROR, "unable to create rtnetlink socket"); goto err; } memset(&h->rtnl_local, 0, sizeof(h->rtnl_local)); h->rtnl_local.nl_family = AF_NETLINK; h->rtnl_local.nl_groups = RTMGRP_LINK; if (bind(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, addrlen) < 0) { rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket"); goto err_close; } if (getsockname(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, &addrlen) < 0) { rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)"); goto err_close; } if (addrlen != sizeof(h->rtnl_local)) { rtnl_log(LOG_ERROR, "invalid address size %u", addr_len); goto err_close; } if (h->rtnl_local.nl_family != AF_NETLINK) { rtnl_log(LOG_ERROR, "invalid AF %u", h->rtnl_local.nl_family); goto err_close; } h->rtnl_seq = time(NULL); return h; err_close: close(h->rtnl_fd); err: free(h); return NULL; }