1ea81ac2eSAlexander Aring /* 6LoWPAN fragment reassembly 2ea81ac2eSAlexander Aring * 3ea81ac2eSAlexander Aring * 4ea81ac2eSAlexander Aring * Authors: 5ea81ac2eSAlexander Aring * Alexander Aring <aar@pengutronix.de> 6ea81ac2eSAlexander Aring * 7ea81ac2eSAlexander Aring * Based on: net/ipv6/reassembly.c 8ea81ac2eSAlexander Aring * 9ea81ac2eSAlexander Aring * This program is free software; you can redistribute it and/or 10ea81ac2eSAlexander Aring * modify it under the terms of the GNU General Public License 11ea81ac2eSAlexander Aring * as published by the Free Software Foundation; either version 12ea81ac2eSAlexander Aring * 2 of the License, or (at your option) any later version. 13ea81ac2eSAlexander Aring */ 14ea81ac2eSAlexander Aring 15ea81ac2eSAlexander Aring #define pr_fmt(fmt) "6LoWPAN: " fmt 16ea81ac2eSAlexander Aring 17ea81ac2eSAlexander Aring #include <linux/net.h> 18ea81ac2eSAlexander Aring #include <linux/list.h> 19ea81ac2eSAlexander Aring #include <linux/netdevice.h> 20ea81ac2eSAlexander Aring #include <linux/random.h> 21ea81ac2eSAlexander Aring #include <linux/jhash.h> 22ea81ac2eSAlexander Aring #include <linux/skbuff.h> 23ea81ac2eSAlexander Aring #include <linux/slab.h> 24ea81ac2eSAlexander Aring #include <linux/export.h> 25ea81ac2eSAlexander Aring 26ea81ac2eSAlexander Aring #include <net/ieee802154_netdev.h> 27ea81ac2eSAlexander Aring #include <net/6lowpan.h> 28ea81ac2eSAlexander Aring #include <net/ipv6.h> 29ea81ac2eSAlexander Aring #include <net/inet_frag.h> 30ea81ac2eSAlexander Aring 318691ee59SAlexander Aring #include "6lowpan_i.h" 32ea81ac2eSAlexander Aring 33ea81ac2eSAlexander Aring static const char lowpan_frags_cache_name[] = "lowpan-frags"; 34ea81ac2eSAlexander Aring 35ea81ac2eSAlexander Aring struct lowpan_frag_info { 36ea81ac2eSAlexander Aring u16 d_tag; 37ea81ac2eSAlexander Aring u16 d_size; 38ea81ac2eSAlexander Aring u8 d_offset; 39ea81ac2eSAlexander Aring }; 40ea81ac2eSAlexander Aring 41ea81ac2eSAlexander Aring static struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb) 42ea81ac2eSAlexander Aring { 43ea81ac2eSAlexander Aring return (struct lowpan_frag_info *)skb->cb; 44ea81ac2eSAlexander Aring } 45ea81ac2eSAlexander Aring 46ea81ac2eSAlexander Aring static struct inet_frags lowpan_frags; 47ea81ac2eSAlexander Aring 48ea81ac2eSAlexander Aring static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, 49f4606583SAlexander Aring struct sk_buff *prev, struct net_device *ldev); 50ea81ac2eSAlexander Aring 51ea81ac2eSAlexander Aring static unsigned int lowpan_hash_frag(u16 tag, u16 d_size, 52ea81ac2eSAlexander Aring const struct ieee802154_addr *saddr, 53ea81ac2eSAlexander Aring const struct ieee802154_addr *daddr) 54ea81ac2eSAlexander Aring { 55ea81ac2eSAlexander Aring net_get_random_once(&lowpan_frags.rnd, sizeof(lowpan_frags.rnd)); 56ea81ac2eSAlexander Aring return jhash_3words(ieee802154_addr_hash(saddr), 57ea81ac2eSAlexander Aring ieee802154_addr_hash(daddr), 58ea81ac2eSAlexander Aring (__force u32)(tag + (d_size << 16)), 59ea81ac2eSAlexander Aring lowpan_frags.rnd); 60ea81ac2eSAlexander Aring } 61ea81ac2eSAlexander Aring 62ea81ac2eSAlexander Aring static unsigned int lowpan_hashfn(const struct inet_frag_queue *q) 63ea81ac2eSAlexander Aring { 64ea81ac2eSAlexander Aring const struct lowpan_frag_queue *fq; 65ea81ac2eSAlexander Aring 66ea81ac2eSAlexander Aring fq = container_of(q, struct lowpan_frag_queue, q); 67ea81ac2eSAlexander Aring return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr); 68ea81ac2eSAlexander Aring } 69ea81ac2eSAlexander Aring 70ea81ac2eSAlexander Aring static bool lowpan_frag_match(const struct inet_frag_queue *q, const void *a) 71ea81ac2eSAlexander Aring { 72ea81ac2eSAlexander Aring const struct lowpan_frag_queue *fq; 73ea81ac2eSAlexander Aring const struct lowpan_create_arg *arg = a; 74ea81ac2eSAlexander Aring 75ea81ac2eSAlexander Aring fq = container_of(q, struct lowpan_frag_queue, q); 76ea81ac2eSAlexander Aring return fq->tag == arg->tag && fq->d_size == arg->d_size && 77ea81ac2eSAlexander Aring ieee802154_addr_equal(&fq->saddr, arg->src) && 78ea81ac2eSAlexander Aring ieee802154_addr_equal(&fq->daddr, arg->dst); 79ea81ac2eSAlexander Aring } 80ea81ac2eSAlexander Aring 81ea81ac2eSAlexander Aring static void lowpan_frag_init(struct inet_frag_queue *q, const void *a) 82ea81ac2eSAlexander Aring { 83ea81ac2eSAlexander Aring const struct lowpan_create_arg *arg = a; 84ea81ac2eSAlexander Aring struct lowpan_frag_queue *fq; 85ea81ac2eSAlexander Aring 86ea81ac2eSAlexander Aring fq = container_of(q, struct lowpan_frag_queue, q); 87ea81ac2eSAlexander Aring 88ea81ac2eSAlexander Aring fq->tag = arg->tag; 89ea81ac2eSAlexander Aring fq->d_size = arg->d_size; 90ea81ac2eSAlexander Aring fq->saddr = *arg->src; 91ea81ac2eSAlexander Aring fq->daddr = *arg->dst; 92ea81ac2eSAlexander Aring } 93ea81ac2eSAlexander Aring 94ea81ac2eSAlexander Aring static void lowpan_frag_expire(unsigned long data) 95ea81ac2eSAlexander Aring { 96ea81ac2eSAlexander Aring struct frag_queue *fq; 97ea81ac2eSAlexander Aring struct net *net; 98ea81ac2eSAlexander Aring 99ea81ac2eSAlexander Aring fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); 100ea81ac2eSAlexander Aring net = container_of(fq->q.net, struct net, ieee802154_lowpan.frags); 101ea81ac2eSAlexander Aring 102ea81ac2eSAlexander Aring spin_lock(&fq->q.lock); 103ea81ac2eSAlexander Aring 104ea81ac2eSAlexander Aring if (fq->q.flags & INET_FRAG_COMPLETE) 105ea81ac2eSAlexander Aring goto out; 106ea81ac2eSAlexander Aring 107ea81ac2eSAlexander Aring inet_frag_kill(&fq->q, &lowpan_frags); 108ea81ac2eSAlexander Aring out: 109ea81ac2eSAlexander Aring spin_unlock(&fq->q.lock); 110ea81ac2eSAlexander Aring inet_frag_put(&fq->q, &lowpan_frags); 111ea81ac2eSAlexander Aring } 112ea81ac2eSAlexander Aring 113ea81ac2eSAlexander Aring static inline struct lowpan_frag_queue * 114ea81ac2eSAlexander Aring fq_find(struct net *net, const struct lowpan_frag_info *frag_info, 115ea81ac2eSAlexander Aring const struct ieee802154_addr *src, 116ea81ac2eSAlexander Aring const struct ieee802154_addr *dst) 117ea81ac2eSAlexander Aring { 118ea81ac2eSAlexander Aring struct inet_frag_queue *q; 119ea81ac2eSAlexander Aring struct lowpan_create_arg arg; 120ea81ac2eSAlexander Aring unsigned int hash; 121ea81ac2eSAlexander Aring struct netns_ieee802154_lowpan *ieee802154_lowpan = 122ea81ac2eSAlexander Aring net_ieee802154_lowpan(net); 123ea81ac2eSAlexander Aring 124ea81ac2eSAlexander Aring arg.tag = frag_info->d_tag; 125ea81ac2eSAlexander Aring arg.d_size = frag_info->d_size; 126ea81ac2eSAlexander Aring arg.src = src; 127ea81ac2eSAlexander Aring arg.dst = dst; 128ea81ac2eSAlexander Aring 129ea81ac2eSAlexander Aring hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst); 130ea81ac2eSAlexander Aring 131ea81ac2eSAlexander Aring q = inet_frag_find(&ieee802154_lowpan->frags, 132ea81ac2eSAlexander Aring &lowpan_frags, &arg, hash); 133ea81ac2eSAlexander Aring if (IS_ERR_OR_NULL(q)) { 134ea81ac2eSAlexander Aring inet_frag_maybe_warn_overflow(q, pr_fmt()); 135ea81ac2eSAlexander Aring return NULL; 136ea81ac2eSAlexander Aring } 137ea81ac2eSAlexander Aring return container_of(q, struct lowpan_frag_queue, q); 138ea81ac2eSAlexander Aring } 139ea81ac2eSAlexander Aring 140ea81ac2eSAlexander Aring static int lowpan_frag_queue(struct lowpan_frag_queue *fq, 141ea81ac2eSAlexander Aring struct sk_buff *skb, const u8 frag_type) 142ea81ac2eSAlexander Aring { 143ea81ac2eSAlexander Aring struct sk_buff *prev, *next; 144f4606583SAlexander Aring struct net_device *ldev; 145ea81ac2eSAlexander Aring int end, offset; 146ea81ac2eSAlexander Aring 147ea81ac2eSAlexander Aring if (fq->q.flags & INET_FRAG_COMPLETE) 148ea81ac2eSAlexander Aring goto err; 149ea81ac2eSAlexander Aring 150ea81ac2eSAlexander Aring offset = lowpan_cb(skb)->d_offset << 3; 151ea81ac2eSAlexander Aring end = lowpan_cb(skb)->d_size; 152ea81ac2eSAlexander Aring 153ea81ac2eSAlexander Aring /* Is this the final fragment? */ 154ea81ac2eSAlexander Aring if (offset + skb->len == end) { 155ea81ac2eSAlexander Aring /* If we already have some bits beyond end 156ea81ac2eSAlexander Aring * or have different end, the segment is corrupted. 157ea81ac2eSAlexander Aring */ 158ea81ac2eSAlexander Aring if (end < fq->q.len || 159ea81ac2eSAlexander Aring ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) 160ea81ac2eSAlexander Aring goto err; 161ea81ac2eSAlexander Aring fq->q.flags |= INET_FRAG_LAST_IN; 162ea81ac2eSAlexander Aring fq->q.len = end; 163ea81ac2eSAlexander Aring } else { 164ea81ac2eSAlexander Aring if (end > fq->q.len) { 165ea81ac2eSAlexander Aring /* Some bits beyond end -> corruption. */ 166ea81ac2eSAlexander Aring if (fq->q.flags & INET_FRAG_LAST_IN) 167ea81ac2eSAlexander Aring goto err; 168ea81ac2eSAlexander Aring fq->q.len = end; 169ea81ac2eSAlexander Aring } 170ea81ac2eSAlexander Aring } 171ea81ac2eSAlexander Aring 172ea81ac2eSAlexander Aring /* Find out which fragments are in front and at the back of us 173ea81ac2eSAlexander Aring * in the chain of fragments so far. We must know where to put 174ea81ac2eSAlexander Aring * this fragment, right? 175ea81ac2eSAlexander Aring */ 176ea81ac2eSAlexander Aring prev = fq->q.fragments_tail; 177ea81ac2eSAlexander Aring if (!prev || lowpan_cb(prev)->d_offset < lowpan_cb(skb)->d_offset) { 178ea81ac2eSAlexander Aring next = NULL; 179ea81ac2eSAlexander Aring goto found; 180ea81ac2eSAlexander Aring } 181ea81ac2eSAlexander Aring prev = NULL; 182ea81ac2eSAlexander Aring for (next = fq->q.fragments; next != NULL; next = next->next) { 183ea81ac2eSAlexander Aring if (lowpan_cb(next)->d_offset >= lowpan_cb(skb)->d_offset) 184ea81ac2eSAlexander Aring break; /* bingo! */ 185ea81ac2eSAlexander Aring prev = next; 186ea81ac2eSAlexander Aring } 187ea81ac2eSAlexander Aring 188ea81ac2eSAlexander Aring found: 189ea81ac2eSAlexander Aring /* Insert this fragment in the chain of fragments. */ 190ea81ac2eSAlexander Aring skb->next = next; 191ea81ac2eSAlexander Aring if (!next) 192ea81ac2eSAlexander Aring fq->q.fragments_tail = skb; 193ea81ac2eSAlexander Aring if (prev) 194ea81ac2eSAlexander Aring prev->next = skb; 195ea81ac2eSAlexander Aring else 196ea81ac2eSAlexander Aring fq->q.fragments = skb; 197ea81ac2eSAlexander Aring 198f4606583SAlexander Aring ldev = skb->dev; 199f4606583SAlexander Aring if (ldev) 200ea81ac2eSAlexander Aring skb->dev = NULL; 201ea81ac2eSAlexander Aring 202ea81ac2eSAlexander Aring fq->q.stamp = skb->tstamp; 203ea81ac2eSAlexander Aring if (frag_type == LOWPAN_DISPATCH_FRAG1) { 204ea81ac2eSAlexander Aring /* Calculate uncomp. 6lowpan header to estimate full size */ 205ea81ac2eSAlexander Aring fq->q.meat += lowpan_uncompress_size(skb, NULL); 206ea81ac2eSAlexander Aring fq->q.flags |= INET_FRAG_FIRST_IN; 207ea81ac2eSAlexander Aring } else { 208ea81ac2eSAlexander Aring fq->q.meat += skb->len; 209ea81ac2eSAlexander Aring } 2100e60d245SFlorian Westphal add_frag_mem_limit(fq->q.net, skb->truesize); 211ea81ac2eSAlexander Aring 212ea81ac2eSAlexander Aring if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && 213ea81ac2eSAlexander Aring fq->q.meat == fq->q.len) { 214ea81ac2eSAlexander Aring int res; 215ea81ac2eSAlexander Aring unsigned long orefdst = skb->_skb_refdst; 216ea81ac2eSAlexander Aring 217ea81ac2eSAlexander Aring skb->_skb_refdst = 0UL; 218f4606583SAlexander Aring res = lowpan_frag_reasm(fq, prev, ldev); 219ea81ac2eSAlexander Aring skb->_skb_refdst = orefdst; 220ea81ac2eSAlexander Aring return res; 221ea81ac2eSAlexander Aring } 222ea81ac2eSAlexander Aring 223ea81ac2eSAlexander Aring return -1; 224ea81ac2eSAlexander Aring err: 225ea81ac2eSAlexander Aring kfree_skb(skb); 226ea81ac2eSAlexander Aring return -1; 227ea81ac2eSAlexander Aring } 228ea81ac2eSAlexander Aring 229ea81ac2eSAlexander Aring /* Check if this packet is complete. 230ea81ac2eSAlexander Aring * Returns NULL on failure by any reason, and pointer 231ea81ac2eSAlexander Aring * to current nexthdr field in reassembled frame. 232ea81ac2eSAlexander Aring * 233ea81ac2eSAlexander Aring * It is called with locked fq, and caller must check that 234ea81ac2eSAlexander Aring * queue is eligible for reassembly i.e. it is not COMPLETE, 235ea81ac2eSAlexander Aring * the last and the first frames arrived and all the bits are here. 236ea81ac2eSAlexander Aring */ 237ea81ac2eSAlexander Aring static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev, 238f4606583SAlexander Aring struct net_device *ldev) 239ea81ac2eSAlexander Aring { 240ea81ac2eSAlexander Aring struct sk_buff *fp, *head = fq->q.fragments; 241ea81ac2eSAlexander Aring int sum_truesize; 242ea81ac2eSAlexander Aring 243ea81ac2eSAlexander Aring inet_frag_kill(&fq->q, &lowpan_frags); 244ea81ac2eSAlexander Aring 245ea81ac2eSAlexander Aring /* Make the one we just received the head. */ 246ea81ac2eSAlexander Aring if (prev) { 247ea81ac2eSAlexander Aring head = prev->next; 248ea81ac2eSAlexander Aring fp = skb_clone(head, GFP_ATOMIC); 249ea81ac2eSAlexander Aring 250ea81ac2eSAlexander Aring if (!fp) 251ea81ac2eSAlexander Aring goto out_oom; 252ea81ac2eSAlexander Aring 253ea81ac2eSAlexander Aring fp->next = head->next; 254ea81ac2eSAlexander Aring if (!fp->next) 255ea81ac2eSAlexander Aring fq->q.fragments_tail = fp; 256ea81ac2eSAlexander Aring prev->next = fp; 257ea81ac2eSAlexander Aring 258ea81ac2eSAlexander Aring skb_morph(head, fq->q.fragments); 259ea81ac2eSAlexander Aring head->next = fq->q.fragments->next; 260ea81ac2eSAlexander Aring 261ea81ac2eSAlexander Aring consume_skb(fq->q.fragments); 262ea81ac2eSAlexander Aring fq->q.fragments = head; 263ea81ac2eSAlexander Aring } 264ea81ac2eSAlexander Aring 265ea81ac2eSAlexander Aring /* Head of list must not be cloned. */ 266ea81ac2eSAlexander Aring if (skb_unclone(head, GFP_ATOMIC)) 267ea81ac2eSAlexander Aring goto out_oom; 268ea81ac2eSAlexander Aring 269ea81ac2eSAlexander Aring /* If the first fragment is fragmented itself, we split 270ea81ac2eSAlexander Aring * it to two chunks: the first with data and paged part 271ea81ac2eSAlexander Aring * and the second, holding only fragments. 272ea81ac2eSAlexander Aring */ 273ea81ac2eSAlexander Aring if (skb_has_frag_list(head)) { 274ea81ac2eSAlexander Aring struct sk_buff *clone; 275ea81ac2eSAlexander Aring int i, plen = 0; 276ea81ac2eSAlexander Aring 277ea81ac2eSAlexander Aring clone = alloc_skb(0, GFP_ATOMIC); 278ea81ac2eSAlexander Aring if (!clone) 279ea81ac2eSAlexander Aring goto out_oom; 280ea81ac2eSAlexander Aring clone->next = head->next; 281ea81ac2eSAlexander Aring head->next = clone; 282ea81ac2eSAlexander Aring skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; 283ea81ac2eSAlexander Aring skb_frag_list_init(head); 284ea81ac2eSAlexander Aring for (i = 0; i < skb_shinfo(head)->nr_frags; i++) 285ea81ac2eSAlexander Aring plen += skb_frag_size(&skb_shinfo(head)->frags[i]); 286ea81ac2eSAlexander Aring clone->len = head->data_len - plen; 287ea81ac2eSAlexander Aring clone->data_len = clone->len; 288ea81ac2eSAlexander Aring head->data_len -= clone->len; 289ea81ac2eSAlexander Aring head->len -= clone->len; 2900e60d245SFlorian Westphal add_frag_mem_limit(fq->q.net, clone->truesize); 291ea81ac2eSAlexander Aring } 292ea81ac2eSAlexander Aring 293ea81ac2eSAlexander Aring WARN_ON(head == NULL); 294ea81ac2eSAlexander Aring 295ea81ac2eSAlexander Aring sum_truesize = head->truesize; 296ea81ac2eSAlexander Aring for (fp = head->next; fp;) { 297ea81ac2eSAlexander Aring bool headstolen; 298ea81ac2eSAlexander Aring int delta; 299ea81ac2eSAlexander Aring struct sk_buff *next = fp->next; 300ea81ac2eSAlexander Aring 301ea81ac2eSAlexander Aring sum_truesize += fp->truesize; 302ea81ac2eSAlexander Aring if (skb_try_coalesce(head, fp, &headstolen, &delta)) { 303ea81ac2eSAlexander Aring kfree_skb_partial(fp, headstolen); 304ea81ac2eSAlexander Aring } else { 305ea81ac2eSAlexander Aring if (!skb_shinfo(head)->frag_list) 306ea81ac2eSAlexander Aring skb_shinfo(head)->frag_list = fp; 307ea81ac2eSAlexander Aring head->data_len += fp->len; 308ea81ac2eSAlexander Aring head->len += fp->len; 309ea81ac2eSAlexander Aring head->truesize += fp->truesize; 310ea81ac2eSAlexander Aring } 311ea81ac2eSAlexander Aring fp = next; 312ea81ac2eSAlexander Aring } 3130e60d245SFlorian Westphal sub_frag_mem_limit(fq->q.net, sum_truesize); 314ea81ac2eSAlexander Aring 315ea81ac2eSAlexander Aring head->next = NULL; 316f4606583SAlexander Aring head->dev = ldev; 317ea81ac2eSAlexander Aring head->tstamp = fq->q.stamp; 318ea81ac2eSAlexander Aring 319ea81ac2eSAlexander Aring fq->q.fragments = NULL; 320ea81ac2eSAlexander Aring fq->q.fragments_tail = NULL; 321ea81ac2eSAlexander Aring 322ea81ac2eSAlexander Aring return 1; 323ea81ac2eSAlexander Aring out_oom: 324ea81ac2eSAlexander Aring net_dbg_ratelimited("lowpan_frag_reasm: no memory for reassembly\n"); 325ea81ac2eSAlexander Aring return -1; 326ea81ac2eSAlexander Aring } 327ea81ac2eSAlexander Aring 328ea81ac2eSAlexander Aring static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type, 329ea81ac2eSAlexander Aring struct lowpan_frag_info *frag_info) 330ea81ac2eSAlexander Aring { 331ea81ac2eSAlexander Aring bool fail; 332ea81ac2eSAlexander Aring u8 pattern = 0, low = 0; 333ea81ac2eSAlexander Aring __be16 d_tag = 0; 334ea81ac2eSAlexander Aring 335ea81ac2eSAlexander Aring fail = lowpan_fetch_skb(skb, &pattern, 1); 336ea81ac2eSAlexander Aring fail |= lowpan_fetch_skb(skb, &low, 1); 337ea81ac2eSAlexander Aring frag_info->d_size = (pattern & 7) << 8 | low; 338ea81ac2eSAlexander Aring fail |= lowpan_fetch_skb(skb, &d_tag, 2); 339ea81ac2eSAlexander Aring frag_info->d_tag = ntohs(d_tag); 340ea81ac2eSAlexander Aring 341ea81ac2eSAlexander Aring if (frag_type == LOWPAN_DISPATCH_FRAGN) { 342ea81ac2eSAlexander Aring fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1); 343ea81ac2eSAlexander Aring } else { 344ea81ac2eSAlexander Aring skb_reset_network_header(skb); 345ea81ac2eSAlexander Aring frag_info->d_offset = 0; 346ea81ac2eSAlexander Aring } 347ea81ac2eSAlexander Aring 348ea81ac2eSAlexander Aring if (unlikely(fail)) 349ea81ac2eSAlexander Aring return -EIO; 350ea81ac2eSAlexander Aring 351ea81ac2eSAlexander Aring return 0; 352ea81ac2eSAlexander Aring } 353ea81ac2eSAlexander Aring 354ea81ac2eSAlexander Aring int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) 355ea81ac2eSAlexander Aring { 356ea81ac2eSAlexander Aring struct lowpan_frag_queue *fq; 357ea81ac2eSAlexander Aring struct net *net = dev_net(skb->dev); 358ea81ac2eSAlexander Aring struct lowpan_frag_info *frag_info = lowpan_cb(skb); 359ea81ac2eSAlexander Aring struct ieee802154_addr source, dest; 360ea81ac2eSAlexander Aring int err; 361ea81ac2eSAlexander Aring 362ea81ac2eSAlexander Aring source = mac_cb(skb)->source; 363ea81ac2eSAlexander Aring dest = mac_cb(skb)->dest; 364ea81ac2eSAlexander Aring 365ea81ac2eSAlexander Aring err = lowpan_get_frag_info(skb, frag_type, frag_info); 366ea81ac2eSAlexander Aring if (err < 0) 367ea81ac2eSAlexander Aring goto err; 368ea81ac2eSAlexander Aring 369ea81ac2eSAlexander Aring if (frag_info->d_size > IPV6_MIN_MTU) { 370ea81ac2eSAlexander Aring net_warn_ratelimited("lowpan_frag_rcv: datagram size exceeds MTU\n"); 371ea81ac2eSAlexander Aring goto err; 372ea81ac2eSAlexander Aring } 373ea81ac2eSAlexander Aring 374ea81ac2eSAlexander Aring fq = fq_find(net, frag_info, &source, &dest); 375ea81ac2eSAlexander Aring if (fq != NULL) { 376ea81ac2eSAlexander Aring int ret; 377ea81ac2eSAlexander Aring 378ea81ac2eSAlexander Aring spin_lock(&fq->q.lock); 379ea81ac2eSAlexander Aring ret = lowpan_frag_queue(fq, skb, frag_type); 380ea81ac2eSAlexander Aring spin_unlock(&fq->q.lock); 381ea81ac2eSAlexander Aring 382ea81ac2eSAlexander Aring inet_frag_put(&fq->q, &lowpan_frags); 383ea81ac2eSAlexander Aring return ret; 384ea81ac2eSAlexander Aring } 385ea81ac2eSAlexander Aring 386ea81ac2eSAlexander Aring err: 387ea81ac2eSAlexander Aring kfree_skb(skb); 388ea81ac2eSAlexander Aring return -1; 389ea81ac2eSAlexander Aring } 390ea81ac2eSAlexander Aring EXPORT_SYMBOL(lowpan_frag_rcv); 391ea81ac2eSAlexander Aring 392ea81ac2eSAlexander Aring #ifdef CONFIG_SYSCTL 393ea81ac2eSAlexander Aring static int zero; 394ea81ac2eSAlexander Aring 395ea81ac2eSAlexander Aring static struct ctl_table lowpan_frags_ns_ctl_table[] = { 396ea81ac2eSAlexander Aring { 397ea81ac2eSAlexander Aring .procname = "6lowpanfrag_high_thresh", 398ea81ac2eSAlexander Aring .data = &init_net.ieee802154_lowpan.frags.high_thresh, 399ea81ac2eSAlexander Aring .maxlen = sizeof(int), 400ea81ac2eSAlexander Aring .mode = 0644, 401ea81ac2eSAlexander Aring .proc_handler = proc_dointvec_minmax, 402ea81ac2eSAlexander Aring .extra1 = &init_net.ieee802154_lowpan.frags.low_thresh 403ea81ac2eSAlexander Aring }, 404ea81ac2eSAlexander Aring { 405ea81ac2eSAlexander Aring .procname = "6lowpanfrag_low_thresh", 406ea81ac2eSAlexander Aring .data = &init_net.ieee802154_lowpan.frags.low_thresh, 407ea81ac2eSAlexander Aring .maxlen = sizeof(int), 408ea81ac2eSAlexander Aring .mode = 0644, 409ea81ac2eSAlexander Aring .proc_handler = proc_dointvec_minmax, 410ea81ac2eSAlexander Aring .extra1 = &zero, 411ea81ac2eSAlexander Aring .extra2 = &init_net.ieee802154_lowpan.frags.high_thresh 412ea81ac2eSAlexander Aring }, 413ea81ac2eSAlexander Aring { 414ea81ac2eSAlexander Aring .procname = "6lowpanfrag_time", 415ea81ac2eSAlexander Aring .data = &init_net.ieee802154_lowpan.frags.timeout, 416ea81ac2eSAlexander Aring .maxlen = sizeof(int), 417ea81ac2eSAlexander Aring .mode = 0644, 418ea81ac2eSAlexander Aring .proc_handler = proc_dointvec_jiffies, 419ea81ac2eSAlexander Aring }, 420ea81ac2eSAlexander Aring { } 421ea81ac2eSAlexander Aring }; 422ea81ac2eSAlexander Aring 423ea81ac2eSAlexander Aring /* secret interval has been deprecated */ 424ea81ac2eSAlexander Aring static int lowpan_frags_secret_interval_unused; 425ea81ac2eSAlexander Aring static struct ctl_table lowpan_frags_ctl_table[] = { 426ea81ac2eSAlexander Aring { 427ea81ac2eSAlexander Aring .procname = "6lowpanfrag_secret_interval", 428ea81ac2eSAlexander Aring .data = &lowpan_frags_secret_interval_unused, 429ea81ac2eSAlexander Aring .maxlen = sizeof(int), 430ea81ac2eSAlexander Aring .mode = 0644, 431ea81ac2eSAlexander Aring .proc_handler = proc_dointvec_jiffies, 432ea81ac2eSAlexander Aring }, 433ea81ac2eSAlexander Aring { } 434ea81ac2eSAlexander Aring }; 435ea81ac2eSAlexander Aring 436ea81ac2eSAlexander Aring static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) 437ea81ac2eSAlexander Aring { 438ea81ac2eSAlexander Aring struct ctl_table *table; 439ea81ac2eSAlexander Aring struct ctl_table_header *hdr; 440ea81ac2eSAlexander Aring struct netns_ieee802154_lowpan *ieee802154_lowpan = 441ea81ac2eSAlexander Aring net_ieee802154_lowpan(net); 442ea81ac2eSAlexander Aring 443ea81ac2eSAlexander Aring table = lowpan_frags_ns_ctl_table; 444ea81ac2eSAlexander Aring if (!net_eq(net, &init_net)) { 445ea81ac2eSAlexander Aring table = kmemdup(table, sizeof(lowpan_frags_ns_ctl_table), 446ea81ac2eSAlexander Aring GFP_KERNEL); 447ea81ac2eSAlexander Aring if (table == NULL) 448ea81ac2eSAlexander Aring goto err_alloc; 449ea81ac2eSAlexander Aring 450ea81ac2eSAlexander Aring table[0].data = &ieee802154_lowpan->frags.high_thresh; 451ea81ac2eSAlexander Aring table[0].extra1 = &ieee802154_lowpan->frags.low_thresh; 452ea81ac2eSAlexander Aring table[0].extra2 = &init_net.ieee802154_lowpan.frags.high_thresh; 453ea81ac2eSAlexander Aring table[1].data = &ieee802154_lowpan->frags.low_thresh; 454ea81ac2eSAlexander Aring table[1].extra2 = &ieee802154_lowpan->frags.high_thresh; 455ea81ac2eSAlexander Aring table[2].data = &ieee802154_lowpan->frags.timeout; 456ea81ac2eSAlexander Aring 457ea81ac2eSAlexander Aring /* Don't export sysctls to unprivileged users */ 458ea81ac2eSAlexander Aring if (net->user_ns != &init_user_ns) 459ea81ac2eSAlexander Aring table[0].procname = NULL; 460ea81ac2eSAlexander Aring } 461ea81ac2eSAlexander Aring 462ea81ac2eSAlexander Aring hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table); 463ea81ac2eSAlexander Aring if (hdr == NULL) 464ea81ac2eSAlexander Aring goto err_reg; 465ea81ac2eSAlexander Aring 466ea81ac2eSAlexander Aring ieee802154_lowpan->sysctl.frags_hdr = hdr; 467ea81ac2eSAlexander Aring return 0; 468ea81ac2eSAlexander Aring 469ea81ac2eSAlexander Aring err_reg: 470ea81ac2eSAlexander Aring if (!net_eq(net, &init_net)) 471ea81ac2eSAlexander Aring kfree(table); 472ea81ac2eSAlexander Aring err_alloc: 473ea81ac2eSAlexander Aring return -ENOMEM; 474ea81ac2eSAlexander Aring } 475ea81ac2eSAlexander Aring 476ea81ac2eSAlexander Aring static void __net_exit lowpan_frags_ns_sysctl_unregister(struct net *net) 477ea81ac2eSAlexander Aring { 478ea81ac2eSAlexander Aring struct ctl_table *table; 479ea81ac2eSAlexander Aring struct netns_ieee802154_lowpan *ieee802154_lowpan = 480ea81ac2eSAlexander Aring net_ieee802154_lowpan(net); 481ea81ac2eSAlexander Aring 482ea81ac2eSAlexander Aring table = ieee802154_lowpan->sysctl.frags_hdr->ctl_table_arg; 483ea81ac2eSAlexander Aring unregister_net_sysctl_table(ieee802154_lowpan->sysctl.frags_hdr); 484ea81ac2eSAlexander Aring if (!net_eq(net, &init_net)) 485ea81ac2eSAlexander Aring kfree(table); 486ea81ac2eSAlexander Aring } 487ea81ac2eSAlexander Aring 488ea81ac2eSAlexander Aring static struct ctl_table_header *lowpan_ctl_header; 489ea81ac2eSAlexander Aring 490ea81ac2eSAlexander Aring static int __init lowpan_frags_sysctl_register(void) 491ea81ac2eSAlexander Aring { 492ea81ac2eSAlexander Aring lowpan_ctl_header = register_net_sysctl(&init_net, 493ea81ac2eSAlexander Aring "net/ieee802154/6lowpan", 494ea81ac2eSAlexander Aring lowpan_frags_ctl_table); 495ea81ac2eSAlexander Aring return lowpan_ctl_header == NULL ? -ENOMEM : 0; 496ea81ac2eSAlexander Aring } 497ea81ac2eSAlexander Aring 498ea81ac2eSAlexander Aring static void lowpan_frags_sysctl_unregister(void) 499ea81ac2eSAlexander Aring { 500ea81ac2eSAlexander Aring unregister_net_sysctl_table(lowpan_ctl_header); 501ea81ac2eSAlexander Aring } 502ea81ac2eSAlexander Aring #else 503ea81ac2eSAlexander Aring static inline int lowpan_frags_ns_sysctl_register(struct net *net) 504ea81ac2eSAlexander Aring { 505ea81ac2eSAlexander Aring return 0; 506ea81ac2eSAlexander Aring } 507ea81ac2eSAlexander Aring 508ea81ac2eSAlexander Aring static inline void lowpan_frags_ns_sysctl_unregister(struct net *net) 509ea81ac2eSAlexander Aring { 510ea81ac2eSAlexander Aring } 511ea81ac2eSAlexander Aring 512ea81ac2eSAlexander Aring static inline int __init lowpan_frags_sysctl_register(void) 513ea81ac2eSAlexander Aring { 514ea81ac2eSAlexander Aring return 0; 515ea81ac2eSAlexander Aring } 516ea81ac2eSAlexander Aring 517ea81ac2eSAlexander Aring static inline void lowpan_frags_sysctl_unregister(void) 518ea81ac2eSAlexander Aring { 519ea81ac2eSAlexander Aring } 520ea81ac2eSAlexander Aring #endif 521ea81ac2eSAlexander Aring 522ea81ac2eSAlexander Aring static int __net_init lowpan_frags_init_net(struct net *net) 523ea81ac2eSAlexander Aring { 524ea81ac2eSAlexander Aring struct netns_ieee802154_lowpan *ieee802154_lowpan = 525ea81ac2eSAlexander Aring net_ieee802154_lowpan(net); 526ea81ac2eSAlexander Aring 527ea81ac2eSAlexander Aring ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH; 528ea81ac2eSAlexander Aring ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH; 529ea81ac2eSAlexander Aring ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT; 530ea81ac2eSAlexander Aring 531ea81ac2eSAlexander Aring inet_frags_init_net(&ieee802154_lowpan->frags); 532ea81ac2eSAlexander Aring 533ea81ac2eSAlexander Aring return lowpan_frags_ns_sysctl_register(net); 534ea81ac2eSAlexander Aring } 535ea81ac2eSAlexander Aring 536ea81ac2eSAlexander Aring static void __net_exit lowpan_frags_exit_net(struct net *net) 537ea81ac2eSAlexander Aring { 538ea81ac2eSAlexander Aring struct netns_ieee802154_lowpan *ieee802154_lowpan = 539ea81ac2eSAlexander Aring net_ieee802154_lowpan(net); 540ea81ac2eSAlexander Aring 541ea81ac2eSAlexander Aring lowpan_frags_ns_sysctl_unregister(net); 542ea81ac2eSAlexander Aring inet_frags_exit_net(&ieee802154_lowpan->frags, &lowpan_frags); 543ea81ac2eSAlexander Aring } 544ea81ac2eSAlexander Aring 545ea81ac2eSAlexander Aring static struct pernet_operations lowpan_frags_ops = { 546ea81ac2eSAlexander Aring .init = lowpan_frags_init_net, 547ea81ac2eSAlexander Aring .exit = lowpan_frags_exit_net, 548ea81ac2eSAlexander Aring }; 549ea81ac2eSAlexander Aring 550ea81ac2eSAlexander Aring int __init lowpan_net_frag_init(void) 551ea81ac2eSAlexander Aring { 552ea81ac2eSAlexander Aring int ret; 553ea81ac2eSAlexander Aring 554ea81ac2eSAlexander Aring ret = lowpan_frags_sysctl_register(); 555ea81ac2eSAlexander Aring if (ret) 556ea81ac2eSAlexander Aring return ret; 557ea81ac2eSAlexander Aring 558ea81ac2eSAlexander Aring ret = register_pernet_subsys(&lowpan_frags_ops); 559ea81ac2eSAlexander Aring if (ret) 560ea81ac2eSAlexander Aring goto err_pernet; 561ea81ac2eSAlexander Aring 562ea81ac2eSAlexander Aring lowpan_frags.hashfn = lowpan_hashfn; 563ea81ac2eSAlexander Aring lowpan_frags.constructor = lowpan_frag_init; 564ea81ac2eSAlexander Aring lowpan_frags.destructor = NULL; 565ea81ac2eSAlexander Aring lowpan_frags.skb_free = NULL; 566ea81ac2eSAlexander Aring lowpan_frags.qsize = sizeof(struct frag_queue); 567ea81ac2eSAlexander Aring lowpan_frags.match = lowpan_frag_match; 568ea81ac2eSAlexander Aring lowpan_frags.frag_expire = lowpan_frag_expire; 569ea81ac2eSAlexander Aring lowpan_frags.frags_cache_name = lowpan_frags_cache_name; 570ea81ac2eSAlexander Aring ret = inet_frags_init(&lowpan_frags); 571ea81ac2eSAlexander Aring if (ret) 572ea81ac2eSAlexander Aring goto err_pernet; 573ea81ac2eSAlexander Aring 574ea81ac2eSAlexander Aring return ret; 575ea81ac2eSAlexander Aring err_pernet: 576ea81ac2eSAlexander Aring lowpan_frags_sysctl_unregister(); 577ea81ac2eSAlexander Aring return ret; 578ea81ac2eSAlexander Aring } 579ea81ac2eSAlexander Aring 580ea81ac2eSAlexander Aring void lowpan_net_frag_exit(void) 581ea81ac2eSAlexander Aring { 582ea81ac2eSAlexander Aring inet_frags_fini(&lowpan_frags); 583ea81ac2eSAlexander Aring lowpan_frags_sysctl_unregister(); 584ea81ac2eSAlexander Aring unregister_pernet_subsys(&lowpan_frags_ops); 585ea81ac2eSAlexander Aring } 586