예제 #1
0
/** 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;
}
예제 #2
0
파일: rtnl.c 프로젝트: LazyZhu/rt-n56u-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;
}