go.net/ipv6: implement getsockopt, setsockopt syscalls
This CL implements a part of syscall package that's not included
in Go 1.1 release for not to annoy people who need some package
in go.net sub repository with Go 1.1.
Update golang/go#6548
R=dave, dsymonds, adg
CC=golang-dev
https://golang.org/cl/19940044
diff --git a/ipv6/sys.go b/ipv6/sys.go
new file mode 100644
index 0000000..18b1aca
--- /dev/null
+++ b/ipv6/sys.go
@@ -0,0 +1,23 @@
+// Copyright 2013 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 ipv6
+
+type sysSockoptLen uint32
+
+const (
+ sysSizeofPacketInfo = 0x14
+ sysSizeofMulticastReq = 0x14
+ sysSizeofICMPFilter = 0x20
+)
+
+type sysPacketInfo struct {
+ IP [16]byte
+ IfIndex uint32
+}
+
+type sysMulticastReq struct {
+ IP [16]byte
+ IfIndex uint32
+}
diff --git a/ipv6/sys_bsd.go b/ipv6/sys_bsd.go
new file mode 100644
index 0000000..4a08217
--- /dev/null
+++ b/ipv6/sys_bsd.go
@@ -0,0 +1,48 @@
+// Copyright 2013 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.
+
+// +build freebsd netbsd openbsd
+
+package ipv6
+
+import (
+ "net"
+ "syscall"
+)
+
+// RFC 3493 options
+const (
+ // See /usr/include/netinet6/in6.h.
+ sysSockoptUnicastHopLimit = 0x4
+ sysSockoptMulticastHopLimit = 0xa
+ sysSockoptMulticastInterface = 0x9
+ sysSockoptMulticastLoopback = 0xb
+ sysSockoptJoinGroup = 0xc
+ sysSockoptLeaveGroup = 0xd
+)
+
+// RFC 3542 options
+const (
+ // See /usr/include/netinet6/in6.h.
+ sysSockoptReceiveTrafficClass = 0x39
+ sysSockoptTrafficClass = 0x3d
+ sysSockoptReceiveHopLimit = 0x25
+ sysSockoptHopLimit = 0x2f
+ sysSockoptReceivePacketInfo = 0x24
+ sysSockoptPacketInfo = 0x2e
+ sysSockoptReceivePathMTU = 0x2b
+ sysSockoptPathMTU = 0x2c
+ sysSockoptNextHop = 0x30
+ sysSockoptChecksum = 0x1a
+
+ // See /usr/include/netinet6/in6.h.
+ sysSockoptICMPFilter = 0x12
+)
+
+func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
+ sa.Len = syscall.SizeofSockaddrInet6
+ sa.Family = syscall.AF_INET6
+ copy(sa.Addr[:], ip)
+ sa.Scope_id = uint32(ifindex)
+}
diff --git a/ipv6/sys_darwin.go b/ipv6/sys_darwin.go
new file mode 100644
index 0000000..3d07dff
--- /dev/null
+++ b/ipv6/sys_darwin.go
@@ -0,0 +1,54 @@
+// Copyright 2013 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 ipv6
+
+import (
+ "net"
+ "syscall"
+)
+
+// RFC 2292 options
+const (
+ // See /usr/include/netinet6/in6.h.
+ sysSockopt2292HopLimit = 0x14
+ sysSockopt2292PacketInfo = 0x13
+ sysSockopt2292NextHop = 0x15
+)
+
+// RFC 3493 options
+const (
+ // See /usr/include/netinet6/in6.h.
+ sysSockoptUnicastHopLimit = 0x4
+ sysSockoptMulticastHopLimit = 0xa
+ sysSockoptMulticastInterface = 0x9
+ sysSockoptMulticastLoopback = 0xb
+ sysSockoptJoinGroup = 0xc
+ sysSockoptLeaveGroup = 0xd
+)
+
+// RFC 3542 options
+const (
+ // See /usr/include/netinet6/in6.h.
+ sysSockoptReceiveTrafficClass = 0x23
+ sysSockoptTrafficClass = 0x24
+ sysSockoptReceiveHopLimit = 0x25
+ sysSockoptHopLimit = 0x2f
+ sysSockoptReceivePacketInfo = 0x3d
+ sysSockoptPacketInfo = 0x2e
+ sysSockoptReceivePathMTU = 0x2b
+ sysSockoptPathMTU = 0x2c
+ sysSockoptNextHop = 0x30
+ sysSockoptChecksum = 0x1a
+
+ // See /usr/include/netinet6/in6.h.
+ sysSockoptICMPFilter = 0x12
+)
+
+func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
+ sa.Len = syscall.SizeofSockaddrInet6
+ sa.Family = syscall.AF_INET6
+ copy(sa.Addr[:], ip)
+ sa.Scope_id = uint32(ifindex)
+}
diff --git a/ipv6/sys_linux.go b/ipv6/sys_linux.go
new file mode 100644
index 0000000..d90c8cb
--- /dev/null
+++ b/ipv6/sys_linux.go
@@ -0,0 +1,45 @@
+// Copyright 2013 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 ipv6
+
+import (
+ "net"
+ "syscall"
+)
+
+// RFC 3493 options
+const (
+ // See /usr/include/linux/in6.h.
+ sysSockoptUnicastHopLimit = 0x10
+ sysSockoptMulticastHopLimit = 0x12
+ sysSockoptMulticastInterface = 0x11
+ sysSockoptMulticastLoopback = 0x13
+ sysSockoptJoinGroup = 0x14
+ sysSockoptLeaveGroup = 0x15
+)
+
+// RFC 3542 options
+const (
+ // See /usr/include/linux/ipv6.h,in6.h.
+ sysSockoptReceiveTrafficClass = 0x42
+ sysSockoptTrafficClass = 0x43
+ sysSockoptReceiveHopLimit = 0x33
+ sysSockoptHopLimit = 0x34
+ sysSockoptReceivePacketInfo = 0x31
+ sysSockoptPacketInfo = 0x32
+ sysSockoptReceivePathMTU = 0x3c
+ sysSockoptPathMTU = 0x3d
+ sysSockoptNextHop = 0x9
+ sysSockoptChecksum = 0x7
+
+ // See /usr/include/linux/icmpv6.h.
+ sysSockoptICMPFilter = 0x1
+)
+
+func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
+ sa.Family = syscall.AF_INET6
+ copy(sa.Addr[:], ip)
+ sa.Scope_id = uint32(ifindex)
+}
diff --git a/ipv6/sys_unix.go b/ipv6/sys_unix.go
new file mode 100644
index 0000000..40cdfc4
--- /dev/null
+++ b/ipv6/sys_unix.go
@@ -0,0 +1,16 @@
+// Copyright 2013 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.
+
+// +build darwin freebsd linux netbsd openbsd
+
+package ipv6
+
+import "syscall"
+
+const sysSizeofMTUInfo = 0x20
+
+type sysMTUInfo struct {
+ Addr syscall.RawSockaddrInet6
+ MTU uint32
+}
diff --git a/ipv6/sys_windows.go b/ipv6/sys_windows.go
new file mode 100644
index 0000000..c09672f
--- /dev/null
+++ b/ipv6/sys_windows.go
@@ -0,0 +1,33 @@
+// Copyright 2013 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 ipv6
+
+import (
+ "net"
+ "syscall"
+)
+
+// RFC 3493 options
+const (
+ // See ws2tcpip.h.
+ sysSockoptUnicastHopLimit = 0x4
+ sysSockoptMulticastHopLimit = 0xa
+ sysSockoptMulticastInterface = 0x9
+ sysSockoptMulticastLoopback = 0xb
+ sysSockoptJoinGroup = 0xc
+ sysSockoptLeaveGroup = 0xd
+)
+
+// RFC 3542 options
+const (
+ // See ws2tcpip.h.
+ sysSockoptPacketInfo = 0x13
+)
+
+func setSockaddr(sa *syscall.RawSockaddrInet6, ip net.IP, ifindex int) {
+ sa.Family = syscall.AF_INET6
+ copy(sa.Addr[:], ip)
+ sa.Scope_id = uint32(ifindex)
+}
diff --git a/ipv6/syscall_linux_386.go b/ipv6/syscall_linux_386.go
new file mode 100644
index 0000000..a386636
--- /dev/null
+++ b/ipv6/syscall_linux_386.go
@@ -0,0 +1,42 @@
+// Copyright 2009 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.
+
+// This code is a duplicate of syscall/syscall_linux_386.go with small
+// modifications.
+
+package ipv6
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// On x86 Linux, all the socket calls go through an extra indirection,
+// I think because the 5-register system call interface can't handle
+// the 6-argument calls like sendto and recvfrom. Instead the
+// arguments to the underlying system call are the number below and a
+// pointer to an array of uintptr. We hide the pointer in the
+// socketcall assembly to avoid allocation on every system call.
+
+const (
+ // See /usr/include/linux/net.h.
+ _SETSOCKOPT = 14
+ _GETSOCKOPT = 15
+)
+
+var socketcall func(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
+
+func getsockopt(fd int, level int, name int, v uintptr, l *sysSockoptLen) error {
+ if _, errno := socketcall(_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
+ return error(errno)
+ }
+ return nil
+}
+
+func setsockopt(fd int, level int, name int, v uintptr, l uintptr) error {
+ if _, errno := socketcall(_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), v, l, 0); errno != 0 {
+ return error(errno)
+ }
+ return nil
+}
diff --git a/ipv6/syscall_linux_386.s b/ipv6/syscall_linux_386.s
new file mode 100644
index 0000000..34c0457
--- /dev/null
+++ b/ipv6/syscall_linux_386.s
@@ -0,0 +1,56 @@
+// Copyright 2009 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.
+
+// This code is a duplicate of syscall/syscall_linux_386.s with small
+// modifications.
+
+#define SYS_SOCKETCALL 102 // from zsysnum_linux_386.go
+
+// func socketcallnosplit7(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// Kernel interface gets call sub-number and pointer to a0 for Go 1.1.
+TEXT ·socketcallnosplit7(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL $SYS_SOCKETCALL, AX // syscall entry
+ MOVL 4(SP), BX // socket call number
+ LEAL 8(SP), CX // pointer to call arguments
+ MOVL $0, DX
+ MOVL $0, SI
+ MOVL $0, DI
+ CALL *runtime·_vdso(SB)
+ CMPL AX, $0xfffff001
+ JLS ok1
+ MOVL $-1, 32(SP) // n
+ NEGL AX
+ MOVL AX, 36(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok1:
+ MOVL AX, 32(SP) // n
+ MOVL $0, 36(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+// func socketcallnosplit4(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// Kernel interface gets call sub-number and pointer to a0 for Go 1.2.
+TEXT ·socketcallnosplit4(SB),4,$0-40
+ CALL runtime·entersyscall(SB)
+ MOVL $SYS_SOCKETCALL, AX // syscall entry
+ MOVL 4(SP), BX // socket call number
+ LEAL 8(SP), CX // pointer to call arguments
+ MOVL $0, DX
+ MOVL $0, SI
+ MOVL $0, DI
+ CALL *runtime·_vdso(SB)
+ CMPL AX, $0xfffff001
+ JLS ok2
+ MOVL $-1, 32(SP) // n
+ NEGL AX
+ MOVL AX, 36(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok2:
+ MOVL AX, 32(SP) // n
+ MOVL $0, 36(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/ipv6/syscall_nosplit4_linux_386.go b/ipv6/syscall_nosplit4_linux_386.go
new file mode 100644
index 0000000..6d4ac09
--- /dev/null
+++ b/ipv6/syscall_nosplit4_linux_386.go
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+// +build go1.2
+
+package ipv6
+
+import "syscall"
+
+func socketcallnosplit4(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
+
+func init() {
+ socketcall = socketcallnosplit4
+}
diff --git a/ipv6/syscall_nosplit7_linux_386.go b/ipv6/syscall_nosplit7_linux_386.go
new file mode 100644
index 0000000..2e4da7b
--- /dev/null
+++ b/ipv6/syscall_nosplit7_linux_386.go
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+// +build go1.1,!go1.2
+
+package ipv6
+
+import "syscall"
+
+func socketcallnosplit7(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
+
+func init() {
+ socketcall = socketcallnosplit7
+}
diff --git a/ipv6/syscall_unix.go b/ipv6/syscall_unix.go
new file mode 100644
index 0000000..d88dab5
--- /dev/null
+++ b/ipv6/syscall_unix.go
@@ -0,0 +1,26 @@
+// Copyright 2013 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.
+
+// +build darwin freebsd linux,amd64 linux,arm netbsd openbsd
+
+package ipv6
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func getsockopt(fd int, level, name int, v uintptr, l *sysSockoptLen) error {
+ if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
+ return error(errno)
+ }
+ return nil
+}
+
+func setsockopt(fd int, level int, name int, v uintptr, l uintptr) error {
+ if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
+ return error(errno)
+ }
+ return nil
+}