DECnet: Only use neigh_ops for adding the link layer header

Other users users of the neighbour table use neigh->output as the method
to decided when and which link-layer header to place on a packet.
DECnet has been using neigh->output to decide which DECnet headers to
place on a packet depending which neighbour the packet is destined for.

The DECnet usage isn't totally wrong but it can run into problems if the
neighbour output function is run for a second time as the teql driver
and the bridge netfilter code can do.

Therefore to avoid pathologic problems later down the line and make the
neighbour code easier to understand by refactoring the decnet output
code to only use a neighbour method to add a link layer header to a
packet.

This is done by moving the neigbhour operations lookup from
dn_to_neigh_output to dn_neigh_output_packet.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric W. Biederman 2015-03-04 10:16:43 -06:00 committed by David S. Miller
parent 616f45416c
commit aaa4e70404
3 changed files with 55 additions and 60 deletions

View file

@ -22,6 +22,7 @@ int dn_neigh_router_hello(struct sk_buff *skb);
int dn_neigh_endnode_hello(struct sk_buff *skb);
void dn_neigh_pointopoint_hello(struct sk_buff *skb);
int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n);
int dn_to_neigh_output(struct sk_buff *skb);
extern struct neigh_table dn_neigh_table;

View file

@ -49,41 +49,17 @@
#include <net/dn_route.h>
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 neighbour *, struct sk_buff *);
static int dn_short_output(struct neighbour *, struct sk_buff *);
static int dn_phase3_output(struct neighbour *, struct sk_buff *);
static void dn_neigh_error_report(struct neighbour *, struct sk_buff *);
static int dn_neigh_output(struct neighbour *neigh, struct sk_buff *skb);
/*
* For talking to broadcast devices: Ethernet & PPP
* Operations for adding the link layer header.
*/
static const struct neigh_ops dn_long_ops = {
static const struct neigh_ops dn_neigh_ops = {
.family = AF_DECnet,
.error_report = dn_long_error_report,
.output = dn_long_output,
.connected_output = dn_long_output,
};
/*
* For talking to pointopoint and multidrop devices: DDCMP and X.25
*/
static const struct neigh_ops dn_short_ops = {
.family = AF_DECnet,
.error_report = dn_short_error_report,
.output = dn_short_output,
.connected_output = dn_short_output,
};
/*
* For talking to DECnet phase III nodes
*/
static const struct neigh_ops dn_phase3_ops = {
.family = AF_DECnet,
.error_report = dn_short_error_report, /* Can use short version here */
.output = dn_phase3_output,
.connected_output = dn_phase3_output,
.error_report = dn_neigh_error_report,
.output = dn_neigh_output,
.connected_output = dn_neigh_output,
};
static u32 dn_neigh_hash(const void *pkey,
@ -153,16 +129,9 @@ static int dn_neigh_construct(struct neighbour *neigh)
__neigh_parms_put(neigh->parms);
neigh->parms = neigh_parms_clone(parms);
if (dn_db->use_long)
neigh->ops = &dn_long_ops;
else
neigh->ops = &dn_short_ops;
rcu_read_unlock();
if (dn->flags & DN_NDFLAG_P3)
neigh->ops = &dn_phase3_ops;
neigh->ops = &dn_neigh_ops;
neigh->nud_state = NUD_NOARP;
neigh->output = neigh->ops->connected_output;
@ -194,24 +163,16 @@ static int dn_neigh_construct(struct neighbour *neigh)
return 0;
}
static void dn_long_error_report(struct neighbour *neigh, struct sk_buff *skb)
static void dn_neigh_error_report(struct neighbour *neigh, struct sk_buff *skb)
{
printk(KERN_DEBUG "dn_long_error_report: called\n");
printk(KERN_DEBUG "dn_neigh_error_report: called\n");
kfree_skb(skb);
}
static void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb)
{
printk(KERN_DEBUG "dn_short_error_report: called\n");
kfree_skb(skb);
}
static int dn_neigh_output_packet(struct sk_buff *skb)
static int dn_neigh_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct dn_route *rt = (struct dn_route *)dst;
struct neighbour *neigh = rt->n;
struct net_device *dev = neigh->dev;
char mac_addr[ETH_ALEN];
unsigned int seq;
@ -233,6 +194,18 @@ static int dn_neigh_output_packet(struct sk_buff *skb)
return err;
}
static int dn_neigh_output_packet(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct dn_route *rt = (struct dn_route *)dst;
struct neighbour *neigh = rt->n;
return neigh->output(neigh, skb);
}
/*
* For talking to broadcast devices: Ethernet & PPP
*/
static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct net_device *dev = neigh->dev;
@ -276,6 +249,9 @@ static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb)
neigh->dev, dn_neigh_output_packet);
}
/*
* For talking to pointopoint and multidrop devices: DDCMP and X.25
*/
static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct net_device *dev = neigh->dev;
@ -313,7 +289,8 @@ static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb)
}
/*
* Phase 3 output is the same is short output, execpt that
* For talking to DECnet phase III nodes
* Phase 3 output is the same as short output, execpt that
* it clears the area bits before transmission.
*/
static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
@ -351,6 +328,32 @@ static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb)
neigh->dev, dn_neigh_output_packet);
}
int dn_to_neigh_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct dn_route *rt = (struct dn_route *) dst;
struct neighbour *neigh = rt->n;
struct dn_neigh *dn = (struct dn_neigh *)neigh;
struct dn_dev *dn_db;
bool use_long;
rcu_read_lock();
dn_db = rcu_dereference(neigh->dev->dn_ptr);
if (dn_db == NULL) {
rcu_read_unlock();
return -EINVAL;
}
use_long = dn_db->use_long;
rcu_read_unlock();
if (dn->flags & DN_NDFLAG_P3)
return dn_phase3_output(neigh, skb);
if (use_long)
return dn_long_output(neigh, skb);
else
return dn_short_output(neigh, skb);
}
/*
* Unfortunately, the neighbour code uses the device in its hash
* function, so we don't get any advantage from it. This function

View file

@ -743,15 +743,6 @@ out:
return NET_RX_DROP;
}
static int dn_to_neigh_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct dn_route *rt = (struct dn_route *) dst;
struct neighbour *n = rt->n;
return n->output(n, skb);
}
static int dn_output(struct sock *sk, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);