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 }