DECnet: Only use neigh_ops for adding the link layer header
authorEric W. Biederman <ebiederm@xmission.com>
Wed, 4 Mar 2015 16:16:43 +0000 (10:16 -0600)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 Mar 2015 19:54:22 +0000 (14:54 -0500)
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>
include/net/dn_neigh.h
net/decnet/dn_neigh.c
net/decnet/dn_route.c

index fac4e3f4a6d3c0ede92af3d4df4c24319a94c0a0..0f26aa707e62a13225031797c9c2edadbff05a3a 100644 (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;
 
index ee7d1cef002743b7972071e662c48c01db889a52..be1f08cdad29135238c59c52f7c6bbc6548d39d2 100644 (file)
 #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 *);
-
-
-/*
- * For talking to broadcast devices: Ethernet & PPP
- */
-static const struct neigh_ops dn_long_ops = {
-       .family =               AF_DECnet,
-       .error_report =         dn_long_error_report,
-       .output =               dn_long_output,
-       .connected_output =     dn_long_output,
-};
+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 pointopoint and multidrop devices: DDCMP and X.25
+ * Operations for adding the link layer header.
  */
-static const struct neigh_ops dn_short_ops = {
+static const struct neigh_ops dn_neigh_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)
-{
-       printk(KERN_DEBUG "dn_long_error_report: called\n");
-       kfree_skb(skb);
-}
-
-
-static void dn_short_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_short_error_report: called\n");
+       printk(KERN_DEBUG "dn_neigh_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
index 3b81092771f8b7beb74349a84819046f7c080df1..771815575dbdce112ea96af3aaf88f8cf9e8b9e3 100644 (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);