summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/fragmentation.c121
-rw-r--r--net/batman-adv/fragmentation.h3
-rw-r--r--net/batman-adv/send.c21
-rw-r--r--net/batman-adv/soft-interface.c7
-rw-r--r--net/batman-adv/types.h6
5 files changed, 154 insertions, 4 deletions
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c
index c829d3cee89c..271d321b3a04 100644
--- a/net/batman-adv/fragmentation.c
+++ b/net/batman-adv/fragmentation.c
@@ -368,3 +368,124 @@ out:
368 batadv_neigh_node_free_ref(neigh_node); 368 batadv_neigh_node_free_ref(neigh_node);
369 return ret; 369 return ret;
370} 370}
371
372/**
373 * batadv_frag_create - create a fragment from skb
374 * @skb: skb to create fragment from
375 * @frag_head: header to use in new fragment
376 * @mtu: size of new fragment
377 *
378 * Split the passed skb into two fragments: A new one with size matching the
379 * passed mtu and the old one with the rest. The new skb contains data from the
380 * tail of the old skb.
381 *
382 * Returns the new fragment, NULL on error.
383 */
384static struct sk_buff *batadv_frag_create(struct sk_buff *skb,
385 struct batadv_frag_packet *frag_head,
386 unsigned int mtu)
387{
388 struct sk_buff *skb_fragment;
389 unsigned header_size = sizeof(*frag_head);
390 unsigned fragment_size = mtu - header_size;
391
392 skb_fragment = netdev_alloc_skb(NULL, mtu + ETH_HLEN);
393 if (!skb_fragment)
394 goto err;
395
396 skb->priority = TC_PRIO_CONTROL;
397
398 /* Eat the last mtu-bytes of the skb */
399 skb_reserve(skb_fragment, header_size + ETH_HLEN);
400 skb_split(skb, skb_fragment, skb->len - fragment_size);
401
402 /* Add the header */
403 skb_push(skb_fragment, header_size);
404 memcpy(skb_fragment->data, frag_head, header_size);
405
406err:
407 return skb_fragment;
408}
409
410/**
411 * batadv_frag_send_packet - create up to 16 fragments from the passed skb
412 * @skb: skb to create fragments from
413 * @orig_node: final destination of the created fragments
414 * @neigh_node: next-hop of the created fragments
415 *
416 * Returns true on success, false otherwise.
417 */
418bool batadv_frag_send_packet(struct sk_buff *skb,
419 struct batadv_orig_node *orig_node,
420 struct batadv_neigh_node *neigh_node)
421{
422 struct batadv_priv *bat_priv;
423 struct batadv_hard_iface *primary_if;
424 struct batadv_frag_packet frag_header;
425 struct sk_buff *skb_fragment;
426 unsigned mtu = neigh_node->if_incoming->net_dev->mtu;
427 unsigned header_size = sizeof(frag_header);
428 unsigned max_fragment_size, max_packet_size;
429
430 /* To avoid merge and refragmentation at next-hops we never send
431 * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE
432 */
433 mtu = min_t(unsigned, mtu, BATADV_FRAG_MAX_FRAG_SIZE);
434 max_fragment_size = (mtu - header_size - ETH_HLEN);
435 max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS;
436
437 /* Don't even try to fragment, if we need more than 16 fragments */
438 if (skb->len > max_packet_size)
439 goto out_err;
440
441 bat_priv = orig_node->bat_priv;
442 primary_if = batadv_primary_if_get_selected(bat_priv);
443 if (!primary_if)
444 goto out_err;
445
446 /* Create one header to be copied to all fragments */
447 frag_header.header.packet_type = BATADV_UNICAST_FRAG;
448 frag_header.header.version = BATADV_COMPAT_VERSION;
449 frag_header.header.ttl = BATADV_TTL;
450 frag_header.seqno = htons(atomic_inc_return(&bat_priv->frag_seqno));
451 frag_header.reserved = 0;
452 frag_header.no = 0;
453 frag_header.total_size = htons(skb->len);
454 memcpy(frag_header.orig, primary_if->net_dev->dev_addr, ETH_ALEN);
455 memcpy(frag_header.dest, orig_node->orig, ETH_ALEN);
456
457 /* Eat and send fragments from the tail of skb */
458 while (skb->len > max_fragment_size) {
459 skb_fragment = batadv_frag_create(skb, &frag_header, mtu);
460 if (!skb_fragment)
461 goto out_err;
462
463 batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
464 batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
465 skb_fragment->len + ETH_HLEN);
466 batadv_send_skb_packet(skb_fragment, neigh_node->if_incoming,
467 neigh_node->addr);
468 frag_header.no++;
469
470 /* The initial check in this function should cover this case */
471 if (frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1)
472 goto out_err;
473 }
474
475 /* Make room for the fragment header. */
476 if (batadv_skb_head_push(skb, header_size) < 0 ||
477 pskb_expand_head(skb, header_size + ETH_HLEN, 0, GFP_ATOMIC) < 0)
478 goto out_err;
479
480 memcpy(skb->data, &frag_header, header_size);
481
482 /* Send the last fragment */
483 batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
484 batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
485 skb->len + ETH_HLEN);
486 batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
487
488 return true;
489out_err:
490 return false;
491}
diff --git a/net/batman-adv/fragmentation.h b/net/batman-adv/fragmentation.h
index 883a6f46005e..ca029e2676e7 100644
--- a/net/batman-adv/fragmentation.h
+++ b/net/batman-adv/fragmentation.h
@@ -27,6 +27,9 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,
27 struct batadv_orig_node *orig_node_src); 27 struct batadv_orig_node *orig_node_src);
28bool batadv_frag_skb_buffer(struct sk_buff **skb, 28bool batadv_frag_skb_buffer(struct sk_buff **skb,
29 struct batadv_orig_node *orig_node); 29 struct batadv_orig_node *orig_node);
30bool batadv_frag_send_packet(struct sk_buff *skb,
31 struct batadv_orig_node *orig_node,
32 struct batadv_neigh_node *neigh_node);
30 33
31/** 34/**
32 * batadv_frag_check_entry - check if a list of fragments has timed out 35 * batadv_frag_check_entry - check if a list of fragments has timed out
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index b8356ec067bf..1a1aa59d78ee 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -28,8 +28,7 @@
28#include "gateway_client.h" 28#include "gateway_client.h"
29#include "originator.h" 29#include "originator.h"
30#include "network-coding.h" 30#include "network-coding.h"
31 31#include "fragmentation.h"
32#include <linux/if_ether.h>
33 32
34static void batadv_send_outstanding_bcast_packet(struct work_struct *work); 33static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
35 34
@@ -109,7 +108,19 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
109 /* batadv_find_router() increases neigh_nodes refcount if found. */ 108 /* batadv_find_router() increases neigh_nodes refcount if found. */
110 neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); 109 neigh_node = batadv_find_router(bat_priv, orig_node, recv_if);
111 if (!neigh_node) 110 if (!neigh_node)
112 return ret; 111 goto out;
112
113 /* Check if the skb is too large to send in one piece and fragment
114 * it if needed.
115 */
116 if (atomic_read(&bat_priv->fragmentation) &&
117 skb->len > neigh_node->if_incoming->net_dev->mtu) {
118 /* Fragment and send packet. */
119 if (batadv_frag_send_packet(skb, orig_node, neigh_node))
120 ret = NET_XMIT_SUCCESS;
121
122 goto out;
123 }
113 124
114 /* try to network code the packet, if it is received on an interface 125 /* try to network code the packet, if it is received on an interface
115 * (i.e. being forwarded). If the packet originates from this node or if 126 * (i.e. being forwarded). If the packet originates from this node or if
@@ -123,7 +134,9 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
123 ret = NET_XMIT_SUCCESS; 134 ret = NET_XMIT_SUCCESS;
124 } 135 }
125 136
126 batadv_neigh_node_free_ref(neigh_node); 137out:
138 if (neigh_node)
139 batadv_neigh_node_free_ref(neigh_node);
127 140
128 return ret; 141 return ret;
129} 142}
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index dd189e6bf05a..18b1fd915d1f 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -442,6 +442,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
442static int batadv_softif_init_late(struct net_device *dev) 442static int batadv_softif_init_late(struct net_device *dev)
443{ 443{
444 struct batadv_priv *bat_priv; 444 struct batadv_priv *bat_priv;
445 uint32_t random_seqno;
445 int ret; 446 int ret;
446 size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; 447 size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM;
447 448
@@ -491,6 +492,10 @@ static int batadv_softif_init_late(struct net_device *dev)
491 bat_priv->tt.last_changeset = NULL; 492 bat_priv->tt.last_changeset = NULL;
492 bat_priv->tt.last_changeset_len = 0; 493 bat_priv->tt.last_changeset_len = 0;
493 494
495 /* randomize initial seqno to avoid collision */
496 get_random_bytes(&random_seqno, sizeof(random_seqno));
497 atomic_set(&bat_priv->frag_seqno, random_seqno);
498
494 bat_priv->primary_if = NULL; 499 bat_priv->primary_if = NULL;
495 bat_priv->num_ifaces = 0; 500 bat_priv->num_ifaces = 0;
496 501
@@ -758,6 +763,8 @@ static const struct {
758 { "mgmt_tx_bytes" }, 763 { "mgmt_tx_bytes" },
759 { "mgmt_rx" }, 764 { "mgmt_rx" },
760 { "mgmt_rx_bytes" }, 765 { "mgmt_rx_bytes" },
766 { "frag_tx" },
767 { "frag_tx_bytes" },
761 { "frag_rx" }, 768 { "frag_rx" },
762 { "frag_rx_bytes" }, 769 { "frag_rx_bytes" },
763 { "frag_fwd" }, 770 { "frag_fwd" },
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 5a2cc7a9a620..d517d5dde6ad 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -300,6 +300,8 @@ struct batadv_bcast_duplist_entry {
300 * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter 300 * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter
301 * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter 301 * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter
302 * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter 302 * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter
303 * @BATADV_CNT_FRAG_TX: transmitted fragment traffic packet counter
304 * @BATADV_CNT_FRAG_TX_BYTES: transmitted fragment traffic bytes counter
303 * @BATADV_CNT_FRAG_RX: received fragment traffic packet counter 305 * @BATADV_CNT_FRAG_RX: received fragment traffic packet counter
304 * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter 306 * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter
305 * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter 307 * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter
@@ -341,6 +343,8 @@ enum batadv_counters {
341 BATADV_CNT_MGMT_TX_BYTES, 343 BATADV_CNT_MGMT_TX_BYTES,
342 BATADV_CNT_MGMT_RX, 344 BATADV_CNT_MGMT_RX,
343 BATADV_CNT_MGMT_RX_BYTES, 345 BATADV_CNT_MGMT_RX_BYTES,
346 BATADV_CNT_FRAG_TX,
347 BATADV_CNT_FRAG_TX_BYTES,
344 BATADV_CNT_FRAG_RX, 348 BATADV_CNT_FRAG_RX,
345 BATADV_CNT_FRAG_RX_BYTES, 349 BATADV_CNT_FRAG_RX_BYTES,
346 BATADV_CNT_FRAG_FWD, 350 BATADV_CNT_FRAG_FWD,
@@ -542,6 +546,7 @@ struct batadv_priv_nc {
542 * @aggregated_ogms: bool indicating whether OGM aggregation is enabled 546 * @aggregated_ogms: bool indicating whether OGM aggregation is enabled
543 * @bonding: bool indicating whether traffic bonding is enabled 547 * @bonding: bool indicating whether traffic bonding is enabled
544 * @fragmentation: bool indicating whether traffic fragmentation is enabled 548 * @fragmentation: bool indicating whether traffic fragmentation is enabled
549 * @frag_seqno: incremental counter to identify chains of egress fragments
545 * @ap_isolation: bool indicating whether ap isolation is enabled 550 * @ap_isolation: bool indicating whether ap isolation is enabled
546 * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is 551 * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is
547 * enabled 552 * enabled
@@ -585,6 +590,7 @@ struct batadv_priv {
585 atomic_t aggregated_ogms; 590 atomic_t aggregated_ogms;
586 atomic_t bonding; 591 atomic_t bonding;
587 atomic_t fragmentation; 592 atomic_t fragmentation;
593 atomic_t frag_seqno;
588 atomic_t ap_isolation; 594 atomic_t ap_isolation;
589#ifdef CONFIG_BATMAN_ADV_BLA 595#ifdef CONFIG_BATMAN_ADV_BLA
590 atomic_t bridge_loop_avoidance; 596 atomic_t bridge_loop_avoidance;