unix: add AF_IUCV and SockaddrIUCV

On z series machines the IUCV address family is used to communicate
between parts of the machine and other VMs that may be running.

This adds support for addressing these services using AF_IUCV.

Fixes golang/go#40826

Change-Id: I3aba3beb5cb98d9c548d7abc874ca86fb25c8a52
GitHub-Last-Rev: b964d186b45dd907f4ae302ea9b1ff63e3592eb6
GitHub-Pull-Request: golang/sys#76
Reviewed-on: https://go-review.googlesource.com/c/sys/+/248777
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/linux/types.go b/unix/linux/types.go
index 31a20c7..b1daba7 100644
--- a/unix/linux/types.go
+++ b/unix/linux/types.go
@@ -257,6 +257,16 @@
 #endif
 };
 
+// copied from /usr/include/netiucv/iucv.h modified with explicit signed chars.
+struct sockaddr_iucv {
+	sa_family_t siucv_family;
+	unsigned short siucv_port;
+	unsigned int siucv_addr;
+	signed char siucv_nodeid[8];
+	signed char siucv_user_id[8];
+	signed char siucv_name[8];
+};
+
 #ifdef __ARM_EABI__
 typedef struct user_regs PtraceRegs;
 #elif defined(__aarch64__)
@@ -540,6 +550,8 @@
 
 type RawSockaddrL2TPIP6 C.struct_sockaddr_l2tpip6
 
+type RawSockaddrIUCV C.struct_sockaddr_iucv
+
 type RawSockaddr C.struct_sockaddr
 
 type RawSockaddrAny C.struct_sockaddr_any
@@ -594,6 +606,7 @@
 	SizeofSockaddrTIPC      = C.sizeof_struct_sockaddr_tipc
 	SizeofSockaddrL2TPIP    = C.sizeof_struct_sockaddr_l2tpip
 	SizeofSockaddrL2TPIP6   = C.sizeof_struct_sockaddr_l2tpip6
+	SizeofSockaddrIUCV      = C.sizeof_struct_sockaddr_iucv
 	SizeofLinger            = C.sizeof_struct_linger
 	SizeofIovec             = C.sizeof_struct_iovec
 	SizeofIPMreq            = C.sizeof_struct_ip_mreq
diff --git a/unix/syscall_internal_linux_test.go b/unix/syscall_internal_linux_test.go
index af48c2a..a690b99 100644
--- a/unix/syscall_internal_linux_test.go
+++ b/unix/syscall_internal_linux_test.go
@@ -157,6 +157,18 @@
 			},
 		},
 		{
+			name: "AF_IUCV",
+			rsa: sockaddrIUCVToAny(RawSockaddrIUCV{
+				Family:  AF_IUCV,
+				User_id: [8]int8{'*', 'M', 'S', 'G', ' ', ' ', ' ', ' '},
+				Name:    [8]int8{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
+			}),
+			sa: &SockaddrIUCV{
+				UserID: "*MSG    ",
+				Name:   "        ",
+			},
+		},
+		{
 			name: "AF_MAX EAFNOSUPPORT",
 			rsa: &RawSockaddrAny{
 				Addr: RawSockaddr{
@@ -505,3 +517,12 @@
 
 	return &out
 }
+
+func sockaddrIUCVToAny(in RawSockaddrIUCV) *RawSockaddrAny {
+	var out RawSockaddrAny
+	copy(
+		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
+		(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
+	)
+	return &out
+}
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go
index 027bcaf..e12f9ba 100644
--- a/unix/syscall_linux.go
+++ b/unix/syscall_linux.go
@@ -885,6 +885,32 @@
 	return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP6, nil
 }
 
+// SockaddrIUCV implements the Sockaddr interface for AF_IUCV sockets.
+type SockaddrIUCV struct {
+	UserID string
+	Name   string
+	raw    RawSockaddrIUCV
+}
+
+func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
+	sa.raw.Family = AF_IUCV
+	// These are EBCDIC encoded by the kernel, but we still need to pad them
+	// with blanks. Initializing with blanks allows the caller to feed in either
+	// a padded or an unpadded string.
+	for i := 0; i < 8; i++ {
+		sa.raw.Nodeid[i] = ' '
+		sa.raw.User_id[i] = ' '
+		sa.raw.Name[i] = ' '
+	}
+	for i, b := range []byte(sa.UserID[:8]) {
+		sa.raw.User_id[i] = int8(b)
+	}
+	for i, b := range []byte(sa.Name[:8]) {
+		sa.raw.Name[i] = int8(b)
+	}
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil
+}
+
 func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
 	switch rsa.Addr.Family {
 	case AF_NETLINK:
@@ -1065,6 +1091,23 @@
 		}
 
 		return sa, nil
+	case AF_IUCV:
+		pp := (*RawSockaddrIUCV)(unsafe.Pointer(rsa))
+
+		var user [8]byte
+		var name [8]byte
+
+		for i := 0; i < 8; i++ {
+			user[i] = byte(pp.User_id[i])
+			name[i] = byte(pp.Name[i])
+		}
+
+		sa := &SockaddrIUCV{
+			UserID: string(user[:]),
+			Name:   string(name[:]),
+		}
+		return sa, nil
+
 	}
 	return nil, EAFNOSUPPORT
 }
diff --git a/unix/ztypes_linux.go b/unix/ztypes_linux.go
index 83364d7..77449a9 100644
--- a/unix/ztypes_linux.go
+++ b/unix/ztypes_linux.go
@@ -310,6 +310,15 @@
 	Conn_id  uint32
 }
 
+type RawSockaddrIUCV struct {
+	Family  uint16
+	Port    uint16
+	Addr    uint32
+	Nodeid  [8]int8
+	User_id [8]int8
+	Name    [8]int8
+}
+
 type _Socklen uint32
 
 type Linger struct {
@@ -422,6 +431,7 @@
 	SizeofSockaddrTIPC      = 0x10
 	SizeofSockaddrL2TPIP    = 0x10
 	SizeofSockaddrL2TPIP6   = 0x20
+	SizeofSockaddrIUCV      = 0x20
 	SizeofLinger            = 0x8
 	SizeofIPMreq            = 0x8
 	SizeofIPMreqn           = 0xc