seqlock_t ha_lock;
unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
struct hh_cache hh;
- int (*output)(struct sk_buff *skb);
+ int (*output)(struct neighbour *, struct sk_buff *);
const struct neigh_ops *ops;
struct rcu_head rcu;
struct net_device *dev;
struct neigh_ops {
int family;
- void (*solicit)(struct neighbour *, struct sk_buff*);
- void (*error_report)(struct neighbour *, struct sk_buff*);
- int (*output)(struct sk_buff*);
- int (*connected_output)(struct sk_buff*);
+ void (*solicit)(struct neighbour *, struct sk_buff *);
+ void (*error_report)(struct neighbour *, struct sk_buff *);
+ int (*output)(struct neighbour *, struct sk_buff *);
+ int (*connected_output)(struct neighbour *, struct sk_buff *);
};
struct pneigh_entry {
u32 flags);
extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
-extern int neigh_resolve_output(struct sk_buff *skb);
-extern int neigh_connected_output(struct sk_buff *skb);
-extern int neigh_compat_output(struct sk_buff *skb);
+extern int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb);
+extern int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb);
+extern int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb);
+extern int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb);
extern struct neighbour *neigh_event_ns(struct neigh_table *tbl,
u8 *lladdr, void *saddr,
struct net_device *dev);
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
return neigh_hh_output(hh, skb);
else
- return n->output(skb);
+ return n->output(n, skb);
}
static inline struct neighbour *
.family = AF_INET,
.solicit = clip_neigh_solicit,
.error_report = clip_neigh_error,
- .output = dev_queue_xmit,
- .connected_output = dev_queue_xmit,
+ .output = neigh_direct_output,
+ .connected_output = neigh_direct_output,
};
static int clip_constructor(struct neighbour *neigh)
neigh_hh_bridge(&neigh->hh, skb);
skb->dev = nf_bridge->physindev;
return br_handle_frame_finish(skb);
- } else if (dst->neighbour) {
+ } else {
/* the neighbour function below overwrites the complete
* MAC header, so we save the Ethernet source address and
* protocol number. */
skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
/* tell br_dev_xmit to continue with forwarding */
nf_bridge->mask |= BRNF_BRIDGED_DNAT;
- return dst->neighbour->output(skb);
+ return neigh->output(neigh, skb);
}
free_skb:
kfree_skb(skb);
static DEFINE_RWLOCK(neigh_tbl_lock);
-static int neigh_blackhole(struct sk_buff *skb)
+static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
{
kfree_skb(skb);
return -ENETDOWN;
/* On shaper/eql skb->dst->neighbour != neigh :( */
if (skb_dst(skb) && skb_dst(skb)->neighbour)
n1 = skb_dst(skb)->neighbour;
- n1->output(skb);
+ n1->output(n1, skb);
write_lock_bh(&neigh->lock);
}
skb_queue_purge(&neigh->arp_queue);
* but resolution is not made yet.
*/
-int neigh_compat_output(struct sk_buff *skb)
+int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
/* Slow and careful. */
-int neigh_resolve_output(struct sk_buff *skb)
+int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
- struct neighbour *neigh;
int rc = 0;
- if (!dst || !(neigh = dst->neighbour))
+ if (!dst)
goto discard;
__skb_pull(skb, skb_network_offset(skb));
return rc;
discard:
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
- dst, dst ? dst->neighbour : NULL);
+ dst, neigh);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
/* As fast as possible without hh cache */
-int neigh_connected_output(struct sk_buff *skb)
+int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
{
- int err;
- struct dst_entry *dst = skb_dst(skb);
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
unsigned int seq;
+ int err;
__skb_pull(skb, skb_network_offset(skb));
}
EXPORT_SYMBOL(neigh_connected_output);
+int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
+{
+ return dev_queue_xmit(skb);
+}
+EXPORT_SYMBOL(neigh_direct_output);
+
static void neigh_proxy_process(unsigned long arg)
{
struct neigh_table *tbl = (struct neigh_table *)arg;
static int dn_neigh_construct(struct neighbour *);
static void dn_long_error_report(struct neighbour *, struct sk_buff *);
static void dn_short_error_report(struct neighbour *, struct sk_buff *);
-static int dn_long_output(struct sk_buff *);
-static int dn_short_output(struct sk_buff *);
-static int dn_phase3_output(struct sk_buff *);
+static int dn_long_output(struct neighbour *, struct sk_buff *);
+static int dn_short_output(struct neighbour *, struct sk_buff *);
+static int dn_phase3_output(struct neighbour *, struct sk_buff *);
/*
return -EINVAL;
}
-static int dn_long_output(struct sk_buff *skb)
+static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
{
- struct dst_entry *dst = skb_dst(skb);
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
unsigned char *data;
neigh->dev, dn_neigh_output_packet);
}
-static int dn_short_output(struct sk_buff *skb)
+static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
{
- struct dst_entry *dst = skb_dst(skb);
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
struct dn_short_packet *sp;
* Phase 3 output is the same is short output, execpt that
* it clears the area bits before transmission.
*/
-static int dn_phase3_output(struct sk_buff *skb)
+static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
{
- struct dst_entry *dst = skb_dst(skb);
- struct neighbour *neigh = dst->neighbour;
struct net_device *dev = neigh->dev;
int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
struct dn_short_packet *sp;
return NET_RX_DROP;
}
+static int dn_to_neigh_output(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb_dst(skb);
+ struct neighbour *n = dst->neighbour;
+
+ return n->output(n, skb);
+}
+
static int dn_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
cb->hops = 0;
return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev,
- neigh->output);
+ dn_to_neigh_output);
error:
if (net_ratelimit())
struct dst_entry *dst = skb_dst(skb);
struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
struct dn_route *rt;
- struct neighbour *neigh = dst->neighbour;
int header_len;
#ifdef CONFIG_NETFILTER
struct net_device *dev = skb->dev;
cb->rt_flags |= DN_RT_F_IE;
return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev,
- neigh->output);
+ dn_to_neigh_output);
drop:
kfree_skb(skb);
static const struct neigh_ops arp_direct_ops = {
.family = AF_INET,
- .output = dev_queue_xmit,
- .connected_output = dev_queue_xmit,
+ .output = neigh_direct_output,
+ .connected_output = neigh_direct_output,
};
static const struct neigh_ops arp_broken_ops = {
if (!dev->header_ops) {
neigh->nud_state = NUD_NOARP;
neigh->ops = &arp_direct_ops;
- neigh->output = dev_queue_xmit;
+ neigh->output = neigh_direct_output;
} else {
/* Good devices (checked by reading texts, but only Ethernet is
tested)
static const struct neigh_ops ndisc_direct_ops = {
.family = AF_INET6,
- .output = dev_queue_xmit,
- .connected_output = dev_queue_xmit,
+ .output = neigh_direct_output,
+ .connected_output = neigh_direct_output,
};
struct neigh_table nd_tbl = {
if (!dev->header_ops) {
neigh->nud_state = NUD_NOARP;
neigh->ops = &ndisc_direct_ops;
- neigh->output = dev_queue_xmit;
+ neigh->output = neigh_direct_output;
} else {
if (is_multicast) {
neigh->nud_state = NUD_NOARP;