summaryrefslogtreecommitdiff
path: root/drivers/staging/batman-adv/routing.c
diff options
context:
space:
mode:
authorAndreas Langer <an.langer@gmx.de>2010-09-04 23:58:25 (GMT)
committerGreg Kroah-Hartman <gregkh@suse.de>2010-09-05 07:29:45 (GMT)
commite63760e59542ed872f7a5b1605a46e03b879d909 (patch)
treee93a45f0ad5224fa2213a6d04e9806422dac7e7a /drivers/staging/batman-adv/routing.c
parent24c76fc07b7680536fa372905f16b57a45c0d514 (diff)
downloadlinux-fsl-qoriq-e63760e59542ed872f7a5b1605a46e03b879d909.tar.xz
Staging: batman-adv: layer2 unicast packet fragmentation
This patch implements a simple layer2 fragmentation to allow traffic exchange over network interfaces with a MTU smaller than 1500 bytes. The fragmentation splits the big packets into two parts and marks the frames accordingly. The receiving end buffers the packets to reassemble the orignal packet before passing it to the higher layers. This feature makes it necessary to modify the batman-adv encapsulation for unicast packets by adding a sequence number, flags and the originator address. This modifcation is part of a seperate packet type for fragemented packets to keep the original overhead as low as possible. This patch enables the feature by default to ensure the data traffic can travel through the network. But it also prints a warning to notify the user about the performance implications. Note: Fragmentation should be avoided at all costs since it has a dramatic impact on the performance, especially when it comes wifi networks. Instead of a single packet, 2 packets have to be sent! Not only valuable airtime is wasted but also packetloss decreases the throughput. A link with 50% packetloss and fragmentation enabled is pretty much unusable. Signed-off-by: Andreas Langer <an.langer@gmx.de> [sven.eckelmann@gmx.de: Rework on top of current version] Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/batman-adv/routing.c')
-rw-r--r--drivers/staging/batman-adv/routing.c115
1 files changed, 95 insertions, 20 deletions
diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c
index 032195e..d8e77ac 100644
--- a/drivers/staging/batman-adv/routing.c
+++ b/drivers/staging/batman-adv/routing.c
@@ -32,6 +32,7 @@
#include "ring_buffer.h"
#include "vis.h"
#include "aggregation.h"
+#include "unicast.h"
static DECLARE_WAIT_QUEUE_HEAD(thread_wait);
@@ -1105,43 +1106,43 @@ struct neigh_node *find_router(struct orig_node *orig_node,
return router;
}
-int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
+static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
{
- struct unicast_packet *unicast_packet;
- struct orig_node *orig_node;
- struct neigh_node *router;
struct ethhdr *ethhdr;
- struct batman_if *batman_if;
- struct sk_buff *skb_old;
- uint8_t dstaddr[ETH_ALEN];
- int hdr_size = sizeof(struct unicast_packet);
- unsigned long flags;
/* drop packet if it has not necessary minimum size */
if (skb_headlen(skb) < hdr_size)
- return NET_RX_DROP;
+ return -1;
ethhdr = (struct ethhdr *) skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_bcast(ethhdr->h_dest))
- return NET_RX_DROP;
+ return -1;
/* packet with broadcast sender address */
if (is_bcast(ethhdr->h_source))
- return NET_RX_DROP;
+ return -1;
/* not for me */
if (!is_my_mac(ethhdr->h_dest))
- return NET_RX_DROP;
+ return -1;
- unicast_packet = (struct unicast_packet *) skb->data;
+ return 0;
+}
- /* packet for me */
- if (is_my_mac(unicast_packet->dest)) {
- interface_rx(skb, hdr_size);
- return NET_RX_SUCCESS;
- }
+static int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
+ int hdr_size)
+{
+ struct orig_node *orig_node;
+ struct neigh_node *router;
+ struct batman_if *batman_if;
+ struct sk_buff *skb_old;
+ uint8_t dstaddr[ETH_ALEN];
+ unsigned long flags;
+ struct unicast_packet *unicast_packet =
+ (struct unicast_packet *) skb->data;
+ struct ethhdr *ethhdr = (struct ethhdr *) skb_mac_header(skb);
/* TTL exceeded */
if (unicast_packet->ttl < 2) {
@@ -1172,7 +1173,7 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
spin_unlock_irqrestore(&orig_hash_lock, flags);
/* create a copy of the skb, if needed, to modify it. */
- if (!skb_clone_writable(skb, sizeof(struct unicast_packet))) {
+ if (!skb_clone_writable(skb, hdr_size)) {
skb_old = skb;
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb)
@@ -1191,6 +1192,80 @@ int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
return NET_RX_SUCCESS;
}
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+ struct unicast_packet *unicast_packet;
+ int hdr_size = sizeof(struct unicast_packet);
+
+ if (check_unicast_packet(skb, hdr_size) < 0)
+ return NET_RX_DROP;
+
+ unicast_packet = (struct unicast_packet *) skb->data;
+
+ /* packet for me */
+ if (is_my_mac(unicast_packet->dest)) {
+ interface_rx(skb, hdr_size);
+ return NET_RX_SUCCESS;
+ }
+
+ return route_unicast_packet(skb, recv_if, hdr_size);
+}
+
+int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+ struct unicast_frag_packet *unicast_packet;
+ struct orig_node *orig_node;
+ struct frag_packet_list_entry *tmp_frag_entry;
+ int hdr_size = sizeof(struct unicast_frag_packet);
+ unsigned long flags;
+
+ if (check_unicast_packet(skb, hdr_size) < 0)
+ return NET_RX_DROP;
+
+ unicast_packet = (struct unicast_frag_packet *) skb->data;
+
+ /* packet for me */
+ if (is_my_mac(unicast_packet->dest)) {
+
+ spin_lock_irqsave(&orig_hash_lock, flags);
+ orig_node = ((struct orig_node *)
+ hash_find(orig_hash, unicast_packet->orig));
+
+ if (!orig_node) {
+ pr_warning("couldn't find orig node for "
+ "fragmentation\n");
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_DROP;
+ }
+
+ orig_node->last_frag_packet = jiffies;
+
+ if (list_empty(&orig_node->frag_list))
+ create_frag_buffer(&orig_node->frag_list);
+
+ tmp_frag_entry =
+ search_frag_packet(&orig_node->frag_list,
+ unicast_packet);
+
+ if (!tmp_frag_entry) {
+ create_frag_entry(&orig_node->frag_list, skb);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ return NET_RX_SUCCESS;
+ }
+
+ skb = merge_frag_packet(&orig_node->frag_list,
+ tmp_frag_entry, skb);
+ spin_unlock_irqrestore(&orig_hash_lock, flags);
+ if (!skb)
+ return NET_RX_DROP;
+
+ interface_rx(skb, hdr_size);
+ return NET_RX_SUCCESS;
+ }
+
+ return route_unicast_packet(skb, recv_if, hdr_size);
+}
+
int recv_bcast_packet(struct sk_buff *skb)
{
struct orig_node *orig_node;