diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 14e3f017966b2654862decf88ad2835aa338dd22..afb8237b0a8cfee75cd6a0a692e41c392e730073 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -358,6 +358,7 @@ void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie); void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *)); +int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *); void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *)); @@ -511,4 +512,6 @@ static inline void neigh_ha_snapshot(char *dst, const struct neighbour *n, memcpy(dst, n->ha, dev->addr_len); } while (read_seqretry(&n->ha_lock, seq)); } + + #endif diff --git a/net/core/neighbour.c b/net/core/neighbour.c index fe3c6eac5805788be5c1e1bda1375afff24c4126..cffaf00561e7782333710deaa193756d9a3ed06e 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2391,6 +2391,40 @@ void __neigh_for_each_release(struct neigh_table *tbl, } EXPORT_SYMBOL(__neigh_for_each_release); +int neigh_xmit(int family, 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 { + struct neigh_table *tbl; + struct neighbour *neigh; + + err = -ENETDOWN; + tbl = neigh_find_table(family); + if (!tbl) + goto out; + neigh = __neigh_lookup_noref(tbl, addr, dev); + if (!neigh) + neigh = __neigh_create(tbl, addr, dev, false); + err = PTR_ERR(neigh); + if (IS_ERR(neigh)) + goto out_kfree_skb; + err = neigh->output(neigh, skb); + } +out: + return err; +out_kfree_skb: + kfree_skb(skb); + goto out; +} +EXPORT_SYMBOL(neigh_xmit); + #ifdef CONFIG_PROC_FS static struct neighbour *neigh_get_first(struct seq_file *seq)