Ejemplo n.º 1
0
int usnic_nl_rt_lookup(uint32_t src_addr, uint32_t dst_addr, int oif,
			uint32_t *nh_addr)
{
	struct usnic_nl_sk	*unlsk;
	struct nl_msg		*nlm;
	struct rtmsg		rmsg;
	struct usnic_rt_cb_arg	arg;
	int			err;

retry:
	unlsk = NULL;
	err = usnic_nl_sk_alloc(&unlsk, NETLINK_ROUTE);
	if (err)
		return err;

	memset(&rmsg, 0, sizeof(rmsg));
	rmsg.rtm_family = AF_INET;
	rmsg.rtm_dst_len = sizeof(dst_addr) * CHAR_BIT;
	rmsg.rtm_src_len = sizeof(src_addr) * CHAR_BIT;

	nlm = nlmsg_alloc_simple(RTM_GETROUTE, 0);
	if (!nlm) {
		usnic_err("Failed to alloc nl message, %s\n",
				NL_GETERROR(err));
		err = ENOMEM;
		goto out;
	}
	nlmsg_append(nlm, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
	nla_put_u32(nlm, RTA_DST, dst_addr);
	nla_put_u32(nlm, RTA_SRC, src_addr);

	err = usnic_nl_send_query(unlsk, nlm, NETLINK_ROUTE, NLM_F_REQUEST);
	nlmsg_free(nlm);
	if (err < 0) {
		usnic_err("Failed to send RTM_GETROUTE query message, error %s\n",
				NL_GETERROR(err));
                err = EINVAL;
		goto out;
	}

	memset(&arg, 0, sizeof(arg));
	arg.oif		= oif;
	arg.unlsk	= unlsk;
	err = nl_socket_modify_cb(unlsk->nlh, NL_CB_MSG_IN, NL_CB_CUSTOM,
					usnic_rt_raw_parse_cb, &arg);
	if (err != 0) {
		usnic_err("Failed to setup callback function, error %s\n",
				NL_GETERROR(err));
                err = EINVAL;
		goto out;
	}

	/* Sometimes the recvmsg can fail because something is
	 * temporarily out of resources.  In this case, delay a little
	 * and try again. */
	do {
		err = 0;
		NL_RECVMSGS(unlsk->nlh, arg, EAGAIN, err, out);
		if (err == EAGAIN) {
			usleep(5);
		}
	} while (err == EAGAIN);

	/* If we got a reply back that indicated that the kernel was
	 * too busy to handle this request, delay a little and try
	 * again. */
        if (arg.retry) {
            usleep(5);
            goto retry;
        }

	if (arg.found) {
		*nh_addr = arg.nh_addr;
		err = 0;
	} else {
		err = EHOSTUNREACH;
	}

out:
	usnic_nl_sk_free(unlsk);
	return err;
}
Ejemplo n.º 2
0
int usnic_nl_rt_lookup(uint32_t src_addr, uint32_t dst_addr, int oif,
			uint32_t *nh_addr)
{
	struct usnic_nl_sk	*unlsk;
	struct nl_msg		*nlm;
	struct rtmsg		rmsg;
	struct usnic_rt_cb_arg	arg;
	int			err;

	unlsk = NULL;
	err = usnic_nl_sk_alloc(&unlsk, NETLINK_ROUTE);
	if (err)
		return err;

	memset(&rmsg, 0, sizeof(rmsg));
	rmsg.rtm_family = AF_INET;
	rmsg.rtm_dst_len = sizeof(dst_addr) * CHAR_BIT;
	rmsg.rtm_src_len = sizeof(src_addr) * CHAR_BIT;

	nlm = nlmsg_alloc_simple(RTM_GETROUTE, 0);
	if (!nlm) {
		usnic_err("Failed to alloc nl message, %s\n",
				NL_GETERROR(err));
		err = ENOMEM;
		goto out;
	}
	nlmsg_append(nlm, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
	nla_put_u32(nlm, RTA_DST, dst_addr);
	nla_put_u32(nlm, RTA_SRC, src_addr);

	err = usnic_nl_send_query(unlsk, nlm, NETLINK_ROUTE, NLM_F_REQUEST);
	nlmsg_free(nlm);
	if (err < 0) {
		usnic_err("Failed to send RTM_GETROUTE query message, error %s\n",
				NL_GETERROR(err));
                err = EINVAL;
		goto out;
	}

	memset(&arg, 0, sizeof(arg));
	arg.oif		= oif;
	arg.unlsk	= unlsk;
	err = nl_socket_modify_cb(unlsk->nlh, NL_CB_MSG_IN, NL_CB_CUSTOM,
					usnic_rt_raw_parse_cb, &arg);
	if (err != 0) {
		usnic_err("Failed to setup callback function, error %s\n",
				NL_GETERROR(err));
                err = EINVAL;
		goto out;
	}

	NL_RECVMSGS(unlsk->nlh, arg, EHOSTUNREACH, err, out);

	if (arg.found) {
		*nh_addr = arg.nh_addr;
		err = 0;
	} else {
		err = EHOSTUNREACH;
	}

out:
	usnic_nl_sk_free(unlsk);
	return err;
}