瀏覽代碼

go.net/ipv6: restructure sticky socket option handling

This CL chops existing sticky socket option handlers and puts them
into platform-dependent sticky socket option binding table for
supporting multicast features such as source filtering for any-source
multicast, source-specific multicast.

LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/144570043
Mikio Hara 11 年之前
父節點
當前提交
da4ebece07

+ 22 - 0
ipv6/sockopt_asmreq_unix.go

@@ -0,0 +1,22 @@
+// 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
+
+package ipv6
+
+import (
+	"net"
+	"os"
+	"unsafe"
+)
+
+func setsockoptIPMreq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
+	var mreq sysIPv6Mreq
+	copy(mreq.Multiaddr[:], grp)
+	if ifi != nil {
+		mreq.setIfindex(ifi.Index)
+	}
+	return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&mreq), sysSizeofIPv6Mreq))
+}

+ 21 - 0
ipv6/sockopt_asmreq_windows.go

@@ -0,0 +1,21 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ipv6
+
+import (
+	"net"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+func setsockoptIPMreq(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
+	var mreq sysIPv6Mreq
+	copy(mreq.Multiaddr[:], grp)
+	if ifi != nil {
+		mreq.setIfindex(ifi.Index)
+	}
+	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&mreq)), sysSizeofIPv6Mreq))
+}

+ 0 - 70
ipv6/sockopt_rfc2292_unix.go

@@ -1,70 +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
-
-package ipv6
-
-import (
-	"os"
-	"syscall"
-	"unsafe"
-)
-
-func ipv6ReceiveTrafficClass(fd int) (bool, error) {
-	return false, errOpNoSupport
-}
-
-func setIPv6ReceiveTrafficClass(fd int, v bool) error {
-	return errOpNoSupport
-}
-
-func ipv6ReceiveHopLimit(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292HopLimit)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6ReceiveHopLimit(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292HopLimit, boolint(v)))
-}
-
-func ipv6ReceivePacketInfo(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292PacketInfo)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6ReceivePacketInfo(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockopt2292PacketInfo, boolint(v)))
-}
-
-func ipv6PathMTU(fd int) (int, error) {
-	return 0, errOpNoSupport
-}
-
-func ipv6ReceivePathMTU(fd int) (bool, error) {
-	return false, errOpNoSupport
-}
-
-func setIPv6ReceivePathMTU(fd int, v bool) error {
-	return errOpNoSupport
-}
-
-func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
-	var v ICMPFilter
-	l := sysSockoptLen(sysSizeofICMPFilter)
-	if err := getsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&v.sysICMPFilter), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	return &v, nil
-}
-
-func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
-	return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&f.sysICMPFilter), sysSizeofICMPFilter))
-}

+ 0 - 19
ipv6/sockopt_rfc3493_bsd.go

@@ -1,19 +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 netbsd openbsd
-
-package ipv6
-
-import (
-	"os"
-	"syscall"
-)
-
-func setIPv6Checksum(fd int, on bool, offset int) error {
-	if !on {
-		offset = -1
-	}
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptChecksum, offset))
-}

+ 0 - 17
ipv6/sockopt_rfc3493_linux.go

@@ -1,17 +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.
-
-package ipv6
-
-import (
-	"os"
-	"syscall"
-)
-
-func setIPv6Checksum(fd int, on bool, offset int) error {
-	if !on {
-		offset = -1
-	}
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolReserved, sysSockoptChecksum, offset))
-}

+ 0 - 115
ipv6/sockopt_rfc3493_unix.go

@@ -1,115 +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
-
-package ipv6
-
-import (
-	"net"
-	"os"
-	"syscall"
-	"unsafe"
-)
-
-func ipv6TrafficClass(fd int) (int, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptTrafficClass)
-	if err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return v, nil
-}
-
-func setIPv6TrafficClass(fd, v int) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptTrafficClass, v))
-}
-
-func ipv6HopLimit(fd int) (int, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit)
-	if err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return v, nil
-}
-
-func setIPv6HopLimit(fd, v int) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, v))
-}
-
-func ipv6Checksum(fd int) (bool, int, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptChecksum)
-	if err != nil {
-		return false, 0, os.NewSyscallError("getsockopt", err)
-	}
-	on := true
-	if v == -1 {
-		on = false
-	}
-	return on, v, nil
-}
-
-func ipv6MulticastHopLimit(fd int) (int, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit)
-	if err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return v, nil
-}
-
-func setIPv6MulticastHopLimit(fd, v int) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, v))
-}
-
-func ipv6MulticastInterface(fd int) (*net.Interface, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface)
-	if err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	if v == 0 {
-		return nil, nil
-	}
-	ifi, err := net.InterfaceByIndex(v)
-	if err != nil {
-		return nil, err
-	}
-	return ifi, nil
-}
-
-func setIPv6MulticastInterface(fd int, ifi *net.Interface) error {
-	var v int
-	if ifi != nil {
-		v = ifi.Index
-	}
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, v))
-}
-
-func ipv6MulticastLoopback(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6MulticastLoopback(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, boolint(v)))
-}
-
-func joinIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
-	mreq := sysMulticastReq{}
-	copy(mreq.IP[:], grp)
-	if ifi != nil {
-		mreq.IfIndex = uint32(ifi.Index)
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptJoinGroup, unsafe.Pointer(&mreq), sysSizeofMulticastReq))
-}
-
-func leaveIPv6Group(fd int, ifi *net.Interface, grp net.IP) error {
-	mreq := sysMulticastReq{}
-	copy(mreq.IP[:], grp)
-	if ifi != nil {
-		mreq.IfIndex = uint32(ifi.Index)
-	}
-	return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6, sysSockoptLeaveGroup, unsafe.Pointer(&mreq), sysSizeofMulticastReq))
-}

+ 0 - 116
ipv6/sockopt_rfc3493_windows.go

@@ -1,116 +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.
-
-package ipv6
-
-import (
-	"net"
-	"os"
-	"syscall"
-	"unsafe"
-)
-
-func ipv6TrafficClass(fd syscall.Handle) (int, error) {
-	// TODO(mikio): Implement this
-	return 0, syscall.EWINDOWS
-}
-
-func setIPv6TrafficClass(fd syscall.Handle, v int) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}
-
-func ipv6HopLimit(fd syscall.Handle) (int, error) {
-	var v int32
-	l := int32(4)
-	if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return int(v), nil
-}
-
-func setIPv6HopLimit(fd syscall.Handle, v int) error {
-	vv := int32(v)
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptUnicastHopLimit, (*byte)(unsafe.Pointer(&vv)), 4))
-}
-
-func ipv6Checksum(fd syscall.Handle) (bool, int, error) {
-	// TODO(mikio): Implement this
-	return false, 0, syscall.EWINDOWS
-}
-
-func ipv6MulticastHopLimit(fd syscall.Handle) (int, error) {
-	var v int32
-	l := int32(4)
-	if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return int(v), nil
-}
-
-func setIPv6MulticastHopLimit(fd syscall.Handle, v int) error {
-	vv := int32(v)
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastHopLimit, (*byte)(unsafe.Pointer(&vv)), 4))
-}
-
-func ipv6MulticastInterface(fd syscall.Handle) (*net.Interface, error) {
-	var v int32
-	l := int32(4)
-	if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	if v == 0 {
-		return nil, nil
-	}
-	ifi, err := net.InterfaceByIndex(int(v))
-	if err != nil {
-		return nil, err
-	}
-	return ifi, nil
-}
-
-func setIPv6MulticastInterface(fd syscall.Handle, ifi *net.Interface) error {
-	var v int32
-	if ifi != nil {
-		v = int32(ifi.Index)
-	}
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastInterface, (*byte)(unsafe.Pointer(&v)), 4))
-}
-
-func ipv6MulticastLoopback(fd syscall.Handle) (bool, error) {
-	var v int32
-	l := int32(4)
-	if err := syscall.Getsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&v)), &l); err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6MulticastLoopback(fd syscall.Handle, v bool) error {
-	vv := int32(boolint(v))
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptMulticastLoopback, (*byte)(unsafe.Pointer(&vv)), 4))
-}
-
-func joinIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
-	mreq := sysMulticastReq{}
-	copy(mreq.IP[:], grp)
-	if ifi != nil {
-		mreq.IfIndex = uint32(ifi.Index)
-	}
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptJoinGroup, (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofMulticastReq)))
-}
-
-func leaveIPv6Group(fd syscall.Handle, ifi *net.Interface, grp net.IP) error {
-	mreq := sysMulticastReq{}
-	copy(mreq.IP[:], grp)
-	if ifi != nil {
-		mreq.IfIndex = uint32(ifi.Index)
-	}
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, ianaProtocolIPv6, sysSockoptLeaveGroup, (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofMulticastReq)))
-}
-
-func setIPv6Checksum(fd syscall.Handle, on bool, offset int) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}

+ 0 - 12
ipv6/sockopt_rfc3542_stub.go

@@ -1,12 +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 solaris
-
-package ipv6
-
-func ipv6PathMTU(fd int) (int, error) {
-	// TODO(mikio): Implement this
-	return 0, errOpNoSupport
-}

+ 0 - 83
ipv6/sockopt_rfc3542_unix.go

@@ -1,83 +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 dragonfly freebsd linux netbsd openbsd
-
-package ipv6
-
-import (
-	"os"
-	"syscall"
-	"unsafe"
-)
-
-func ipv6ReceiveTrafficClass(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveTrafficClass)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6ReceiveTrafficClass(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveTrafficClass, boolint(v)))
-}
-
-func ipv6ReceiveHopLimit(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveHopLimit)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6ReceiveHopLimit(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceiveHopLimit, boolint(v)))
-}
-
-func ipv6ReceivePacketInfo(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePacketInfo)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6ReceivePacketInfo(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePacketInfo, boolint(v)))
-}
-
-func ipv6PathMTU(fd int) (int, error) {
-	var v sysMTUInfo
-	l := sysSockoptLen(sysSizeofMTUInfo)
-	if err := getsockopt(fd, ianaProtocolIPv6, sysSockoptPathMTU, unsafe.Pointer(&v), &l); err != nil {
-		return 0, os.NewSyscallError("getsockopt", err)
-	}
-	return int(v.MTU), nil
-}
-
-func ipv6ReceivePathMTU(fd int) (bool, error) {
-	v, err := syscall.GetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePathMTU)
-	if err != nil {
-		return false, os.NewSyscallError("getsockopt", err)
-	}
-	return v == 1, nil
-}
-
-func setIPv6ReceivePathMTU(fd int, v bool) error {
-	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, ianaProtocolIPv6, sysSockoptReceivePathMTU, boolint(v)))
-}
-
-func ipv6ICMPFilter(fd int) (*ICMPFilter, error) {
-	var v ICMPFilter
-	l := sysSockoptLen(sysSizeofICMPFilter)
-	if err := getsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&v.sysICMPFilter), &l); err != nil {
-		return nil, os.NewSyscallError("getsockopt", err)
-	}
-	return &v, nil
-}
-
-func setIPv6ICMPFilter(fd int, f *ICMPFilter) error {
-	return os.NewSyscallError("setsockopt", setsockopt(fd, ianaProtocolIPv6ICMP, sysSockoptICMPFilter, unsafe.Pointer(&f.sysICMPFilter), sysSizeofICMPFilter))
-}

+ 0 - 62
ipv6/sockopt_rfc3542_windows.go

@@ -1,62 +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.
-
-package ipv6
-
-import "syscall"
-
-func ipv6ReceiveTrafficClass(fd syscall.Handle) (bool, error) {
-	// TODO(mikio): Implement this
-	return false, syscall.EWINDOWS
-}
-
-func setIPv6ReceiveTrafficClass(fd syscall.Handle, v bool) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}
-
-func ipv6ReceiveHopLimit(fd syscall.Handle) (bool, error) {
-	// TODO(mikio): Implement this
-	return false, syscall.EWINDOWS
-}
-
-func setIPv6ReceiveHopLimit(fd syscall.Handle, v bool) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}
-
-func ipv6ReceivePacketInfo(fd syscall.Handle) (bool, error) {
-	// TODO(mikio): Implement this
-	return false, syscall.EWINDOWS
-}
-
-func setIPv6ReceivePacketInfo(fd syscall.Handle, v bool) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}
-
-func ipv6PathMTU(fd syscall.Handle) (int, error) {
-	// TODO(mikio): Implement this
-	return 0, syscall.EWINDOWS
-}
-
-func ipv6ReceivePathMTU(fd syscall.Handle) (bool, error) {
-	// TODO(mikio): Implement this
-	return false, syscall.EWINDOWS
-}
-
-func setIPv6ReceivePathMTU(fd syscall.Handle, v bool) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}
-
-func ipv6ICMPFilter(fd syscall.Handle) (*ICMPFilter, error) {
-	// TODO(mikio): Implement this
-	return nil, syscall.EWINDOWS
-}
-
-func setIPv6ICMPFilter(fd syscall.Handle, f *ICMPFilter) error {
-	// TODO(mikio): Implement this
-	return syscall.EWINDOWS
-}

+ 41 - 0
ipv6/sockopt_stub.go

@@ -0,0 +1,41 @@
+// 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 solaris
+
+package ipv6
+
+import "net"
+
+func getInt(fd int, opt *sockOpt) (int, error) {
+	return 0, errOpNoSupport
+}
+
+func setInt(fd int, opt *sockOpt, v int) error {
+	return errOpNoSupport
+}
+
+func getInterface(fd int, opt *sockOpt) (*net.Interface, error) {
+	return nil, errOpNoSupport
+}
+
+func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error {
+	return errOpNoSupport
+}
+
+func getICMPFilter(fd int, opt *sockOpt) (*ICMPFilter, error) {
+	return nil, errOpNoSupport
+}
+
+func setICMPFilter(fd int, opt *sockOpt, f *ICMPFilter) error {
+	return errOpNoSupport
+}
+
+func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) {
+	return nil, 0, errOpNoSupport
+}
+
+func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
+	return errOpNoSupport
+}

+ 108 - 0
ipv6/sockopt_unix.go

@@ -0,0 +1,108 @@
+// 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
+
+package ipv6
+
+import (
+	"net"
+	"os"
+	"unsafe"
+)
+
+func getInt(fd int, opt *sockOpt) (int, error) {
+	if opt.name < 1 || opt.typ != ssoTypeInt {
+		return 0, errOpNoSupport
+	}
+	var i int32
+	l := sysSockoptLen(4)
+	if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil {
+		return 0, os.NewSyscallError("getsockopt", err)
+	}
+	return int(i), nil
+}
+
+func setInt(fd int, opt *sockOpt, v int) error {
+	if opt.name < 1 || opt.typ != ssoTypeInt {
+		return errOpNoSupport
+	}
+	i := int32(v)
+	return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), sysSockoptLen(4)))
+}
+
+func getInterface(fd int, opt *sockOpt) (*net.Interface, error) {
+	if opt.name < 1 || opt.typ != ssoTypeInterface {
+		return nil, errOpNoSupport
+	}
+	var i int32
+	l := sysSockoptLen(4)
+	if err := getsockopt(fd, 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))
+	if err != nil {
+		return nil, err
+	}
+	return ifi, nil
+}
+
+func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error {
+	if opt.name < 1 || opt.typ != ssoTypeInterface {
+		return errOpNoSupport
+	}
+	var i int32
+	if ifi != nil {
+		i = int32(ifi.Index)
+	}
+	return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), sysSockoptLen(4)))
+}
+
+func getICMPFilter(fd int, opt *sockOpt) (*ICMPFilter, error) {
+	if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
+		return nil, errOpNoSupport
+	}
+	var f ICMPFilter
+	l := sysSockoptLen(sysSizeofICMPv6Filter)
+	if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&f.sysICMPv6Filter), &l); err != nil {
+		return nil, os.NewSyscallError("getsockopt", err)
+	}
+	return &f, nil
+}
+
+func setICMPFilter(fd int, opt *sockOpt, f *ICMPFilter) error {
+	if opt.name < 1 || opt.typ != ssoTypeICMPFilter {
+		return errOpNoSupport
+	}
+	return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&f.sysICMPv6Filter), sysSizeofICMPv6Filter))
+}
+
+func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) {
+	if opt.name < 1 || opt.typ != ssoTypeMTUInfo {
+		return nil, 0, errOpNoSupport
+	}
+	var mi sysIPv6Mtuinfo
+	l := sysSockoptLen(sysSizeofIPv6Mtuinfo)
+	if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&mi), &l); err != nil {
+		return nil, 0, os.NewSyscallError("getsockopt", err)
+	}
+	if mi.Addr.Scope_id == 0 {
+		return nil, int(mi.Mtu), nil
+	}
+	ifi, err := net.InterfaceByIndex(int(mi.Addr.Scope_id))
+	if err != nil {
+		return nil, 0, err
+	}
+	return ifi, int(mi.Mtu), nil
+}
+
+func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
+	if opt.name < 1 || opt.typ != ssoTypeIPMreq {
+		return errOpNoSupport
+	}
+	return setsockoptIPMreq(fd, opt, ifi, grp)
+}

+ 81 - 0
ipv6/sockopt_windows.go

@@ -0,0 +1,81 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ipv6
+
+import (
+	"net"
+	"os"
+	"syscall"
+	"unsafe"
+)
+
+func getInt(fd syscall.Handle, opt *sockOpt) (int, error) {
+	if opt.name < 1 || opt.typ != ssoTypeInt {
+		return 0, errOpNoSupport
+	}
+	var i int32
+	l := int32(4)
+	if err := syscall.Getsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil {
+		return 0, os.NewSyscallError("getsockopt", err)
+	}
+	return int(i), nil
+}
+
+func setInt(fd syscall.Handle, opt *sockOpt, v int) error {
+	if opt.name < 1 || opt.typ != ssoTypeInt {
+		return errOpNoSupport
+	}
+	i := int32(v)
+	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4))
+}
+
+func getInterface(fd syscall.Handle, opt *sockOpt) (*net.Interface, error) {
+	if opt.name < 1 || opt.typ != ssoTypeInterface {
+		return nil, errOpNoSupport
+	}
+	var i int32
+	l := int32(4)
+	if err := syscall.Getsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil {
+		return nil, os.NewSyscallError("getsockopt", err)
+	}
+	if i == 0 {
+		return nil, nil
+	}
+	ifi, err := net.InterfaceByIndex(int(i))
+	if err != nil {
+		return nil, err
+	}
+	return ifi, nil
+}
+
+func setInterface(fd syscall.Handle, opt *sockOpt, ifi *net.Interface) error {
+	if opt.name < 1 || opt.typ != ssoTypeInterface {
+		return errOpNoSupport
+	}
+	var i int32
+	if ifi != nil {
+		i = int32(ifi.Index)
+	}
+	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4))
+}
+
+func getICMPFilter(fd syscall.Handle, opt *sockOpt) (*ICMPFilter, error) {
+	return nil, errOpNoSupport
+}
+
+func setICMPFilter(fd syscall.Handle, opt *sockOpt, f *ICMPFilter) error {
+	return errOpNoSupport
+}
+
+func getMTUInfo(fd syscall.Handle, opt *sockOpt) (*net.Interface, int, error) {
+	return nil, 0, errOpNoSupport
+}
+
+func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error {
+	if opt.name < 1 || opt.typ != ssoTypeIPMreq {
+		return errOpNoSupport
+	}
+	return setsockoptIPMreq(fd, opt, ifi, grp)
+}