ipv6: plumb in the standard library of Go 1.9 by using internal/socket package

This change uses the internal/socket package to ensure that the ipv6
package works with all supported versions of the Go standard library.

Fixes golang/go#19051.

Change-Id: I74911a8c5bba79e082a10d64e621ed415be1c033
Reviewed-on: https://go-review.googlesource.com/37042
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/ipv6/bpfopt_linux.go b/ipv6/bpfopt_linux.go
deleted file mode 100644
index daf7ea8..0000000
--- a/ipv6/bpfopt_linux.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 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 (
-	"os"
-	"unsafe"
-
-	"golang.org/x/net/bpf"
-	"golang.org/x/net/internal/netreflect"
-)
-
-// SetBPF attaches a BPF program to the connection.
-//
-// Only supported on Linux.
-func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
-	}
-	prog := sockFProg{
-		Len:    uint16(len(filter)),
-		Filter: (*sockFilter)(unsafe.Pointer(&filter[0])),
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, sysSOL_SOCKET, sysSO_ATTACH_FILTER, unsafe.Pointer(&prog), uint32(unsafe.Sizeof(prog))))
-}
diff --git a/ipv6/bpfopt_stub.go b/ipv6/bpfopt_stub.go
deleted file mode 100644
index 2e4de5f..0000000
--- a/ipv6/bpfopt_stub.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 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 !linux
-
-package ipv6
-
-import "golang.org/x/net/bpf"
-
-// SetBPF attaches a BPF program to the connection.
-//
-// Only supported on Linux.
-func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
-	return errOpNoSupport
-}
diff --git a/ipv6/control_stub.go b/ipv6/control_stub.go
index 24b40a8..963d200 100644
--- a/ipv6/control_stub.go
+++ b/ipv6/control_stub.go
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build nacl plan9
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
 
 package ipv6
 
-func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
+import "golang.org/x/net/internal/socket"
+
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
 	return errOpNoSupport
 }
 
diff --git a/ipv6/control_unix.go b/ipv6/control_unix.go
index 7bd4210..29a59e0 100644
--- a/ipv6/control_unix.go
+++ b/ipv6/control_unix.go
@@ -11,13 +11,14 @@
 	"syscall"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
-func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
 	opt.Lock()
 	defer opt.Unlock()
-	if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
-		if err := setInt(s, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
+	if so, ok := sockOpts[ssoReceiveTrafficClass]; ok && cf&FlagTrafficClass != 0 {
+		if err := so.SetInt(c, boolint(on)); err != nil {
 			return err
 		}
 		if on {
@@ -26,8 +27,8 @@
 			opt.clear(FlagTrafficClass)
 		}
 	}
-	if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
-		if err := setInt(s, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
+	if so, ok := sockOpts[ssoReceiveHopLimit]; ok && cf&FlagHopLimit != 0 {
+		if err := so.SetInt(c, boolint(on)); err != nil {
 			return err
 		}
 		if on {
@@ -36,8 +37,8 @@
 			opt.clear(FlagHopLimit)
 		}
 	}
-	if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
-		if err := setInt(s, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
+	if so, ok := sockOpts[ssoReceivePacketInfo]; ok && cf&flagPacketInfo != 0 {
+		if err := so.SetInt(c, boolint(on)); err != nil {
 			return err
 		}
 		if on {
@@ -46,8 +47,8 @@
 			opt.clear(cf & flagPacketInfo)
 		}
 	}
-	if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
-		if err := setInt(s, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
+	if so, ok := sockOpts[ssoReceivePathMTU]; ok && cf&FlagPathMTU != 0 {
+		if err := so.SetInt(c, boolint(on)); err != nil {
 			return err
 		}
 		if on {
diff --git a/ipv6/control_windows.go b/ipv6/control_windows.go
index feef6ab..97bb1e4 100644
--- a/ipv6/control_windows.go
+++ b/ipv6/control_windows.go
@@ -4,9 +4,13 @@
 
 package ipv6
 
-import "syscall"
+import (
+	"syscall"
 
-func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
+	"golang.org/x/net/internal/socket"
+)
+
+func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
 	// TODO(mikio): implement this
 	return syscall.EWINDOWS
 }
diff --git a/ipv6/defs_linux.go b/ipv6/defs_linux.go
index 8a967fd..3308cb2 100644
--- a/ipv6/defs_linux.go
+++ b/ipv6/defs_linux.go
@@ -120,6 +120,8 @@
 	sizeofGroupSourceReq = C.sizeof_struct_group_source_req
 
 	sizeofICMPv6Filter = C.sizeof_struct_icmp6_filter
+
+	sizeofSockFprog = C.sizeof_struct_sock_fprog
 )
 
 type kernelSockaddrStorage C.struct___kernel_sockaddr_storage
diff --git a/ipv6/dgramopt_posix.go b/ipv6/dgramopt.go
similarity index 69%
rename from ipv6/dgramopt_posix.go
rename to ipv6/dgramopt.go
index a448cba..703dafe 100644
--- a/ipv6/dgramopt_posix.go
+++ b/ipv6/dgramopt.go
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
-
 package ipv6
 
 import (
 	"net"
 	"syscall"
 
-	"golang.org/x/net/internal/netreflect"
+	"golang.org/x/net/bpf"
 )
 
 // MulticastHopLimit returns the hop limit field value for outgoing
@@ -19,11 +17,11 @@
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return 0, err
+	so, ok := sockOpts[ssoMulticastHopLimit]
+	if !ok {
+		return 0, errOpNoSupport
 	}
-	return getInt(s, &sockOpts[ssoMulticastHopLimit])
+	return so.GetInt(c.Conn)
 }
 
 // SetMulticastHopLimit sets the hop limit field value for future
@@ -32,11 +30,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoMulticastHopLimit]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setInt(s, &sockOpts[ssoMulticastHopLimit], hoplim)
+	return so.SetInt(c.Conn, hoplim)
 }
 
 // MulticastInterface returns the default interface for multicast
@@ -45,11 +43,11 @@
 	if !c.ok() {
 		return nil, syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return nil, err
+	so, ok := sockOpts[ssoMulticastInterface]
+	if !ok {
+		return nil, errOpNoSupport
 	}
-	return getInterface(s, &sockOpts[ssoMulticastInterface])
+	return so.getMulticastInterface(c.Conn)
 }
 
 // SetMulticastInterface sets the default interface for future
@@ -58,11 +56,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoMulticastInterface]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setInterface(s, &sockOpts[ssoMulticastInterface], ifi)
+	return so.setMulticastInterface(c.Conn, ifi)
 }
 
 // MulticastLoopback reports whether transmitted multicast packets
@@ -71,11 +69,11 @@
 	if !c.ok() {
 		return false, syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return false, err
+	so, ok := sockOpts[ssoMulticastLoopback]
+	if !ok {
+		return false, errOpNoSupport
 	}
-	on, err := getInt(s, &sockOpts[ssoMulticastLoopback])
+	on, err := so.GetInt(c.Conn)
 	if err != nil {
 		return false, err
 	}
@@ -88,11 +86,11 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoMulticastLoopback]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setInt(s, &sockOpts[ssoMulticastLoopback], boolint(on))
+	return so.SetInt(c.Conn, boolint(on))
 }
 
 // JoinGroup joins the group address group on the interface ifi.
@@ -108,15 +106,15 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoJoinGroup]
+	if !ok {
+		return errOpNoSupport
 	}
 	grp := netAddrToIP16(group)
 	if grp == nil {
 		return errMissingAddress
 	}
-	return setGroup(s, &sockOpts[ssoJoinGroup], ifi, grp)
+	return so.setGroup(c.Conn, ifi, grp)
 }
 
 // LeaveGroup leaves the group address group on the interface ifi
@@ -126,15 +124,15 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoLeaveGroup]
+	if !ok {
+		return errOpNoSupport
 	}
 	grp := netAddrToIP16(group)
 	if grp == nil {
 		return errMissingAddress
 	}
-	return setGroup(s, &sockOpts[ssoLeaveGroup], ifi, grp)
+	return so.setGroup(c.Conn, ifi, grp)
 }
 
 // JoinSourceSpecificGroup joins the source-specific group comprising
@@ -147,9 +145,9 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoJoinSourceGroup]
+	if !ok {
+		return errOpNoSupport
 	}
 	grp := netAddrToIP16(group)
 	if grp == nil {
@@ -159,7 +157,7 @@
 	if src == nil {
 		return errMissingAddress
 	}
-	return setSourceGroup(s, &sockOpts[ssoJoinSourceGroup], ifi, grp, src)
+	return so.setSourceGroup(c.Conn, ifi, grp, src)
 }
 
 // LeaveSourceSpecificGroup leaves the source-specific group on the
@@ -168,9 +166,9 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoLeaveSourceGroup]
+	if !ok {
+		return errOpNoSupport
 	}
 	grp := netAddrToIP16(group)
 	if grp == nil {
@@ -180,7 +178,7 @@
 	if src == nil {
 		return errMissingAddress
 	}
-	return setSourceGroup(s, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src)
+	return so.setSourceGroup(c.Conn, ifi, grp, src)
 }
 
 // ExcludeSourceSpecificGroup excludes the source-specific group from
@@ -190,9 +188,9 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoBlockSourceGroup]
+	if !ok {
+		return errOpNoSupport
 	}
 	grp := netAddrToIP16(group)
 	if grp == nil {
@@ -202,7 +200,7 @@
 	if src == nil {
 		return errMissingAddress
 	}
-	return setSourceGroup(s, &sockOpts[ssoBlockSourceGroup], ifi, grp, src)
+	return so.setSourceGroup(c.Conn, ifi, grp, src)
 }
 
 // IncludeSourceSpecificGroup includes the excluded source-specific
@@ -211,9 +209,9 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoUnblockSourceGroup]
+	if !ok {
+		return errOpNoSupport
 	}
 	grp := netAddrToIP16(group)
 	if grp == nil {
@@ -223,7 +221,7 @@
 	if src == nil {
 		return errMissingAddress
 	}
-	return setSourceGroup(s, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src)
+	return so.setSourceGroup(c.Conn, ifi, grp, src)
 }
 
 // Checksum reports whether the kernel will compute, store or verify a
@@ -234,11 +232,11 @@
 	if !c.ok() {
 		return false, 0, syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return false, 0, err
+	so, ok := sockOpts[ssoChecksum]
+	if !ok {
+		return false, 0, errOpNoSupport
 	}
-	offset, err = getInt(s, &sockOpts[ssoChecksum])
+	offset, err = so.GetInt(c.Conn)
 	if err != nil {
 		return false, 0, err
 	}
@@ -255,14 +253,14 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoChecksum]
+	if !ok {
+		return errOpNoSupport
 	}
 	if !on {
 		offset = -1
 	}
-	return setInt(s, &sockOpts[ssoChecksum], offset)
+	return so.SetInt(c.Conn, offset)
 }
 
 // ICMPFilter returns an ICMP filter.
@@ -270,11 +268,11 @@
 	if !c.ok() {
 		return nil, syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return nil, err
+	so, ok := sockOpts[ssoICMPFilter]
+	if !ok {
+		return nil, errOpNoSupport
 	}
-	return getICMPFilter(s, &sockOpts[ssoICMPFilter])
+	return so.getICMPFilter(c.Conn)
 }
 
 // SetICMPFilter deploys the ICMP filter.
@@ -282,9 +280,23 @@
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoICMPFilter]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setICMPFilter(s, &sockOpts[ssoICMPFilter], f)
+	return so.setICMPFilter(c.Conn, f)
+}
+
+// SetBPF attaches a BPF program to the connection.
+//
+// Only supported on Linux.
+func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	so, ok := sockOpts[ssoAttachFilter]
+	if !ok {
+		return errOpNoSupport
+	}
+	return so.setBPF(c.Conn, filter)
 }
diff --git a/ipv6/dgramopt_stub.go b/ipv6/dgramopt_stub.go
deleted file mode 100644
index 82b0686..0000000
--- a/ipv6/dgramopt_stub.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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 nacl plan9
-
-package ipv6
-
-import "net"
-
-// MulticastHopLimit returns the hop limit field value for outgoing
-// multicast packets.
-func (c *dgramOpt) MulticastHopLimit() (int, error) {
-	return 0, errOpNoSupport
-}
-
-// SetMulticastHopLimit sets the hop limit field value for future
-// outgoing multicast packets.
-func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
-	return errOpNoSupport
-}
-
-// MulticastInterface returns the default interface for multicast
-// packet transmissions.
-func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
-	return nil, errOpNoSupport
-}
-
-// SetMulticastInterface sets the default interface for future
-// multicast packet transmissions.
-func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
-	return errOpNoSupport
-}
-
-// MulticastLoopback reports whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) MulticastLoopback() (bool, error) {
-	return false, errOpNoSupport
-}
-
-// SetMulticastLoopback sets whether transmitted multicast packets
-// should be copied and send back to the originator.
-func (c *dgramOpt) SetMulticastLoopback(on bool) error {
-	return errOpNoSupport
-}
-
-// JoinGroup joins the group address group on the interface ifi.
-// By default all sources that can cast data to group are accepted.
-// It's possible to mute and unmute data transmission from a specific
-// source by using ExcludeSourceSpecificGroup and
-// IncludeSourceSpecificGroup.
-// JoinGroup uses the system assigned multicast interface when ifi is
-// nil, although this is not recommended because the assignment
-// depends on platforms and sometimes it might require routing
-// configuration.
-func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
-	return errOpNoSupport
-}
-
-// LeaveGroup leaves the group address group on the interface ifi
-// regardless of whether the group is any-source group or
-// source-specific group.
-func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
-	return errOpNoSupport
-}
-
-// JoinSourceSpecificGroup joins the source-specific group comprising
-// group and source on the interface ifi.
-// JoinSourceSpecificGroup uses the system assigned multicast
-// interface when ifi is nil, although this is not recommended because
-// the assignment depends on platforms and sometimes it might require
-// routing configuration.
-func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
-	return errOpNoSupport
-}
-
-// LeaveSourceSpecificGroup leaves the source-specific group on the
-// interface ifi.
-func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
-	return errOpNoSupport
-}
-
-// ExcludeSourceSpecificGroup excludes the source-specific group from
-// the already joined any-source groups by JoinGroup on the interface
-// ifi.
-func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
-	return errOpNoSupport
-}
-
-// IncludeSourceSpecificGroup includes the excluded source-specific
-// group by ExcludeSourceSpecificGroup again on the interface ifi.
-func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
-	return errOpNoSupport
-}
-
-// Checksum reports whether the kernel will compute, store or verify a
-// checksum for both incoming and outgoing packets. If on is true, it
-// returns an offset in bytes into the data of where the checksum
-// field is located.
-func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
-	return false, 0, errOpNoSupport
-}
-
-// SetChecksum enables the kernel checksum processing. If on is ture,
-// the offset should be an offset in bytes into the data of where the
-// checksum field is located.
-func (c *dgramOpt) SetChecksum(on bool, offset int) error {
-	return errOpNoSupport
-}
-
-// ICMPFilter returns an ICMP filter.
-func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
-	return nil, errOpNoSupport
-}
-
-// SetICMPFilter deploys the ICMP filter.
-func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
-	return errOpNoSupport
-}
diff --git a/ipv6/endpoint.go b/ipv6/endpoint.go
index ce0b0ce..001d267 100644
--- a/ipv6/endpoint.go
+++ b/ipv6/endpoint.go
@@ -9,7 +9,7 @@
 	"syscall"
 	"time"
 
-	"golang.org/x/net/internal/netreflect"
+	"golang.org/x/net/internal/socket"
 )
 
 // BUG(mikio): On Windows, the JoinSourceSpecificGroup,
@@ -25,7 +25,7 @@
 }
 
 type genericOpt struct {
-	net.Conn
+	*socket.Conn
 }
 
 func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
@@ -33,14 +33,14 @@
 // PathMTU returns a path MTU value for the destination associated
 // with the endpoint.
 func (c *Conn) PathMTU() (int, error) {
-	if !c.genericOpt.ok() {
+	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	s, err := netreflect.SocketOf(c.genericOpt.Conn)
-	if err != nil {
-		return 0, err
+	so, ok := sockOpts[ssoPathMTU]
+	if !ok {
+		return 0, errOpNoSupport
 	}
-	_, mtu, err := getMTUInfo(s, &sockOpts[ssoPathMTU])
+	_, mtu, err := so.getMTUInfo(c.Conn)
 	if err != nil {
 		return 0, err
 	}
@@ -49,8 +49,9 @@
 
 // NewConn returns a new Conn.
 func NewConn(c net.Conn) *Conn {
+	cc, _ := socket.NewConn(c)
 	return &Conn{
-		genericOpt: genericOpt{Conn: c},
+		genericOpt: genericOpt{Conn: cc},
 	}
 }
 
@@ -66,10 +67,10 @@
 }
 
 type dgramOpt struct {
-	net.PacketConn
+	*socket.Conn
 }
 
-func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil }
+func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
 
 // SetControlMessage allows to receive the per packet basis IP-level
 // socket options.
@@ -77,11 +78,7 @@
 	if !c.payloadHandler.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.dgramOpt.PacketConn)
-	if err != nil {
-		return err
-	}
-	return setControlMessage(s, &c.payloadHandler.rawOpt, cf, on)
+	return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
 }
 
 // SetDeadline sets the read and write deadlines associated with the
@@ -122,9 +119,10 @@
 // NewPacketConn returns a new PacketConn using c as its underlying
 // transport.
 func NewPacketConn(c net.PacketConn) *PacketConn {
+	cc, _ := socket.NewConn(c.(net.Conn))
 	return &PacketConn{
-		genericOpt:     genericOpt{Conn: c.(net.Conn)},
-		dgramOpt:       dgramOpt{PacketConn: c},
+		genericOpt:     genericOpt{Conn: cc},
+		dgramOpt:       dgramOpt{Conn: cc},
 		payloadHandler: payloadHandler{PacketConn: c},
 	}
 }
diff --git a/ipv6/genericopt.go b/ipv6/genericopt.go
new file mode 100644
index 0000000..e9dbc2e
--- /dev/null
+++ b/ipv6/genericopt.go
@@ -0,0 +1,58 @@
+// 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 "syscall"
+
+// TrafficClass returns the traffic class field value for outgoing
+// packets.
+func (c *genericOpt) TrafficClass() (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	so, ok := sockOpts[ssoTrafficClass]
+	if !ok {
+		return 0, errOpNoSupport
+	}
+	return so.GetInt(c.Conn)
+}
+
+// SetTrafficClass sets the traffic class field value for future
+// outgoing packets.
+func (c *genericOpt) SetTrafficClass(tclass int) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	so, ok := sockOpts[ssoTrafficClass]
+	if !ok {
+		return errOpNoSupport
+	}
+	return so.SetInt(c.Conn, tclass)
+}
+
+// HopLimit returns the hop limit field value for outgoing packets.
+func (c *genericOpt) HopLimit() (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	so, ok := sockOpts[ssoHopLimit]
+	if !ok {
+		return 0, errOpNoSupport
+	}
+	return so.GetInt(c.Conn)
+}
+
+// SetHopLimit sets the hop limit field value for future outgoing
+// packets.
+func (c *genericOpt) SetHopLimit(hoplim int) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	so, ok := sockOpts[ssoHopLimit]
+	if !ok {
+		return errOpNoSupport
+	}
+	return so.SetInt(c.Conn, hoplim)
+}
diff --git a/ipv6/genericopt_posix.go b/ipv6/genericopt_posix.go
deleted file mode 100644
index 0a8d988..0000000
--- a/ipv6/genericopt_posix.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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 dragonfly freebsd linux netbsd openbsd solaris windows
-
-package ipv6
-
-import (
-	"syscall"
-
-	"golang.org/x/net/internal/netreflect"
-)
-
-// TrafficClass returns the traffic class field value for outgoing
-// packets.
-func (c *genericOpt) TrafficClass() (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return 0, err
-	}
-	return getInt(s, &sockOpts[ssoTrafficClass])
-}
-
-// SetTrafficClass sets the traffic class field value for future
-// outgoing packets.
-func (c *genericOpt) SetTrafficClass(tclass int) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return err
-	}
-	return setInt(s, &sockOpts[ssoTrafficClass], tclass)
-}
-
-// HopLimit returns the hop limit field value for outgoing packets.
-func (c *genericOpt) HopLimit() (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return 0, err
-	}
-	return getInt(s, &sockOpts[ssoHopLimit])
-}
-
-// SetHopLimit sets the hop limit field value for future outgoing
-// packets.
-func (c *genericOpt) SetHopLimit(hoplim int) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return err
-	}
-	return setInt(s, &sockOpts[ssoHopLimit], hoplim)
-}
diff --git a/ipv6/genericopt_stub.go b/ipv6/genericopt_stub.go
deleted file mode 100644
index 9dfc57d..0000000
--- a/ipv6/genericopt_stub.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 nacl plan9
-
-package ipv6
-
-// TrafficClass returns the traffic class field value for outgoing
-// packets.
-func (c *genericOpt) TrafficClass() (int, error) {
-	return 0, errOpNoSupport
-}
-
-// SetTrafficClass sets the traffic class field value for future
-// outgoing packets.
-func (c *genericOpt) SetTrafficClass(tclass int) error {
-	return errOpNoSupport
-}
-
-// HopLimit returns the hop limit field value for outgoing packets.
-func (c *genericOpt) HopLimit() (int, error) {
-	return 0, errOpNoSupport
-}
-
-// SetHopLimit sets the hop limit field value for future outgoing
-// packets.
-func (c *genericOpt) SetHopLimit(hoplim int) error {
-	return errOpNoSupport
-}
diff --git a/ipv6/icmp_stub.go b/ipv6/icmp_stub.go
index 3cd84e1..c4b9be6 100644
--- a/ipv6/icmp_stub.go
+++ b/ipv6/icmp_stub.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build nacl plan9
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
 
 package ipv6
 
diff --git a/ipv6/sockopt.go b/ipv6/sockopt.go
index f0cfc2f..cc3907d 100644
--- a/ipv6/sockopt.go
+++ b/ipv6/sockopt.go
@@ -4,6 +4,8 @@
 
 package ipv6
 
+import "golang.org/x/net/internal/socket"
+
 // Sticky socket options
 const (
 	ssoTrafficClass        = iota // header field for unicast packet, RFC 3542
@@ -24,23 +26,18 @@
 	ssoLeaveSourceGroup           // source-specific multicast
 	ssoBlockSourceGroup           // any-source or source-specific multicast
 	ssoUnblockSourceGroup         // any-source or source-specific multicast
-	ssoMax
+	ssoAttachFilter               // attach BPF for filtering inbound traffic
 )
 
 // Sticky socket option value types
 const (
-	ssoTypeInt = iota + 1
-	ssoTypeInterface
-	ssoTypeICMPFilter
-	ssoTypeMTUInfo
-	ssoTypeIPMreq
+	ssoTypeIPMreq = iota + 1
 	ssoTypeGroupReq
 	ssoTypeGroupSourceReq
 )
 
 // A sockOpt represents a binding for sticky socket option.
 type sockOpt struct {
-	level int // option level
-	name  int // option name, must be equal or greater than 1
-	typ   int // option value type, must be equal or greater than 1
+	socket.Option
+	typ int // hint for option value type; optional
 }
diff --git a/ipv6/sockopt_posix.go b/ipv6/sockopt_posix.go
index e0a3fa6..0eac86e 100644
--- a/ipv6/sockopt_posix.go
+++ b/ipv6/sockopt_posix.go
@@ -8,88 +8,55 @@
 
 import (
 	"net"
-	"os"
 	"unsafe"
+
+	"golang.org/x/net/bpf"
+	"golang.org/x/net/internal/socket"
 )
 
-func getInt(s uintptr, opt *sockOpt) (int, error) {
-	if opt.name < 1 || opt.typ != ssoTypeInt {
-		return 0, errOpNoSupport
-	}
-	var i int32
-	l := uint32(4)
-	if err := getsockopt(s, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return int(i), nil
-}
-
-func setInt(s uintptr, opt *sockOpt, v int) error {
-	if opt.name < 1 || opt.typ != ssoTypeInt {
-		return errOpNoSupport
-	}
-	i := int32(v)
-	return os.NewSyscallError("setsockopt", setsockopt(s, opt.level, opt.name, unsafe.Pointer(&i), 4))
-}
-
-func getInterface(s uintptr, opt *sockOpt) (*net.Interface, error) {
-	if opt.name < 1 || opt.typ != ssoTypeInterface {
-		return nil, errOpNoSupport
-	}
-	var i int32
-	l := uint32(4)
-	if err := getsockopt(s, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	if i == 0 {
-		return nil, nil
-	}
-	ifi, err := net.InterfaceByIndex(int(i))
+func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
+	n, err := so.GetInt(c)
 	if err != nil {
 		return nil, err
 	}
-	return ifi, nil
+	return net.InterfaceByIndex(n)
 }
 
-func setInterface(s uintptr, opt *sockOpt, ifi *net.Interface) error {
-	if opt.name < 1 || opt.typ != ssoTypeInterface {
-		return errOpNoSupport
-	}
-	var i int32
+func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
+	var n int
 	if ifi != nil {
-		i = int32(ifi.Index)
+		n = ifi.Index
 	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, opt.level, opt.name, unsafe.Pointer(&i), 4))
+	return so.SetInt(c, n)
 }
 
-func getICMPFilter(s uintptr, opt *sockOpt) (*ICMPFilter, error) {
-	if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
+func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
+	b := make([]byte, so.Len)
+	n, err := so.Get(c, b)
+	if err != nil {
+		return nil, err
+	}
+	if n != sizeofICMPv6Filter {
 		return nil, errOpNoSupport
 	}
-	var f ICMPFilter
-	l := uint32(sizeofICMPv6Filter)
-	if err := getsockopt(s, opt.level, opt.name, unsafe.Pointer(&f.icmpv6Filter), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	return &f, nil
+	return (*ICMPFilter)(unsafe.Pointer(&b[0])), nil
 }
 
-func setICMPFilter(s uintptr, opt *sockOpt, f *ICMPFilter) error {
-	if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
-		return errOpNoSupport
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, opt.level, opt.name, unsafe.Pointer(&f.icmpv6Filter), sizeofICMPv6Filter))
+func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
+	b := (*[sizeofICMPv6Filter]byte)(unsafe.Pointer(f))[:sizeofICMPv6Filter]
+	return so.Set(c, b)
 }
 
-func getMTUInfo(s uintptr, opt *sockOpt) (*net.Interface, int, error) {
-	if opt.name < 1 || opt.typ != ssoTypeMTUInfo {
+func (so *sockOpt) getMTUInfo(c *socket.Conn) (*net.Interface, int, error) {
+	b := make([]byte, so.Len)
+	n, err := so.Get(c, b)
+	if err != nil {
+		return nil, 0, err
+	}
+	if n != sizeofIPv6Mtuinfo {
 		return nil, 0, errOpNoSupport
 	}
-	var mi ipv6Mtuinfo
-	l := uint32(sizeofIPv6Mtuinfo)
-	if err := getsockopt(s, opt.level, opt.name, unsafe.Pointer(&mi), &l); err != nil {
-		return nil, 0, os.NewSyscallError("getsockopt", err)
-	}
+	mi := (*ipv6Mtuinfo)(unsafe.Pointer(&b[0]))
 	if mi.Addr.Scope_id == 0 {
 		return nil, int(mi.Mtu), nil
 	}
@@ -100,23 +67,21 @@
 	return ifi, int(mi.Mtu), nil
 }
 
-func setGroup(s uintptr, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
-	if opt.name < 1 {
-		return errOpNoSupport
-	}
-	switch opt.typ {
+func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	switch so.typ {
 	case ssoTypeIPMreq:
-		return setsockoptIPMreq(s, opt, ifi, grp)
+		return so.setIPMreq(c, ifi, grp)
 	case ssoTypeGroupReq:
-		return setsockoptGroupReq(s, opt, ifi, grp)
+		return so.setGroupReq(c, ifi, grp)
 	default:
 		return errOpNoSupport
 	}
 }
 
-func setSourceGroup(s uintptr, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
-	if opt.name < 1 || opt.typ != ssoTypeGroupSourceReq {
-		return errOpNoSupport
-	}
-	return setsockoptGroupSourceReq(s, opt, ifi, grp, src)
+func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
+	return so.setGroupSourceReq(c, ifi, grp, src)
+}
+
+func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
+	return so.setAttachFilter(c, f)
 }
diff --git a/ipv6/sockopt_ssmreq_stub.go b/ipv6/sockopt_ssmreq_stub.go
deleted file mode 100644
index 1a88290..0000000
--- a/ipv6/sockopt_ssmreq_stub.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-// +build !darwin,!freebsd,!linux,!solaris
-
-package ipv6
-
-import "net"
-
-func setsockoptGroupReq(s uintptr, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
-	return errOpNoSupport
-}
-
-func setsockoptGroupSourceReq(s uintptr, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
-	return errOpNoSupport
-}
diff --git a/ipv6/sockopt_ssmreq_unix.go b/ipv6/sockopt_ssmreq_unix.go
deleted file mode 100644
index f3668ae..0000000
--- a/ipv6/sockopt_ssmreq_unix.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-// +build darwin freebsd linux solaris
-
-package ipv6
-
-import (
-	"net"
-	"os"
-	"unsafe"
-)
-
-var freebsd32o64 bool
-
-func setsockoptGroupReq(s uintptr, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
-	var gr groupReq
-	if ifi != nil {
-		gr.Interface = uint32(ifi.Index)
-	}
-	gr.setGroup(grp)
-	var p unsafe.Pointer
-	var l uint32
-	if freebsd32o64 {
-		var d [sizeofGroupReq + 4]byte
-		s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
-		copy(d[:4], s[:4])
-		copy(d[8:], s[4:])
-		p = unsafe.Pointer(&d[0])
-		l = sizeofGroupReq + 4
-	} else {
-		p = unsafe.Pointer(&gr)
-		l = sizeofGroupReq
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, opt.level, opt.name, p, l))
-}
-
-func setsockoptGroupSourceReq(s uintptr, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error {
-	var gsr groupSourceReq
-	if ifi != nil {
-		gsr.Interface = uint32(ifi.Index)
-	}
-	gsr.setSourceGroup(grp, src)
-	var p unsafe.Pointer
-	var l uint32
-	if freebsd32o64 {
-		var d [sizeofGroupSourceReq + 4]byte
-		s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
-		copy(d[:4], s[:4])
-		copy(d[8:], s[4:])
-		p = unsafe.Pointer(&d[0])
-		l = sizeofGroupSourceReq + 4
-	} else {
-		p = unsafe.Pointer(&gsr)
-		l = sizeofGroupSourceReq
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, opt.level, opt.name, p, l))
-}
diff --git a/ipv6/sockopt_stub.go b/ipv6/sockopt_stub.go
index 6d59a00..1f4a273 100644
--- a/ipv6/sockopt_stub.go
+++ b/ipv6/sockopt_stub.go
@@ -2,12 +2,45 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build nacl plan9
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
 
 package ipv6
 
-import "net"
+import (
+	"net"
 
-func getMTUInfo(s uintptr, opt *sockOpt) (*net.Interface, int, error) {
+	"golang.org/x/net/bpf"
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
+	return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
+	return errOpNoSupport
+}
+
+func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
+	return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
+	return errOpNoSupport
+}
+
+func (so *sockOpt) getMTUInfo(c *socket.Conn) (*net.Interface, int, error) {
 	return nil, 0, errOpNoSupport
 }
+
+func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	return errOpNoSupport
+}
+
+func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
+	return errOpNoSupport
+}
+
+func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
+	return errOpNoSupport
+}
diff --git a/ipv6/sockopt_asmreq_posix.go b/ipv6/sys_asmreq.go
similarity index 63%
rename from ipv6/sockopt_asmreq_posix.go
rename to ipv6/sys_asmreq.go
index cd36739..b0510c0 100644
--- a/ipv6/sockopt_asmreq_posix.go
+++ b/ipv6/sys_asmreq.go
@@ -8,15 +8,17 @@
 
 import (
 	"net"
-	"os"
 	"unsafe"
+
+	"golang.org/x/net/internal/socket"
 )
 
-func setsockoptIPMreq(s uintptr, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
+func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
 	var mreq ipv6Mreq
 	copy(mreq.Multiaddr[:], grp)
 	if ifi != nil {
 		mreq.setIfindex(ifi.Index)
 	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, opt.level, opt.name, unsafe.Pointer(&mreq), sizeofIPv6Mreq))
+	b := (*[sizeofIPv6Mreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPv6Mreq]
+	return so.Set(c, b)
 }
diff --git a/ipv6/sys_asmreq_stub.go b/ipv6/sys_asmreq_stub.go
new file mode 100644
index 0000000..eece961
--- /dev/null
+++ b/ipv6/sys_asmreq_stub.go
@@ -0,0 +1,17 @@
+// 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,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
+
+package ipv6
+
+import (
+	"net"
+
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	return errOpNoSupport
+}
diff --git a/ipv6/sys_bpf.go b/ipv6/sys_bpf.go
new file mode 100644
index 0000000..b2dbcb2
--- /dev/null
+++ b/ipv6/sys_bpf.go
@@ -0,0 +1,23 @@
+// Copyright 2017 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 linux
+
+package ipv6
+
+import (
+	"unsafe"
+
+	"golang.org/x/net/bpf"
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
+	prog := sockFProg{
+		Len:    uint16(len(f)),
+		Filter: (*sockFilter)(unsafe.Pointer(&f[0])),
+	}
+	b := (*[sizeofSockFprog]byte)(unsafe.Pointer(&prog))[:sizeofSockFprog]
+	return so.Set(c, b)
+}
diff --git a/ipv6/sys_bpf_stub.go b/ipv6/sys_bpf_stub.go
new file mode 100644
index 0000000..676bea5
--- /dev/null
+++ b/ipv6/sys_bpf_stub.go
@@ -0,0 +1,16 @@
+// Copyright 2017 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 !linux
+
+package ipv6
+
+import (
+	"golang.org/x/net/bpf"
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
+	return errOpNoSupport
+}
diff --git a/ipv6/sys_bsd.go b/ipv6/sys_bsd.go
index c22f8ac..e416eaa 100644
--- a/ipv6/sys_bsd.go
+++ b/ipv6/sys_bsd.go
@@ -11,6 +11,7 @@
 	"syscall"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -22,21 +23,21 @@
 		ctlPathMTU:      {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTrafficClass:        {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
-		ssoHopLimit:            {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
-		ssoMulticastInterface:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastHopLimit:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
-		ssoMulticastLoopback:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
-		ssoReceiveHopLimit:     {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
-		ssoReceivePacketInfo:   {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
-		ssoReceivePathMTU:      {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
-		ssoPathMTU:             {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
-		ssoChecksum:            {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
-		ssoICMPFilter:          {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
-		ssoJoinGroup:           {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
-		ssoLeaveGroup:          {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+	sockOpts = map[int]*sockOpt{
+		ssoTrafficClass:        {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+		ssoHopLimit:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+		ssoMulticastInterface:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+		ssoMulticastHopLimit:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+		ssoMulticastLoopback:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+		ssoReceiveHopLimit:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+		ssoReceivePacketInfo:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+		ssoReceivePathMTU:      {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+		ssoPathMTU:             {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+		ssoChecksum:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+		ssoICMPFilter:          {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+		ssoJoinGroup:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:          {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
 	}
 )
 
diff --git a/ipv6/sys_darwin.go b/ipv6/sys_darwin.go
index ffcc9d4..e3d0443 100644
--- a/ipv6/sys_darwin.go
+++ b/ipv6/sys_darwin.go
@@ -12,6 +12,7 @@
 	"unsafe"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -20,17 +21,17 @@
 		ctlPacketInfo: {sysIPV6_2292PKTINFO, sizeofInet6Pktinfo, marshal2292PacketInfo, parsePacketInfo},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoHopLimit:           {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
-		ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastHopLimit:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
-		ssoMulticastLoopback:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveHopLimit:    {iana.ProtocolIPv6, sysIPV6_2292HOPLIMIT, ssoTypeInt},
-		ssoReceivePacketInfo:  {iana.ProtocolIPv6, sysIPV6_2292PKTINFO, ssoTypeInt},
-		ssoChecksum:           {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
-		ssoICMPFilter:         {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
-		ssoJoinGroup:          {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
-		ssoLeaveGroup:         {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+	sockOpts = map[int]*sockOpt{
+		ssoHopLimit:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+		ssoMulticastHopLimit:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveHopLimit:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_2292HOPLIMIT, Len: 4}},
+		ssoReceivePacketInfo:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_2292PKTINFO, Len: 4}},
+		ssoChecksum:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+		ssoICMPFilter:         {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
 	}
 )
 
@@ -57,18 +58,18 @@
 	ctlOpts[ctlPacketInfo] = ctlOpt{sysIPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo}
 	ctlOpts[ctlNextHop] = ctlOpt{sysIPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop}
 	ctlOpts[ctlPathMTU] = ctlOpt{sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU}
-	sockOpts[ssoTrafficClass] = sockOpt{iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt}
-	sockOpts[ssoReceiveTrafficClass] = sockOpt{iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt}
-	sockOpts[ssoReceiveHopLimit] = sockOpt{iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt}
-	sockOpts[ssoReceivePacketInfo] = sockOpt{iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt}
-	sockOpts[ssoReceivePathMTU] = sockOpt{iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt}
-	sockOpts[ssoPathMTU] = sockOpt{iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo}
-	sockOpts[ssoJoinGroup] = sockOpt{iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq}
-	sockOpts[ssoLeaveGroup] = sockOpt{iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq}
-	sockOpts[ssoJoinSourceGroup] = sockOpt{iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq}
-	sockOpts[ssoLeaveSourceGroup] = sockOpt{iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq}
-	sockOpts[ssoBlockSourceGroup] = sockOpt{iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq}
-	sockOpts[ssoUnblockSourceGroup] = sockOpt{iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq}
+	sockOpts[ssoTrafficClass] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}}
+	sockOpts[ssoReceiveTrafficClass] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}}
+	sockOpts[ssoReceiveHopLimit] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}}
+	sockOpts[ssoReceivePacketInfo] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}}
+	sockOpts[ssoReceivePathMTU] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}}
+	sockOpts[ssoPathMTU] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}}
+	sockOpts[ssoJoinGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+	sockOpts[ssoLeaveGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+	sockOpts[ssoJoinSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+	sockOpts[ssoLeaveSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+	sockOpts[ssoBlockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+	sockOpts[ssoUnblockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
 }
 
 func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
diff --git a/ipv6/sys_freebsd.go b/ipv6/sys_freebsd.go
index fd5204b..e9349dc 100644
--- a/ipv6/sys_freebsd.go
+++ b/ipv6/sys_freebsd.go
@@ -12,6 +12,7 @@
 	"unsafe"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -23,25 +24,25 @@
 		ctlPathMTU:      {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTrafficClass:        {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
-		ssoHopLimit:            {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
-		ssoMulticastInterface:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastHopLimit:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
-		ssoMulticastLoopback:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
-		ssoReceiveHopLimit:     {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
-		ssoReceivePacketInfo:   {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
-		ssoReceivePathMTU:      {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
-		ssoPathMTU:             {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
-		ssoChecksum:            {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
-		ssoICMPFilter:          {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
-		ssoJoinGroup:           {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
-		ssoLeaveGroup:          {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
-		ssoJoinSourceGroup:     {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoLeaveSourceGroup:    {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoBlockSourceGroup:    {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
-		ssoUnblockSourceGroup:  {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+	sockOpts = map[int]sockOpt{
+		ssoTrafficClass:        {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+		ssoHopLimit:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+		ssoMulticastInterface:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+		ssoMulticastHopLimit:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+		ssoMulticastLoopback:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+		ssoReceiveHopLimit:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+		ssoReceivePacketInfo:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+		ssoReceivePathMTU:      {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+		ssoPathMTU:             {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+		ssoChecksum:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+		ssoICMPFilter:          {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+		ssoJoinGroup:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoLeaveGroup:          {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoJoinSourceGroup:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoLeaveSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoBlockSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoUnblockSourceGroup:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
 	}
 )
 
diff --git a/ipv6/sys_linux.go b/ipv6/sys_linux.go
index 42f5f78..bc21810 100644
--- a/ipv6/sys_linux.go
+++ b/ipv6/sys_linux.go
@@ -10,6 +10,7 @@
 	"unsafe"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -20,25 +21,26 @@
 		ctlPathMTU:      {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTrafficClass:        {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
-		ssoHopLimit:            {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
-		ssoMulticastInterface:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastHopLimit:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
-		ssoMulticastLoopback:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
-		ssoReceiveHopLimit:     {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
-		ssoReceivePacketInfo:   {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
-		ssoReceivePathMTU:      {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
-		ssoPathMTU:             {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
-		ssoChecksum:            {iana.ProtocolReserved, sysIPV6_CHECKSUM, ssoTypeInt},
-		ssoICMPFilter:          {iana.ProtocolIPv6ICMP, sysICMPV6_FILTER, ssoTypeICMPFilter},
-		ssoJoinGroup:           {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
-		ssoLeaveGroup:          {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
-		ssoJoinSourceGroup:     {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoLeaveSourceGroup:    {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoBlockSourceGroup:    {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
-		ssoUnblockSourceGroup:  {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+	sockOpts = map[int]*sockOpt{
+		ssoTrafficClass:        {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+		ssoHopLimit:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+		ssoMulticastInterface:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+		ssoMulticastHopLimit:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+		ssoMulticastLoopback:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+		ssoReceiveHopLimit:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+		ssoReceivePacketInfo:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+		ssoReceivePathMTU:      {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+		ssoPathMTU:             {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+		ssoChecksum:            {Option: socket.Option{Level: iana.ProtocolReserved, Name: sysIPV6_CHECKSUM, Len: 4}},
+		ssoICMPFilter:          {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMPV6_FILTER, Len: sizeofICMPv6Filter}},
+		ssoJoinGroup:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoLeaveGroup:          {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoJoinSourceGroup:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoLeaveSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoBlockSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoUnblockSourceGroup:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoAttachFilter:        {Option: socket.Option{Level: sysSOL_SOCKET, Name: sysSO_ATTACH_FILTER, Len: sizeofSockFprog}},
 	}
 )
 
diff --git a/ipv6/sys_linux_386.s b/ipv6/sys_linux_386.s
deleted file mode 100644
index b85551a..0000000
--- a/ipv6/sys_linux_386.s
+++ /dev/null
@@ -1,8 +0,0 @@
-// 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.
-
-#include "textflag.h"
-
-TEXT	·socketcall(SB),NOSPLIT,$0-36
-	JMP	syscall·socketcall(SB)
diff --git a/ipv6/sys_solaris.go b/ipv6/sys_solaris.go
index 9bd2d66..d348b5f 100644
--- a/ipv6/sys_solaris.go
+++ b/ipv6/sys_solaris.go
@@ -10,6 +10,7 @@
 	"unsafe"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -21,25 +22,25 @@
 		ctlPathMTU:      {sysIPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTrafficClass:        {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt},
-		ssoHopLimit:            {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
-		ssoMulticastInterface:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastHopLimit:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
-		ssoMulticastLoopback:   {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt},
-		ssoReceiveHopLimit:     {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt},
-		ssoReceivePacketInfo:   {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt},
-		ssoReceivePathMTU:      {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt},
-		ssoPathMTU:             {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo},
-		ssoChecksum:            {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt},
-		ssoICMPFilter:          {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter},
-		ssoJoinGroup:           {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
-		ssoLeaveGroup:          {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
-		ssoJoinSourceGroup:     {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoLeaveSourceGroup:    {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoBlockSourceGroup:    {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
-		ssoUnblockSourceGroup:  {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+	sockOpts = map[int]*sockOpt{
+		ssoTrafficClass:        {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_TCLASS, Len: 4}},
+		ssoHopLimit:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+		ssoMulticastInterface:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+		ssoMulticastHopLimit:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+		ssoMulticastLoopback:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVTCLASS, Len: 4}},
+		ssoReceiveHopLimit:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVHOPLIMIT, Len: 4}},
+		ssoReceivePacketInfo:   {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPKTINFO, Len: 4}},
+		ssoReceivePathMTU:      {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_RECVPATHMTU, Len: 4}},
+		ssoPathMTU:             {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
+		ssoChecksum:            {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_CHECKSUM, Len: 4}},
+		ssoICMPFilter:          {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: sysICMP6_FILTER, Len: sizeofICMPv6Filter}},
+		ssoJoinGroup:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoLeaveGroup:          {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoJoinSourceGroup:     {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoLeaveSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoBlockSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoUnblockSourceGroup:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
 	}
 )
 
diff --git a/ipv6/sys_solaris_amd64.s b/ipv6/sys_solaris_amd64.s
deleted file mode 100644
index 39d76af..0000000
--- a/ipv6/sys_solaris_amd64.s
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2016 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.
-
-#include "textflag.h"
-
-TEXT ·sysvicall6(SB),NOSPLIT,$0-88
-	JMP	syscall·sysvicall6(SB)
diff --git a/ipv6/sys_ssmreq.go b/ipv6/sys_ssmreq.go
new file mode 100644
index 0000000..add8ccc
--- /dev/null
+++ b/ipv6/sys_ssmreq.go
@@ -0,0 +1,54 @@
+// 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.
+
+// +build darwin freebsd linux solaris
+
+package ipv6
+
+import (
+	"net"
+	"unsafe"
+
+	"golang.org/x/net/internal/socket"
+)
+
+var freebsd32o64 bool
+
+func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	var gr groupReq
+	if ifi != nil {
+		gr.Interface = uint32(ifi.Index)
+	}
+	gr.setGroup(grp)
+	var b []byte
+	if freebsd32o64 {
+		var d [sizeofGroupReq + 4]byte
+		s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
+		copy(d[:4], s[:4])
+		copy(d[8:], s[4:])
+		b = d[:]
+	} else {
+		b = (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))[:sizeofGroupReq]
+	}
+	return so.Set(c, b)
+}
+
+func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
+	var gsr groupSourceReq
+	if ifi != nil {
+		gsr.Interface = uint32(ifi.Index)
+	}
+	gsr.setSourceGroup(grp, src)
+	var b []byte
+	if freebsd32o64 {
+		var d [sizeofGroupSourceReq + 4]byte
+		s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
+		copy(d[:4], s[:4])
+		copy(d[8:], s[4:])
+		b = d[:]
+	} else {
+		b = (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))[:sizeofGroupSourceReq]
+	}
+	return so.Set(c, b)
+}
diff --git a/ipv6/sys_ssmreq_stub.go b/ipv6/sys_ssmreq_stub.go
new file mode 100644
index 0000000..581ee49
--- /dev/null
+++ b/ipv6/sys_ssmreq_stub.go
@@ -0,0 +1,21 @@
+// 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.
+
+// +build !darwin,!freebsd,!linux,!solaris
+
+package ipv6
+
+import (
+	"net"
+
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	return errOpNoSupport
+}
+
+func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
+	return errOpNoSupport
+}
diff --git a/ipv6/sys_stub.go b/ipv6/sys_stub.go
index 7663bfc..b845388 100644
--- a/ipv6/sys_stub.go
+++ b/ipv6/sys_stub.go
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build nacl plan9
+// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
 
 package ipv6
 
 var (
 	ctlOpts = [ctlMax]ctlOpt{}
 
-	sockOpts = [ssoMax]sockOpt{}
+	sockOpts = map[int]*sockOpt{}
 )
diff --git a/ipv6/sys_windows.go b/ipv6/sys_windows.go
index 003c507..fc36b01 100644
--- a/ipv6/sys_windows.go
+++ b/ipv6/sys_windows.go
@@ -9,6 +9,7 @@
 	"syscall"
 
 	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 const (
@@ -53,13 +54,13 @@
 var (
 	ctlOpts = [ctlMax]ctlOpt{}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoHopLimit:           {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt},
-		ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastHopLimit:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt},
-		ssoMulticastLoopback:  {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt},
-		ssoJoinGroup:          {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq},
-		ssoLeaveGroup:         {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq},
+	sockOpts = map[int]*sockOpt{
+		ssoHopLimit:           {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_UNICAST_HOPS, Len: 4}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_IF, Len: 4}},
+		ssoMulticastHopLimit:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_HOPS, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_MULTICAST_LOOP, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIPv6, Name: sysIPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
 	}
 )
 
diff --git a/ipv6/syscall_linux_386.go b/ipv6/syscall_linux_386.go
deleted file mode 100644
index 5184dbe..0000000
--- a/ipv6/syscall_linux_386.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-package ipv6
-
-import (
-	"syscall"
-	"unsafe"
-)
-
-const (
-	sysGETSOCKOPT = 0xf
-	sysSETSOCKOPT = 0xe
-)
-
-func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno)
-
-func getsockopt(s uintptr, level, name int, v unsafe.Pointer, l *uint32) error {
-	if _, errno := socketcall(sysGETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
-		return error(errno)
-	}
-	return nil
-}
-
-func setsockopt(s uintptr, level, name int, v unsafe.Pointer, l uint32) error {
-	if _, errno := socketcall(sysSETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
-		return error(errno)
-	}
-	return nil
-}
diff --git a/ipv6/syscall_solaris.go b/ipv6/syscall_solaris.go
deleted file mode 100644
index 2a5c8ee..0000000
--- a/ipv6/syscall_solaris.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2016 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 (
-	"syscall"
-	"unsafe"
-)
-
-//go:cgo_import_dynamic libc___xnet_getsockopt __xnet_getsockopt "libsocket.so"
-//go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
-
-//go:linkname procGetsockopt libc___xnet_getsockopt
-//go:linkname procSetsockopt libc_setsockopt
-
-var (
-	procGetsockopt uintptr
-	procSetsockopt uintptr
-)
-
-func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (uintptr, uintptr, syscall.Errno)
-
-func getsockopt(s uintptr, level, name int, v unsafe.Pointer, l *uint32) error {
-	_, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procGetsockopt)), 5, s, uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0)
-	if errno != 0 {
-		return error(errno)
-	}
-	return nil
-}
-
-func setsockopt(s uintptr, level, name int, v unsafe.Pointer, l uint32) error {
-	if _, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procSetsockopt)), 5, s, uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
-		return error(errno)
-	}
-	return nil
-}
diff --git a/ipv6/syscall_unix.go b/ipv6/syscall_unix.go
deleted file mode 100644
index 58a75b5..0000000
--- a/ipv6/syscall_unix.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 dragonfly freebsd linux,!386 netbsd openbsd
-
-package ipv6
-
-import (
-	"syscall"
-	"unsafe"
-)
-
-func getsockopt(s uintptr, level, name int, v unsafe.Pointer, l *uint32) error {
-	if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 {
-		return error(errno)
-	}
-	return nil
-}
-
-func setsockopt(s uintptr, level, name int, v unsafe.Pointer, l uint32) error {
-	if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 {
-		return error(errno)
-	}
-	return nil
-}
diff --git a/ipv6/syscall_windows.go b/ipv6/syscall_windows.go
deleted file mode 100644
index c1f649d..0000000
--- a/ipv6/syscall_windows.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2016 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 (
-	"syscall"
-	"unsafe"
-)
-
-func getsockopt(s uintptr, level, name int, v unsafe.Pointer, l *uint32) error {
-	return syscall.Getsockopt(syscall.Handle(s), int32(level), int32(name), (*byte)(v), (*int32)(unsafe.Pointer(l)))
-}
-
-func setsockopt(s uintptr, level, name int, v unsafe.Pointer, l uint32) error {
-	return syscall.Setsockopt(syscall.Handle(s), int32(level), int32(name), (*byte)(v), int32(l))
-}
diff --git a/ipv6/zsys_linux_386.go b/ipv6/zsys_linux_386.go
index f5a4109..73aa8c6 100644
--- a/ipv6/zsys_linux_386.go
+++ b/ipv6/zsys_linux_386.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_amd64.go b/ipv6/zsys_linux_amd64.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_amd64.go
+++ b/ipv6/zsys_linux_amd64.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_arm.go b/ipv6/zsys_linux_arm.go
index f5a4109..73aa8c6 100644
--- a/ipv6/zsys_linux_arm.go
+++ b/ipv6/zsys_linux_arm.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_arm64.go b/ipv6/zsys_linux_arm64.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_arm64.go
+++ b/ipv6/zsys_linux_arm64.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_mips.go b/ipv6/zsys_linux_mips.go
index f5a4109..73aa8c6 100644
--- a/ipv6/zsys_linux_mips.go
+++ b/ipv6/zsys_linux_mips.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_mips64.go b/ipv6/zsys_linux_mips64.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_mips64.go
+++ b/ipv6/zsys_linux_mips64.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_mips64le.go b/ipv6/zsys_linux_mips64le.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_mips64le.go
+++ b/ipv6/zsys_linux_mips64le.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_mipsle.go b/ipv6/zsys_linux_mipsle.go
index f5a4109..73aa8c6 100644
--- a/ipv6/zsys_linux_mipsle.go
+++ b/ipv6/zsys_linux_mipsle.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_ppc.go b/ipv6/zsys_linux_ppc.go
index be2dbd6..c9bf6a8 100644
--- a/ipv6/zsys_linux_ppc.go
+++ b/ipv6/zsys_linux_ppc.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_ppc64.go b/ipv6/zsys_linux_ppc64.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_ppc64.go
+++ b/ipv6/zsys_linux_ppc64.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_ppc64le.go b/ipv6/zsys_linux_ppc64le.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_ppc64le.go
+++ b/ipv6/zsys_linux_ppc64le.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {
diff --git a/ipv6/zsys_linux_s390x.go b/ipv6/zsys_linux_s390x.go
index f9376b6..b64f015 100644
--- a/ipv6/zsys_linux_s390x.go
+++ b/ipv6/zsys_linux_s390x.go
@@ -98,6 +98,8 @@
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPv6Filter = 0x20
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {