summaryrefslogtreecommitdiff
path: root/net/ax25
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-03-03 00:43:46 +0300
committerDavid S. Miller <davem@davemloft.net>2015-03-03 00:43:46 +0300
commitb898441f4ece44933af90b116b467f7864dd1ae7 (patch)
tree56316bfd883fa759f7a6fc7744088028b64e7b85 /net/ax25
parent61e021f3b86cbbcc04cbe8ac7b7da2b8c94b5e8e (diff)
parent435e8eb27edb4da0b47b9b980239bd59057a7362 (diff)
downloadlinux-b898441f4ece44933af90b116b467f7864dd1ae7.tar.xz
Merge branch 'neigh_cleanups'
Eric W. Biederman says: ==================== Neighbour table and ax25 cleanups While looking at the neighbour table to what it would take to allow using next hops in a different address family than the current packets I found a partial resolution for my issues and I stumbled upon some work that makes the neighbour table code easier to understand and maintain. Long ago in a much younger kernel ax25 found a hack to use dev_rebuild_header to transmit it's packets instead of going through what today is ndo_start_xmit. When the neighbour table was rewritten into it's current form the ax25 code was such a challenge that arp_broken_ops appeard in arp.c and neigh_compat_output appeared in neighbour.c to keep the ax25 hack alive. With a little bit of work I was able to remove some of the hack that is the ax25 transmit path for ip packets and to isolate what remains into a slightly more readable piece of code in ax25_ip.c. Removing the need for the generic code to worry about ax25 special cases. After cleaning up the old ax25 hacks I also performed a little bit of work on neigh_resolve_output to remove the need for a dst entry and to ensure cached headers get a deterministic protocol value in their cached header. This guarantees that a cached header will not be different depending on which protocol of packet is transmitted, and it allows packets to be transmitted that don't have a dst entry. There remains a small amount of code that takes advantage of when packets have a dst entry but that is something different. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ax25')
-rw-r--r--net/ax25/ax25_ip.c76
1 files changed, 60 insertions, 16 deletions
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 67de6b33f2c3..e030c64ebfb7 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -46,9 +46,9 @@
#ifdef CONFIG_INET
-int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned int len)
+static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
{
unsigned char *buff;
@@ -100,7 +100,7 @@ int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
return -AX25_HEADER_LEN; /* Unfinished header */
}
-int ax25_rebuild_header(struct sk_buff *skb)
+static int ax25_neigh_xmit(struct sk_buff *skb)
{
struct sk_buff *ourskb;
unsigned char *bp = skb->data;
@@ -115,9 +115,6 @@ int ax25_rebuild_header(struct sk_buff *skb)
dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8);
- if (arp_find(bp + 1, skb))
- return 1;
-
route = ax25_get_route(dst, NULL);
if (route) {
digipeat = route->digipeat;
@@ -129,6 +126,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
dev = skb->dev;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
+ kfree_skb(skb);
goto put;
}
@@ -215,28 +213,74 @@ put:
return 1;
}
+static int ax25_neigh_output(struct neighbour *neigh, struct sk_buff *skb)
+{
+ /* Except for calling ax25_neigh_xmit instead of
+ * dev_queue_xmit this is neigh_resolve_output.
+ */
+ int rc = 0;
+
+ if (!neigh_event_send(neigh, skb)) {
+ int err;
+ struct net_device *dev = neigh->dev;
+ unsigned int seq;
+
+ do {
+ __skb_pull(skb, skb_network_offset(skb));
+ seq = read_seqbegin(&neigh->ha_lock);
+ err = dev_hard_header(skb, dev, ntohs(skb->protocol),
+ neigh->ha, NULL, skb->len);
+ } while (read_seqretry(&neigh->ha_lock, seq));
+
+ if (err >= 0) {
+ ax25_neigh_xmit(skb);
+ } else
+ goto out_kfree_skb;
+ }
+out:
+ return rc;
+
+out_kfree_skb:
+ rc = -EINVAL;
+ kfree_skb(skb);
+ goto out;
+}
+
+int ax25_neigh_construct(struct neighbour *neigh)
+{
+ /* This trouble could be saved if ax25 would right a proper
+ * dev_queue_xmit function.
+ */
+ struct ax25_neigh_priv *priv = neighbour_priv(neigh);
+
+ if (neigh->tbl->family != AF_INET)
+ return -EINVAL;
+
+ priv->ops = *neigh->ops;
+ priv->ops.output = ax25_neigh_output;
+ priv->ops.connected_output = ax25_neigh_output;
+ return 0;
+}
+
#else /* INET */
-int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *daddr,
- const void *saddr, unsigned int len)
+static int ax25_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
{
return -AX25_HEADER_LEN;
}
-int ax25_rebuild_header(struct sk_buff *skb)
+int ax25_neigh_construct(struct neighbour *neigh)
{
- return 1;
+ return 0;
}
-
#endif
const struct header_ops ax25_header_ops = {
.create = ax25_hard_header,
- .rebuild = ax25_rebuild_header,
};
-EXPORT_SYMBOL(ax25_hard_header);
-EXPORT_SYMBOL(ax25_rebuild_header);
EXPORT_SYMBOL(ax25_header_ops);
+EXPORT_SYMBOL(ax25_neigh_construct);