519 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 520 { 521 struct net_device *dev; 522 struct sk_buff *frag; 523 struct rt6_info *rt = (struct rt6_info*)skb->dst; 524 struct ipv6hdr *tmp_hdr; 525 struct frag_hdr *fh; 526 unsigned int mtu, hlen, left, len; 527 u32 frag_id = 0; 528 int ptr, offset = 0, err=0; 529 u8 *prevhdr, nexthdr = 0; 530 531 dev = rt->u.dst.dev; //取得路由项中的设备 532 hlen = ip6_find_1stfragopt(skb, &prevhdr);// 533 nexthdr = *prevhdr; 534 //去掉分片头和ip头 535 mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr); 1 快分片 //如果已经在tcp分片,先查验第一个分片是否满足不用分片的条件,如果满足快速查验其他分片,有问题就跳到慢分片处处理 537 if (skb_shinfo(skb)->frag_list) { 1.1 查看第一个分片 538 int first_len = skb_pagelen(skb); //取得第一个分片长度 539 //查看第一个分片是否已经满足不用分片条件 540 if (first_len - hlen > mtu || //是否大于MTU 541 ((first_len - hlen) & 7) || //是否8字节对齐 542 skb_cloned(skb)) //是否克隆包 543 goto slow_path; 1.2 查看其他分片 545 for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) 546 { /* Correct geometry. */ 547 if (frag->len > mtu || 548 ((frag->len & 7) && frag->next) || 549 skb_headroom(frag) < hlen) 550 goto slow_path; 551 552 /* Correct socket ownership. */ 553 if (frag->sk == NULL) 554 goto slow_path; 555 556 /* Partially cloned skb? */ 557 if (skb_shared(frag)) //如果是共享数据包,不能被修改 558 goto slow_path; 559 } 560 561 err = 0; 562 offset = 0; 563 frag = skb_shinfo(skb)->frag_list; 564 skb_shinfo(skb)->frag_list = NULL; 1.3 设置主数据包头部 565 /* BUILD HEADER */ 1.3.1 将头部放在临时区域 567 tmp_hdr = kmalloc(hlen, GFP_ATOMIC); 568 if (!tmp_hdr) { 569 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 570 return -ENOMEM; 571 } 572 573 *prevhdr = NEXTHDR_FRAGMENT; 574 memcpy(tmp_hdr, skb->nh.raw, hlen); 1.3.2 加入分片头部 575 __skb_pull(skb, hlen); 576 fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr)); 1.3.3 原头部放回 577 skb->nh.raw = __skb_push(skb, hlen); 578 memcpy(skb->nh.raw, tmp_hdr, hlen); 1.3.4 设置分片头部 580 ipv6_select_ident(skb, fh); 581 fh->nexthdr = nexthdr; 582 fh->reserved = 0; 583 fh->frag_off = htons(IP6_MF); 584 frag_id = fh->identification; 585 586 first_len = skb_pagelen(skb); 587 skb->data_len = first_len - skb_headlen(skb); 588 skb->len = first_len; 589 skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); 590 1.4 发送所有分片 592 for (;;) { 593 /* Prepare header of the next frame, 594 * before previous one went down. */ 595 if (frag) { 1.4.1 设置个分段数据包头部 596 frag->ip_summed = CHECKSUM_NONE; 597 frag->h.raw = frag->data; 598 fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr)); 599 frag->nh.raw = __skb_push(frag, hlen); 600 memcpy(frag->nh.raw, tmp_hdr, hlen); 601 offset += skb->len - hlen - sizeof(struct frag_hdr); 602 fh->nexthdr = nexthdr; 603 fh->reserved = 0; 604 fh->frag_off = htons(offset); 605 if (frag->next != NULL) 606 fh->frag_off |= htons(IP6_MF); 607 fh->identification = frag_id; 608 frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); 609 ip6_copy_metadata(frag, skb); 610 } 1.4.2 发送数据报 612 err = output(skb); 613 if (err || !frag) 614 break; 615 616 skb = frag; 617 frag = skb->next; 618 skb->next = NULL; 619 } 620 621 if (tmp_hdr) 622 kfree(tmp_hdr); 623 624 if (err == 0) { 625 IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); 626 return 0; 627 } 1.4.3 释放节点 629 while (frag) { 630 skb = frag->next; 631 kfree_skb(frag); 632 frag = skb; 633 } 634 635 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 636 return err; 637 } 2 慢分片 639 slow_path: 640 left = skb->len - hlen; /* Space per frame */ 641 ptr = hlen; /* Where to start from */ 642 643 /* 644 * Fragment the datagram. 645 */ 646 647 *prevhdr = NEXTHDR_FRAGMENT; 648 649 /* 650 * Keep copying data until we run out. 651 */ 652 while(left > 0) { 2.1 分片 2.1.1 设置分片长度 653 len = left; 654 /* IF: it doesn't fit, use 'mtu' - the data space left */ 655 if (len > mtu) 656 len = mtu; 657 /* IF: we are not sending upto and including the packet end 658 then align the next start on an eight byte boundary */ 659 if (len < left) { 660 len &= ~7; 661 } 662 /* 663 * Allocate buffer. 664 */ 2.1.2 分配分片数据报空间 665 666 if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { 667 NETDEBUG(printk(KERN_INFO "IPv6: frag: no memory for new fragment!\n")); 668 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 669 err = -ENOMEM; 670 goto fail; 671 } 672 673 /* 674 * Set up data on packet 675 */ 676 2.1.3 初始化数据包结构 677 ip6_copy_metadata(frag, skb); 678 skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev)); 679 skb_put(frag, len + hlen + sizeof(struct frag_hdr)); 680 frag->nh.raw = frag->data; 681 fh = (struct frag_hdr*)(frag->data + hlen); 682 frag->h.raw = frag->data + hlen + sizeof(struct frag_hdr); 683 684 /* 685 * Charge the memory for the fragment to any owner 686 * it might possess 687 */ 688 if (skb->sk) 689 skb_set_owner_w(frag, skb->sk); 690 691 /* 692 * Copy the packet header into the new buffer. 693 */ 2.1.4 设置数据包内容 694 memcpy(frag->nh.raw, skb->data, hlen); //拷贝数据报头 695 696 /* 697 * Build fragment header. 698 */ 699 fh->nexthdr = nexthdr; 700 fh->reserved = 0; 701 if (frag_id) { 702 ipv6_select_ident(skb, fh); 703 frag_id = fh->identification; 704 } else 705 fh->identification = frag_id; 706 707 /* 708 * Copy a block of the IP datagram. 709 */ 710 if (skb_copy_bits(skb, ptr, frag->h.raw, len)) //拷贝数据 711 BUG(); 712 left -= len; 713 714 fh->frag_off = htons(offset); 715 if (left > 0) 716 fh->frag_off |= htons(IP6_MF); 717 frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); 718 719 ptr += len; 720 offset += len; 721 722 /* 723 * Put this fragment into the sending queue. 724 */ 725 726 IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); 727 2.2 发送 728 err = output(frag); 729 if (err) 730 goto fail; 731 } 732 kfree_skb(skb); 733 IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); 734 return err; 735 736 fail: 737 kfree_skb(skb); 738 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 739 return err; 740 }
?