// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ipv4

import (
	
	
	
	

	
)

const (
	Version   = 4  // protocol version
	HeaderLen = 20 // header length without extension headers
)

type HeaderFlags int

const (
	MoreFragments HeaderFlags = 1 << iota // more fragments flag
	DontFragment                          // don't fragment flag
)

// A Header represents an IPv4 header.
type Header struct {
	Version  int         // protocol version
	Len      int         // header length
	TOS      int         // type-of-service
	TotalLen int         // packet total length
	ID       int         // identification
	Flags    HeaderFlags // flags
	FragOff  int         // fragment offset
	TTL      int         // time-to-live
	Protocol int         // next protocol
	Checksum int         // checksum
	Src      net.IP      // source address
	Dst      net.IP      // destination address
	Options  []byte      // options, extension headers
}

func ( *Header) () string {
	if  == nil {
		return "<nil>"
	}
	return fmt.Sprintf("ver=%d hdrlen=%d tos=%#x totallen=%d id=%#x flags=%#x fragoff=%#x ttl=%d proto=%d cksum=%#x src=%v dst=%v", .Version, .Len, .TOS, .TotalLen, .ID, .Flags, .FragOff, .TTL, .Protocol, .Checksum, .Src, .Dst)
}

// Marshal returns the binary encoding of h.
//
// The returned slice is in the format used by a raw IP socket on the
// local system.
// This may differ from the wire format, depending on the system.
func ( *Header) () ([]byte, error) {
	if  == nil {
		return nil, errNilHeader
	}
	if .Len < HeaderLen {
		return nil, errHeaderTooShort
	}
	 := HeaderLen + len(.Options)
	 := make([]byte, )
	[0] = byte(Version<<4 | ( >> 2 & 0x0f))
	[1] = byte(.TOS)
	 := (.FragOff & 0x1fff) | int(.Flags<<13)
	switch runtime.GOOS {
	case "darwin", "ios", "dragonfly", "netbsd":
		socket.NativeEndian.PutUint16([2:4], uint16(.TotalLen))
		socket.NativeEndian.PutUint16([6:8], uint16())
	case "freebsd":
		if freebsdVersion < 1100000 {
			socket.NativeEndian.PutUint16([2:4], uint16(.TotalLen))
			socket.NativeEndian.PutUint16([6:8], uint16())
		} else {
			binary.BigEndian.PutUint16([2:4], uint16(.TotalLen))
			binary.BigEndian.PutUint16([6:8], uint16())
		}
	default:
		binary.BigEndian.PutUint16([2:4], uint16(.TotalLen))
		binary.BigEndian.PutUint16([6:8], uint16())
	}
	binary.BigEndian.PutUint16([4:6], uint16(.ID))
	[8] = byte(.TTL)
	[9] = byte(.Protocol)
	binary.BigEndian.PutUint16([10:12], uint16(.Checksum))
	if  := .Src.To4();  != nil {
		copy([12:16], [:net.IPv4len])
	}
	if  := .Dst.To4();  != nil {
		copy([16:20], [:net.IPv4len])
	} else {
		return nil, errMissingAddress
	}
	if len(.Options) > 0 {
		copy([HeaderLen:], .Options)
	}
	return , nil
}

// Parse parses b as an IPv4 header and stores the result in h.
//
// The provided b must be in the format used by a raw IP socket on the
// local system.
// This may differ from the wire format, depending on the system.
func ( *Header) ( []byte) error {
	if  == nil ||  == nil {
		return errNilHeader
	}
	if len() < HeaderLen {
		return errHeaderTooShort
	}
	 := int([0]&0x0f) << 2
	if len() <  {
		return errExtHeaderTooShort
	}
	.Version = int([0] >> 4)
	.Len = 
	.TOS = int([1])
	.ID = int(binary.BigEndian.Uint16([4:6]))
	.TTL = int([8])
	.Protocol = int([9])
	.Checksum = int(binary.BigEndian.Uint16([10:12]))
	.Src = net.IPv4([12], [13], [14], [15])
	.Dst = net.IPv4([16], [17], [18], [19])
	switch runtime.GOOS {
	case "darwin", "ios", "dragonfly", "netbsd":
		.TotalLen = int(socket.NativeEndian.Uint16([2:4])) + 
		.FragOff = int(socket.NativeEndian.Uint16([6:8]))
	case "freebsd":
		if freebsdVersion < 1100000 {
			.TotalLen = int(socket.NativeEndian.Uint16([2:4]))
			if freebsdVersion < 1000000 {
				.TotalLen += 
			}
			.FragOff = int(socket.NativeEndian.Uint16([6:8]))
		} else {
			.TotalLen = int(binary.BigEndian.Uint16([2:4]))
			.FragOff = int(binary.BigEndian.Uint16([6:8]))
		}
	default:
		.TotalLen = int(binary.BigEndian.Uint16([2:4]))
		.FragOff = int(binary.BigEndian.Uint16([6:8]))
	}
	.Flags = HeaderFlags(.FragOff&0xe000) >> 13
	.FragOff = .FragOff & 0x1fff
	 :=  - HeaderLen
	if  > 0 && len() >=  {
		if cap(.Options) <  {
			.Options = make([]byte, )
		} else {
			.Options = .Options[:]
		}
		copy(.Options, [HeaderLen:])
	}
	return nil
}

// ParseHeader parses b as an IPv4 header.
//
// The provided b must be in the format used by a raw IP socket on the
// local system.
// This may differ from the wire format, depending on the system.
func ( []byte) (*Header, error) {
	 := new(Header)
	if  := .Parse();  != nil {
		return nil, 
	}
	return , nil
}