ipv4: work around FreeBSD 12 kernel running COMPAT_FREEBSD32

On FreeBSD 12 kernel running COMPAT_FREEBSD32, it looks like the system
call recvmsg always returns an incorrect​ length for the out-of-band
data. This change adjusts the length when it looks incorrect.

Fixes golang/go#30899.

Change-Id: Ibb0cbcf9b1f5f959279c20395916d47bd75d289c
Reviewed-on: https://go-review.googlesource.com/c/net/+/168077
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/ipv4/batch.go b/ipv4/batch.go
index fbe0cfd..6ea1a6d 100644
--- a/ipv4/batch.go
+++ b/ipv4/batch.go
@@ -89,6 +89,12 @@
 			n = 0
 			err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
 		}
+		if compatFreeBSD32 {
+			l := len(ms[0].OOB)
+			if 0 < ms[0].NN && ms[0].NN < l {
+				ms[0].NN = l
+			}
+		}
 		return n, err
 	}
 }
@@ -152,6 +158,12 @@
 			n = 0
 			err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
 		}
+		if compatFreeBSD32 {
+			l := len(ms[0].OOB)
+			if 0 < ms[0].NN && ms[0].NN < l {
+				ms[0].NN = l
+			}
+		}
 		return n, err
 	}
 }
diff --git a/ipv4/helper.go b/ipv4/helper.go
index d054952..198ec3b 100644
--- a/ipv4/helper.go
+++ b/ipv4/helper.go
@@ -23,7 +23,8 @@
 	errNotImplemented           = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
 
 	// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
-	freebsdVersion uint32
+	freebsdVersion  uint32
+	compatFreeBSD32 bool // 386 emulation on amd64
 )
 
 func boolint(b bool) int {
diff --git a/ipv4/packet.go b/ipv4/packet.go
index 30e0951..7c15307 100644
--- a/ipv4/packet.go
+++ b/ipv4/packet.go
@@ -46,6 +46,12 @@
 		return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
 	}
 	if m.NN > 0 {
+		if compatFreeBSD32 {
+			l := len(m.OOB)
+			if m.NN < l {
+				m.NN = l
+			}
+		}
 		cm = new(ControlMessage)
 		if err := cm.Parse(m.OOB[:m.NN]); err != nil {
 			return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
diff --git a/ipv4/payload_cmsg.go b/ipv4/payload_cmsg.go
index e8b21c5..cbceda1 100644
--- a/ipv4/payload_cmsg.go
+++ b/ipv4/payload_cmsg.go
@@ -49,6 +49,12 @@
 		return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType}
 	}
 	if m.NN > 0 {
+		if compatFreeBSD32 {
+			l := len(m.OOB)
+			if m.NN < l {
+				m.NN = l
+			}
+		}
 		cm = new(ControlMessage)
 		if err := cm.Parse(m.OOB[:m.NN]); err != nil {
 			return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
diff --git a/ipv4/sys_ssmreq.go b/ipv4/sys_ssmreq.go
index 95eea2b..eeced7f 100644
--- a/ipv4/sys_ssmreq.go
+++ b/ipv4/sys_ssmreq.go
@@ -13,8 +13,6 @@
 	"golang.org/x/net/internal/socket"
 )
 
-var compatFreeBSD32 bool // 386 emulation on amd64
-
 func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
 	var gr groupReq
 	if ifi != nil {