unix: implement AF_SYSTEM/AF_SYS_CONTROL sockets on darwin

See https://developer.apple.com/documentation/kernel/sockaddr_ctl for
details.

AF_SYSTEM is darwin-specific, so the BSD-specific anyToSockaddr func
needs to call GOOS-specific funcs which return nil, EAFNOSUPPORT on all
BSD platforms but darwin.

For golang/go#41868

Change-Id: Id7794aba5988dd9511053b76be5efeb66c104a26
Reviewed-on: https://go-review.googlesource.com/c/sys/+/264638
Trust: Tobias Klauser <tobias.klauser@gmail.com>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matt Layher <mdlayher@gmail.com>
diff --git a/unix/mkerrors.sh b/unix/mkerrors.sh
index 2363df8..4a92a55 100755
--- a/unix/mkerrors.sh
+++ b/unix/mkerrors.sh
@@ -66,6 +66,7 @@
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
+#include <sys/sys_domain.h>
 #include <sys/sysctl.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
diff --git a/unix/syscall_bsd.go b/unix/syscall_bsd.go
index 123536a..bc634a2 100644
--- a/unix/syscall_bsd.go
+++ b/unix/syscall_bsd.go
@@ -277,7 +277,7 @@
 		}
 		return sa, nil
 	}
-	return nil, EAFNOSUPPORT
+	return anyToSockaddrGOOS(fd, rsa)
 }
 
 func Accept(fd int) (nfd int, sa Sockaddr, err error) {
diff --git a/unix/syscall_darwin.go b/unix/syscall_darwin.go
index 7fc58d6..bf4dc9a 100644
--- a/unix/syscall_darwin.go
+++ b/unix/syscall_darwin.go
@@ -31,6 +31,36 @@
 	raw    RawSockaddrDatalink
 }
 
+// SockaddrCtl implements the Sockaddr interface for AF_SYSTEM type sockets.
+type SockaddrCtl struct {
+	ID   uint32
+	Unit uint32
+	raw  RawSockaddrCtl
+}
+
+func (sa *SockaddrCtl) sockaddr() (unsafe.Pointer, _Socklen, error) {
+	sa.raw.Sc_len = SizeofSockaddrCtl
+	sa.raw.Sc_family = AF_SYSTEM
+	sa.raw.Ss_sysaddr = AF_SYS_CONTROL
+	sa.raw.Sc_id = sa.ID
+	sa.raw.Sc_unit = sa.Unit
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrCtl, nil
+}
+
+func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
+	switch rsa.Addr.Family {
+	case AF_SYSTEM:
+		pp := (*RawSockaddrCtl)(unsafe.Pointer(rsa))
+		if pp.Ss_sysaddr == AF_SYS_CONTROL {
+			sa := new(SockaddrCtl)
+			sa.ID = pp.Sc_id
+			sa.Unit = pp.Sc_unit
+			return sa, nil
+		}
+	}
+	return nil, EAFNOSUPPORT
+}
+
 // Some external packages rely on SYS___SYSCTL being defined to implement their
 // own sysctl wrappers. Provide it here, even though direct syscalls are no
 // longer supported on darwin.
diff --git a/unix/syscall_freebsd.go b/unix/syscall_freebsd.go
index f6db02a..acc00c2 100644
--- a/unix/syscall_freebsd.go
+++ b/unix/syscall_freebsd.go
@@ -54,6 +54,10 @@
 	raw    RawSockaddrDatalink
 }
 
+func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
+	return nil, EAFNOSUPPORT
+}
+
 // Translate "kern.hostname" to []_C_int{0,1,2,3}.
 func nametomib(name string) (mib []_C_int, err error) {
 	const siz = unsafe.Sizeof(mib[0])
diff --git a/unix/syscall_internal_darwin_test.go b/unix/syscall_internal_darwin_test.go
new file mode 100644
index 0000000..529e977
--- /dev/null
+++ b/unix/syscall_internal_darwin_test.go
@@ -0,0 +1,132 @@
+// Copyright 2020 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 unix
+
+import (
+	"reflect"
+	"testing"
+	"unsafe"
+)
+
+func Test_anyToSockaddr_darwin(t *testing.T) {
+	tests := []struct {
+		name string
+		rsa  *RawSockaddrAny
+		sa   Sockaddr
+		err  error
+	}{
+		{
+			name: "AF_SYSTEM emtpy",
+			rsa:  sockaddrCtlToAny(RawSockaddrCtl{}),
+			err:  EAFNOSUPPORT,
+		},
+		{
+			name: "AF_SYSTEM no sysaddr",
+			rsa: sockaddrCtlToAny(RawSockaddrCtl{
+				Sc_family: AF_SYSTEM,
+			}),
+			err: EAFNOSUPPORT,
+		},
+		{
+			name: "AF_SYSTEM/AF_SYS_CONTROL empty ",
+			rsa: sockaddrCtlToAny(RawSockaddrCtl{
+				Sc_family:  AF_SYSTEM,
+				Ss_sysaddr: AF_SYS_CONTROL,
+			}),
+			sa: &SockaddrCtl{},
+		},
+		{
+			name: "AF_SYSTEM ID and unit",
+			rsa: sockaddrCtlToAny(RawSockaddrCtl{
+				Sc_family:  AF_SYSTEM,
+				Ss_sysaddr: AF_SYS_CONTROL,
+				Sc_id:      0x42,
+				Sc_unit:    0xC71,
+			}),
+			sa: &SockaddrCtl{
+				ID:   0x42,
+				Unit: 0xC71,
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			fd := int(0)
+			var err error
+			sa, err := anyToSockaddr(fd, tt.rsa)
+			if err != tt.err {
+				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
+			}
+
+			if !reflect.DeepEqual(sa, tt.sa) {
+				t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
+			}
+		})
+	}
+}
+
+func TestSockaddrCtl_sockaddr(t *testing.T) {
+	tests := []struct {
+		name string
+		sa   *SockaddrCtl
+		raw  *RawSockaddrCtl
+		err  error
+	}{
+		{
+			name: "empty",
+			sa:   &SockaddrCtl{},
+			raw: &RawSockaddrCtl{
+				Sc_len:     SizeofSockaddrCtl,
+				Sc_family:  AF_SYSTEM,
+				Ss_sysaddr: AF_SYS_CONTROL,
+			},
+		},
+		{
+			name: "with ID and unit",
+			sa: &SockaddrCtl{
+				ID:   0x42,
+				Unit: 0xff,
+			},
+			raw: &RawSockaddrCtl{
+				Sc_len:     SizeofSockaddrCtl,
+				Sc_family:  AF_SYSTEM,
+				Ss_sysaddr: AF_SYS_CONTROL,
+				Sc_id:      0x42,
+				Sc_unit:    0xff,
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			out, l, err := tt.sa.sockaddr()
+			if err != tt.err {
+				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
+			}
+
+			// Must be 0 on error or a fixed size otherwise.
+			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrCtl) {
+				t.Fatalf("unexpected Socklen: %d", l)
+			}
+
+			if out != nil {
+				raw := (*RawSockaddrCtl)(out)
+				if !reflect.DeepEqual(raw, tt.raw) {
+					t.Fatalf("unexpected RawSockaddrCtl:\n got: %#v\nwant: %#v", raw, tt.raw)
+				}
+			}
+		})
+	}
+}
+
+func sockaddrCtlToAny(in RawSockaddrCtl) *RawSockaddrAny {
+	var out RawSockaddrAny
+	copy(
+		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
+		(*(*[SizeofSockaddrCtl]byte)(unsafe.Pointer(&in)))[:],
+	)
+	return &out
+}
diff --git a/unix/syscall_netbsd.go b/unix/syscall_netbsd.go
index dbd5e03..1e6843b 100644
--- a/unix/syscall_netbsd.go
+++ b/unix/syscall_netbsd.go
@@ -31,6 +31,10 @@
 	raw    RawSockaddrDatalink
 }
 
+func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
+	return nil, EAFNOSUPPORT
+}
+
 func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
 
 func sysctlNodes(mib []_C_int) (nodes []Sysctlnode, err error) {
diff --git a/unix/syscall_openbsd.go b/unix/syscall_openbsd.go
index 2c1f46e..6a50b50 100644
--- a/unix/syscall_openbsd.go
+++ b/unix/syscall_openbsd.go
@@ -31,6 +31,10 @@
 	raw    RawSockaddrDatalink
 }
 
+func anyToSockaddrGOOS(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
+	return nil, EAFNOSUPPORT
+}
+
 func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
 
 func nametomib(name string) (mib []_C_int, err error) {
diff --git a/unix/types_darwin.go b/unix/types_darwin.go
index 95b89ea..1764b31 100644
--- a/unix/types_darwin.go
+++ b/unix/types_darwin.go
@@ -146,6 +146,8 @@
 
 type RawSockaddrAny C.struct_sockaddr_any
 
+type RawSockaddrCtl C.struct_sockaddr_ctl
+
 type _Socklen C.socklen_t
 
 type Linger C.struct_linger
@@ -174,6 +176,7 @@
 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any
 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un
 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+	SizeofSockaddrCtl      = C.sizeof_struct_sockaddr_ctl
 	SizeofLinger           = C.sizeof_struct_linger
 	SizeofIPMreq           = C.sizeof_struct_ip_mreq
 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
diff --git a/unix/zerrors_darwin_386.go b/unix/zerrors_darwin_386.go
index c8f9f7a..ec376f5 100644
--- a/unix/zerrors_darwin_386.go
+++ b/unix/zerrors_darwin_386.go
@@ -45,6 +45,7 @@
 	AF_SIP                            = 0x18
 	AF_SNA                            = 0xb
 	AF_SYSTEM                         = 0x20
+	AF_SYS_CONTROL                    = 0x2
 	AF_UNIX                           = 0x1
 	AF_UNSPEC                         = 0x0
 	AF_UTUN                           = 0x26
diff --git a/unix/zerrors_darwin_amd64.go b/unix/zerrors_darwin_amd64.go
index 7180064..fea5dfa 100644
--- a/unix/zerrors_darwin_amd64.go
+++ b/unix/zerrors_darwin_amd64.go
@@ -45,6 +45,7 @@
 	AF_SIP                            = 0x18
 	AF_SNA                            = 0xb
 	AF_SYSTEM                         = 0x20
+	AF_SYS_CONTROL                    = 0x2
 	AF_UNIX                           = 0x1
 	AF_UNSPEC                         = 0x0
 	AF_UTUN                           = 0x26
diff --git a/unix/zerrors_darwin_arm.go b/unix/zerrors_darwin_arm.go
index 3b9ca75..03feefb 100644
--- a/unix/zerrors_darwin_arm.go
+++ b/unix/zerrors_darwin_arm.go
@@ -45,6 +45,7 @@
 	AF_SIP                            = 0x18
 	AF_SNA                            = 0xb
 	AF_SYSTEM                         = 0x20
+	AF_SYS_CONTROL                    = 0x2
 	AF_UNIX                           = 0x1
 	AF_UNSPEC                         = 0x0
 	AF_UTUN                           = 0x26
diff --git a/unix/zerrors_darwin_arm64.go b/unix/zerrors_darwin_arm64.go
index 4687c73..b40fb1f 100644
--- a/unix/zerrors_darwin_arm64.go
+++ b/unix/zerrors_darwin_arm64.go
@@ -45,6 +45,7 @@
 	AF_SIP                            = 0x18
 	AF_SNA                            = 0xb
 	AF_SYSTEM                         = 0x20
+	AF_SYS_CONTROL                    = 0x2
 	AF_UNIX                           = 0x1
 	AF_UNSPEC                         = 0x0
 	AF_UTUN                           = 0x26
diff --git a/unix/ztypes_darwin_386.go b/unix/ztypes_darwin_386.go
index 9ea0293..830fbb3 100644
--- a/unix/ztypes_darwin_386.go
+++ b/unix/ztypes_darwin_386.go
@@ -194,6 +194,15 @@
 	Pad  [92]int8
 }
 
+type RawSockaddrCtl struct {
+	Sc_len      uint8
+	Sc_family   uint8
+	Ss_sysaddr  uint16
+	Sc_id       uint32
+	Sc_unit     uint32
+	Sc_reserved [5]uint32
+}
+
 type _Socklen uint32
 
 type Linger struct {
@@ -258,6 +267,7 @@
 	SizeofSockaddrAny      = 0x6c
 	SizeofSockaddrUnix     = 0x6a
 	SizeofSockaddrDatalink = 0x14
+	SizeofSockaddrCtl      = 0x20
 	SizeofLinger           = 0x8
 	SizeofIPMreq           = 0x8
 	SizeofIPv6Mreq         = 0x14
diff --git a/unix/ztypes_darwin_amd64.go b/unix/ztypes_darwin_amd64.go
index 255e6cb..e53a7c4 100644
--- a/unix/ztypes_darwin_amd64.go
+++ b/unix/ztypes_darwin_amd64.go
@@ -199,6 +199,15 @@
 	Pad  [92]int8
 }
 
+type RawSockaddrCtl struct {
+	Sc_len      uint8
+	Sc_family   uint8
+	Ss_sysaddr  uint16
+	Sc_id       uint32
+	Sc_unit     uint32
+	Sc_reserved [5]uint32
+}
+
 type _Socklen uint32
 
 type Linger struct {
@@ -263,6 +272,7 @@
 	SizeofSockaddrAny      = 0x6c
 	SizeofSockaddrUnix     = 0x6a
 	SizeofSockaddrDatalink = 0x14
+	SizeofSockaddrCtl      = 0x20
 	SizeofLinger           = 0x8
 	SizeofIPMreq           = 0x8
 	SizeofIPv6Mreq         = 0x14
diff --git a/unix/ztypes_darwin_arm.go b/unix/ztypes_darwin_arm.go
index e21c828..98be973 100644
--- a/unix/ztypes_darwin_arm.go
+++ b/unix/ztypes_darwin_arm.go
@@ -194,6 +194,15 @@
 	Pad  [92]int8
 }
 
+type RawSockaddrCtl struct {
+	Sc_len      uint8
+	Sc_family   uint8
+	Ss_sysaddr  uint16
+	Sc_id       uint32
+	Sc_unit     uint32
+	Sc_reserved [5]uint32
+}
+
 type _Socklen uint32
 
 type Linger struct {
@@ -258,6 +267,7 @@
 	SizeofSockaddrAny      = 0x6c
 	SizeofSockaddrUnix     = 0x6a
 	SizeofSockaddrDatalink = 0x14
+	SizeofSockaddrCtl      = 0x20
 	SizeofLinger           = 0x8
 	SizeofIPMreq           = 0x8
 	SizeofIPv6Mreq         = 0x14
diff --git a/unix/ztypes_darwin_arm64.go b/unix/ztypes_darwin_arm64.go
index 5eff2c1..ddae5af 100644
--- a/unix/ztypes_darwin_arm64.go
+++ b/unix/ztypes_darwin_arm64.go
@@ -199,6 +199,15 @@
 	Pad  [92]int8
 }
 
+type RawSockaddrCtl struct {
+	Sc_len      uint8
+	Sc_family   uint8
+	Ss_sysaddr  uint16
+	Sc_id       uint32
+	Sc_unit     uint32
+	Sc_reserved [5]uint32
+}
+
 type _Socklen uint32
 
 type Linger struct {
@@ -263,6 +272,7 @@
 	SizeofSockaddrAny      = 0x6c
 	SizeofSockaddrUnix     = 0x6a
 	SizeofSockaddrDatalink = 0x14
+	SizeofSockaddrCtl      = 0x20
 	SizeofLinger           = 0x8
 	SizeofIPMreq           = 0x8
 	SizeofIPv6Mreq         = 0x14