}
EXPORT_SYMBOL(__neigh_for_each_release);
-int neigh_xmit(int family, struct net_device *dev,
+int neigh_xmit(int index, struct net_device *dev,
const void *addr, struct sk_buff *skb)
{
- int err;
- if (family == AF_PACKET) {
- err = dev_hard_header(skb, dev, ntohs(skb->protocol),
- addr, NULL, skb->len);
- if (err < 0)
- goto out_kfree_skb;
- err = dev_queue_xmit(skb);
- } else {
+ int err = -EAFNOSUPPORT;
+ if (likely(index < NEIGH_NR_TABLES)) {
struct neigh_table *tbl;
struct neighbour *neigh;
- err = -ENETDOWN;
- tbl = neigh_find_table(family);
+ tbl = neigh_tables[index];
if (!tbl)
goto out;
neigh = __neigh_lookup_noref(tbl, addr, dev);
goto out_kfree_skb;
err = neigh->output(neigh, skb);
}
+ else if (index == NEIGH_LINK_TABLE) {
+ err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+ addr, NULL, skb->len);
+ if (err < 0)
+ goto out_kfree_skb;
+ err = dev_queue_xmit(skb);
+ }
out:
return err;
out_kfree_skb:
struct rcu_head rt_rcu;
u32 rt_label[MAX_NEW_LABELS];
u8 rt_protocol; /* routing protocol that set this entry */
- u8 rt_labels:2,
- rt_via_alen:6;
- unsigned short rt_via_family;
+ u8 rt_labels;
+ u8 rt_via_alen;
+ u8 rt_via_table;
u8 rt_via[0];
};
}
}
- err = neigh_xmit(rt->rt_via_family, out_dev, rt->rt_via, skb);
+ err = neigh_xmit(rt->rt_via_table, out_dev, rt->rt_via, skb);
if (err)
net_dbg_ratelimited("%s: packet transmission failed: %d\n",
__func__, err);
struct mpls_route_config {
u32 rc_protocol;
u32 rc_ifindex;
- u16 rc_via_family;
+ u16 rc_via_table;
u16 rc_via_alen;
u8 rc_via[MAX_VIA_ALEN];
u32 rc_label;
goto errout;
err = -EINVAL;
- if ((cfg->rc_via_family == AF_PACKET) &&
+ if ((cfg->rc_via_table == NEIGH_LINK_TABLE) &&
(dev->addr_len != cfg->rc_via_alen))
goto errout;
rt->rt_label[i] = cfg->rc_output_label[i];
rt->rt_protocol = cfg->rc_protocol;
RCU_INIT_POINTER(rt->rt_dev, dev);
- rt->rt_via_family = cfg->rc_via_family;
+ rt->rt_via_table = cfg->rc_via_table;
memcpy(rt->rt_via, cfg->rc_via, cfg->rc_via_alen);
mpls_route_update(net, index, NULL, rt, &cfg->rc_nlinfo);
};
static int nla_put_via(struct sk_buff *skb,
- u16 family, const void *addr, int alen)
+ u8 table, const void *addr, int alen)
{
+ static const int table_to_family[NEIGH_NR_TABLES + 1] = {
+ AF_INET, AF_INET6, AF_DECnet, AF_PACKET,
+ };
struct nlattr *nla;
struct rtvia *via;
+ int family = AF_UNSPEC;
nla = nla_reserve(skb, RTA_VIA, alen + 2);
if (!nla)
return -EMSGSIZE;
+ if (table <= NEIGH_NR_TABLES)
+ family = table_to_family[table];
+
via = nla_data(nla);
via->rtvia_family = family;
memcpy(via->rtvia_addr, addr, alen);
struct rtvia *via = nla_data(nla);
if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
goto errout;
- cfg->rc_via_family = via->rtvia_family;
cfg->rc_via_alen = nla_len(nla) -
offsetof(struct rtvia, rtvia_addr);
if (cfg->rc_via_alen > MAX_VIA_ALEN)
goto errout;
/* Validate the address family */
- switch(cfg->rc_via_family) {
+ switch(via->rtvia_family) {
case AF_PACKET:
+ cfg->rc_via_table = NEIGH_LINK_TABLE;
break;
case AF_INET:
+ cfg->rc_via_table = NEIGH_ARP_TABLE;
if (cfg->rc_via_alen != 4)
goto errout;
break;
case AF_INET6:
+ cfg->rc_via_table = NEIGH_ND_TABLE;
if (cfg->rc_via_alen != 16)
goto errout;
break;
if (rt->rt_labels &&
nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label))
goto nla_put_failure;
- if (nla_put_via(skb, rt->rt_via_family, rt->rt_via, rt->rt_via_alen))
+ if (nla_put_via(skb, rt->rt_via_table, rt->rt_via, rt->rt_via_alen))
goto nla_put_failure;
dev = rtnl_dereference(rt->rt_dev);
if (dev && nla_put_u32(skb, RTA_OIF, dev->ifindex))
goto nort0;
RCU_INIT_POINTER(rt0->rt_dev, lo);
rt0->rt_protocol = RTPROT_KERNEL;
- rt0->rt_via_family = AF_PACKET;
+ rt0->rt_via_table = NEIGH_LINK_TABLE;
memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len);
}
if (limit > LABEL_IPV6_EXPLICIT_NULL) {
goto nort2;
RCU_INIT_POINTER(rt2->rt_dev, lo);
rt2->rt_protocol = RTPROT_KERNEL;
- rt2->rt_via_family = AF_PACKET;
+ rt2->rt_via_table = NEIGH_LINK_TABLE;
memcpy(rt2->rt_via, lo->dev_addr, lo->addr_len);
}