reassembly.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * IPv6 fragment reassembly
  3.  * Linux INET6 implementation 
  4.  *
  5.  * Authors:
  6.  * Pedro Roque <roque@di.fc.ul.pt>
  7.  *
  8.  * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $
  9.  *
  10.  * Based on: net/ipv4/ip_fragment.c
  11.  *
  12.  * This program is free software; you can redistribute it and/or
  13.  *      modify it under the terms of the GNU General Public License
  14.  *      as published by the Free Software Foundation; either version
  15.  *      2 of the License, or (at your option) any later version.
  16.  */
  17. /* 
  18.  * Fixes:
  19.  * Andi Kleen Make it work with multiple hosts.
  20.  * More RFC compliance.
  21.  *
  22.  *      Horst von Brand Add missing #include <linux/string.h>
  23.  * Alexey Kuznetsov SMP races, threading, cleanup.
  24.  */
  25. #include <linux/config.h>
  26. #include <linux/errno.h>
  27. #include <linux/types.h>
  28. #include <linux/string.h>
  29. #include <linux/socket.h>
  30. #include <linux/sockios.h>
  31. #include <linux/sched.h>
  32. #include <linux/net.h>
  33. #include <linux/netdevice.h>
  34. #include <linux/in6.h>
  35. #include <linux/ipv6.h>
  36. #include <linux/icmpv6.h>
  37. #include <net/sock.h>
  38. #include <net/snmp.h>
  39. #include <net/ipv6.h>
  40. #include <net/protocol.h>
  41. #include <net/transp_v6.h>
  42. #include <net/rawv6.h>
  43. #include <net/ndisc.h>
  44. #include <net/addrconf.h>
  45. int sysctl_ip6frag_high_thresh = 256*1024;
  46. int sysctl_ip6frag_low_thresh = 192*1024;
  47. int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT;
  48. struct ip6frag_skb_cb
  49. {
  50. struct inet6_skb_parm h;
  51. int offset;
  52. };
  53. #define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb))
  54. /*
  55.  * Equivalent of ipv4 struct ipq
  56.  */
  57. struct frag_queue
  58. {
  59. struct frag_queue *next;
  60. __u32 id; /* fragment id */
  61. struct in6_addr saddr;
  62. struct in6_addr daddr;
  63. spinlock_t lock;
  64. atomic_t refcnt;
  65. struct timer_list timer; /* expire timer */
  66. struct sk_buff *fragments;
  67. int len;
  68. int meat;
  69. int iif;
  70. struct timeval stamp;
  71. unsigned int csum;
  72. __u8 last_in; /* has first/last segment arrived? */
  73. #define COMPLETE 4
  74. #define FIRST_IN 2
  75. #define LAST_IN 1
  76. __u16 nhoffset;
  77. struct frag_queue **pprev;
  78. };
  79. /* Hash table. */
  80. #define IP6Q_HASHSZ 64
  81. static struct frag_queue *ip6_frag_hash[IP6Q_HASHSZ];
  82. static rwlock_t ip6_frag_lock = RW_LOCK_UNLOCKED;
  83. int ip6_frag_nqueues = 0;
  84. static __inline__ void __fq_unlink(struct frag_queue *fq)
  85. {
  86. if(fq->next)
  87. fq->next->pprev = fq->pprev;
  88. *fq->pprev = fq->next;
  89. ip6_frag_nqueues--;
  90. }
  91. static __inline__ void fq_unlink(struct frag_queue *fq)
  92. {
  93. write_lock(&ip6_frag_lock);
  94. __fq_unlink(fq);
  95. write_unlock(&ip6_frag_lock);
  96. }
  97. static __inline__ unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
  98.   struct in6_addr *daddr)
  99. {
  100. unsigned int h = saddr->s6_addr32[3] ^ daddr->s6_addr32[3] ^ id;
  101. h ^= (h>>16);
  102. h ^= (h>>8);
  103. return h & (IP6Q_HASHSZ - 1);
  104. }
  105. atomic_t ip6_frag_mem = ATOMIC_INIT(0);
  106. /* Memory Tracking Functions. */
  107. extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
  108. {
  109. atomic_sub(skb->truesize, &ip6_frag_mem);
  110. kfree_skb(skb);
  111. }
  112. extern __inline__ void frag_free_queue(struct frag_queue *fq)
  113. {
  114. atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem);
  115. kfree(fq);
  116. }
  117. extern __inline__ struct frag_queue *frag_alloc_queue(void)
  118. {
  119. struct frag_queue *fq = kmalloc(sizeof(struct frag_queue), GFP_ATOMIC);
  120. if(!fq)
  121. return NULL;
  122. atomic_add(sizeof(struct frag_queue), &ip6_frag_mem);
  123. return fq;
  124. }
  125. /* Destruction primitives. */
  126. /* Complete destruction of fq. */
  127. static void ip6_frag_destroy(struct frag_queue *fq)
  128. {
  129. struct sk_buff *fp;
  130. BUG_TRAP(fq->last_in&COMPLETE);
  131. BUG_TRAP(del_timer(&fq->timer) == 0);
  132. /* Release all fragment data. */
  133. fp = fq->fragments;
  134. while (fp) {
  135. struct sk_buff *xp = fp->next;
  136. frag_kfree_skb(fp);
  137. fp = xp;
  138. }
  139. frag_free_queue(fq);
  140. }
  141. static __inline__ void fq_put(struct frag_queue *fq)
  142. {
  143. if (atomic_dec_and_test(&fq->refcnt))
  144. ip6_frag_destroy(fq);
  145. }
  146. /* Kill fq entry. It is not destroyed immediately,
  147.  * because caller (and someone more) holds reference count.
  148.  */
  149. static __inline__ void fq_kill(struct frag_queue *fq)
  150. {
  151. if (del_timer(&fq->timer))
  152. atomic_dec(&fq->refcnt);
  153. if (!(fq->last_in & COMPLETE)) {
  154. fq_unlink(fq);
  155. atomic_dec(&fq->refcnt);
  156. fq->last_in |= COMPLETE;
  157. }
  158. }
  159. static void ip6_evictor(void)
  160. {
  161. int i, progress;
  162. do {
  163. if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh)
  164. return;
  165. progress = 0;
  166. for (i = 0; i < IP6Q_HASHSZ; i++) {
  167. struct frag_queue *fq;
  168. if (ip6_frag_hash[i] == NULL)
  169. continue;
  170. read_lock(&ip6_frag_lock);
  171. if ((fq = ip6_frag_hash[i]) != NULL) {
  172. /* find the oldest queue for this hash bucket */
  173. while (fq->next)
  174. fq = fq->next;
  175. atomic_inc(&fq->refcnt);
  176. read_unlock(&ip6_frag_lock);
  177. spin_lock(&fq->lock);
  178. if (!(fq->last_in&COMPLETE))
  179. fq_kill(fq);
  180. spin_unlock(&fq->lock);
  181. fq_put(fq);
  182. IP6_INC_STATS_BH(Ip6ReasmFails);
  183. progress = 1;
  184. continue;
  185. }
  186. read_unlock(&ip6_frag_lock);
  187. }
  188. } while (progress);
  189. }
  190. static void ip6_frag_expire(unsigned long data)
  191. {
  192. struct frag_queue *fq = (struct frag_queue *) data;
  193. spin_lock(&fq->lock);
  194. if (fq->last_in & COMPLETE)
  195. goto out;
  196. fq_kill(fq);
  197. IP6_INC_STATS_BH(Ip6ReasmTimeout);
  198. IP6_INC_STATS_BH(Ip6ReasmFails);
  199. /* Send error only if the first segment arrived. */
  200. if (fq->last_in&FIRST_IN && fq->fragments) {
  201. struct net_device *dev = dev_get_by_index(fq->iif);
  202. /*
  203.    But use as source device on which LAST ARRIVED
  204.    segment was received. And do not use fq->dev
  205.    pointer directly, device might already disappeared.
  206.  */
  207. if (dev) {
  208. fq->fragments->dev = dev;
  209. icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
  210.     dev);
  211. dev_put(dev);
  212. }
  213. }
  214. out:
  215. spin_unlock(&fq->lock);
  216. fq_put(fq);
  217. }
  218. /* Creation primitives. */
  219. static struct frag_queue *ip6_frag_intern(unsigned int hash,
  220.   struct frag_queue *fq_in)
  221. {
  222. struct frag_queue *fq;
  223. write_lock(&ip6_frag_lock);
  224. #ifdef CONFIG_SMP
  225. for (fq = ip6_frag_hash[hash]; fq; fq = fq->next) {
  226. if (fq->id == fq_in->id && 
  227.     !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
  228.     !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
  229. atomic_inc(&fq->refcnt);
  230. write_unlock(&ip6_frag_lock);
  231. fq_in->last_in |= COMPLETE;
  232. fq_put(fq_in);
  233. return fq;
  234. }
  235. }
  236. #endif
  237. fq = fq_in;
  238. if (!mod_timer(&fq->timer, jiffies + sysctl_ip6frag_time))
  239. atomic_inc(&fq->refcnt);
  240. atomic_inc(&fq->refcnt);
  241. if((fq->next = ip6_frag_hash[hash]) != NULL)
  242. fq->next->pprev = &fq->next;
  243. ip6_frag_hash[hash] = fq;
  244. fq->pprev = &ip6_frag_hash[hash];
  245. ip6_frag_nqueues++;
  246. write_unlock(&ip6_frag_lock);
  247. return fq;
  248. }
  249. static struct frag_queue *
  250. ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr *dst)
  251. {
  252. struct frag_queue *fq;
  253. if ((fq = frag_alloc_queue()) == NULL)
  254. goto oom;
  255. memset(fq, 0, sizeof(struct frag_queue));
  256. fq->id = id;
  257. ipv6_addr_copy(&fq->saddr, src);
  258. ipv6_addr_copy(&fq->daddr, dst);
  259. /* init_timer has been done by the memset */
  260. fq->timer.function = ip6_frag_expire;
  261. fq->timer.data = (long) fq;
  262. fq->lock = SPIN_LOCK_UNLOCKED;
  263. atomic_set(&fq->refcnt, 1);
  264. return ip6_frag_intern(hash, fq);
  265. oom:
  266. IP6_INC_STATS_BH(Ip6ReasmFails);
  267. return NULL;
  268. }
  269. static __inline__ struct frag_queue *
  270. fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
  271. {
  272. struct frag_queue *fq;
  273. unsigned int hash = ip6qhashfn(id, src, dst);
  274. read_lock(&ip6_frag_lock);
  275. for(fq = ip6_frag_hash[hash]; fq; fq = fq->next) {
  276. if (fq->id == id && 
  277.     !ipv6_addr_cmp(src, &fq->saddr) &&
  278.     !ipv6_addr_cmp(dst, &fq->daddr)) {
  279. atomic_inc(&fq->refcnt);
  280. read_unlock(&ip6_frag_lock);
  281. return fq;
  282. }
  283. }
  284. read_unlock(&ip6_frag_lock);
  285. return ip6_frag_create(hash, id, src, dst);
  286. }
  287. static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, 
  288.    struct frag_hdr *fhdr, int nhoff)
  289. {
  290. struct sk_buff *prev, *next;
  291. int offset, end;
  292. if (fq->last_in & COMPLETE)
  293. goto err;
  294. offset = ntohs(fhdr->frag_off) & ~0x7;
  295. end = offset + (ntohs(skb->nh.ipv6h->payload_len) -
  296. ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
  297. if ((unsigned int)end >= 65536) {
  298.   icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
  299.   return;
  300. }
  301.   if (skb->ip_summed == CHECKSUM_HW)
  302.   skb->csum = csum_sub(skb->csum,
  303.        csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0));
  304. /* Is this the final fragment? */
  305. if (!(fhdr->frag_off & __constant_htons(0x0001))) {
  306. /* If we already have some bits beyond end
  307.  * or have different end, the segment is corrupted.
  308.  */
  309. if (end < fq->len ||
  310.     ((fq->last_in & LAST_IN) && end != fq->len))
  311. goto err;
  312. fq->last_in |= LAST_IN;
  313. fq->len = end;
  314. } else {
  315. /* Check if the fragment is rounded to 8 bytes.
  316.  * Required by the RFC.
  317.  */
  318. if (end & 0x7) {
  319. /* RFC2460 says always send parameter problem in
  320.  * this case. -DaveM
  321.  */
  322. icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, 
  323.   offsetof(struct ipv6hdr, payload_len));
  324. return;
  325. }
  326. if (end > fq->len) {
  327. /* Some bits beyond end -> corruption. */
  328. if (fq->last_in & LAST_IN)
  329. goto err;
  330. fq->len = end;
  331. }
  332. }
  333. if (end == offset)
  334. goto err;
  335. /* Point into the IP datagram 'data' part. */
  336. if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data))
  337. goto err;
  338. if (end-offset < skb->len) {
  339. if (pskb_trim(skb, end - offset))
  340. goto err;
  341. if (skb->ip_summed != CHECKSUM_UNNECESSARY)
  342. skb->ip_summed = CHECKSUM_NONE;
  343. }
  344. /* Find out which fragments are in front and at the back of us
  345.  * in the chain of fragments so far.  We must know where to put
  346.  * this fragment, right?
  347.  */
  348. prev = NULL;
  349. for(next = fq->fragments; next != NULL; next = next->next) {
  350. if (FRAG6_CB(next)->offset >= offset)
  351. break; /* bingo! */
  352. prev = next;
  353. }
  354. /* We found where to put this one.  Check for overlap with
  355.  * preceding fragment, and, if needed, align things so that
  356.  * any overlaps are eliminated.
  357.  */
  358. if (prev) {
  359. int i = (FRAG6_CB(prev)->offset + prev->len) - offset;
  360. if (i > 0) {
  361. offset += i;
  362. if (end <= offset)
  363. goto err;
  364. if (!pskb_pull(skb, i))
  365. goto err;
  366. if (skb->ip_summed != CHECKSUM_UNNECESSARY)
  367. skb->ip_summed = CHECKSUM_NONE;
  368. }
  369. }
  370. /* Look for overlap with succeeding segments.
  371.  * If we can merge fragments, do it.
  372.  */
  373. while (next && FRAG6_CB(next)->offset < end) {
  374. int i = end - FRAG6_CB(next)->offset; /* overlap is 'i' bytes */
  375. if (i < next->len) {
  376. /* Eat head of the next overlapped fragment
  377.  * and leave the loop. The next ones cannot overlap.
  378.  */
  379. if (!pskb_pull(next, i))
  380. goto err;
  381. FRAG6_CB(next)->offset += i; /* next fragment */
  382. fq->meat -= i;
  383. if (next->ip_summed != CHECKSUM_UNNECESSARY)
  384. next->ip_summed = CHECKSUM_NONE;
  385. break;
  386. } else {
  387. struct sk_buff *free_it = next;
  388. /* Old fragmnet is completely overridden with
  389.  * new one drop it.
  390.  */
  391. next = next->next;
  392. if (prev)
  393. prev->next = next;
  394. else
  395. fq->fragments = next;
  396. fq->meat -= free_it->len;
  397. frag_kfree_skb(free_it);
  398. }
  399. }
  400. FRAG6_CB(skb)->offset = offset;
  401. /* Insert this fragment in the chain of fragments. */
  402. skb->next = next;
  403. if (prev)
  404. prev->next = skb;
  405. else
  406. fq->fragments = skb;
  407. if (skb->dev)
  408. fq->iif = skb->dev->ifindex;
  409. skb->dev = NULL;
  410. fq->stamp = skb->stamp;
  411. fq->meat += skb->len;
  412. atomic_add(skb->truesize, &ip6_frag_mem);
  413. /* The first fragment.
  414.  * nhoffset is obtained from the first fragment, of course.
  415.  */
  416. if (offset == 0) {
  417. fq->nhoffset = nhoff;
  418. fq->last_in |= FIRST_IN;
  419. }
  420. return;
  421. err:
  422. kfree_skb(skb);
  423. }
  424. /*
  425.  * Check if this packet is complete.
  426.  * Returns NULL on failure by any reason, and pointer
  427.  * to current nexthdr field in reassembled frame.
  428.  *
  429.  * It is called with locked fq, and caller must check that
  430.  * queue is eligible for reassembly i.e. it is not COMPLETE,
  431.  * the last and the first frames arrived and all the bits are here.
  432.  */
  433. static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
  434.   struct net_device *dev)
  435. {
  436. struct sk_buff *fp, *head = fq->fragments;
  437. int    remove_fraghdr = 0;
  438. int    payload_len;
  439. int    nhoff;
  440. fq_kill(fq);
  441. BUG_TRAP(head != NULL);
  442. BUG_TRAP(FRAG6_CB(head)->offset == 0);
  443. /* Unfragmented part is taken from the first segment. */
  444. payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
  445. nhoff = head->h.raw - head->nh.raw;
  446. if (payload_len > 65535) {
  447. payload_len -= 8;
  448. if (payload_len > 65535)
  449. goto out_oversize;
  450. remove_fraghdr = 1;
  451. }
  452. /* Head of list must not be cloned. */
  453. if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
  454. goto out_oom;
  455. /* If the first fragment is fragmented itself, we split
  456.  * it to two chunks: the first with data and paged part
  457.  * and the second, holding only fragments. */
  458. if (skb_shinfo(head)->frag_list) {
  459. struct sk_buff *clone;
  460. int i, plen = 0;
  461. if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
  462. goto out_oom;
  463. clone->next = head->next;
  464. head->next = clone;
  465. skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
  466. skb_shinfo(head)->frag_list = NULL;
  467. for (i=0; i<skb_shinfo(head)->nr_frags; i++)
  468. plen += skb_shinfo(head)->frags[i].size;
  469. clone->len = clone->data_len = head->data_len - plen;
  470. head->data_len -= clone->len;
  471. head->len -= clone->len;
  472. clone->csum = 0;
  473. clone->ip_summed = head->ip_summed;
  474. atomic_add(clone->truesize, &ip6_frag_mem);
  475. }
  476. /* Normally we do not remove frag header from datagram, but
  477.  * we have to do this and to relocate header, when payload
  478.  * is > 65535-8. */
  479. if (remove_fraghdr) {
  480. nhoff = fq->nhoffset;
  481. head->nh.raw[nhoff] = head->h.raw[0];
  482. memmove(head->head+8, head->head, (head->data-head->head)-8);
  483. head->mac.raw += 8;
  484. head->nh.raw += 8;
  485. } else {
  486. ((struct frag_hdr*)head->h.raw)->frag_off = 0;
  487. }
  488. skb_shinfo(head)->frag_list = head->next;
  489. head->h.raw = head->data;
  490. skb_push(head, head->data - head->nh.raw);
  491. atomic_sub(head->truesize, &ip6_frag_mem);
  492. for (fp=head->next; fp; fp = fp->next) {
  493. head->data_len += fp->len;
  494. head->len += fp->len;
  495. if (head->ip_summed != fp->ip_summed)
  496. head->ip_summed = CHECKSUM_NONE;
  497. else if (head->ip_summed == CHECKSUM_HW)
  498. head->csum = csum_add(head->csum, fp->csum);
  499. head->truesize += fp->truesize;
  500. atomic_sub(fp->truesize, &ip6_frag_mem);
  501. }
  502. head->next = NULL;
  503. head->dev = dev;
  504. head->stamp = fq->stamp;
  505. head->nh.ipv6h->payload_len = ntohs(payload_len);
  506. *skb_in = head;
  507. /* Yes, and fold redundant checksum back. 8) */
  508. if (head->ip_summed == CHECKSUM_HW)
  509. head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
  510. IP6_INC_STATS_BH(Ip6ReasmOKs);
  511. fq->fragments = NULL;
  512. return nhoff;
  513. out_oversize:
  514. if (net_ratelimit())
  515. printk(KERN_DEBUG "ip6_frag_reasm: payload len = %dn", payload_len);
  516. goto out_fail;
  517. out_oom:
  518. if (net_ratelimit())
  519. printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassemblyn");
  520. out_fail:
  521. IP6_INC_STATS_BH(Ip6ReasmFails);
  522. return -1;
  523. }
  524. int ipv6_reassembly(struct sk_buff **skbp, int nhoff)
  525. {
  526. struct sk_buff *skb = *skbp; 
  527. struct net_device *dev = skb->dev;
  528. struct frag_hdr *fhdr;
  529. struct frag_queue *fq;
  530. struct ipv6hdr *hdr;
  531. hdr = skb->nh.ipv6h;
  532. IP6_INC_STATS_BH(Ip6ReasmReqds);
  533. /* Jumbo payload inhibits frag. header */
  534. if (hdr->payload_len==0) {
  535. icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
  536. return -1;
  537. }
  538. if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
  539. icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
  540. return -1;
  541. }
  542. hdr = skb->nh.ipv6h;
  543. fhdr = (struct frag_hdr *)skb->h.raw;
  544. if (!(fhdr->frag_off & __constant_htons(0xFFF9))) {
  545. /* It is not a fragmented frame */
  546. skb->h.raw += sizeof(struct frag_hdr);
  547. IP6_INC_STATS_BH(Ip6ReasmOKs);
  548. return (u8*)fhdr - skb->nh.raw;
  549. }
  550. if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
  551. ip6_evictor();
  552. if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr)) != NULL) {
  553. int ret = -1;
  554. spin_lock(&fq->lock);
  555. ip6_frag_queue(fq, skb, fhdr, nhoff);
  556. if (fq->last_in == (FIRST_IN|LAST_IN) &&
  557.     fq->meat == fq->len)
  558. ret = ip6_frag_reasm(fq, skbp, dev);
  559. spin_unlock(&fq->lock);
  560. fq_put(fq);
  561. return ret;
  562. }
  563. IP6_INC_STATS_BH(Ip6ReasmFails);
  564. kfree_skb(skb);
  565. return -1;
  566. }