Merge "icmp: make Marshal of MessageBody, ParseMessage work correctly on parameter problem message"
diff --git a/icmp/dstunreach.go b/icmp/dstunreach.go
index 8241017..3f843cd 100644
--- a/icmp/dstunreach.go
+++ b/icmp/dstunreach.go
@@ -19,7 +19,7 @@
 }
 
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *DstUnreach) Marshal() ([]byte, error) {
+func (p *DstUnreach) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	copy(b[4:], p.Data)
 	return b, nil
@@ -27,7 +27,7 @@
 
 // parseDstUnreach parses b as an ICMP destination unreachable message
 // body.
-func parseDstUnreach(b []byte) (MessageBody, error) {
+func parseDstUnreach(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
diff --git a/icmp/echo.go b/icmp/echo.go
index dfac9cb..6b373fc 100644
--- a/icmp/echo.go
+++ b/icmp/echo.go
@@ -20,7 +20,7 @@
 }
 
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *Echo) Marshal() ([]byte, error) {
+func (p *Echo) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
 	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
@@ -29,7 +29,7 @@
 }
 
 // parseEcho parses b as an ICMP echo request or reply message body.
-func parseEcho(b []byte) (MessageBody, error) {
+func parseEcho(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
diff --git a/icmp/message.go b/icmp/message.go
index 3d89108..13398a0 100644
--- a/icmp/message.go
+++ b/icmp/message.go
@@ -63,7 +63,7 @@
 		b = append(psh, b...)
 	}
 	if m.Body != nil && m.Body.Len() != 0 {
-		mb, err := m.Body.Marshal()
+		mb, err := m.Body.Marshal(m.Type.Protocol())
 		if err != nil {
 			return nil, err
 		}
@@ -93,7 +93,7 @@
 	return b[len(psh):], nil
 }
 
-var parseFns = map[Type]func([]byte) (MessageBody, error){
+var parseFns = map[Type]func(int, []byte) (MessageBody, error){
 	ipv4.ICMPTypeDestinationUnreachable: parseDstUnreach,
 	ipv4.ICMPTypeTimeExceeded:           parseTimeExceeded,
 	ipv4.ICMPTypeParameterProblem:       parseParamProb,
@@ -127,9 +127,9 @@
 		return nil, syscall.EINVAL
 	}
 	if fn, ok := parseFns[m.Type]; !ok {
-		m.Body, err = parseDefaultMessageBody(b[4:])
+		m.Body, err = parseDefaultMessageBody(proto, b[4:])
 	} else {
-		m.Body, err = fn(b[4:])
+		m.Body, err = fn(proto, b[4:])
 	}
 	if err != nil {
 		return nil, err
diff --git a/icmp/messagebody.go b/icmp/messagebody.go
index f653ab6..30f2df8 100644
--- a/icmp/messagebody.go
+++ b/icmp/messagebody.go
@@ -10,7 +10,8 @@
 	Len() int
 
 	// Marshal returns the binary enconding of ICMP message body.
-	Marshal() ([]byte, error)
+	// Proto must be either the ICMPv4 or ICMPv6 protocol number.
+	Marshal(proto int) ([]byte, error)
 }
 
 // A DefaultMessageBody represents the default message body.
@@ -27,12 +28,12 @@
 }
 
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *DefaultMessageBody) Marshal() ([]byte, error) {
+func (p *DefaultMessageBody) Marshal(proto int) ([]byte, error) {
 	return p.Data, nil
 }
 
 // parseDefaultMessageBody parses b as an ICMP message body.
-func parseDefaultMessageBody(b []byte) (MessageBody, error) {
+func parseDefaultMessageBody(proto int, b []byte) (MessageBody, error) {
 	p := &DefaultMessageBody{Data: make([]byte, len(b))}
 	copy(p.Data, b)
 	return p, nil
diff --git a/icmp/packettoobig.go b/icmp/packettoobig.go
index fc10192..0628e38 100644
--- a/icmp/packettoobig.go
+++ b/icmp/packettoobig.go
@@ -19,7 +19,7 @@
 }
 
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *PacketTooBig) Marshal() ([]byte, error) {
+func (p *PacketTooBig) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	b[0], b[1], b[2], b[3] = byte(p.MTU>>24), byte(p.MTU>>16), byte(p.MTU>>8), byte(p.MTU)
 	copy(b[4:], p.Data)
@@ -27,7 +27,7 @@
 }
 
 // parsePacketTooBig parses b as an ICMP packet too big message body.
-func parsePacketTooBig(b []byte) (MessageBody, error) {
+func parsePacketTooBig(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
diff --git a/icmp/paramprob.go b/icmp/paramprob.go
index be32ce0..ecf80ec 100644
--- a/icmp/paramprob.go
+++ b/icmp/paramprob.go
@@ -4,6 +4,8 @@
 
 package icmp
 
+import "golang.org/x/net/internal/iana"
+
 // A ParamProb represents an ICMP parameter problem message body.
 type ParamProb struct {
 	Pointer uintptr // offset within the data where the error was detected
@@ -19,20 +21,31 @@
 }
 
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *ParamProb) Marshal() ([]byte, error) {
+func (p *ParamProb) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
-	b[0], b[1], b[2], b[3] = byte(p.Pointer>>24), byte(p.Pointer>>16), byte(p.Pointer>>8), byte(p.Pointer)
+	switch proto {
+	case iana.ProtocolICMP:
+		b[0] = byte(p.Pointer)
+	case iana.ProtocolIPv6ICMP:
+		b[0], b[1], b[2], b[3] = byte(p.Pointer>>24), byte(p.Pointer>>16), byte(p.Pointer>>8), byte(p.Pointer)
+	}
 	copy(b[4:], p.Data)
 	return b, nil
 }
 
 // parseParamProb parses b as an ICMP parameter problem message body.
-func parseParamProb(b []byte) (MessageBody, error) {
+func parseParamProb(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 	}
-	p := &ParamProb{Pointer: uintptr(b[0])<<24 | uintptr(b[1])<<16 | uintptr(b[2])<<8 | uintptr(b[3])}
+	p := &ParamProb{}
+	switch proto {
+	case iana.ProtocolICMP:
+		p.Pointer = uintptr(b[0])
+	case iana.ProtocolIPv6ICMP:
+		p.Pointer = uintptr(b[0])<<24 | uintptr(b[1])<<16 | uintptr(b[2])<<8 | uintptr(b[3])
+	}
 	if bodyLen > 4 {
 		p.Data = make([]byte, bodyLen-4)
 		copy(p.Data, b[4:])
diff --git a/icmp/timeexceeded.go b/icmp/timeexceeded.go
index 993a150..0f0bb91 100644
--- a/icmp/timeexceeded.go
+++ b/icmp/timeexceeded.go
@@ -18,14 +18,14 @@
 }
 
 // Marshal implements the Marshal method of MessageBody interface.
-func (p *TimeExceeded) Marshal() ([]byte, error) {
+func (p *TimeExceeded) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
 	copy(b[4:], p.Data)
 	return b, nil
 }
 
 // parseTimeExceeded parses b as an ICMP time exceeded message body.
-func parseTimeExceeded(b []byte) (MessageBody, error) {
+func parseTimeExceeded(proto int, b []byte) (MessageBody, error) {
 	bodyLen := len(b)
 	if bodyLen < 4 {
 		return nil, errMessageTooShort