aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/fragmentation.c
diff options
context:
space:
mode:
authorMartin Hundebøll <martin@hundeboll.net>2013-05-23 10:53:03 -0400
committerAntonio Quartulli <antonio@meshcoding.com>2013-10-12 05:58:35 -0400
commitee75ed88879af88558818a5c6609d85f60ff0df4 (patch)
treeeb5edeaf224c481e962f8108bca429c6b1cc31d9 /net/batman-adv/fragmentation.c
parent610bfc6bc99bc83680d190ebc69359a05fc7f605 (diff)
batman-adv: Fragment and send skbs larger than mtu
Non-broadcast packets larger than MTU are fragmented and sent with an encapsulating header. Up to 16 fragments are supported, which are sent in reverse order on the wire to allow minimal memory copying when creating fragments. Signed-off-by: Martin Hundebøll <martin@hundeboll.net> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
Diffstat (limited to 'net/batman-adv/fragmentation.c')
-rw-r--r--net/batman-adv/fragmentation.c121
1 files changed, 121 insertions, 0 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}