Ejemplo n.º 1
0
static struct nlattr *
find_dump_kind(const struct nlmsghdr *n)
{
	struct nlattr *tb1, *tb2[TCA_ACT_MAX + 1];
	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
	struct nlattr *nla[TCAA_MAX + 1];
	struct nlattr *kind;

	if (nlmsg_parse(n, sizeof(struct tcamsg), nla, TCAA_MAX, NULL) < 0)
		return NULL;
	tb1 = nla[TCA_ACT_TAB];
	if (tb1 == NULL)
		return NULL;

	if (nla_parse(tb, TCA_ACT_MAX_PRIO, nla_data(tb1),
		      NLMSG_ALIGN(nla_len(tb1)), NULL) < 0)
		return NULL;

	if (tb[1] == NULL)
		return NULL;
	if (nla_parse(tb2, TCA_ACT_MAX, nla_data(tb[1]),
		      nla_len(tb[1]), NULL) < 0)
		return NULL;
	kind = tb2[TCA_ACT_KIND];

	return kind;
}
Ejemplo n.º 2
0
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct nlattr *tb[IFLA_MAX+1];
	struct net_device *dev = NULL;
	struct sk_buff *nskb;
	char *iw_buf = NULL, *iw = NULL;
	int iw_buf_len = 0;
	int err;

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
	if (err < 0)
		return err;

	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index >= 0) {
		dev = dev_get_by_index(ifm->ifi_index);
		if (dev == NULL)
			return -ENODEV;
	} else
		return -EINVAL;


#ifdef CONFIG_NET_WIRELESS_RTNETLINK
	if (tb[IFLA_WIRELESS]) {
		/* Call Wireless Extensions. We need to know the size before
		 * we can alloc. Various stuff checked in there... */
		err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]),
					     nla_len(tb[IFLA_WIRELESS]),
					     &iw_buf, &iw_buf_len);
		if (err < 0)
			goto errout;

		iw += IW_EV_POINT_OFF;
	}
#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */

	nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL);
	if (nskb == NULL) {
		err = -ENOBUFS;
		goto errout;
	}

	err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK,
			       NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_size */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
		goto errout;
	}
	err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
	kfree(iw_buf);
	dev_put(dev);

	return err;
}
Ejemplo n.º 3
0
static NMIP6Device *
process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
{
	struct nlmsghdr *hdr = nlmsg_hdr (msg);
	struct ifinfomsg *ifi;
	NMIP6Device *device;
	struct nlattr *tb[IFLA_MAX + 1];
	struct nlattr *pi[IFLA_INET6_MAX + 1];
	int err;

	/* FIXME: we have to do this manually for now since libnl doesn't yet
	 * support the IFLA_PROTINFO attribute of NEWLINK messages.  When it does,
	 * we can get rid of this function and just grab IFLA_PROTINFO from
	 * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
	 * the PROTINFO.
	 */
	err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
	if (err < 0) {
		nm_log_dbg (LOGD_IP6, "ignoring invalid newlink netlink message "
				      "while parsing PROTINFO attribute");
		return NULL;
	}

	ifi = nlmsg_data (hdr);
	if (ifi->ifi_family != AF_INET6) {
		nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family);
		return NULL;
	}

	device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
	if (!device || device->addrconf_complete) {
		nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device",
		            device ? device->iface : "(none)");
		return NULL;
	}

	if (!tb[IFLA_PROTINFO]) {
		nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface);
		return NULL;
	}

	err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
	if (err < 0) {
		nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface);
		return NULL;
	}
	if (!pi[IFLA_INET6_FLAGS]) {
		nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface);
		return NULL;
	}

	device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
	nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags);

	return device;
}
Ejemplo n.º 4
0
static int ct_restore_callback(struct nlmsghdr *nlh)
{
    struct nfgenmsg *msg;
    struct nlattr *tb[CTA_MAX + 1], *tbp[CTA_PROTOINFO_MAX + 1], *tb_tcp[CTA_PROTOINFO_TCP_MAX + 1];
    int err;

    msg = (nfgenmsg *)NLMSG_DATA(nlh);

    if (msg->nfgen_family != AF_INET && msg->nfgen_family != AF_INET6)
        return 0;

    err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, NULL);
    if (err < 0)
        return -1;

    if (restore_mark != 0 || restore_mark_mask != -1) {
        uint32_t* mark = (uint32_t*)nla_data(tb[CTA_MARK]);
        //printf("old mark: 0x%08x\n", ntohl(*mark));
        *mark = (*mark & restore_mark_mask) ^ restore_mark;
        //printf("new mark: 0x%08x\n", ntohl(*mark));
    }

    if (!tb[CTA_PROTOINFO])
        return 0;

    err = nla_parse_nested(tbp, CTA_PROTOINFO_MAX, tb[CTA_PROTOINFO], NULL);
    if (err < 0)
        return -1;

    if (!tbp[CTA_PROTOINFO_TCP])
        return 0;

    err = nla_parse_nested(tb_tcp, CTA_PROTOINFO_TCP_MAX, tbp[CTA_PROTOINFO_TCP], NULL);
    if (err < 0)
        return -1;

    if (tb_tcp[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) {
        struct nf_ct_tcp_flags *flags;

        flags = (nf_ct_tcp_flags *)nla_data(tb_tcp[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]);
        flags->flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
        flags->mask |= IP_CT_TCP_FLAG_BE_LIBERAL;
    }

    if (tb_tcp[CTA_PROTOINFO_TCP_FLAGS_REPLY]) {
        struct nf_ct_tcp_flags *flags;

        flags = (nf_ct_tcp_flags *)nla_data(tb_tcp[CTA_PROTOINFO_TCP_FLAGS_REPLY]);
        flags->flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
        flags->mask |= IP_CT_TCP_FLAG_BE_LIBERAL;
    }

    return 0;
}
Ejemplo n.º 5
0
int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr)
{
	u32 maxattr = tipc_genl_family.maxattr;

	*attr = genl_family_attrbuf(&tipc_genl_family);
	if (!*attr)
		return -EOPNOTSUPP;

	return nlmsg_parse(nlh, GENL_HDRLEN, *attr, maxattr, tipc_nl_policy,
			   NULL);
}
Ejemplo n.º 6
0
static struct sk_buff *brc_send_command(struct sk_buff *request,
					struct nlattr **attrs)
{
	unsigned long int flags;
	struct sk_buff *reply;
	int error;

	mutex_lock(&brc_serial);

	/* Increment sequence number first, so that we ignore any replies
	 * to stale requests. */
	spin_lock_irqsave(&brc_lock, flags);
	nlmsg_hdr(request)->nlmsg_seq = ++brc_seq;
	INIT_COMPLETION(brc_done);
	spin_unlock_irqrestore(&brc_lock, flags);

	nlmsg_end(request, nlmsg_hdr(request));

	/* Send message. */
	error = genlmsg_multicast(request, 0, brc_mc_group.id, GFP_KERNEL);
	if (error < 0)
		goto error;

	/* Wait for reply. */
	error = -ETIMEDOUT;
	if (!wait_for_completion_timeout(&brc_done, BRC_TIMEOUT)) {
		pr_warn("timed out waiting for userspace\n");
		goto error;
    }

	/* Grab reply. */
	spin_lock_irqsave(&brc_lock, flags);
	reply = brc_reply;
	brc_reply = NULL;
	spin_unlock_irqrestore(&brc_lock, flags);

	mutex_unlock(&brc_serial);

	/* Re-parse message.  Can't fail, since it parsed correctly once
	 * already. */
	error = nlmsg_parse(nlmsg_hdr(reply), GENL_HDRLEN,
			    attrs, BRC_GENL_A_MAX, brc_genl_policy);
	WARN_ON(error);

	return reply;

error:
	mutex_unlock(&brc_serial);
	return ERR_PTR(error);
}
Ejemplo n.º 7
0
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
{
	struct net *net = sock_net(skb->sk);
	struct nlattr *tca[TCA_ACT_MAX + 1];
	u32 portid = skb ? NETLINK_CB(skb).portid : 0;
	int ret = 0, ovr = 0;

	if ((n->nlmsg_type != RTM_GETACTION) && !capable(CAP_NET_ADMIN))
		return -EPERM;

	ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
	if (ret < 0)
		return ret;

	if (tca[TCA_ACT_TAB] == NULL) {
		pr_notice("tc_ctl_action: received NO action attribs\n");
		return -EINVAL;
	}

	/* n->nlmsg_flags & NLM_F_CREATE */
	switch (n->nlmsg_type) {
	case RTM_NEWACTION:
		/* we are going to assume all other flags
		 * imply create only if it doesn't exist
		 * Note that CREATE | EXCL implies that
		 * but since we want avoid ambiguity (eg when flags
		 * is zero) then just set this
		 */
		if (n->nlmsg_flags & NLM_F_REPLACE)
			ovr = 1;
replay:
		ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr);
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
				    portid, RTM_DELACTION);
		break;
	case RTM_GETACTION:
		ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
				    portid, RTM_GETACTION);
		break;
	default:
		BUG();
	}

	return ret;
}
Ejemplo n.º 8
0
static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct net *net = sock_net(skb->sk);
	struct nlattr *tb[IFA_MAX+1];
	struct in_device *in_dev;
	struct ifaddrmsg *ifm;
	struct in_ifaddr *ifa, **ifap;
	int err = -EINVAL;

	ASSERT_RTNL();

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
	if (err < 0)
		goto errout;

	ifm = nlmsg_data(nlh);
	in_dev = inetdev_by_index(net, ifm->ifa_index);
	if (in_dev == NULL) {
		err = -ENODEV;
		goto errout;
	}

	__in_dev_put(in_dev);

	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
	     ifap = &ifa->ifa_next) {
		if (tb[IFA_LOCAL] &&
		    ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
			continue;

		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
			continue;

		if (tb[IFA_ADDRESS] &&
		    (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
		    !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
			continue;

		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
		return 0;
	}

	err = -EADDRNOTAVAIL;
errout:
	return err;
}
Ejemplo n.º 9
0
static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
{
	struct net *net = sock_net(skb->sk);
	struct nlattr *tca[TCA_ACT_MAX + 1];
	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
	int ret = 0, ovr = 0;

	if (net != &init_net)
		return -EINVAL;

	ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
	if (ret < 0)
		return ret;

	if (tca[TCA_ACT_TAB] == NULL) {
		printk("tc_ctl_action: received NO action attribs\n");
		return -EINVAL;
	}

	
	switch (n->nlmsg_type) {
	case RTM_NEWACTION:
		
		if (n->nlmsg_flags&NLM_F_REPLACE)
			ovr = 1;
replay:
		ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr);
		if (ret == -EAGAIN)
			goto replay;
		break;
	case RTM_DELACTION:
		ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION);
		break;
	case RTM_GETACTION:
		ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION);
		break;
	default:
		BUG();
	}

	return ret;
}
Ejemplo n.º 10
0
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct nlattr *tb[IFLA_MAX+1];
	struct net_device *dev = NULL;
	struct sk_buff *nskb;
	int err;

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
	if (err < 0)
		return err;

	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index > 0) {
		dev = dev_get_by_index(ifm->ifi_index);
		if (dev == NULL)
			return -ENODEV;
	} else
		return -EINVAL;

	nskb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL);
	if (nskb == NULL) {
		err = -ENOBUFS;
		goto errout;
	}

	err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).pid,
			       nlh->nlmsg_seq, 0, 0);
	if (err < 0) {
		/* -EMSGSIZE implies BUG in if_nlmsg_size */
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(nskb);
		goto errout;
	}
	err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
	dev_put(dev);

	return err;
}
Ejemplo n.º 11
0
int netlink_receive_one(struct nlmsghdr *hdr, void *arg)
{
	struct nlattr *tb[NETLINK_DIAG_MAX+1];
	struct netlink_diag_msg *m;
	struct netlink_sk_desc *sd;
	unsigned long *groups;

	m = NLMSG_DATA(hdr);
	pr_debug("Collect netlink sock 0x%x\n", m->ndiag_ino);

	sd = xmalloc(sizeof(*sd));
	if (!sd)
		return -1;

	sd->protocol = m->ndiag_protocol;
	sd->portid = m->ndiag_portid;
	sd->dst_portid = m->ndiag_dst_portid;
	sd->dst_group = m->ndiag_dst_group;
	sd->state = m->ndiag_state;

	nlmsg_parse(hdr, sizeof(struct netlink_diag_msg), tb, NETLINK_DIAG_MAX, NULL);

	if (tb[NETLINK_DIAG_GROUPS]) {
		sd->gsize = nla_len(tb[NETLINK_DIAG_GROUPS]);
		groups = nla_data(tb[NETLINK_DIAG_GROUPS]);

		sd->groups = xmalloc(sd->gsize);
		if (!sd->groups) {
			xfree(sd);
			return -1;
		}
		memcpy(sd->groups, groups, sd->gsize);
	} else {
		sd->groups = NULL;
		sd->gsize = 0;
	}

	return sk_collect_one(m->ndiag_ino, PF_NETLINK, &sd->sd);
}
Ejemplo n.º 12
0
static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
{
	struct nlattr **attrbuf = genl_family_attrbuf(&nfc_genl_family);
	struct nfc_dev *dev;
	int rc;
	u32 idx;

	rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize,
			 attrbuf, nfc_genl_family.maxattr, nfc_genl_policy);
	if (rc < 0)
		return ERR_PTR(rc);

	if (!attrbuf[NFC_ATTR_DEVICE_INDEX])
		return ERR_PTR(-EINVAL);

	idx = nla_get_u32(attrbuf[NFC_ATTR_DEVICE_INDEX]);

	dev = nfc_get_device(idx);
	if (!dev)
		return ERR_PTR(-ENODEV);

	return dev;
}
Ejemplo n.º 13
0
static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
			   struct nlmsghdr *n, struct nl_parser_param *pp)
{
	struct rtnl_rule *rule;
	struct fib_rule_hdr *frh;
	struct nlattr *tb[FRA_MAX+1];
	int err = 1, family;

	rule = rtnl_rule_alloc();
	if (!rule) {
		err = -NLE_NOMEM;
		goto errout;
	}

	rule->ce_msgtype = n->nlmsg_type;
	frh = nlmsg_data(n);

	err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy);
	if (err < 0)
		goto errout;

	rule->r_family = family = frh->family;
	rule->r_table = frh->table;
	rule->r_action = frh->action;
	rule->r_flags = frh->flags;

	rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION |
			 RULE_ATTR_FLAGS);

	/* ipv4 only */
	if (frh->tos) {
		rule->r_dsfield = frh->tos;
		rule->ce_mask |= RULE_ATTR_DSFIELD;
	}

	if (tb[FRA_TABLE]) {
		rule->r_table = nla_get_u32(tb[FRA_TABLE]);
		rule->ce_mask |= RULE_ATTR_TABLE;
	}

	if (tb[FRA_IIFNAME]) {
		nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ);
		rule->ce_mask |= RULE_ATTR_IIFNAME;
	}

	if (tb[FRA_OIFNAME]) {
		nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ);
		rule->ce_mask |= RULE_ATTR_OIFNAME;
	}

	if (tb[FRA_PRIORITY]) {
		rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]);
		rule->ce_mask |= RULE_ATTR_PRIO;
	}

	if (tb[FRA_FWMARK]) {
		rule->r_mark = nla_get_u32(tb[FRA_FWMARK]);
		rule->ce_mask |= RULE_ATTR_MARK;
	}

	if (tb[FRA_FWMASK]) {
		rule->r_mask = nla_get_u32(tb[FRA_FWMASK]);
		rule->ce_mask |= RULE_ATTR_MASK;
	}

	if (tb[FRA_GOTO]) {
		rule->r_goto = nla_get_u32(tb[FRA_GOTO]);
		rule->ce_mask |= RULE_ATTR_GOTO;
	}

	if (tb[FRA_SRC]) {
		if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family)))
			goto errout_enomem;

		nl_addr_set_prefixlen(rule->r_src, frh->src_len);
		rule->ce_mask |= RULE_ATTR_SRC;
	}

	if (tb[FRA_DST]) {
		if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family)))
			goto errout_enomem;
		nl_addr_set_prefixlen(rule->r_dst, frh->dst_len);
		rule->ce_mask |= RULE_ATTR_DST;
	}

	/* ipv4 only */
	if (tb[FRA_FLOW]) {
		rule->r_flow = nla_get_u32(tb[FRA_FLOW]);
		rule->ce_mask |= RULE_ATTR_FLOW;
	}

	err = pp->pp_cb((struct nl_object *) rule, pp);
errout:
	rtnl_rule_put(rule);
	return err;

errout_enomem:
	err = -NLE_NOMEM;
	goto errout;
}
Ejemplo n.º 14
0
Archivo: log.c Proyecto: DINKIN/tuo
struct nfnl_log *nfnlmsg_log_parse(struct nlmsghdr *nlh)
{
	struct nfnl_log *log;
	struct nlattr *tb[NFULA_MAX+1];
	struct nlattr *attr;
	int err;

	log = nfnl_log_alloc();
	if (!log)
		return NULL;

	log->ce_msgtype = nlh->nlmsg_type;

	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX,
			  log_policy);
	if (err < 0)
		goto errout;

	nfnl_log_set_family(log, nfnlmsg_family(nlh));

	attr = tb[NFULA_PACKET_HDR];
	if (attr) {
		struct nfulnl_msg_packet_hdr *hdr = nla_data(attr);

		nfnl_log_set_hwproto(log, hdr->hw_protocol);
		nfnl_log_set_hook(log, hdr->hook);
	}

	attr = tb[NFULA_MARK];
	if (attr)
		nfnl_log_set_mark(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_TIMESTAMP];
	if (attr) {
		struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr);
		struct timeval tv;

		tv.tv_sec = ntohll(timestamp->sec);
		tv.tv_usec = ntohll(timestamp->usec);
		nfnl_log_set_timestamp(log, &tv);
	}

	attr = tb[NFULA_IFINDEX_INDEV];
	if (attr)
		nfnl_log_set_indev(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_IFINDEX_OUTDEV];
	if (attr)
		nfnl_log_set_outdev(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_IFINDEX_PHYSINDEV];
	if (attr)
		nfnl_log_set_physindev(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_IFINDEX_PHYSOUTDEV];
	if (attr)
		nfnl_log_set_physoutdev(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_HWADDR];
	if (attr) {
		struct nfulnl_msg_packet_hw *hw = nla_data(attr);

		nfnl_log_set_hwaddr(log, hw->hw_addr, ntohs(hw->hw_addrlen));
	}

	attr = tb[NFULA_PAYLOAD];
	if (attr) {
		err = nfnl_log_set_payload(log, nla_data(attr), nla_len(attr));
		if (err < 0)
			goto errout;
	}

	attr = tb[NFULA_PREFIX];
	if (attr) {
		err = nfnl_log_set_prefix(log, nla_data(attr));
		if (err < 0)
			goto errout;
	}

	attr = tb[NFULA_UID];
	if (attr)
		nfnl_log_set_uid(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_SEQ];
	if (attr)
		nfnl_log_set_seq(log, ntohl(nla_get_u32(attr)));

	attr = tb[NFULA_SEQ_GLOBAL];
	if (attr)
		nfnl_log_set_seq_global(log, ntohl(nla_get_u32(attr)));

	return log;

errout:
	nfnl_log_put(log);
	return NULL;
}
Ejemplo n.º 15
0
static int rtnl_raw_parse_cb(struct nl_msg *msg, void *arg)
{
	struct nl_lookup_arg *lookup_arg = (struct nl_lookup_arg *)arg;
	struct usnic_rtnl_sk *unlsk = lookup_arg->unlsk;
	struct nlmsghdr	*nlm_hdr = nlmsg_hdr(msg);
	struct rtmsg *rtm;
	struct nlattr *tb[RTA_MAX + 1];
	int found = 0;
	int err;

#if WANT_DEBUG_MSGS
	nl_msg_dump(msg, stderr);
#endif /* WANT_DEBUG_MSGS */

	lookup_arg->nh_addr	= 0;
	lookup_arg->found 	= 0;
	lookup_arg->replied	= 0;
	lookup_arg->msg_count++;

	if (nlm_hdr->nlmsg_pid != nl_socket_get_local_port(unlsk->nlh)
		|| nlm_hdr->nlmsg_seq != unlsk->seq) {
		usnic_err("Not an expected reply msg pid: %u local pid: %u "
				"msg seq: %u expected seq: %u\n",
				nlm_hdr->nlmsg_pid, nl_socket_get_local_port(unlsk->nlh),
				nlm_hdr->nlmsg_seq, unlsk->seq);
		return NL_SKIP;
	}
	lookup_arg->replied = 1;

	if (nlm_hdr->nlmsg_type == NLMSG_ERROR) {
		struct nlmsgerr *e = (struct nlmsgerr *)nlmsg_data(nlm_hdr);
		if (nlm_hdr->nlmsg_len >= (__u32)nlmsg_msg_size(sizeof(*e))) {
			usnic_err("Received a netlink error message %d\n",
					e->error);
		}
		else {
			usnic_err("Received a truncated netlink error message\n");
		}
		return NL_STOP;
	}

	if (nlm_hdr->nlmsg_type != RTM_NEWROUTE) {
		usnic_err("Received an invalid route request reply message\n");
		return NL_STOP;
	}

	rtm = nlmsg_data(nlm_hdr);
	if (rtm->rtm_family != AF_INET) {
		usnic_err("RTM message contains invalid AF family\n");
		return NL_STOP;
	}

        init_route_policy(route_policy);
	err = nlmsg_parse(nlm_hdr, sizeof(struct rtmsg), tb, RTA_MAX,
			  route_policy);
	if (err < 0) {
		usnic_err("nlmsg parse error %d\n", err);
		return NL_STOP;
	}

	if (tb[RTA_OIF]) {
		if (nla_get_u32(tb[RTA_OIF]) == (uint32_t)lookup_arg->oif)
			found = 1;
		else
			usnic_err("Retrieved route has a different outgoing interface %d (expected %d)\n",
					nla_get_u32(tb[RTA_OIF]),
					lookup_arg->oif);
	}

        if (found && tb[RTA_METRICS]) {
            lookup_arg->metric = (int)nla_get_u32(tb[RTA_METRICS]);
        }

	if (found && tb[RTA_GATEWAY])
		lookup_arg->nh_addr = nla_get_u32(tb[RTA_GATEWAY]);

	lookup_arg->found = found;
	return NL_STOP;
}
Ejemplo n.º 16
0
int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g)
{
	struct nlattr *tb[TCA_MAX + 1];
	struct tcmsg *tm;
	int err;

	err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
	if (err < 0)
		return err;

	if (tb[TCA_KIND] == NULL)
		return -NLE_MISSING_ATTR;

	nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ);

	tm = nlmsg_data(n);
	g->tc_family  = tm->tcm_family;
	g->tc_ifindex = tm->tcm_ifindex;
	g->tc_handle  = tm->tcm_handle;
	g->tc_parent  = tm->tcm_parent;
	g->tc_info    = tm->tcm_info;

	g->ce_mask = (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE |
		      TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND);

	if (tb[TCA_OPTIONS]) {
		g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
		if (!g->tc_opts)
			return -NLE_NOMEM;
		g->ce_mask |= TCA_ATTR_OPTS;
	}
	

	if (tb[TCA_STATS2]) {
		struct nlattr *tbs[TCA_STATS_MAX + 1];

		err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
				       tc_stats2_policy);
		if (err < 0)
			return err;

		if (tbs[TCA_STATS_BASIC]) {
			struct gnet_stats_basic *bs;
			
			bs = nla_data(tbs[TCA_STATS_BASIC]);
			g->tc_stats[RTNL_TC_BYTES]	= bs->bytes;
			g->tc_stats[RTNL_TC_PACKETS]	= bs->packets;
		}

		if (tbs[TCA_STATS_RATE_EST]) {
			struct gnet_stats_rate_est *re;

			re = nla_data(tbs[TCA_STATS_RATE_EST]);
			g->tc_stats[RTNL_TC_RATE_BPS]	= re->bps;
			g->tc_stats[RTNL_TC_RATE_PPS]	= re->pps;
		}
		
		if (tbs[TCA_STATS_QUEUE]) {
			struct gnet_stats_queue *q;

			q = nla_data(tbs[TCA_STATS_QUEUE]);
			g->tc_stats[RTNL_TC_QLEN]	= q->qlen;
			g->tc_stats[RTNL_TC_BACKLOG]	= q->backlog;
			g->tc_stats[RTNL_TC_DROPS]	= q->drops;
			g->tc_stats[RTNL_TC_REQUEUES]	= q->requeues;
			g->tc_stats[RTNL_TC_OVERLIMITS]	= q->overlimits;
		}

		g->ce_mask |= TCA_ATTR_STATS;
		
		if (tbs[TCA_STATS_APP]) {
			g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
			if (g->tc_xstats == NULL)
				return -NLE_NOMEM;
		} else
			goto compat_xstats;
	} else {
		if (tb[TCA_STATS]) {
			struct tc_stats *st = nla_data(tb[TCA_STATS]);

			g->tc_stats[RTNL_TC_BYTES]	= st->bytes;
			g->tc_stats[RTNL_TC_PACKETS]	= st->packets;
			g->tc_stats[RTNL_TC_RATE_BPS]	= st->bps;
			g->tc_stats[RTNL_TC_RATE_PPS]	= st->pps;
			g->tc_stats[RTNL_TC_QLEN]	= st->qlen;
			g->tc_stats[RTNL_TC_BACKLOG]	= st->backlog;
			g->tc_stats[RTNL_TC_DROPS]	= st->drops;
			g->tc_stats[RTNL_TC_OVERLIMITS]	= st->overlimits;

			g->ce_mask |= TCA_ATTR_STATS;
		}

compat_xstats:
		if (tb[TCA_XSTATS]) {
			g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
			if (g->tc_xstats == NULL)
				return -NLE_NOMEM;
			g->ce_mask |= TCA_ATTR_XSTATS;
		}
	}


	return 0;
}
Ejemplo n.º 17
0
Archivo: tc.c Proyecto: acooks/libnl
int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
{
	struct nl_cache *link_cache;
	struct rtnl_tc_ops *ops;
	struct nlattr *tb[TCA_MAX + 1];
	char kind[TCKINDSIZ];
	struct tcmsg *tm;
	int err;

	tc->ce_msgtype = n->nlmsg_type;

	err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
	if (err < 0)
		return err;

	if (tb[TCA_KIND] == NULL)
		return -NLE_MISSING_ATTR;

	nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind));
	rtnl_tc_set_kind(tc, kind);

	tm = nlmsg_data(n);
	tc->tc_family  = tm->tcm_family;
	tc->tc_ifindex = tm->tcm_ifindex;
	tc->tc_handle  = tm->tcm_handle;
	tc->tc_parent  = tm->tcm_parent;
	tc->tc_info    = tm->tcm_info;

	tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE|
		        TCA_ATTR_PARENT | TCA_ATTR_INFO);

	if (tb[TCA_OPTIONS]) {
		tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
		if (!tc->tc_opts)
			return -NLE_NOMEM;
		tc->ce_mask |= TCA_ATTR_OPTS;
	}

	if (tb[TCA_STATS2]) {
		struct nlattr *tbs[TCA_STATS_MAX + 1];

		err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
				       tc_stats2_policy);
		if (err < 0)
			return err;

		if (tbs[TCA_STATS_BASIC]) {
			struct gnet_stats_basic *bs;
			
			bs = nla_data(tbs[TCA_STATS_BASIC]);
			tc->tc_stats[RTNL_TC_BYTES]	= bs->bytes;
			tc->tc_stats[RTNL_TC_PACKETS]	= bs->packets;
		}

		if (tbs[TCA_STATS_RATE_EST]) {
			struct gnet_stats_rate_est *re;

			re = nla_data(tbs[TCA_STATS_RATE_EST]);
			tc->tc_stats[RTNL_TC_RATE_BPS]	= re->bps;
			tc->tc_stats[RTNL_TC_RATE_PPS]	= re->pps;
		}
		
		if (tbs[TCA_STATS_QUEUE]) {
			struct gnet_stats_queue *q;

			q = nla_data(tbs[TCA_STATS_QUEUE]);
			tc->tc_stats[RTNL_TC_QLEN]	= q->qlen;
			tc->tc_stats[RTNL_TC_BACKLOG]	= q->backlog;
			tc->tc_stats[RTNL_TC_DROPS]	= q->drops;
			tc->tc_stats[RTNL_TC_REQUEUES]	= q->requeues;
			tc->tc_stats[RTNL_TC_OVERLIMITS]	= q->overlimits;
		}

		tc->ce_mask |= TCA_ATTR_STATS;
		
		if (tbs[TCA_STATS_APP]) {
			tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
			if (tc->tc_xstats == NULL)
				return -NLE_NOMEM;
			tc->ce_mask |= TCA_ATTR_XSTATS;
		} else
			goto compat_xstats;
	} else {
		if (tb[TCA_STATS]) {
			struct tc_stats *st = nla_data(tb[TCA_STATS]);

			tc->tc_stats[RTNL_TC_BYTES]	= st->bytes;
			tc->tc_stats[RTNL_TC_PACKETS]	= st->packets;
			tc->tc_stats[RTNL_TC_RATE_BPS]	= st->bps;
			tc->tc_stats[RTNL_TC_RATE_PPS]	= st->pps;
			tc->tc_stats[RTNL_TC_QLEN]	= st->qlen;
			tc->tc_stats[RTNL_TC_BACKLOG]	= st->backlog;
			tc->tc_stats[RTNL_TC_DROPS]	= st->drops;
			tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits;

			tc->ce_mask |= TCA_ATTR_STATS;
		}

compat_xstats:
		if (tb[TCA_XSTATS]) {
			tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
			if (tc->tc_xstats == NULL)
				return -NLE_NOMEM;
			tc->ce_mask |= TCA_ATTR_XSTATS;
		}
	}

	ops = rtnl_tc_get_ops(tc);
	if (ops && ops->to_msg_parser) {
		void *data = rtnl_tc_data(tc);

		if (!data)
			return -NLE_NOMEM;

		err = ops->to_msg_parser(tc, data);
		if (err < 0)
			return err;
	}

	if ((link_cache = __nl_cache_mngt_require("route/link"))) {
		struct rtnl_link *link;

		if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) {
			rtnl_tc_set_link(tc, link);

			/* rtnl_tc_set_link incs refcnt */
			rtnl_link_put(link);
		}
	}

	return 0;
}
Ejemplo n.º 18
0
int packet_receive_one(struct nlmsghdr *hdr, void *arg)
{
	struct packet_diag_msg *m;
	struct nlattr *tb[PACKET_DIAG_MAX + 1];
	struct packet_sock_desc *sd;

	m = NLMSG_DATA(hdr);
	nlmsg_parse(hdr, sizeof(struct packet_diag_msg),
			tb, PACKET_DIAG_MAX, NULL);
	pr_info("Collect packet sock %u %u\n", m->pdiag_ino, (unsigned int)m->pdiag_num);

	if (!tb[PACKET_DIAG_INFO]) {
		pr_err("No packet sock info in nlm\n");
		return -1;
	}

	if (!tb[PACKET_DIAG_MCLIST]) {
		pr_err("No packet sock mclist in nlm\n");
		return -1;
	}

	sd = xmalloc(sizeof(*sd));
	if (!sd)
		return -1;

	sd->file_id = 0;
	sd->type = m->pdiag_type;
	sd->proto = htons(m->pdiag_num);
	sd->rx = NULL;
	sd->tx = NULL;
	memcpy(&sd->nli, nla_data(tb[PACKET_DIAG_INFO]), sizeof(sd->nli));

	if (packet_save_mreqs(sd, tb[PACKET_DIAG_MCLIST]))
		goto err;

	if (tb[PACKET_DIAG_FANOUT])
		sd->fanout = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_FANOUT]);
	else
		sd->fanout = NO_FANOUT;

	if (tb[PACKET_DIAG_RX_RING]) {
		sd->rx = xmalloc(sizeof(*sd->rx));
		if (sd->rx == NULL)
			goto err;
		memcpy(sd->rx, RTA_DATA(tb[PACKET_DIAG_RX_RING]), sizeof(*sd->rx));
	}

	if (tb[PACKET_DIAG_TX_RING]) {
		sd->tx = xmalloc(sizeof(*sd->tx));
		if (sd->tx == NULL)
			goto err;
		memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx));
	}

	return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd);
err:
	xfree(sd->tx);
	xfree(sd->rx);
	xfree(sd);
	return -1;
}
Ejemplo n.º 19
0
/*
Filter by network address
*/
bool conditional_filter(struct nlmsghdr *nlh)
{
    struct nfgenmsg *msg;
    msg = (nfgenmsg *)NLMSG_DATA(nlh);

    if (filter_af != 0 && msg->nfgen_family != filter_af)
        return false;

    if (filter == NULL)
    {
        return true;
    }

    //Root data storage
    struct nlattr *tb[CTA_MAX + 1];

    //Pointer to the current tb being queried
    struct nlattr ** tb_cur = tb;
    int err;
    char* data;
    bool ret = true;

    err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, NULL);
    if (err < 0)
        goto out;

    //printf("root: %d\n", CTA_MAX + 1);


    for (int i = 0; i < filter_len; i++)
    {
        cr_filter* f = &filter[i];

        if (f->key == CTA_UNSPEC)
        {
            assert(i != 0);
            //printf("&&\n");
            // &&
            tb_cur = tb;
        }
        else if (f->max != 0)
        {
            //printf("nested: %d, %d\n", f->key, f->max);

            err = nla_parse_nested((struct nlattr **)f->internal, f->max, tb_cur[f->key], NULL);
            if (err < 0)
            {
                return true;//error
            }

            tb_cur = (nlattr **)f->internal;
        }
        else if (f->compare_len != 0)
        {
            //printf("compare len: %d\n", f->compare_len);
            data = (char *)nla_data(tb_cur[f->key]);

            ret = memcmp(data, f->compare, f->compare_len) == 0;
            if (!ret)
            {
                return ret;
            }
        }
    }

out:
    return ret;
}
Ejemplo n.º 20
0
struct rtnl_addr *rtnl_addr_alloc_from_msg(struct nl_msg *msg)
{
	struct nlattr *tb[IFA_MAX+1];
	struct rtnl_addr *addr;
	struct ifaddrmsg *ifa;
	struct nlmsghdr *nlh;
	int err, peer_prefix = 0;

	nlh = nlmsg_hdr(msg);

	addr = rtnl_addr_alloc();
	if (!addr)
		goto errout;

	err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
	if (err < 0)
		goto errout_free;

	ifa = nlmsg_data(nlh);
	addr->a_family = ifa->ifa_family;
	addr->a_prefixlen = ifa->ifa_prefixlen;
	addr->a_flags = ifa->ifa_flags;
	addr->a_scope = ifa->ifa_scope;
	addr->a_ifindex = ifa->ifa_index;

	addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN |
			ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX);

	if (tb[IFA_LABEL]) {
		nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ);
		addr->a_mask |= ADDR_ATTR_LABEL;
	}

	if (tb[IFA_CACHEINFO]) {
		struct ifa_cacheinfo *ca;

		ca = nla_data(tb[IFA_CACHEINFO]);
		addr->a_cacheinfo.aci_prefered = ca->ifa_prefered;
		addr->a_cacheinfo.aci_valid = ca->ifa_valid;
		addr->a_cacheinfo.aci_cstamp = ca->cstamp;
		addr->a_cacheinfo.aci_tstamp = ca->tstamp;
		addr->a_mask |= ADDR_ATTR_CACHEINFO;
	}

	if (tb[IFA_LOCAL]) {
		addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family);
		if (!addr->a_local)
			goto errout_free;
		addr->a_mask |= ADDR_ATTR_LOCAL;
	}

	if (tb[IFA_ADDRESS]) {
		struct nl_addr *a;

		a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family);
		if (!a)
			goto errout_free;

		/* IPv6 sends the local address as IFA_ADDRESS with
		 * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
		 * with IFA_ADDRESS being the peer address if they differ */
		if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
			addr->a_local = a;
			addr->a_mask |= ADDR_ATTR_LOCAL;
		} else {
			addr->a_peer = a;
			addr->a_mask |= ADDR_ATTR_PEER;
			peer_prefix = 1;
		}
	}

	nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local,
			      addr->a_prefixlen);

	if (tb[IFA_BROADCAST]) {
		addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family);
		if (!addr->a_bcast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_BROADCAST;
	}

	if (tb[IFA_ANYCAST]) {
		addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family);
		if (!addr->a_anycast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_ANYCAST;
	}

	if (tb[IFA_MULTICAST]) {
		addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST],
						 addr->a_family);
		if (!addr->a_multicast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_MULTICAST;
	}

	return addr;

errout_free:
	rtnl_addr_free(addr);
errout:
	return NULL;
}
Ejemplo n.º 21
0
static int addr_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
			   void *arg)
{
	struct rtnl_addr *addr;
	struct nl_parser_param *pp = arg;
	struct ifaddrmsg *ifa;
	struct nlattr *tb[IFA_MAX+1];
	int err = -ENOMEM, peer_prefix = 0;

	addr = rtnl_addr_alloc();
	if (!addr) {
		err = nl_errno(ENOMEM);
		goto errout;
	}
	addr->ce_msgtype = nlh->nlmsg_type;

	err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
	if (err < 0)
		goto errout_free;

	ifa = nlmsg_data(nlh);
	addr->a_family = ifa->ifa_family;
	addr->a_prefixlen = ifa->ifa_prefixlen;
	addr->a_flags = ifa->ifa_flags;
	addr->a_scope = ifa->ifa_scope;
	addr->a_ifindex = ifa->ifa_index;

	addr->a_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN |
			ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX);

	if (tb[IFA_LABEL]) {
		nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ);
		addr->a_mask |= ADDR_ATTR_LABEL;
	}

	if (tb[IFA_CACHEINFO]) {
		struct ifa_cacheinfo *ca;
		
		ca = nla_data(tb[IFA_CACHEINFO]);
		addr->a_cacheinfo.aci_prefered = ca->ifa_prefered;
		addr->a_cacheinfo.aci_valid = ca->ifa_valid;
		addr->a_cacheinfo.aci_cstamp = ca->cstamp;
		addr->a_cacheinfo.aci_tstamp = ca->tstamp;
		addr->a_mask |= ADDR_ATTR_CACHEINFO;
	}

	if (tb[IFA_LOCAL]) {
		addr->a_local = nla_get_addr(tb[IFA_LOCAL], addr->a_family);
		if (!addr->a_local)
			goto errout_free;
		addr->a_mask |= ADDR_ATTR_LOCAL;
	}

	if (tb[IFA_ADDRESS]) {
		struct nl_addr *a;

		a = nla_get_addr(tb[IFA_ADDRESS], addr->a_family);
		if (!a)
			goto errout_free;

		/* IPv6 sends the local address as IFA_ADDRESS with
		 * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
		 * with IFA_ADDRESS being the peer address if they differ */
		if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
			nl_addr_put(addr->a_local);
			addr->a_local = a;
			addr->a_mask |= ADDR_ATTR_LOCAL;
		} else {
			addr->a_peer = a;
			addr->a_mask |= ADDR_ATTR_PEER;
			peer_prefix = 1;
		}
	}

	nl_addr_set_prefixlen(peer_prefix ? addr->a_peer : addr->a_local,
			      addr->a_prefixlen);

	if (tb[IFA_BROADCAST]) {
		addr->a_bcast = nla_get_addr(tb[IFA_BROADCAST], addr->a_family);
		if (!addr->a_bcast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_BROADCAST;
	}

	if (tb[IFA_ANYCAST]) {
		addr->a_anycast = nla_get_addr(tb[IFA_ANYCAST], addr->a_family);
		if (!addr->a_anycast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_ANYCAST;
	}

	if (tb[IFA_MULTICAST]) {
		addr->a_multicast = nla_get_addr(tb[IFA_MULTICAST],
						 addr->a_family);
		if (!addr->a_multicast)
			goto errout_free;

		addr->a_mask |= ADDR_ATTR_MULTICAST;
	}

	err = pp->pp_cb((struct nl_object *) addr, pp);
	if (err < 0)
		goto errout_free;

	return P_ACCEPT;

errout_free:
	rtnl_addr_free(addr);
errout:
	return err;
}
Ejemplo n.º 22
0
Archivo: exp.c Proyecto: arend/libnl
int nfnlmsg_exp_parse(struct nlmsghdr *nlh, struct nfnl_exp **result)
{
	struct nfnl_exp *exp;
	struct nlattr *tb[CTA_MAX+1];
	int err;

	exp = nfnl_exp_alloc();
	if (!exp)
		return -NLE_NOMEM;

	exp->ce_msgtype = nlh->nlmsg_type;

	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_EXPECT_MAX,
			  exp_policy);
	if (err < 0)
		goto errout;

	nfnl_exp_set_family(exp, nfnlmsg_family(nlh));

	if (tb[CTA_EXPECT_TUPLE]) {
		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_EXPECT, tb[CTA_EXPECT_TUPLE]);
		if (err < 0)
			goto errout;
	}
	if (tb[CTA_EXPECT_MASTER]) {
		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASTER, tb[CTA_EXPECT_MASTER]);
		if (err < 0)
			goto errout;
	}
	if (tb[CTA_EXPECT_MASK]) {
		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASK, tb[CTA_EXPECT_MASK]);
		if (err < 0)
			goto errout;
	}

	if (tb[CTA_EXPECT_NAT]) {
		err = exp_parse_nat(exp, tb[CTA_EXPECT_MASK]);
		if (err < 0)
			goto errout;
	}

	if (tb[CTA_EXPECT_CLASS])
		nfnl_exp_set_class(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_CLASS])));

	if (tb[CTA_EXPECT_FN])
		nfnl_exp_set_fn(exp, nla_data(tb[CTA_EXPECT_FN]));

	if (tb[CTA_EXPECT_TIMEOUT])
		nfnl_exp_set_timeout(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_TIMEOUT])));

	if (tb[CTA_EXPECT_ID])
		nfnl_exp_set_id(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_ID])));

	if (tb[CTA_EXPECT_HELP_NAME])
		nfnl_exp_set_helper_name(exp, nla_data(tb[CTA_EXPECT_HELP_NAME]));

	if (tb[CTA_EXPECT_ZONE])
		nfnl_exp_set_zone(exp, ntohs(nla_get_u16(tb[CTA_EXPECT_ZONE])));

	if (tb[CTA_EXPECT_FLAGS])
		nfnl_exp_set_flags(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_FLAGS])));

	*result = exp;
	return 0;

errout:
	nfnl_exp_put(exp);
	return err;
}
Ejemplo n.º 23
0
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
{
	struct net *net = sock_net(skb->sk);
	struct nlattr *tca[TCA_MAX + 1];
	spinlock_t *root_lock;
	struct tcmsg *t;
	u32 protocol;
	u32 prio;
	u32 nprio;
	u32 parent;
	struct net_device *dev;
	struct Qdisc  *q;
	struct tcf_proto **back, **chain;
	struct tcf_proto *tp;
	const struct tcf_proto_ops *tp_ops;
	const struct Qdisc_class_ops *cops;
	unsigned long cl;
	unsigned long fh;
	int err;
	int tp_created = 0;

	if ((n->nlmsg_type != RTM_GETTFILTER) &&
	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
		return -EPERM;

replay:
	err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL);
	if (err < 0)
		return err;

	t = nlmsg_data(n);
	protocol = TC_H_MIN(t->tcm_info);
	prio = TC_H_MAJ(t->tcm_info);
	nprio = prio;
	parent = t->tcm_parent;
	cl = 0;

	if (prio == 0) {
		/* If no priority is given, user wants we allocated it. */
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
			return -ENOENT;
		prio = TC_H_MAKE(0x80000000U, 0U);
	}

	/* Find head of filter chain. */

	/* Find link */
	dev = __dev_get_by_index(net, t->tcm_ifindex);
	if (dev == NULL)
		return -ENODEV;

	/* Find qdisc */
	if (!parent) {
		q = dev->qdisc;
		parent = q->handle;
	} else {
		q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
		if (q == NULL)
			return -EINVAL;
	}

	/* Is it classful? */
	cops = q->ops->cl_ops;
	if (!cops)
		return -EINVAL;

	if (cops->tcf_chain == NULL)
		return -EOPNOTSUPP;

	/* Do we search for filter, attached to class? */
	if (TC_H_MIN(parent)) {
		cl = cops->get(q, parent);
		if (cl == 0)
			return -ENOENT;
	}

	/* And the last stroke */
	chain = cops->tcf_chain(q, cl);
	err = -EINVAL;
	if (chain == NULL)
		goto errout;

	/* Check the chain for existence of proto-tcf with this priority */
	for (back = chain; (tp = *back) != NULL; back = &tp->next) {
		if (tp->prio >= prio) {
			if (tp->prio == prio) {
				if (!nprio ||
				    (tp->protocol != protocol && protocol))
					goto errout;
			} else
				tp = NULL;
			break;
		}
	}

	root_lock = qdisc_root_sleeping_lock(q);

	if (tp == NULL) {
		/* Proto-tcf does not exist, create new one */

		if (tca[TCA_KIND] == NULL || !protocol)
			goto errout;

		err = -ENOENT;
		if (n->nlmsg_type != RTM_NEWTFILTER ||
		    !(n->nlmsg_flags & NLM_F_CREATE))
			goto errout;


		/* Create new proto tcf */

		err = -ENOBUFS;
		tp = kzalloc(sizeof(*tp), GFP_KERNEL);
		if (tp == NULL)
			goto errout;
		err = -ENOENT;
		tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]);
		if (tp_ops == NULL) {
#ifdef CONFIG_MODULES
			struct nlattr *kind = tca[TCA_KIND];
			char name[IFNAMSIZ];

			if (kind != NULL &&
			    nla_strlcpy(name, kind, IFNAMSIZ) < IFNAMSIZ) {
				rtnl_unlock();
				request_module("cls_%s", name);
				rtnl_lock();
				tp_ops = tcf_proto_lookup_ops(kind);
				/* We dropped the RTNL semaphore in order to
				 * perform the module load.  So, even if we
				 * succeeded in loading the module we have to
				 * replay the request.  We indicate this using
				 * -EAGAIN.
				 */
				if (tp_ops != NULL) {
					module_put(tp_ops->owner);
					err = -EAGAIN;
				}
			}
#endif
			kfree(tp);
			goto errout;
		}
		tp->ops = tp_ops;
		tp->protocol = protocol;
		tp->prio = nprio ? : TC_H_MAJ(tcf_auto_prio(*back));
		tp->q = q;
		tp->classify = tp_ops->classify;
		tp->classid = parent;

		err = tp_ops->init(tp);
		if (err != 0) {
			module_put(tp_ops->owner);
			kfree(tp);
			goto errout;
		}

		tp_created = 1;

	} else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind))
Ejemplo n.º 24
0
/**
 * virNetlinkCommand:
 * @nlmsg: pointer to netlink message
 * @respbuf: pointer to pointer where response buffer will be allocated
 * @respbuflen: pointer to integer holding the size of the response buffer
 *      on return of the function.
 * @src_pid: the pid of the process to send a message
 * @dst_pid: the pid of the process to talk to, i.e., pid = 0 for kernel
 * @protocol: netlink protocol
 * @groups: the group identifier
 *
 * Send the given message to the netlink layer and receive response.
 * Returns 0 on success, -1 on error. In case of error, no response
 * buffer will be returned.
 */
int virNetlinkCommand(struct nl_msg *nl_msg,
                      struct nlmsghdr **resp, unsigned int *respbuflen,
                      uint32_t src_pid, uint32_t dst_pid,
                      unsigned int protocol, unsigned int groups)
{
    int ret = -1;
    struct sockaddr_nl nladdr = {
            .nl_family = AF_NETLINK,
            .nl_pid    = dst_pid,
            .nl_groups = 0,
    };
    ssize_t nbytes;
    struct pollfd fds[1];
    int fd;
    int n;
    struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
    virNetlinkHandle *nlhandle = NULL;
    int len = 0;

    if (protocol >= MAX_LINKS) {
        virReportSystemError(EINVAL,
                             _("invalid protocol argument: %d"), protocol);
        goto cleanup;
    }

    if (!(nlhandle = virNetlinkCreateSocket(protocol)))
        goto cleanup;

    fd = nl_socket_get_fd(nlhandle);
    if (fd < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot get netlink socket fd"));
        goto cleanup;
    }

    if (groups && nl_socket_add_membership(nlhandle, groups) < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot add netlink membership"));
        goto cleanup;
    }

    nlmsg_set_dst(nl_msg, &nladdr);

    nlmsg->nlmsg_pid = src_pid ? src_pid : getpid();

    nbytes = nl_send_auto_complete(nlhandle, nl_msg);
    if (nbytes < 0) {
        virReportSystemError(errno,
                             "%s", _("cannot send to netlink socket"));
        goto cleanup;
    }

    memset(fds, 0, sizeof(fds));
    fds[0].fd = fd;
    fds[0].events = POLLIN;

    n = poll(fds, ARRAY_CARDINALITY(fds), NETLINK_ACK_TIMEOUT_S);
    if (n <= 0) {
        if (n < 0)
            virReportSystemError(errno, "%s",
                                 _("error in poll call"));
        if (n == 0)
            virReportSystemError(ETIMEDOUT, "%s",
                                 _("no valid netlink response was received"));
        goto cleanup;
    }

    len = nl_recv(nlhandle, &nladdr, (unsigned char **)resp, NULL);
    if (len == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("nl_recv failed - returned 0 bytes"));
        goto cleanup;
    }
    if (len < 0) {
        virReportSystemError(errno, "%s", _("nl_recv failed"));
        goto cleanup;
    }

    ret = 0;
    *respbuflen = len;
 cleanup:
    if (ret < 0) {
        *resp = NULL;
        *respbuflen = 0;
    }

    virNetlinkFree(nlhandle);
    return ret;
}


/**
 * virNetlinkDumpLink:
 *
 * @ifname:  The name of the interface; only use if ifindex <= 0
 * @ifindex: The interface index; may be <= 0 if ifname is given
 * @data:    Gets a pointer to the raw data from netlink.
             MUST BE FREED BY CALLER!
 * @nlattr:  Pointer to a pointer of netlink attributes that will contain
 *           the results
 * @src_pid: pid used for nl_pid of the local end of the netlink message
 *           (0 == "use getpid()")
 * @dst_pid: pid of destination nl_pid if the kernel
 *           is not the target of the netlink message but it is to be
 *           sent to another process (0 if sending to the kernel)
 *
 * Get information from netlink about an interface given its name or index.
 *
 * Returns 0 on success, -1 on fatal error.
 */
int
virNetlinkDumpLink(const char *ifname, int ifindex,
                   void **nlData, struct nlattr **tb,
                   uint32_t src_pid, uint32_t dst_pid)
{
    int rc = -1;
    struct nlmsghdr *resp = NULL;
    struct nlmsgerr *err;
    struct ifinfomsg ifinfo = {
        .ifi_family = AF_UNSPEC,
        .ifi_index  = ifindex
    };
    unsigned int recvbuflen;
    struct nl_msg *nl_msg;

    if (ifname && ifindex <= 0 && virNetDevGetIndex(ifname, &ifindex) < 0)
        return -1;

    ifinfo.ifi_index = ifindex;

    nl_msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
    if (!nl_msg) {
        virReportOOMError();
        return -1;
    }

    if (nlmsg_append(nl_msg,  &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
        goto buffer_too_small;

    if (ifname) {
        if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
            goto buffer_too_small;
    }

# ifdef RTEXT_FILTER_VF
    /* if this filter exists in the kernel's netlink implementation,
     * we need to set it, otherwise the response message will not
     * contain the IFLA_VFINFO_LIST that we're looking for.
     */
    {
        uint32_t ifla_ext_mask = RTEXT_FILTER_VF;

        if (nla_put(nl_msg, IFLA_EXT_MASK,
                    sizeof(ifla_ext_mask), &ifla_ext_mask) < 0) {
            goto buffer_too_small;
        }
    }
# endif

    if (virNetlinkCommand(nl_msg, &resp, &recvbuflen,
                          src_pid, dst_pid, NETLINK_ROUTE, 0) < 0)
        goto cleanup;

    if (recvbuflen < NLMSG_LENGTH(0) || resp == NULL)
        goto malformed_resp;

    switch (resp->nlmsg_type) {
    case NLMSG_ERROR:
        err = (struct nlmsgerr *)NLMSG_DATA(resp);
        if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err)))
            goto malformed_resp;

        if (err->error) {
            virReportSystemError(-err->error,
                                 _("error dumping %s (%d) interface"),
                                 ifname, ifindex);
            goto cleanup;
        }
        break;

    case GENL_ID_CTRL:
    case NLMSG_DONE:
        rc = nlmsg_parse(resp, sizeof(struct ifinfomsg),
                         tb, IFLA_MAX, NULL);
        if (rc < 0)
            goto malformed_resp;
        break;

    default:
        goto malformed_resp;
    }
    rc = 0;
 cleanup:
    nlmsg_free(nl_msg);
    if (rc < 0)
       VIR_FREE(resp);
    *nlData = resp;
    return rc;

 malformed_resp:
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("malformed netlink response message"));
    goto cleanup;

 buffer_too_small:
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("allocated netlink buffer is too small"));
    goto cleanup;
}
Ejemplo n.º 25
0
/*
Extract a field
*/
bool cr_extract_field(cr_filter* filter,
                      int filter_len,
                      struct nlmsghdr *nlh,
                      void* output, int output_len) {
    struct nfgenmsg *msg;
    msg = (nfgenmsg *)NLMSG_DATA(nlh);


    //Root data storage
    struct nlattr *tb[CTA_MAX + 1];
    struct nlattr ** tb_buf;

    //Pointer to the current tb being queried
    struct nlattr ** tb_cur = tb;
    int err;
    char* data;

    err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX, NULL);
    if (err < 0)
        return false;

    for (int i = 0; i < filter_len; i++)
    {
        cr_filter* f = &filter[i];

        if (f->max != 0)
        {
            if (tb_cur[f->key] == NULL) {
                goto free_err;
            }
            tb_buf = (struct nlattr **)malloc(sizeof(struct nlattr *) * (f->max + 1));
            err = nla_parse_nested(tb_buf, f->max, tb_cur[f->key], NULL);
            if (err < 0)
            {
                goto free_err;
            }

            if (tb_cur != tb) {
                free(tb_cur);
            }
            tb_cur = tb_buf;
        }
        else
        {
            //printf("compare len: %d\n", f->compare_len);
            data = (char *)nla_data(tb_cur[f->key]);
            if (data == NULL) {
                goto free_err;
            }
            memcpy(output, data, output_len);
            if (tb_cur != tb) {
                free(tb_cur);
            }
            return true;
        }
    }
free_err:

    if (tb_cur != tb) {
        free(tb_cur);
    }

    return false;
}
Ejemplo n.º 26
0
int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
{
	struct nfnl_ct *ct;
	struct nlattr *tb[CTA_MAX+1];
	int err;

	ct = nfnl_ct_alloc();
	if (!ct)
		return -NLE_NOMEM;

	ct->ce_msgtype = nlh->nlmsg_type;

	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
			  ct_policy);
	if (err < 0)
		goto errout;

	nfnl_ct_set_family(ct, nfnlmsg_family(nlh));

	if (tb[CTA_TUPLE_ORIG]) {
		err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
		if (err < 0)
			goto errout;
	}
	if (tb[CTA_TUPLE_REPLY]) {
		err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
		if (err < 0)
			goto errout;
	}

	if (tb[CTA_PROTOINFO]) {
		err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
		if (err < 0)
			goto errout;
	}

	if (tb[CTA_STATUS])
		nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
	if (tb[CTA_TIMEOUT])
		nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
	if (tb[CTA_MARK])
		nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
	if (tb[CTA_USE])
		nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
	if (tb[CTA_ID])
		nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
	if (tb[CTA_ZONE])
		nfnl_ct_set_zone(ct, ntohs(nla_get_u16(tb[CTA_ZONE])));

	if (tb[CTA_COUNTERS_ORIG]) {
		err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
		if (err < 0)
			goto errout;
	}

	if (tb[CTA_COUNTERS_REPLY]) {
		err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
		if (err < 0)
			goto errout;
	}

	if (tb[CTA_TIMESTAMP]) {
		err = ct_parse_timestamp(ct, tb[CTA_TIMESTAMP]);
		if (err < 0)
			goto errout;
	}

	*result = ct;
	return 0;

errout:
	nfnl_ct_put(ct);
	return err;
}
static void copy_cacheinfo_into_route(struct rta_cacheinfo *ci,
				      struct rtnl_route *route)
{
	struct rtnl_rtcacheinfo nci = {
		.rtci_clntref  = ci->rta_clntref,
		.rtci_last_use = ci->rta_lastuse,
		.rtci_expires  = ci->rta_expires,
		.rtci_error    = ci->rta_error,
		.rtci_used     = ci->rta_used,
		.rtci_id       = ci->rta_id,
		.rtci_ts       = ci->rta_ts,
		.rtci_tsage    = ci->rta_tsage,
	};

	rtnl_route_set_cacheinfo(route, &nci);
}

static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
			    struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
	struct rtmsg *rtm;
	struct rtnl_route *route;
	struct nlattr *tb[RTA_MAX + 1];
	struct nl_addr *src = NULL, *dst = NULL, *addr;
	int err;

	route = rtnl_route_alloc();
	if (!route) {
		err = nl_errno(ENOMEM);
		goto errout;
	}

	route->ce_msgtype = nlh->nlmsg_type;

	err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
			  route_policy);
	if (err < 0)
		goto errout;

	rtm = nlmsg_data(nlh);
	rtnl_route_set_family(route, rtm->rtm_family);
	rtnl_route_set_tos(route, rtm->rtm_tos);
	rtnl_route_set_table(route, rtm->rtm_table);
	rtnl_route_set_type(route, rtm->rtm_type);
	rtnl_route_set_scope(route, rtm->rtm_scope);
	rtnl_route_set_protocol(route, rtm->rtm_protocol);
	rtnl_route_set_flags(route, rtm->rtm_flags);

	if (tb[RTA_DST]) {
		dst = nla_get_addr(tb[RTA_DST], rtm->rtm_family);
		if (dst == NULL)
			goto errout_errno;
	} else {
		dst = nl_addr_alloc(0);
		nl_addr_set_family(dst, rtm->rtm_family);
	}

	nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
	err = rtnl_route_set_dst(route, dst);
	if (err < 0)
		goto errout;

	nl_addr_put(dst);

	if (tb[RTA_SRC]) {
		src = nla_get_addr(tb[RTA_SRC], rtm->rtm_family);
		if (src == NULL)
			goto errout_errno;
	} else if (rtm->rtm_src_len)
		src = nl_addr_alloc(0);

	if (src) {
		nl_addr_set_prefixlen(src, rtm->rtm_src_len);
		rtnl_route_set_src(route, src);
		nl_addr_put(src);
	}

	if (tb[RTA_IIF])
		rtnl_route_set_iif(route, nla_get_string(tb[RTA_IIF]));

	if (tb[RTA_OIF])
		rtnl_route_set_oif(route, nla_get_u32(tb[RTA_OIF]));

	if (tb[RTA_GATEWAY]) {
		addr = nla_get_addr(tb[RTA_GATEWAY], route->rt_family);
		if (addr == NULL)
			goto errout_errno;
		rtnl_route_set_gateway(route, addr);
		nl_addr_put(addr);
	}

	if (tb[RTA_PRIORITY])
		rtnl_route_set_prio(route, nla_get_u32(tb[RTA_PRIORITY]));

	if (tb[RTA_PREFSRC]) {
		addr = nla_get_addr(tb[RTA_PREFSRC], route->rt_family);
		if (addr == NULL)
			goto errout_errno;
		rtnl_route_set_pref_src(route, addr);
		nl_addr_put(addr);
	}

	if (tb[RTA_METRICS]) {
		struct nlattr *mtb[RTAX_MAX + 1];
		int i;

		err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
		if (err < 0)
			goto errout;

		for (i = 1; i <= RTAX_MAX; i++) {
			if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
				uint32_t m = nla_get_u32(mtb[i]);
				if (rtnl_route_set_metric(route, i, m) < 0)
					goto errout_errno;
			}
		}
	}

	if (tb[RTA_MULTIPATH]) {
		struct rtnl_nexthop *nh;
		struct rtnexthop *rtnh = nla_data(tb[RTA_MULTIPATH]);
		size_t tlen = nla_len(tb[RTA_MULTIPATH]);

		while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
			nh = rtnl_route_nh_alloc();
			if (!nh)
				goto errout;

			rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
			rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
			rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);

			if (rtnh->rtnh_len > sizeof(*rtnh)) {
				struct nlattr *ntb[RTA_MAX + 1];
				nla_parse(ntb, RTA_MAX, (struct nlattr *)
					  RTNH_DATA(rtnh),
					  rtnh->rtnh_len - sizeof(*rtnh),
					  route_policy);

				if (ntb[RTA_GATEWAY]) {
					nh->rtnh_gateway = nla_get_addr(
							ntb[RTA_GATEWAY],
							route->rt_family);
					nh->rtnh_mask = NEXTHOP_HAS_GATEWAY;
				}
			}

			rtnl_route_add_nexthop(route, nh);
			tlen -= RTNH_ALIGN(rtnh->rtnh_len);
			rtnh = RTNH_NEXT(rtnh);
		}
	}

	if (tb[RTA_FLOW])
		rtnl_route_set_realms(route, nla_get_u32(tb[RTA_FLOW]));

	if (tb[RTA_CACHEINFO])
		copy_cacheinfo_into_route(nla_data(tb[RTA_CACHEINFO]), route);

	if (tb[RTA_MP_ALGO])
		rtnl_route_set_mp_algo(route, nla_get_u32(tb[RTA_MP_ALGO]));

	err = pp->pp_cb((struct nl_object *) route, pp);
	if (err < 0)
		goto errout;

	err = P_ACCEPT;

errout:
	rtnl_route_put(route);
	return err;

errout_errno:
	err = nl_get_errno();
	goto errout;
}

static int route_request_update(struct nl_cache *c, struct nl_handle *h)
{
	return nl_rtgen_request(h, RTM_GETROUTE, AF_UNSPEC, NLM_F_DUMP);
}

/**
 * @name Cache Management
 * @{
 */

/**
 * Build a route cache holding all routes currently configured in the kernel
 * @arg handle		netlink handle
 *
 * Allocates a new cache, initializes it properly and updates it to
 * contain all routes currently configured in the kernel.
 *
 * @note The caller is responsible for destroying and freeing the
 *       cache after using it.
 * @return The cache or NULL if an error has occured.
 */
struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle)
{
	struct nl_cache *cache;

	cache = nl_cache_alloc(&rtnl_route_ops);
	if (!cache)
		return NULL;

	if (handle && nl_cache_refill(handle, cache) < 0) {
		free(cache);
		return NULL;
	}

	return cache;
}

/** @} */

/**
 * @name Route Addition
 * @{
 */

static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
				      int flags)
{
	struct nl_msg *msg;
	struct nl_addr *addr;
	int scope, i, oif, nmetrics = 0;
	struct nlattr *metrics;
	struct rtmsg rtmsg = {
		.rtm_family = rtnl_route_get_family(tmpl),
		.rtm_dst_len = rtnl_route_get_dst_len(tmpl),
		.rtm_src_len = rtnl_route_get_src_len(tmpl),
		.rtm_tos = rtnl_route_get_tos(tmpl),
		.rtm_table = rtnl_route_get_table(tmpl),
		.rtm_type = rtnl_route_get_type(tmpl),
		.rtm_protocol = rtnl_route_get_protocol(tmpl),
		.rtm_flags = rtnl_route_get_flags(tmpl),
	};

	if (rtmsg.rtm_family == AF_UNSPEC) {
		nl_error(EINVAL, "Cannot build route message, address " \
				 "family is unknown.");
		return NULL;
	}

	scope = rtnl_route_get_scope(tmpl);
	if (scope == RT_SCOPE_NOWHERE) {
		if (rtmsg.rtm_type == RTN_LOCAL)
			scope = RT_SCOPE_HOST;
		else {
			/* XXX Change to UNIVERSE if gw || nexthops */
			scope = RT_SCOPE_LINK;
		}
	}

	rtmsg.rtm_scope = scope;

	msg = nlmsg_alloc_simple(cmd, flags);
	if (msg == NULL)
		return NULL;

	if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
		goto nla_put_failure;

	addr = rtnl_route_get_dst(tmpl);
	if (addr)
		NLA_PUT_ADDR(msg, RTA_DST, addr);

	addr = rtnl_route_get_src(tmpl);
	if (addr)
		NLA_PUT_ADDR(msg, RTA_SRC, addr);

	addr = rtnl_route_get_gateway(tmpl);
	if (addr)
		NLA_PUT_ADDR(msg, RTA_GATEWAY, addr);

	addr = rtnl_route_get_pref_src(tmpl);
	if (addr)
		NLA_PUT_ADDR(msg, RTA_PREFSRC, addr);

	NLA_PUT_U32(msg, RTA_PRIORITY, rtnl_route_get_prio(tmpl));

	oif = rtnl_route_get_oif(tmpl);
	if (oif != RTNL_LINK_NOT_FOUND)
		NLA_PUT_U32(msg, RTA_OIF, oif);

	for (i = 1; i <= RTAX_MAX; i++)
		if (rtnl_route_get_metric(tmpl, i) != UINT_MAX)
			nmetrics++;

	if (nmetrics > 0) {
		unsigned int val;

		metrics = nla_nest_start(msg, RTA_METRICS);
		if (metrics == NULL)
			goto nla_put_failure;

		for (i = 1; i <= RTAX_MAX; i++) {
			val = rtnl_route_get_metric(tmpl, i);
			if (val != UINT_MAX)
				NLA_PUT_U32(msg, i, val);
		}

		nla_nest_end(msg, metrics);
	}

#if 0
	RTA_IIF,
	RTA_MULTIPATH,
	RTA_PROTOINFO,
	RTA_FLOW,
	RTA_CACHEINFO,
	RTA_SESSION,
	RTA_MP_ALGO,
#endif

	return msg;

nla_put_failure:
	nlmsg_free(msg);
	return NULL;
}

struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
{
	return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
}

int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route,
		   int flags)
{
	struct nl_msg *msg;
	int err;

	msg = rtnl_route_build_add_request(route, flags);
	if (!msg)
		return nl_get_errno();

	err = nl_send_auto_complete(handle, msg);
	nlmsg_free(msg);
	if (err < 0)
		return err;

	return nl_wait_for_ack(handle);
}

struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags)
{
	return build_route_msg(tmpl, RTM_DELROUTE, flags);
}

int rtnl_route_del(struct nl_handle *handle, struct rtnl_route *route,
		   int flags)
{
	struct nl_msg *msg;
	int err;

	msg = rtnl_route_build_del_request(route, flags);
	if (!msg)
		return nl_get_errno();

	err = nl_send_auto_complete(handle, msg);
	nlmsg_free(msg);
	if (err < 0)
		return err;

	return nl_wait_for_ack(handle);
}

/** @} */

static struct nl_af_group route_groups[] = {
	{ AF_INET,	RTNLGRP_IPV4_ROUTE },
	{ AF_INET6,	RTNLGRP_IPV6_ROUTE },
	{ AF_DECnet,	RTNLGRP_DECnet_ROUTE },
	{ END_OF_GROUP_LIST },
};

static struct nl_cache_ops rtnl_route_ops = {
	.co_name		= "route/route",
	.co_hdrsize		= sizeof(struct rtmsg),
	.co_msgtypes		= {
					{ RTM_NEWROUTE, NL_ACT_NEW, "new" },
					{ RTM_DELROUTE, NL_ACT_DEL, "del" },
					{ RTM_GETROUTE, NL_ACT_GET, "get" },
					END_OF_MSGTYPES_LIST,
				  },
	.co_protocol		= NETLINK_ROUTE,
	.co_groups		= route_groups,
	.co_request_update	= route_request_update,
	.co_msg_parser		= route_msg_parser,
	.co_obj_ops		= &route_obj_ops,
};

static void __init route_init(void)
{
	nl_cache_mngt_register(&rtnl_route_ops);
}

static void __exit route_exit(void)
{
	nl_cache_mngt_unregister(&rtnl_route_ops);
}
Ejemplo n.º 28
0
static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct net_device *dev;
	int err, send_addr_notify = 0, modified = 0;
	struct nlattr *tb[IFLA_MAX+1];
	char ifname[IFNAMSIZ];

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
	if (err < 0)
		goto errout;

	if (tb[IFLA_IFNAME])
		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
	else
		ifname[0] = '\0';

	err = -EINVAL;
	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index > 0)
		dev = dev_get_by_index(ifm->ifi_index);
	else if (tb[IFLA_IFNAME])
		dev = dev_get_by_name(ifname);
	else
		goto errout;

	if (dev == NULL) {
		err = -ENODEV;
		goto errout;
	}

	if (tb[IFLA_ADDRESS] &&
	    nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
		goto errout_dev;

	if (tb[IFLA_BROADCAST] &&
	    nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
		goto errout_dev;

	if (tb[IFLA_MAP]) {
		struct rtnl_link_ifmap *u_map;
		struct ifmap k_map;

		if (!dev->set_config) {
			err = -EOPNOTSUPP;
			goto errout_dev;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto errout_dev;
		}

		u_map = nla_data(tb[IFLA_MAP]);
		k_map.mem_start = (unsigned long) u_map->mem_start;
		k_map.mem_end = (unsigned long) u_map->mem_end;
		k_map.base_addr = (unsigned short) u_map->base_addr;
		k_map.irq = (unsigned char) u_map->irq;
		k_map.dma = (unsigned char) u_map->dma;
		k_map.port = (unsigned char) u_map->port;

		err = dev->set_config(dev, &k_map);
		if (err < 0)
			goto errout_dev;

		modified = 1;
	}

	if (tb[IFLA_ADDRESS]) {
		struct sockaddr *sa;
		int len;

		if (!dev->set_mac_address) {
			err = -EOPNOTSUPP;
			goto errout_dev;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto errout_dev;
		}

		len = sizeof(sa_family_t) + dev->addr_len;
		sa = kmalloc(len, GFP_KERNEL);
		if (!sa) {
			err = -ENOMEM;
			goto errout_dev;
		}
		sa->sa_family = dev->type;
		memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
		       dev->addr_len);
		err = dev->set_mac_address(dev, sa);
		kfree(sa);
		if (err)
			goto errout_dev;
		send_addr_notify = 1;
		modified = 1;
	}

	if (tb[IFLA_MTU]) {
		err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
		if (err < 0)
			goto errout_dev;
		modified = 1;
	}

	/*
	 * Interface selected by interface index but interface
	 * name provided implies that a name change has been
	 * requested.
	 */
	if (ifm->ifi_index > 0 && ifname[0]) {
		err = dev_change_name(dev, ifname);
		if (err < 0)
			goto errout_dev;
		modified = 1;
	}

	if (tb[IFLA_BROADCAST]) {
		nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
		send_addr_notify = 1;
	}


	if (ifm->ifi_flags || ifm->ifi_change) {
		unsigned int flags = ifm->ifi_flags;

		/* bugwards compatibility: ifi_change == 0 is treated as ~0 */
		if (ifm->ifi_change)
			flags = (flags & ifm->ifi_change) |
				(dev->flags & ~ifm->ifi_change);
		dev_change_flags(dev, flags);
	}

	if (tb[IFLA_TXQLEN])
		dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);

	if (tb[IFLA_WEIGHT])
		dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);

	if (tb[IFLA_OPERSTATE])
		set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));

	if (tb[IFLA_LINKMODE]) {
		write_lock_bh(&dev_base_lock);
		dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
		write_unlock_bh(&dev_base_lock);
	}

	err = 0;

errout_dev:
	if (err < 0 && modified && net_ratelimit())
		printk(KERN_WARNING "A link change request failed with "
		       "some changes comitted already. Interface %s may "
		       "have been left with an inconsistent configuration, "
		       "please check.\n", dev->name);

	if (send_addr_notify)
		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);

	dev_put(dev);
errout:
	return err;
}
Ejemplo n.º 29
0
static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
{
	struct nlattr *tb[IFA_MAX+1];
	struct in_ifaddr *ifa;
	struct ifaddrmsg *ifm;
	struct net_device *dev;
	struct in_device *in_dev;
	int err;

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
	if (err < 0)
		goto errout;

	ifm = nlmsg_data(nlh);
	err = -EINVAL;
	if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL)
		goto errout;

	dev = __dev_get_by_index(net, ifm->ifa_index);
	err = -ENODEV;
	if (dev == NULL)
		goto errout;

	in_dev = __in_dev_get_rtnl(dev);
	err = -ENOBUFS;
	if (in_dev == NULL)
		goto errout;

	ifa = inet_alloc_ifa();
	if (ifa == NULL)
		/*
		 * A potential indev allocation can be left alive, it stays
		 * assigned to its device and is destroy with it.
		 */
		goto errout;

	ipv4_devconf_setall(in_dev);
	in_dev_hold(in_dev);

	if (tb[IFA_ADDRESS] == NULL)
		tb[IFA_ADDRESS] = tb[IFA_LOCAL];

	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
	ifa->ifa_flags = ifm->ifa_flags;
	ifa->ifa_scope = ifm->ifa_scope;
	ifa->ifa_dev = in_dev;

	ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
	ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);

	if (tb[IFA_BROADCAST])
		ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);

	if (tb[IFA_LABEL])
		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
	else
		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);

	return ifa;

errout:
	return ERR_PTR(err);
}
Ejemplo n.º 30
0
static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
			   struct nlmsghdr *n, struct nl_parser_param *pp)
{
	struct rtnl_rule *rule;
	struct rtmsg *r;
	struct nlattr *tb[RTA_MAX+1];
	int err = 1, family;

	rule = rtnl_rule_alloc();
	if (!rule) {
		err = -NLE_NOMEM;
		goto errout;
	}

	rule->ce_msgtype = n->nlmsg_type;
	r = nlmsg_data(n);

	err = nlmsg_parse(n, sizeof(*r), tb, RTA_MAX, rule_policy);
	if (err < 0)
		goto errout;

	rule->r_family = family = r->rtm_family;
	rule->r_type = r->rtm_type;
	rule->r_dsfield = r->rtm_tos;
	rule->r_src_len = r->rtm_src_len;
	rule->r_dst_len = r->rtm_dst_len;
	rule->r_table = r->rtm_table;
	rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TYPE | RULE_ATTR_DSFIELD |
			 RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE |
			 RULE_ATTR_TABLE);

	if (tb[RTA_PRIORITY]) {
		rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]);
		rule->ce_mask |= RULE_ATTR_PRIO;
	}

	if (tb[RTA_SRC]) {
		if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
			goto errout_enomem;
		nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len);
		rule->ce_mask |= RULE_ATTR_SRC;
	}

	if (tb[RTA_DST]) {
		if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
			goto errout_enomem;
		nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len);
		rule->ce_mask |= RULE_ATTR_DST;
	}

	if (tb[RTA_PROTOINFO]) {
		rule->r_mark = nla_get_u32(tb[RTA_PROTOINFO]);
		rule->ce_mask |= RULE_ATTR_MARK;
	}

	if (tb[RTA_IIF]) {
		nla_strlcpy(rule->r_iif, tb[RTA_IIF], IFNAMSIZ);
		rule->ce_mask |= RULE_ATTR_IIF;
	}

	if (tb[RTA_FLOW]) {
		rule->r_realms = nla_get_u32(tb[RTA_FLOW]);
		rule->ce_mask |= RULE_ATTR_REALMS;
	}

	if (tb[RTA_GATEWAY]) {
		rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family);
		if (!rule->r_srcmap)
			goto errout_enomem;
		rule->ce_mask |= RULE_ATTR_SRCMAP;
	}

	if (tb[RTA_TABLE]) {
            rule->r_table = nla_get_u32(tb[RTA_TABLE]);
            rule->ce_mask |= RULE_ATTR_TABLE;
        }

	err = pp->pp_cb((struct nl_object *) rule, pp);
errout:
	rtnl_rule_put(rule);
	return err;

errout_enomem:
	err = -NLE_NOMEM;
	goto errout;
}