Ver Fonte

ipv4: 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 ipv4
package works with all supported versions of the Go standard library.

Fixes golang/go#19051.

Change-Id: If0256007c749c319970533823a10afdc1ffbce31
Reviewed-on: https://go-review.googlesource.com/37036
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Mikio Hara há 8 anos atrás
pai
commit
c4fa6e0d08
55 ficheiros alterados com 528 adições e 780 exclusões
  1. 0 28
      ipv4/bpfopt_linux.go
  2. 0 16
      ipv4/bpfopt_stub.go
  3. 4 2
      ipv4/control_stub.go
  4. 10 9
      ipv4/control_unix.go
  5. 6 2
      ipv4/control_windows.go
  6. 2 0
      ipv4/defs_linux.go
  7. 71 59
      ipv4/dgramopt.go
  8. 0 106
      ipv4/dgramopt_stub.go
  9. 24 26
      ipv4/endpoint.go
  10. 17 23
      ipv4/genericopt.go
  11. 0 29
      ipv4/genericopt_stub.go
  12. 10 8
      ipv4/header.go
  13. 4 2
      ipv4/header_test.go
  14. 0 14
      ipv4/helper.go
  15. 1 1
      ipv4/payload_cmsg.go
  16. 6 8
      ipv4/sockopt.go
  17. 0 46
      ipv4/sockopt_asmreq_posix.go
  18. 0 21
      ipv4/sockopt_asmreq_stub.go
  19. 32 83
      ipv4/sockopt_posix.go
  20. 33 2
      ipv4/sockopt_stub.go
  21. 37 1
      ipv4/sys_asmreq.go
  22. 25 0
      ipv4/sys_asmreq_stub.go
  23. 9 9
      ipv4/sys_asmreqn.go
  24. 7 3
      ipv4/sys_asmreqn_stub.go
  25. 23 0
      ipv4/sys_bpf.go
  26. 16 0
      ipv4/sys_bpf_stub.go
  27. 16 13
      ipv4/sys_bsd.go
  28. 24 28
      ipv4/sys_darwin.go
  29. 35 0
      ipv4/sys_dragonfly.go
  30. 20 17
      ipv4/sys_freebsd.go
  31. 20 16
      ipv4/sys_linux.go
  32. 0 8
      ipv4/sys_linux_386.s
  33. 0 32
      ipv4/sys_openbsd.go
  34. 18 15
      ipv4/sys_solaris.go
  35. 0 8
      ipv4/sys_solaris_amd64.s
  36. 11 18
      ipv4/sys_ssmreq.go
  37. 7 3
      ipv4/sys_ssmreq_stub.go
  38. 2 2
      ipv4/sys_stub.go
  39. 14 9
      ipv4/sys_windows.go
  40. 0 31
      ipv4/syscall_linux_386.go
  41. 0 38
      ipv4/syscall_solaris.go
  42. 0 26
      ipv4/syscall_unix.go
  43. 0 18
      ipv4/syscall_windows.go
  44. 2 0
      ipv4/zsys_linux_386.go
  45. 2 0
      ipv4/zsys_linux_amd64.go
  46. 2 0
      ipv4/zsys_linux_arm.go
  47. 2 0
      ipv4/zsys_linux_arm64.go
  48. 2 0
      ipv4/zsys_linux_mips.go
  49. 2 0
      ipv4/zsys_linux_mips64.go
  50. 2 0
      ipv4/zsys_linux_mips64le.go
  51. 2 0
      ipv4/zsys_linux_mipsle.go
  52. 2 0
      ipv4/zsys_linux_ppc.go
  53. 2 0
      ipv4/zsys_linux_ppc64.go
  54. 2 0
      ipv4/zsys_linux_ppc64le.go
  55. 2 0
      ipv4/zsys_linux_s390x.go

+ 0 - 28
ipv4/bpfopt_linux.go

@@ -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 ipv4
-
-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))))
-}

+ 0 - 16
ipv4/bpfopt_stub.go

@@ -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 ipv4
-
-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
-}

+ 4 - 2
ipv4/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 ipv4
 
-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
 }
 

+ 10 - 9
ipv4/control_unix.go

@@ -12,13 +12,14 @@ import (
 	"unsafe"
 
 	"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&FlagTTL != 0 && sockOpts[ssoReceiveTTL].name > 0 {
-		if err := setInt(s, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil {
+	if so, ok := sockOpts[ssoReceiveTTL]; ok && cf&FlagTTL != 0 {
+		if err := so.SetInt(c, boolint(on)); err != nil {
 			return err
 		}
 		if on {
@@ -27,9 +28,9 @@ func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
 			opt.clear(FlagTTL)
 		}
 	}
-	if sockOpts[ssoPacketInfo].name > 0 {
+	if so, ok := sockOpts[ssoPacketInfo]; ok {
 		if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
-			if err := setInt(s, &sockOpts[ssoPacketInfo], boolint(on)); err != nil {
+			if err := so.SetInt(c, boolint(on)); err != nil {
 				return err
 			}
 			if on {
@@ -39,8 +40,8 @@ func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
 			}
 		}
 	} else {
-		if cf&FlagDst != 0 && sockOpts[ssoReceiveDst].name > 0 {
-			if err := setInt(s, &sockOpts[ssoReceiveDst], boolint(on)); err != nil {
+		if so, ok := sockOpts[ssoReceiveDst]; ok && cf&FlagDst != 0 {
+			if err := so.SetInt(c, boolint(on)); err != nil {
 				return err
 			}
 			if on {
@@ -49,8 +50,8 @@ func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
 				opt.clear(FlagDst)
 			}
 		}
-		if cf&FlagInterface != 0 && sockOpts[ssoReceiveInterface].name > 0 {
-			if err := setInt(s, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil {
+		if so, ok := sockOpts[ssoReceiveInterface]; ok && cf&FlagInterface != 0 {
+			if err := so.SetInt(c, boolint(on)); err != nil {
 				return err
 			}
 			if on {

+ 6 - 2
ipv4/control_windows.go

@@ -4,9 +4,13 @@
 
 package ipv4
 
-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
 }

+ 2 - 0
ipv4/defs_linux.go

@@ -93,6 +93,8 @@ const (
 	sizeofGroupSourceReq = C.sizeof_struct_group_source_req
 
 	sizeofICMPFilter = C.sizeof_struct_icmp_filter
+
+	sizeofSockFprog = C.sizeof_struct_sock_fprog
 )
 
 type kernelSockaddrStorage C.struct___kernel_sockaddr_storage

+ 71 - 59
ipv4/dgramopt_posix.go → ipv4/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 ipv4
 
 import (
 	"net"
 	"syscall"
 
-	"golang.org/x/net/internal/netreflect"
+	"golang.org/x/net/bpf"
 )
 
 // MulticastTTL returns the time-to-live field value for outgoing
@@ -19,11 +17,11 @@ func (c *dgramOpt) MulticastTTL() (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return 0, err
+	so, ok := sockOpts[ssoMulticastTTL]
+	if !ok {
+		return 0, errOpNoSupport
 	}
-	return getInt(s, &sockOpts[ssoMulticastTTL])
+	return so.GetInt(c.Conn)
 }
 
 // SetMulticastTTL sets the time-to-live field value for future
@@ -32,11 +30,11 @@ func (c *dgramOpt) SetMulticastTTL(ttl int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.PacketConn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoMulticastTTL]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setInt(s, &sockOpts[ssoMulticastTTL], ttl)
+	return so.SetInt(c.Conn, ttl)
 }
 
 // MulticastInterface returns the default interface for multicast
@@ -45,11 +43,11 @@ func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
 	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 @@ func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
 	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 @@ func (c *dgramOpt) MulticastLoopback() (bool, error) {
 	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 @@ func (c *dgramOpt) SetMulticastLoopback(on bool) error {
 	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 @@ func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
 	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 := netAddrToIP4(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 @@ func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
 	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 := netAddrToIP4(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 @@ func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net
 	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 := netAddrToIP4(group)
 	if grp == nil {
@@ -159,7 +157,7 @@ func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net
 	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 @@ func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source ne
 	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 := netAddrToIP4(group)
 	if grp == nil {
@@ -180,7 +178,7 @@ func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source ne
 	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 @@ func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source
 	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 := netAddrToIP4(group)
 	if grp == nil {
@@ -202,7 +200,7 @@ func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source
 	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 @@ func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source
 	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 := netAddrToIP4(group)
 	if grp == nil {
@@ -223,7 +221,7 @@ func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source
 	if src == nil {
 		return errMissingAddress
 	}
-	return setSourceGroup(s, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src)
+	return so.setSourceGroup(c.Conn, ifi, grp, src)
 }
 
 // ICMPFilter returns an ICMP filter.
@@ -232,11 +230,11 @@ func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
 	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.
@@ -245,9 +243,23 @@ func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
 	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 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 setICMPFilter(s, &sockOpts[ssoICMPFilter], f)
+	return so.setBPF(c.Conn, filter)
 }

+ 0 - 106
ipv4/dgramopt_stub.go

@@ -1,106 +0,0 @@
-// Copyright 2012 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 ipv4
-
-import "net"
-
-// MulticastTTL returns the time-to-live field value for outgoing
-// multicast packets.
-func (c *dgramOpt) MulticastTTL() (int, error) {
-	return 0, errOpNoSupport
-}
-
-// SetMulticastTTL sets the time-to-live field value for future
-// outgoing multicast packets.
-func (c *dgramOpt) SetMulticastTTL(ttl 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
-}
-
-// ICMPFilter returns an ICMP filter.
-// Currently only Linux supports this.
-func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
-	return nil, errOpNoSupport
-}
-
-// SetICMPFilter deploys the ICMP filter.
-// Currently only Linux supports this.
-func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
-	return errOpNoSupport
-}

+ 24 - 26
ipv4/endpoint.go

@@ -9,7 +9,7 @@ import (
 	"syscall"
 	"time"
 
-	"golang.org/x/net/internal/netreflect"
+	"golang.org/x/net/internal/socket"
 )
 
 // BUG(mikio): On Windows, the JoinSourceSpecificGroup,
@@ -25,15 +25,16 @@ type Conn struct {
 }
 
 type genericOpt struct {
-	net.Conn
+	*socket.Conn
 }
 
 func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
 
 // 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},
 	}
 }
 
@@ -49,21 +50,17 @@ type PacketConn struct {
 }
 
 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 sets the per packet IP-level socket options.
 func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
 	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
@@ -104,14 +101,15 @@ func (c *PacketConn) Close() error {
 // NewPacketConn returns a new PacketConn using c as its underlying
 // transport.
 func NewPacketConn(c net.PacketConn) *PacketConn {
+	cc, _ := socket.NewConn(c.(net.Conn))
 	p := &PacketConn{
-		genericOpt:     genericOpt{Conn: c.(net.Conn)},
-		dgramOpt:       dgramOpt{PacketConn: c},
+		genericOpt:     genericOpt{Conn: cc},
+		dgramOpt:       dgramOpt{Conn: cc},
 		payloadHandler: payloadHandler{PacketConn: c},
 	}
-	if _, ok := c.(*net.IPConn); ok && sockOpts[ssoStripHeader].name > 0 {
-		if s, err := netreflect.PacketSocketOf(c); err == nil {
-			setInt(s, &sockOpts[ssoStripHeader], boolint(true))
+	if _, ok := c.(*net.IPConn); ok {
+		if so, ok := sockOpts[ssoStripHeader]; ok {
+			so.SetInt(p.dgramOpt.Conn, boolint(true))
 		}
 	}
 	return p
@@ -133,11 +131,7 @@ func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
 	if !c.packetHandler.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.PacketSocketOf(c.dgramOpt.PacketConn)
-	if err != nil {
-		return err
-	}
-	return setControlMessage(s, &c.packetHandler.rawOpt, cf, on)
+	return setControlMessage(c.dgramOpt.Conn, &c.packetHandler.rawOpt, cf, on)
 }
 
 // SetDeadline sets the read and write deadlines associated with the
@@ -178,16 +172,20 @@ func (c *RawConn) Close() error {
 // NewRawConn returns a new RawConn using c as its underlying
 // transport.
 func NewRawConn(c net.PacketConn) (*RawConn, error) {
+	cc, err := socket.NewConn(c.(net.Conn))
+	if err != nil {
+		return nil, err
+	}
 	r := &RawConn{
-		genericOpt:    genericOpt{Conn: c.(net.Conn)},
-		dgramOpt:      dgramOpt{PacketConn: c},
+		genericOpt:    genericOpt{Conn: cc},
+		dgramOpt:      dgramOpt{Conn: cc},
 		packetHandler: packetHandler{c: c.(*net.IPConn)},
 	}
-	s, err := netreflect.PacketSocketOf(c)
-	if err != nil {
-		return nil, err
+	so, ok := sockOpts[ssoHeaderPrepend]
+	if !ok {
+		return nil, errOpNoSupport
 	}
-	if err := setInt(s, &sockOpts[ssoHeaderPrepend], boolint(true)); err != nil {
+	if err := so.SetInt(r.dgramOpt.Conn, boolint(true)); err != nil {
 		return nil, err
 	}
 	return r, nil

+ 17 - 23
ipv4/genericopt_posix.go → ipv4/genericopt.go

@@ -2,26 +2,20 @@
 // 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 ipv4
 
-import (
-	"syscall"
-
-	"golang.org/x/net/internal/netreflect"
-)
+import "syscall"
 
 // TOS returns the type-of-service field value for outgoing packets.
 func (c *genericOpt) TOS() (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return 0, err
+	so, ok := sockOpts[ssoTOS]
+	if !ok {
+		return 0, errOpNoSupport
 	}
-	return getInt(s, &sockOpts[ssoTOS])
+	return so.GetInt(c.Conn)
 }
 
 // SetTOS sets the type-of-service field value for future outgoing
@@ -30,11 +24,11 @@ func (c *genericOpt) SetTOS(tos int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoTOS]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setInt(s, &sockOpts[ssoTOS], tos)
+	return so.SetInt(c.Conn, tos)
 }
 
 // TTL returns the time-to-live field value for outgoing packets.
@@ -42,11 +36,11 @@ func (c *genericOpt) TTL() (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return 0, err
+	so, ok := sockOpts[ssoTTL]
+	if !ok {
+		return 0, errOpNoSupport
 	}
-	return getInt(s, &sockOpts[ssoTTL])
+	return so.GetInt(c.Conn)
 }
 
 // SetTTL sets the time-to-live field value for future outgoing
@@ -55,9 +49,9 @@ func (c *genericOpt) SetTTL(ttl int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	s, err := netreflect.SocketOf(c.Conn)
-	if err != nil {
-		return err
+	so, ok := sockOpts[ssoTTL]
+	if !ok {
+		return errOpNoSupport
 	}
-	return setInt(s, &sockOpts[ssoTTL], ttl)
+	return so.SetInt(c.Conn, ttl)
 }

+ 0 - 29
ipv4/genericopt_stub.go

@@ -1,29 +0,0 @@
-// Copyright 2012 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 ipv4
-
-// TOS returns the type-of-service field value for outgoing packets.
-func (c *genericOpt) TOS() (int, error) {
-	return 0, errOpNoSupport
-}
-
-// SetTOS sets the type-of-service field value for future outgoing
-// packets.
-func (c *genericOpt) SetTOS(tos int) error {
-	return errOpNoSupport
-}
-
-// TTL returns the time-to-live field value for outgoing packets.
-func (c *genericOpt) TTL() (int, error) {
-	return 0, errOpNoSupport
-}
-
-// SetTTL sets the time-to-live field value for future outgoing
-// packets.
-func (c *genericOpt) SetTTL(ttl int) error {
-	return errOpNoSupport
-}

+ 10 - 8
ipv4/header.go

@@ -10,6 +10,8 @@ import (
 	"net"
 	"runtime"
 	"syscall"
+
+	"golang.org/x/net/internal/socket"
 )
 
 const (
@@ -64,12 +66,12 @@ func (h *Header) Marshal() ([]byte, error) {
 	flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13)
 	switch runtime.GOOS {
 	case "darwin", "dragonfly", "netbsd":
-		nativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
-		nativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
+		socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
+		socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
 	case "freebsd":
 		if freebsdVersion < 1100000 {
-			nativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
-			nativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
+			socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
+			socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
 		} else {
 			binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
 			binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
@@ -118,15 +120,15 @@ func ParseHeader(b []byte) (*Header, error) {
 	}
 	switch runtime.GOOS {
 	case "darwin", "dragonfly", "netbsd":
-		h.TotalLen = int(nativeEndian.Uint16(b[2:4])) + hdrlen
-		h.FragOff = int(nativeEndian.Uint16(b[6:8]))
+		h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4])) + hdrlen
+		h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
 	case "freebsd":
 		if freebsdVersion < 1100000 {
-			h.TotalLen = int(nativeEndian.Uint16(b[2:4]))
+			h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
 			if freebsdVersion < 1000000 {
 				h.TotalLen += hdrlen
 			}
-			h.FragOff = int(nativeEndian.Uint16(b[6:8]))
+			h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
 		} else {
 			h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
 			h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))

+ 4 - 2
ipv4/header_test.go

@@ -12,6 +12,8 @@ import (
 	"runtime"
 	"strings"
 	"testing"
+
+	"golang.org/x/net/internal/socket"
 )
 
 type headerTest struct {
@@ -87,7 +89,7 @@ var headerLittleEndianTest = headerTest{
 
 func TestMarshalHeader(t *testing.T) {
 	tt := &headerLittleEndianTest
-	if nativeEndian != binary.LittleEndian {
+	if socket.NativeEndian != binary.LittleEndian {
 		t.Skip("no test for non-little endian machine yet")
 	}
 
@@ -118,7 +120,7 @@ func TestMarshalHeader(t *testing.T) {
 
 func TestParseHeader(t *testing.T) {
 	tt := &headerLittleEndianTest
-	if nativeEndian != binary.LittleEndian {
+	if socket.NativeEndian != binary.LittleEndian {
 		t.Skip("no test for big endian machine yet")
 	}
 

+ 0 - 14
ipv4/helper.go

@@ -5,10 +5,8 @@
 package ipv4
 
 import (
-	"encoding/binary"
 	"errors"
 	"net"
-	"unsafe"
 )
 
 var (
@@ -23,20 +21,8 @@ var (
 
 	// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
 	freebsdVersion uint32
-
-	nativeEndian binary.ByteOrder
 )
 
-func init() {
-	i := uint32(1)
-	b := (*[4]byte)(unsafe.Pointer(&i))
-	if b[0] == 1 {
-		nativeEndian = binary.LittleEndian
-	} else {
-		nativeEndian = binary.BigEndian
-	}
-}
-
 func boolint(b bool) int {
 	if b {
 		return 1

+ 1 - 1
ipv4/payload_cmsg.go

@@ -27,7 +27,7 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
 			return 0, nil, nil, err
 		}
 	case *net.IPConn:
-		if sockOpts[ssoStripHeader].name > 0 {
+		if _, ok := sockOpts[ssoStripHeader]; ok {
 			if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil {
 				return 0, nil, nil, err
 			}

+ 6 - 8
ipv4/sockopt.go

@@ -4,6 +4,8 @@
 
 package ipv4
 
+import "golang.org/x/net/internal/socket"
+
 // Sticky socket options
 const (
 	ssoTOS                = iota // header field for unicast packet
@@ -24,16 +26,12 @@ const (
 	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 (
-	ssoTypeByte = iota + 1
-	ssoTypeInt
-	ssoTypeInterface
-	ssoTypeICMPFilter
-	ssoTypeIPMreq
+	ssoTypeIPMreq = iota + 1
 	ssoTypeIPMreqn
 	ssoTypeGroupReq
 	ssoTypeGroupSourceReq
@@ -41,6 +39,6 @@ const (
 
 // A sockOpt represents a binding for sticky socket option.
 type sockOpt struct {
-	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
 }

+ 0 - 46
ipv4/sockopt_asmreq_posix.go

@@ -1,46 +0,0 @@
-// Copyright 2012 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 netbsd openbsd solaris windows
-
-package ipv4
-
-import (
-	"net"
-	"os"
-	"unsafe"
-
-	"golang.org/x/net/internal/iana"
-)
-
-func setsockoptIPMreq(s uintptr, name int, ifi *net.Interface, grp net.IP) error {
-	mreq := ipMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
-	if err := setIPMreqInterface(&mreq, ifi); err != nil {
-		return err
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, iana.ProtocolIP, name, unsafe.Pointer(&mreq), sizeofIPMreq))
-}
-
-func getsockoptInterface(s uintptr, name int) (*net.Interface, error) {
-	var b [4]byte
-	l := uint32(4)
-	if err := getsockopt(s, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
-	if err != nil {
-		return nil, err
-	}
-	return ifi, nil
-}
-
-func setsockoptInterface(s uintptr, name int, ifi *net.Interface) error {
-	ip, err := netInterfaceToIP4(ifi)
-	if err != nil {
-		return err
-	}
-	var b [4]byte
-	copy(b[:], ip)
-	return os.NewSyscallError("setsockopt", setsockopt(s, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), uint32(4)))
-}

+ 0 - 21
ipv4/sockopt_asmreq_stub.go

@@ -1,21 +0,0 @@
-// Copyright 2012 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,!netbsd,!openbsd,!solaris,!windows
-
-package ipv4
-
-import "net"
-
-func setsockoptIPMreq(s uintptr, name int, ifi *net.Interface, grp net.IP) error {
-	return errOpNoSupport
-}
-
-func getsockoptInterface(s uintptr, name int) (*net.Interface, error) {
-	return nil, errOpNoSupport
-}
-
-func setsockoptInterface(s uintptr, name int, ifi *net.Interface) error {
-	return errOpNoSupport
-}

+ 32 - 83
ipv4/sockopt_posix.go

@@ -8,115 +8,64 @@ package ipv4
 
 import (
 	"net"
-	"os"
 	"unsafe"
 
-	"golang.org/x/net/internal/iana"
+	"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 != ssoTypeByte && opt.typ != ssoTypeInt) {
-		return 0, errOpNoSupport
-	}
-	var i int32
-	var b byte
-	p := unsafe.Pointer(&i)
-	l := uint32(4)
-	if opt.typ == ssoTypeByte {
-		p = unsafe.Pointer(&b)
-		l = 1
-	}
-	if err := getsockopt(s, iana.ProtocolIP, opt.name, p, &l); err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	if opt.typ == ssoTypeByte {
-		return int(b), nil
-	}
-	return int(i), nil
-}
-
-func setInt(s uintptr, opt *sockOpt, v int) error {
-	if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) {
-		return errOpNoSupport
-	}
-	i := int32(v)
-	var b byte
-	p := unsafe.Pointer(&i)
-	l := uint32(4)
-	if opt.typ == ssoTypeByte {
-		b = byte(v)
-		p = unsafe.Pointer(&b)
-		l = 1
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, iana.ProtocolIP, opt.name, p, l))
-}
-
-func getInterface(s uintptr, opt *sockOpt) (*net.Interface, error) {
-	if opt.name < 1 {
-		return nil, errOpNoSupport
-	}
-	switch opt.typ {
-	case ssoTypeInterface:
-		return getsockoptInterface(s, opt.name)
+func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
+	switch so.typ {
 	case ssoTypeIPMreqn:
-		return getsockoptIPMreqn(s, opt.name)
+		return so.getIPMreqn(c)
 	default:
-		return nil, errOpNoSupport
+		return so.getMulticastIf(c)
 	}
 }
 
-func setInterface(s uintptr, opt *sockOpt, ifi *net.Interface) error {
-	if opt.name < 1 {
-		return errOpNoSupport
-	}
-	switch opt.typ {
-	case ssoTypeInterface:
-		return setsockoptInterface(s, opt.name, ifi)
+func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
+	switch so.typ {
 	case ssoTypeIPMreqn:
-		return setsockoptIPMreqn(s, opt.name, ifi, nil)
+		return so.setIPMreqn(c, ifi, nil)
 	default:
-		return errOpNoSupport
+		return so.setMulticastIf(c, ifi)
 	}
 }
 
-func getICMPFilter(s uintptr, opt *sockOpt) (*ICMPFilter, error) {
-	if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
-		return nil, errOpNoSupport
+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
 	}
-	var f ICMPFilter
-	l := uint32(sizeofICMPFilter)
-	if err := getsockopt(s, iana.ProtocolReserved, opt.name, unsafe.Pointer(&f.icmpFilter), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
+	if n != sizeofICMPFilter {
+		return nil, errOpNoSupport
 	}
-	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, iana.ProtocolReserved, opt.name, unsafe.Pointer(&f.icmpFilter), sizeofICMPFilter))
+func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
+	b := (*[sizeofICMPFilter]byte)(unsafe.Pointer(f))[:sizeofICMPFilter]
+	return so.Set(c, b)
 }
 
-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.name, ifi, grp)
+		return so.setIPMreq(c, ifi, grp)
 	case ssoTypeIPMreqn:
-		return setsockoptIPMreqn(s, opt.name, ifi, grp)
+		return so.setIPMreqn(c, ifi, grp)
 	case ssoTypeGroupReq:
-		return setsockoptGroupReq(s, opt.name, 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.name, 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)
 }

+ 33 - 2
ipv4/sockopt_stub.go

@@ -2,10 +2,41 @@
 // 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 ipv4
 
-func setInt(s uintptr, opt *sockOpt, v int) error {
+import (
+	"net"
+
+	"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) 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
 }

+ 37 - 1
ipv4/sockopt_asmreq.go → ipv4/sys_asmreq.go

@@ -6,7 +6,43 @@
 
 package ipv4
 
-import "net"
+import (
+	"net"
+	"unsafe"
+
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	mreq := ipMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
+	if err := setIPMreqInterface(&mreq, ifi); err != nil {
+		return err
+	}
+	b := (*[sizeofIPMreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPMreq]
+	return so.Set(c, b)
+}
+
+func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
+	var b [4]byte
+	if _, err := so.Get(c, b[:]); err != nil {
+		return nil, err
+	}
+	ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
+	if err != nil {
+		return nil, err
+	}
+	return ifi, nil
+}
+
+func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
+	ip, err := netInterfaceToIP4(ifi)
+	if err != nil {
+		return err
+	}
+	var b [4]byte
+	copy(b[:], ip)
+	return so.Set(c, b[:])
+}
 
 func setIPMreqInterface(mreq *ipMreq, ifi *net.Interface) error {
 	if ifi == nil {

+ 25 - 0
ipv4/sys_asmreq_stub.go

@@ -0,0 +1,25 @@
+// 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 !darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!windows
+
+package ipv4
+
+import (
+	"net"
+
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
+	return errOpNoSupport
+}
+
+func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
+	return nil, errOpNoSupport
+}
+
+func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
+	return errOpNoSupport
+}

+ 9 - 9
ipv4/sockopt_asmreqn_unix.go → ipv4/sys_asmreqn.go

@@ -8,18 +8,17 @@ package ipv4
 
 import (
 	"net"
-	"os"
 	"unsafe"
 
-	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
-func getsockoptIPMreqn(s uintptr, name int) (*net.Interface, error) {
-	var mreqn ipMreqn
-	l := uint32(sizeofIPMreqn)
-	if err := getsockopt(s, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
+func (so *sockOpt) getIPMreqn(c *socket.Conn) (*net.Interface, error) {
+	b := make([]byte, so.Len)
+	if _, err := so.Get(c, b); err != nil {
+		return nil, err
 	}
+	mreqn := (*ipMreqn)(unsafe.Pointer(&b[0]))
 	if mreqn.Ifindex == 0 {
 		return nil, nil
 	}
@@ -30,7 +29,7 @@ func getsockoptIPMreqn(s uintptr, name int) (*net.Interface, error) {
 	return ifi, nil
 }
 
-func setsockoptIPMreqn(s uintptr, name int, ifi *net.Interface, grp net.IP) error {
+func (so *sockOpt) setIPMreqn(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
 	var mreqn ipMreqn
 	if ifi != nil {
 		mreqn.Ifindex = int32(ifi.Index)
@@ -38,5 +37,6 @@ func setsockoptIPMreqn(s uintptr, name int, ifi *net.Interface, grp net.IP) erro
 	if grp != nil {
 		mreqn.Multiaddr = [4]byte{grp[0], grp[1], grp[2], grp[3]}
 	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), sizeofIPMreqn))
+	b := (*[sizeofIPMreqn]byte)(unsafe.Pointer(&mreqn))[:sizeofIPMreqn]
+	return so.Set(c, b)
 }

+ 7 - 3
ipv4/sockopt_asmreqn_stub.go → ipv4/sys_asmreqn_stub.go

@@ -6,12 +6,16 @@
 
 package ipv4
 
-import "net"
+import (
+	"net"
 
-func getsockoptIPMreqn(s uintptr, name int) (*net.Interface, error) {
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) getIPMreqn(c *socket.Conn) (*net.Interface, error) {
 	return nil, errOpNoSupport
 }
 
-func setsockoptIPMreqn(s uintptr, name int, ifi *net.Interface, grp net.IP) error {
+func (so *sockOpt) setIPMreqn(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
 	return errOpNoSupport
 }

+ 23 - 0
ipv4/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 ipv4
+
+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)
+}

+ 16 - 0
ipv4/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 ipv4
+
+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
+}

+ 16 - 13
ipv4/sys_bsd.go

@@ -2,13 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build dragonfly netbsd
+// +build netbsd openbsd
 
 package ipv4
 
 import (
 	"net"
 	"syscall"
+
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -18,17 +21,17 @@ var (
 		ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeByte},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTTL:         {sysIP_RECVTTL, ssoTypeInt},
-		ssoReceiveDst:         {sysIP_RECVDSTADDR, ssoTypeInt},
-		ssoReceiveInterface:   {sysIP_RECVIF, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoJoinGroup:          {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
-		ssoLeaveGroup:         {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
+	sockOpts = map[int]*sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 1}},
+		ssoReceiveTTL:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+		ssoReceiveDst:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+		ssoReceiveInterface:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
 	}
 )

+ 24 - 28
ipv4/sys_darwin.go

@@ -10,6 +10,9 @@ import (
 	"strings"
 	"syscall"
 	"unsafe"
+
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -19,19 +22,19 @@ var (
 		ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeByte},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTTL:         {sysIP_RECVTTL, ssoTypeInt},
-		ssoReceiveDst:         {sysIP_RECVDSTADDR, ssoTypeInt},
-		ssoReceiveInterface:   {sysIP_RECVIF, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoStripHeader:        {sysIP_STRIPHDR, ssoTypeInt},
-		ssoJoinGroup:          {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
-		ssoLeaveGroup:         {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
+	sockOpts = map[int]*sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTTL:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+		ssoReceiveDst:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+		ssoReceiveInterface:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoStripHeader:        {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_STRIPHDR, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
 	}
 )
 
@@ -57,21 +60,14 @@ func init() {
 	ctlOpts[ctlPacketInfo].length = sizeofInetPktinfo
 	ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo
 	ctlOpts[ctlPacketInfo].parse = parsePacketInfo
-	sockOpts[ssoPacketInfo].name = sysIP_RECVPKTINFO
-	sockOpts[ssoPacketInfo].typ = ssoTypeInt
-	sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn
-	sockOpts[ssoJoinGroup].name = sysMCAST_JOIN_GROUP
-	sockOpts[ssoJoinGroup].typ = ssoTypeGroupReq
-	sockOpts[ssoLeaveGroup].name = sysMCAST_LEAVE_GROUP
-	sockOpts[ssoLeaveGroup].typ = ssoTypeGroupReq
-	sockOpts[ssoJoinSourceGroup].name = sysMCAST_JOIN_SOURCE_GROUP
-	sockOpts[ssoJoinSourceGroup].typ = ssoTypeGroupSourceReq
-	sockOpts[ssoLeaveSourceGroup].name = sysMCAST_LEAVE_SOURCE_GROUP
-	sockOpts[ssoLeaveSourceGroup].typ = ssoTypeGroupSourceReq
-	sockOpts[ssoBlockSourceGroup].name = sysMCAST_BLOCK_SOURCE
-	sockOpts[ssoBlockSourceGroup].typ = ssoTypeGroupSourceReq
-	sockOpts[ssoUnblockSourceGroup].name = sysMCAST_UNBLOCK_SOURCE
-	sockOpts[ssoUnblockSourceGroup].typ = ssoTypeGroupSourceReq
+	sockOpts[ssoPacketInfo] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVPKTINFO, Len: 4}}
+	sockOpts[ssoMulticastInterface] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: sizeofIPMreqn}, typ: ssoTypeIPMreqn}
+	sockOpts[ssoJoinGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+	sockOpts[ssoLeaveGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq}
+	sockOpts[ssoJoinSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+	sockOpts[ssoLeaveSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+	sockOpts[ssoBlockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
+	sockOpts[ssoUnblockSourceGroup] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq}
 }
 
 func (pi *inetPktinfo) setIfindex(i int) {

+ 35 - 0
ipv4/sys_dragonfly.go

@@ -0,0 +1,35 @@
+// 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.
+
+package ipv4
+
+import (
+	"net"
+	"syscall"
+
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
+)
+
+var (
+	ctlOpts = [ctlMax]ctlOpt{
+		ctlTTL:       {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
+		ctlDst:       {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
+		ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
+	}
+
+	sockOpts = map[int]*sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTTL:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+		ssoReceiveDst:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+		ssoReceiveInterface:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+	}
+)

+ 20 - 17
ipv4/sys_freebsd.go

@@ -10,6 +10,9 @@ import (
 	"strings"
 	"syscall"
 	"unsafe"
+
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -19,29 +22,29 @@ var (
 		ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeByte},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTTL:         {sysIP_RECVTTL, ssoTypeInt},
-		ssoReceiveDst:         {sysIP_RECVDSTADDR, ssoTypeInt},
-		ssoReceiveInterface:   {sysIP_RECVIF, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoJoinGroup:          {sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
-		ssoLeaveGroup:         {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
-		ssoJoinSourceGroup:    {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoLeaveSourceGroup:   {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoBlockSourceGroup:   {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
-		ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+	sockOpts = map[int]*sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTTL:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+		ssoReceiveDst:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVDSTADDR, Len: 4}},
+		ssoReceiveInterface:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVIF, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoJoinSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoLeaveSourceGroup:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoBlockSourceGroup:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
 	}
 )
 
 func init() {
 	freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate")
 	if freebsdVersion >= 1000000 {
-		sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn
+		sockOpts[ssoMulticastInterface] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: sizeofIPMreqn}, typ: ssoTypeIPMreqn}
 	}
 	if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" {
 		archs, _ := syscall.Sysctl("kern.supported_archs")

+ 20 - 16
ipv4/sys_linux.go

@@ -8,6 +8,9 @@ import (
 	"net"
 	"syscall"
 	"unsafe"
+
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -16,22 +19,23 @@ var (
 		ctlPacketInfo: {sysIP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeInt},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeIPMreqn},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeInt},
-		ssoReceiveTTL:         {sysIP_RECVTTL, ssoTypeInt},
-		ssoPacketInfo:         {sysIP_PKTINFO, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoICMPFilter:         {sysICMP_FILTER, ssoTypeICMPFilter},
-		ssoJoinGroup:          {sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
-		ssoLeaveGroup:         {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
-		ssoJoinSourceGroup:    {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoLeaveSourceGroup:   {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoBlockSourceGroup:   {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
-		ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+	sockOpts = map[int]*sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 4}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: sizeofIPMreqn}, typ: ssoTypeIPMreqn},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+		ssoReceiveTTL:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+		ssoPacketInfo:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_PKTINFO, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoICMPFilter:         {Option: socket.Option{Level: iana.ProtocolReserved, Name: sysICMP_FILTER, Len: sizeofICMPFilter}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoJoinSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoLeaveSourceGroup:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoBlockSourceGroup:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoAttachFilter:       {Option: socket.Option{Level: sysSOL_SOCKET, Name: sysSO_ATTACH_FILTER, Len: sizeofSockFprog}},
 	}
 )
 

+ 0 - 8
ipv4/sys_linux_386.s

@@ -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)

+ 0 - 32
ipv4/sys_openbsd.go

@@ -1,32 +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.
-
-package ipv4
-
-import (
-	"net"
-	"syscall"
-)
-
-var (
-	ctlOpts = [ctlMax]ctlOpt{
-		ctlTTL:       {sysIP_RECVTTL, 1, marshalTTL, parseTTL},
-		ctlDst:       {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
-		ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
-	}
-
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeByte},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeByte},
-		ssoReceiveTTL:         {sysIP_RECVTTL, ssoTypeInt},
-		ssoReceiveDst:         {sysIP_RECVDSTADDR, ssoTypeInt},
-		ssoReceiveInterface:   {sysIP_RECVIF, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoJoinGroup:          {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
-		ssoLeaveGroup:         {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
-	}
-)

+ 18 - 15
ipv4/sys_solaris.go

@@ -8,6 +8,9 @@ import (
 	"net"
 	"syscall"
 	"unsafe"
+
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var (
@@ -16,21 +19,21 @@ var (
 		ctlPacketInfo: {sysIP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
 	}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeByte},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeByte},
-		ssoReceiveTTL:         {sysIP_RECVTTL, ssoTypeInt},
-		ssoPacketInfo:         {sysIP_RECVPKTINFO, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoJoinGroup:          {sysMCAST_JOIN_GROUP, ssoTypeGroupReq},
-		ssoLeaveGroup:         {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq},
-		ssoJoinSourceGroup:    {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoLeaveSourceGroup:   {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq},
-		ssoBlockSourceGroup:   {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq},
-		ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq},
+	sockOpts = map[int]sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 1}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 1}},
+		ssoReceiveTTL:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVTTL, Len: 4}},
+		ssoPacketInfo:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_RECVPKTINFO, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
+		ssoJoinSourceGroup:    {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoLeaveSourceGroup:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoBlockSourceGroup:   {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
+		ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysMCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
 	}
 )
 

+ 0 - 8
ipv4/sys_solaris_amd64.s

@@ -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)

+ 11 - 18
ipv4/sockopt_ssmreq_unix.go → ipv4/sys_ssmreq.go

@@ -8,54 +8,47 @@ package ipv4
 
 import (
 	"net"
-	"os"
 	"unsafe"
 
-	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
 )
 
 var freebsd32o64 bool
 
-func setsockoptGroupReq(s uintptr, name int, ifi *net.Interface, grp net.IP) error {
+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 p unsafe.Pointer
-	var l uint32
+	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:])
-		p = unsafe.Pointer(&d[0])
-		l = sizeofGroupReq + 4
+		b = d[:]
 	} else {
-		p = unsafe.Pointer(&gr)
-		l = sizeofGroupReq
+		b = (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))[:sizeofGroupReq]
 	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, iana.ProtocolIP, name, p, l))
+	return so.Set(c, b)
 }
 
-func setsockoptGroupSourceReq(s uintptr, name int, ifi *net.Interface, grp, src net.IP) error {
+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 p unsafe.Pointer
-	var l uint32
+	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:])
-		p = unsafe.Pointer(&d[0])
-		l = sizeofGroupSourceReq + 4
+		b = d[:]
 	} else {
-		p = unsafe.Pointer(&gsr)
-		l = sizeofGroupSourceReq
+		b = (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))[:sizeofGroupSourceReq]
 	}
-	return os.NewSyscallError("setsockopt", setsockopt(s, iana.ProtocolIP, name, p, l))
+	return so.Set(c, b)
 }

+ 7 - 3
ipv4/sockopt_ssmreq_stub.go → ipv4/sys_ssmreq_stub.go

@@ -6,12 +6,16 @@
 
 package ipv4
 
-import "net"
+import (
+	"net"
 
-func setsockoptGroupReq(s uintptr, name int, ifi *net.Interface, grp net.IP) error {
+	"golang.org/x/net/internal/socket"
+)
+
+func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
 	return errOpNoSupport
 }
 
-func setsockoptGroupSourceReq(s uintptr, name int, ifi *net.Interface, grp, src net.IP) error {
+func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
 	return errOpNoSupport
 }

+ 2 - 2
ipv4/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 ipv4
 
 var (
 	ctlOpts = [ctlMax]ctlOpt{}
 
-	sockOpts = [ssoMax]sockOpt{}
+	sockOpts = map[int]*sockOpt{}
 )

+ 14 - 9
ipv4/sys_windows.go

@@ -4,6 +4,11 @@
 
 package ipv4
 
+import (
+	"golang.org/x/net/internal/iana"
+	"golang.org/x/net/internal/socket"
+)
+
 const (
 	// See ws2tcpip.h.
 	sysIP_OPTIONS                = 0x1
@@ -45,15 +50,15 @@ type ipMreqSource struct {
 var (
 	ctlOpts = [ctlMax]ctlOpt{}
 
-	sockOpts = [ssoMax]sockOpt{
-		ssoTOS:                {sysIP_TOS, ssoTypeInt},
-		ssoTTL:                {sysIP_TTL, ssoTypeInt},
-		ssoMulticastTTL:       {sysIP_MULTICAST_TTL, ssoTypeInt},
-		ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface},
-		ssoMulticastLoopback:  {sysIP_MULTICAST_LOOP, ssoTypeInt},
-		ssoHeaderPrepend:      {sysIP_HDRINCL, ssoTypeInt},
-		ssoJoinGroup:          {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq},
-		ssoLeaveGroup:         {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq},
+	sockOpts = map[int]*sockOpt{
+		ssoTOS:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TOS, Len: 4}},
+		ssoTTL:                {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_TTL, Len: 4}},
+		ssoMulticastTTL:       {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_TTL, Len: 4}},
+		ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_IF, Len: 4}},
+		ssoMulticastLoopback:  {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_MULTICAST_LOOP, Len: 4}},
+		ssoHeaderPrepend:      {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_HDRINCL, Len: 4}},
+		ssoJoinGroup:          {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
+		ssoLeaveGroup:         {Option: socket.Option{Level: iana.ProtocolIP, Name: sysIP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
 	}
 )
 

+ 0 - 31
ipv4/syscall_linux_386.go

@@ -1,31 +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.
-
-package ipv4
-
-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
-}

+ 0 - 38
ipv4/syscall_solaris.go

@@ -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 ipv4
-
-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
-}

+ 0 - 26
ipv4/syscall_unix.go

@@ -1,26 +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 dragonfly freebsd linux,!386 netbsd openbsd
-
-package ipv4
-
-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
-}

+ 0 - 18
ipv4/syscall_windows.go

@@ -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 ipv4
-
-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))
-}

+ 2 - 0
ipv4/zsys_linux_386.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_amd64.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_arm.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_arm64.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_mips.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_mips64.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_mips64le.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_mipsle.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_ppc.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x104
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x8
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_ppc64.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_ppc64le.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {

+ 2 - 0
ipv4/zsys_linux_s390x.go

@@ -70,6 +70,8 @@ const (
 	sizeofGroupSourceReq = 0x108
 
 	sizeofICMPFilter = 0x4
+
+	sizeofSockFprog = 0x10
 )
 
 type kernelSockaddrStorage struct {