public IpV4Packet Defrag(
            IpV4Packet ipPacket
            )
        {
            var result = ipPacket;

            var header = ipPacket.Header;

            if (header.IsFragmented)
            {
                var ufid = ipPacket.Header.UniqueFragmentId;

                var agent = CreateOrGetAgent(ufid);
                result = agent.Consume(ipPacket);

                if (result != null)
                {
                    agentMap_.Remove(ufid);
                }
            }

            return(result);
        }
            public IpV4Packet Consume(
                IpV4Packet packet
                )
            {
                IpV4Packet mergedPacket = null;

                if (packet == null)
                {
                    throw new ArgumentNullException("packet");
                }

                var header = packet.Header;

                var isNotFragmented = false;

                var offsetInterval = default(IntervalInt32);

                switch (header.FragmentFlags)
                {
                case 0x00:
                    if (header.FragmentOffset > 0)
                    {
                        if (lastFragmentHeader_ != null)
                        {
                            throw new Exception("Duplicated last fragment!");
                        }
                        lastFragmentHeader_ = packet.Header;

                        offsetInterval = new IntervalInt32(header.FragmentOffset, holeList_.Range.Maximum);
                    }
                    else
                    {
                        isNotFragmented = true;
                    }
                    break;

                case 0x01:
                    if (header.FragmentOffset == 0)
                    {
                        if (firstFragmentHeader_ != null)
                        {
                            throw new Exception("Duplicated first fragment!");
                        }
                        else
                        {
                            firstFragmentHeader_ = packet.Header;
                        }
                    }

                    if ((header.PayloadLength & ((1 << 3) - 1)) != 0)
                    {
                        throw new FormatException("The length of non-final fragments must be multiple of 8.");
                    }

                    offsetInterval = new IntervalInt32(header.FragmentOffset, (header.PayloadLength > 0 ? header.PayloadLength - 1 : 0));
                    break;

                case 0x02:
                    isNotFragmented = true;
                    break;

                default:
                    throw new FormatException("The fragment flag has an invalid value.");
                }

                if (isNotFragmented)
                {
                    mergedPacket = packet;
                    Reset();
                }
                else
                {
                    try {
                        holeList_.Fill(offsetInterval);
                        payloadMap_.Add(header.FragmentOffset, packet.Payload);

                        if (holeList_.HasNoMoreHoles)
                        {
                            if (lastFragmentHeader_ == null || firstFragmentHeader_ == null)
                            {
                                throw new FormatException("");
                            }

                            var mergedPayloadLength = lastFragmentHeader_.FragmentOffset + lastFragmentHeader_.PayloadLength;
                            var mergedPayloadBuffer = new ByteBuffer(lastFragmentHeader_.FragmentOffset + lastFragmentHeader_.PayloadLength);
                            foreach (var pair in payloadMap_)
                            {
                                mergedPayloadBuffer.Enqueue(pair.Value);
                            }
                            if (mergedPayloadBuffer.Count != mergedPayloadLength)
                            {
                                throw new FormatException("");
                            }

                            mergedPacket = new IpV4Packet(header, mergedPayloadBuffer.Dequeue());

                            Reset();
                        }
                    }
                    catch (Exception e) {
                        Reset();

                        throw e;
                    }
                }

                return(mergedPacket);
            }