From b7eeef9b04b44a70b2a953c4efe35a3fdceba2db Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 9 Mar 2017 19:56:45 +0100 Subject: [PATCH] batman-adv: backport a few maint patches In particular, this fixes packages of a certain range of sizes not being transmitted correctly, leading to hanging TCP connections. --- ...man-adv-backport-a-few-maint-patches.patch | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 patches/packages/routing/0004-batman-adv-backport-a-few-maint-patches.patch diff --git a/patches/packages/routing/0004-batman-adv-backport-a-few-maint-patches.patch b/patches/packages/routing/0004-batman-adv-backport-a-few-maint-patches.patch new file mode 100644 index 00000000..9b8a0223 --- /dev/null +++ b/patches/packages/routing/0004-batman-adv-backport-a-few-maint-patches.patch @@ -0,0 +1,195 @@ +From: Matthias Schiffer +Date: Thu, 9 Mar 2017 19:00:12 +0100 +Subject: batman-adv: backport a few maint patches + +In particular, this fixes packages of a certain range of sizes not being +transmitted correctly, leading to hanging TCP connections. + +diff --git a/batman-adv/patches/1003-batman-adv-Fix-double-free-during-fragment-merge-err.patch b/batman-adv/patches/1003-batman-adv-Fix-double-free-during-fragment-merge-err.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..4d754ecda1451b5c3e25f74da97fab18b7a93c87 +--- /dev/null ++++ b/batman-adv/patches/1003-batman-adv-Fix-double-free-during-fragment-merge-err.patch +@@ -0,0 +1,64 @@ ++From bcb7b6149bd9d1f41dae01ab47e74b8a931a650f Mon Sep 17 00:00:00 2001 ++Message-Id: ++From: Sven Eckelmann ++Date: Sun, 12 Feb 2017 11:26:33 +0100 ++Subject: [PATCH] batman-adv: Fix double free during fragment merge error ++ ++The function batadv_frag_skb_buffer was supposed not to consume the skbuff ++on errors. This was followed in the helper function ++batadv_frag_insert_packet when the skb would potentially be inserted in the ++fragment queue. But it could happen that the next helper function ++batadv_frag_merge_packets would try to merge the fragments and fail. This ++results in a kfree_skb of all the enqueued fragments (including the just ++inserted one). batadv_recv_frag_packet would detect the error in ++batadv_frag_skb_buffer and try to free the skb again. ++ ++The behavior of batadv_frag_skb_buffer (and its helper ++batadv_frag_insert_packet) must therefore be changed to always consume the ++skbuff to have a common behavior and avoid the double kfree_skb. ++ ++Fixes: 9b3eab61754d ("batman-adv: Receive fragmented packets and merge") ++Signed-off-by: Sven Eckelmann ++--- ++ net/batman-adv/fragmentation.c | 8 +++++--- ++ 1 file changed, 5 insertions(+), 3 deletions(-) ++ ++diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c ++index 65536db1..c3e293a3 100644 ++--- a/net/batman-adv/fragmentation.c +++++ b/net/batman-adv/fragmentation.c ++@@ -233,8 +233,10 @@ err_unlock: ++ spin_unlock_bh(&chain->lock); ++ ++ err: ++- if (!ret) +++ if (!ret) { ++ kfree(frag_entry_new); +++ kfree_skb(skb); +++ } ++ ++ return ret; ++ } ++@@ -305,7 +307,7 @@ free: ++ * ++ * There are three possible outcomes: 1) Packet is merged: Return true and ++ * set *skb to merged packet; 2) Packet is buffered: Return true and set *skb ++- * to NULL; 3) Error: Return false and leave skb as is. +++ * to NULL; 3) Error: Return false and free skb. ++ * ++ * Return: true when packet is merged or buffered, false when skb is not not ++ * used. ++@@ -330,9 +332,9 @@ bool batadv_frag_skb_buffer(struct sk_buff **skb, ++ goto out_err; ++ ++ out: ++- *skb = skb_out; ++ ret = true; ++ out_err: +++ *skb = skb_out; ++ return ret; ++ } ++ ++-- ++2.12.0 ++ +diff --git a/batman-adv/patches/1004-batman-adv-Keep-fragments-equally-sized.patch b/batman-adv/patches/1004-batman-adv-Keep-fragments-equally-sized.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..431c0b4a1a722c4c2ebae390bc0c90be18966023 +--- /dev/null ++++ b/batman-adv/patches/1004-batman-adv-Keep-fragments-equally-sized.patch +@@ -0,0 +1,112 @@ ++From 450247570eacc8b6cf5484fe61c50eff804c6416 Mon Sep 17 00:00:00 2001 ++Message-Id: <450247570eacc8b6cf5484fe61c50eff804c6416.1489082253.git.mschiffer@universe-factory.net> ++From: Sven Eckelmann ++Date: Sat, 4 Mar 2017 17:29:25 +0100 ++Subject: [PATCH] batman-adv: Keep fragments equally sized ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit ++ ++The batman-adv fragmentation packets have the design problem that they ++cannot be refragmented and cannot handle padding by the underlying link. ++The latter often leads to problems when networks are incorrectly configured ++and don't use a common MTU. ++ ++The sender could for example fragment a 1271 byte frame (plus external ++ethernet header (14) and batadv unicast header (10)) to fit in a 1280 bytes ++large MTU of the underlying link (max. 1294 byte frames). This would create ++a 1294 bytes large frame (fragment 2) and a 55 bytes large frame ++(fragment 1). The extra 54 bytes are the fragment header (20) added to each ++fragment and the external ethernet header (14) for the second fragment. ++ ++Let us assume that the next hop is then not able to transport 1294 bytes to ++its next hop. The 1294 byte large frame will be dropped but the 55 bytes ++large fragment will still be forwarded to its destination. ++ ++Or let us assume that the underlying hardware requires that each frame has ++a minimum size (e.g. 60 bytes). Then it will pad the 55 bytes frame to 60 ++bytes. The receiver of the 60 bytes frame will no longer be able to ++correctly assemble the two frames together because it is not aware that 5 ++bytes of the 60 bytes frame are padding and don't belong to the reassembled ++frame. ++ ++This can partly be avoided by splitting frames more equally. In this ++example, the 675 and 674 bytes large fragment frames could both potentially ++reach its destination without being too large or too small. ++ ++Reported-by: Martin Weinelt ++Fixes: db56e4ecf5c2 ("batman-adv: Fragment and send skbs larger than mtu") ++Signed-off-by: Sven Eckelmann ++Acked-by: Linus Lüssing ++Signed-off-by: Simon Wunderlich ++--- ++ net/batman-adv/fragmentation.c | 20 +++++++++++++------- ++ 1 file changed, 13 insertions(+), 7 deletions(-) ++ ++diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c ++index c3e293a3..89882ed7 100644 ++--- a/net/batman-adv/fragmentation.c +++++ b/net/batman-adv/fragmentation.c ++@@ -396,7 +396,7 @@ out: ++ * batadv_frag_create - create a fragment from skb ++ * @skb: skb to create fragment from ++ * @frag_head: header to use in new fragment ++- * @mtu: size of new fragment +++ * @fragment_size: size of new fragment ++ * ++ * Split the passed skb into two fragments: A new one with size matching the ++ * passed mtu and the old one with the rest. The new skb contains data from the ++@@ -406,11 +406,11 @@ out: ++ */ ++ static struct sk_buff *batadv_frag_create(struct sk_buff *skb, ++ struct batadv_frag_packet *frag_head, ++- unsigned int mtu) +++ unsigned int fragment_size) ++ { ++ struct sk_buff *skb_fragment; ++ unsigned int header_size = sizeof(*frag_head); ++- unsigned int fragment_size = mtu - header_size; +++ unsigned int mtu = fragment_size + header_size; ++ ++ skb_fragment = netdev_alloc_skb(NULL, mtu + ETH_HLEN); ++ if (!skb_fragment) ++@@ -448,7 +448,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb, ++ struct sk_buff *skb_fragment; ++ unsigned int mtu = neigh_node->if_incoming->net_dev->mtu; ++ unsigned int header_size = sizeof(frag_header); ++- unsigned int max_fragment_size, max_packet_size; +++ unsigned int max_fragment_size, num_fragments; ++ bool ret = false; ++ ++ /* To avoid merge and refragmentation at next-hops we never send ++@@ -456,10 +456,15 @@ bool batadv_frag_send_packet(struct sk_buff *skb, ++ */ ++ mtu = min_t(unsigned int, mtu, BATADV_FRAG_MAX_FRAG_SIZE); ++ max_fragment_size = mtu - header_size; ++- max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS; +++ +++ if (skb->len == 0 || max_fragment_size == 0) +++ return -EINVAL; +++ +++ num_fragments = (skb->len - 1) / max_fragment_size + 1; +++ max_fragment_size = (skb->len - 1) / num_fragments + 1; ++ ++ /* Don't even try to fragment, if we need more than 16 fragments */ ++- if (skb->len > max_packet_size) +++ if (num_fragments > BATADV_FRAG_MAX_FRAGMENTS) ++ goto out_err; ++ ++ bat_priv = orig_node->bat_priv; ++@@ -480,7 +485,8 @@ bool batadv_frag_send_packet(struct sk_buff *skb, ++ ++ /* Eat and send fragments from the tail of skb */ ++ while (skb->len > max_fragment_size) { ++- skb_fragment = batadv_frag_create(skb, &frag_header, mtu); +++ skb_fragment = batadv_frag_create(skb, &frag_header, +++ max_fragment_size); ++ if (!skb_fragment) ++ goto out_err; ++ ++-- ++2.12.0 ++