go.net/ipv6: restructure ancillary data socket option handling

This CL chops existing ancillary data socket option handlers and
puts them into platform dependent ancillary data socket option
binding table for code readability.

LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/164580043
diff --git a/ipv6/control_rfc2292_unix.go b/ipv6/control_rfc2292_unix.go
index 47196c5..54c6a4a 100644
--- a/ipv6/control_rfc2292_unix.go
+++ b/ipv6/control_rfc2292_unix.go
@@ -7,145 +7,47 @@
 package ipv6
 
 import (
-	"net"
-	"os"
 	"syscall"
 	"unsafe"
 )
 
-const pktinfo = FlagDst | FlagInterface
-
-func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
-	opt.Lock()
-	defer opt.Unlock()
-	if cf&FlagHopLimit != 0 {
-		if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
-			return err
-		}
-		if on {
-			opt.set(FlagHopLimit)
-		} else {
-			opt.clear(FlagHopLimit)
-		}
+func marshal2292HopLimit(b []byte, cm *ControlMessage) []byte {
+	m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
+	m.Level = ianaProtocolIPv6
+	m.Type = sysIPV6_2292HOPLIMIT
+	m.SetLen(syscall.CmsgLen(4))
+	if cm != nil {
+		data := b[syscall.CmsgLen(0):]
+		*(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.HopLimit)
 	}
-	if cf&pktinfo != 0 {
-		if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
-			return err
-		}
-		if on {
-			opt.set(cf & pktinfo)
-		} else {
-			opt.clear(cf & pktinfo)
-		}
-	}
-	return nil
+	return b[syscall.CmsgSpace(4):]
 }
 
-func newControlMessage(opt *rawOpt) (oob []byte) {
-	opt.Lock()
-	defer opt.Unlock()
-	l, off := 0, 0
-	if opt.isset(FlagHopLimit) {
-		l += syscall.CmsgSpace(4)
-	}
-	if opt.isset(pktinfo) {
-		l += syscall.CmsgSpace(sysSizeofPacketInfo)
-	}
-	if l > 0 {
-		oob = make([]byte, l)
-		if opt.isset(FlagHopLimit) {
-			m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
-			m.Level = ianaProtocolIPv6
-			m.Type = sysSockopt2292HopLimit
-			m.SetLen(syscall.CmsgLen(4))
-			off += syscall.CmsgSpace(4)
+func marshal2292PacketInfo(b []byte, cm *ControlMessage) []byte {
+	m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
+	m.Level = ianaProtocolIPv6
+	m.Type = sysIPV6_2292PKTINFO
+	m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo))
+	if cm != nil {
+		pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+		if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
+			copy(pi.Addr[:], ip)
 		}
-		if opt.isset(pktinfo) {
-			m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
-			m.Level = ianaProtocolIPv6
-			m.Type = sysSockopt2292PacketInfo
-			m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
-			off += syscall.CmsgSpace(sysSizeofPacketInfo)
+		if cm.IfIndex > 0 {
+			pi.setIfindex(cm.IfIndex)
 		}
 	}
-	return
+	return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):]
 }
 
-func parseControlMessage(b []byte) (*ControlMessage, error) {
-	if len(b) == 0 {
-		return nil, nil
+func marshal2292NextHop(b []byte, cm *ControlMessage) []byte {
+	m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0]))
+	m.Level = ianaProtocolIPv6
+	m.Type = sysIPV6_2292NEXTHOP
+	m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6))
+	if cm != nil {
+		sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)]))
+		sa.setSockaddr(cm.NextHop, cm.IfIndex)
 	}
-	cmsgs, err := syscall.ParseSocketControlMessage(b)
-	if err != nil {
-		return nil, os.NewSyscallError("parse socket control message", err)
-	}
-	cm := &ControlMessage{}
-	for _, m := range cmsgs {
-		if m.Header.Level != ianaProtocolIPv6 {
-			continue
-		}
-		switch m.Header.Type {
-		case sysSockopt2292HopLimit:
-			cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
-		case sysSockopt2292PacketInfo:
-			pi := (*sysPacketInfo)(unsafe.Pointer(&m.Data[0]))
-			cm.IfIndex = int(pi.IfIndex)
-			cm.Dst = pi.IP[:]
-		}
-	}
-	return cm, nil
-}
-
-func marshalControlMessage(cm *ControlMessage) (oob []byte) {
-	if cm == nil {
-		return
-	}
-	l, off := 0, 0
-	if cm.HopLimit > 0 {
-		l += syscall.CmsgSpace(4)
-	}
-	pion := false
-	if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
-		pion = true
-		l += syscall.CmsgSpace(sysSizeofPacketInfo)
-	}
-	if len(cm.NextHop) == net.IPv6len {
-		l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
-	}
-	if l > 0 {
-		oob = make([]byte, l)
-		if cm.HopLimit > 0 {
-			m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
-			m.Level = ianaProtocolIPv6
-			m.Type = sysSockopt2292HopLimit
-			m.SetLen(syscall.CmsgLen(4))
-			data := oob[off+syscall.CmsgLen(0):]
-			*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
-			off += syscall.CmsgSpace(4)
-		}
-		if pion {
-			m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
-			m.Level = ianaProtocolIPv6
-			m.Type = sysSockopt2292PacketInfo
-			m.SetLen(syscall.CmsgLen(sysSizeofPacketInfo))
-			pi := (*sysPacketInfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
-			if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
-				copy(pi.IP[:], ip)
-			}
-			if cm.IfIndex != 0 {
-				pi.IfIndex = uint32(cm.IfIndex)
-			}
-			off += syscall.CmsgSpace(sysSizeofPacketInfo)
-		}
-		if len(cm.NextHop) == net.IPv6len {
-			m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
-			m.Level = ianaProtocolIPv6
-			m.Type = sysSockopt2292NextHop
-			m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
-			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
-			setSockaddr(sa, cm.NextHop, cm.IfIndex)
-			off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
-		}
-	}
-	return
+	return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):]
 }