go.net/ipv4: handle total length field correctly on FreeBSD 10

FreeBSD 10 kernel has changed its incoming IPv4 packet handling
to stop trimming some IPv4 header fields on raw socket IO. This CL
just adapts package's IPv4 header representation to look the same
even on FreeBSD 10 kernel.

For further information:
http://svnweb.freebsd.org/base/head/?view=log&pathrev=226105
http://svnweb.freebsd.org/base/head/?view=log&pathrev=241913
http://svnweb.freebsd.org/base/head/?view=log&pathrev=241923

LGTM=iant
R=golang-codereviews, gobot, dave, iant
CC=golang-codereviews
https://golang.org/cl/53030043
diff --git a/ipv4/header.go b/ipv4/header.go
index e15db01..672f2d3 100644
--- a/ipv4/header.go
+++ b/ipv4/header.go
@@ -121,6 +121,9 @@
 	return b, nil
 }
 
+// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+var freebsdVersion uint32
+
 // ParseHeader parses b as an IPv4 header.
 func ParseHeader(b []byte) (*Header, error) {
 	if len(b) < HeaderLen {
@@ -139,7 +142,9 @@
 		h.FragOff = int(b[posFragOff])<<8 | int(b[posFragOff+1])
 	} else {
 		h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[posTotalLen : posTotalLen+1][0])))
-		h.TotalLen += hdrlen
+		if runtime.GOOS != "freebsd" || freebsdVersion < 1000000 {
+			h.TotalLen += hdrlen
+		}
 		h.FragOff = int(*(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0])))
 	}
 	h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13
diff --git a/ipv4/header_test.go b/ipv4/header_test.go
index 121d1f2..41cba60 100644
--- a/ipv4/header_test.go
+++ b/ipv4/header_test.go
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package ipv4_test
+package ipv4
 
 import (
 	"bytes"
-	"code.google.com/p/go.net/ipv4"
 	"net"
 	"reflect"
 	"runtime"
@@ -14,28 +13,35 @@
 )
 
 var (
-	wireHeaderFromKernel = [ipv4.HeaderLen]byte{
+	wireHeaderFromKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xbe, 0xef,
 		0xca, 0xfe, 0x45, 0xdc,
 		0xff, 0x01, 0xde, 0xad,
 		172, 16, 254, 254,
 		192, 168, 0, 1,
 	}
-	wireHeaderToKernel = [ipv4.HeaderLen]byte{
+	wireHeaderToKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xbe, 0xef,
 		0xca, 0xfe, 0x45, 0xdc,
 		0xff, 0x01, 0xde, 0xad,
 		172, 16, 254, 254,
 		192, 168, 0, 1,
 	}
-	wireHeaderFromTradBSDKernel = [ipv4.HeaderLen]byte{
+	wireHeaderFromTradBSDKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xdb, 0xbe,
 		0xca, 0xfe, 0xdc, 0x45,
 		0xff, 0x01, 0xde, 0xad,
 		172, 16, 254, 254,
 		192, 168, 0, 1,
 	}
-	wireHeaderToTradBSDKernel = [ipv4.HeaderLen]byte{
+	wireHeaderFromFreeBSD10Kernel = [HeaderLen]byte{
+		0x45, 0x01, 0xef, 0xbe,
+		0xca, 0xfe, 0xdc, 0x45,
+		0xff, 0x01, 0xde, 0xad,
+		172, 16, 254, 254,
+		192, 168, 0, 1,
+	}
+	wireHeaderToTradBSDKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xef, 0xbe,
 		0xca, 0xfe, 0xdc, 0x45,
 		0xff, 0x01, 0xde, 0xad,
@@ -45,13 +51,13 @@
 	// TODO(mikio): Add platform dependent wire header formats when
 	// we support new platforms.
 
-	testHeader = &ipv4.Header{
-		Version:  ipv4.Version,
-		Len:      ipv4.HeaderLen,
+	testHeader = &Header{
+		Version:  Version,
+		Len:      HeaderLen,
 		TOS:      1,
 		TotalLen: 0xbeef,
 		ID:       0xcafe,
-		Flags:    ipv4.DontFragment,
+		Flags:    DontFragment,
 		FragOff:  1500,
 		TTL:      255,
 		Protocol: 1,
@@ -67,10 +73,9 @@
 		t.Fatalf("ipv4.Header.Marshal failed: %v", err)
 	}
 	var wh []byte
-	switch runtime.GOOS {
-	case "linux", "openbsd":
+	if supportsNewIPInput {
 		wh = wireHeaderToKernel[:]
-	default:
+	} else {
 		wh = wireHeaderToTradBSDKernel[:]
 	}
 	if !bytes.Equal(b, wh) {
@@ -80,13 +85,16 @@
 
 func TestParseHeader(t *testing.T) {
 	var wh []byte
-	switch runtime.GOOS {
-	case "linux", "openbsd":
+	if supportsNewIPInput {
 		wh = wireHeaderFromKernel[:]
-	default:
-		wh = wireHeaderFromTradBSDKernel[:]
+	} else {
+		if runtime.GOOS == "freebsd" && freebsdVersion >= 1000000 {
+			wh = wireHeaderFromFreeBSD10Kernel[:]
+		} else {
+			wh = wireHeaderFromTradBSDKernel[:]
+		}
 	}
-	h, err := ipv4.ParseHeader(wh)
+	h, err := ParseHeader(wh)
 	if err != nil {
 		t.Fatalf("ipv4.ParseHeader failed: %v", err)
 	}
diff --git a/ipv4/sys_freebsd.go b/ipv4/sys_freebsd.go
new file mode 100644
index 0000000..f361234
--- /dev/null
+++ b/ipv4/sys_freebsd.go
@@ -0,0 +1,11 @@
+// Copyright 2014 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 "syscall"
+
+func init() {
+	freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate")
+}