summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/net/ipv6/control_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/net/ipv6/control_unix.go')
-rw-r--r--vendor/golang.org/x/net/ipv6/control_unix.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/vendor/golang.org/x/net/ipv6/control_unix.go b/vendor/golang.org/x/net/ipv6/control_unix.go
new file mode 100644
index 000000000..46fbdcbe3
--- /dev/null
+++ b/vendor/golang.org/x/net/ipv6/control_unix.go
@@ -0,0 +1,166 @@
+// 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 (
+ "os"
+ "syscall"
+
+ "golang.org/x/net/internal/iana"
+)
+
+func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
+ opt.Lock()
+ defer opt.Unlock()
+ if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
+ if err := setInt(s, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
+ return err
+ }
+ if on {
+ opt.set(FlagTrafficClass)
+ } else {
+ opt.clear(FlagTrafficClass)
+ }
+ }
+ if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
+ if err := setInt(s, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
+ return err
+ }
+ if on {
+ opt.set(FlagHopLimit)
+ } else {
+ opt.clear(FlagHopLimit)
+ }
+ }
+ if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
+ if err := setInt(s, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
+ return err
+ }
+ if on {
+ opt.set(cf & flagPacketInfo)
+ } else {
+ opt.clear(cf & flagPacketInfo)
+ }
+ }
+ if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
+ if err := setInt(s, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
+ return err
+ }
+ if on {
+ opt.set(FlagPathMTU)
+ } else {
+ opt.clear(FlagPathMTU)
+ }
+ }
+ return nil
+}
+
+func newControlMessage(opt *rawOpt) (oob []byte) {
+ opt.RLock()
+ var l int
+ if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
+ l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
+ }
+ if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
+ l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
+ }
+ if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
+ l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
+ }
+ if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
+ l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length)
+ }
+ if l > 0 {
+ oob = make([]byte, l)
+ b := oob
+ if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
+ b = ctlOpts[ctlTrafficClass].marshal(b, nil)
+ }
+ if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
+ b = ctlOpts[ctlHopLimit].marshal(b, nil)
+ }
+ if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
+ b = ctlOpts[ctlPacketInfo].marshal(b, nil)
+ }
+ if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
+ b = ctlOpts[ctlPathMTU].marshal(b, nil)
+ }
+ }
+ opt.RUnlock()
+ return
+}
+
+func parseControlMessage(b []byte) (*ControlMessage, error) {
+ if len(b) == 0 {
+ return nil, nil
+ }
+ 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 != iana.ProtocolIPv6 {
+ continue
+ }
+ switch int(m.Header.Type) {
+ case ctlOpts[ctlTrafficClass].name:
+ ctlOpts[ctlTrafficClass].parse(cm, m.Data[:])
+ case ctlOpts[ctlHopLimit].name:
+ ctlOpts[ctlHopLimit].parse(cm, m.Data[:])
+ case ctlOpts[ctlPacketInfo].name:
+ ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
+ case ctlOpts[ctlPathMTU].name:
+ ctlOpts[ctlPathMTU].parse(cm, m.Data[:])
+ }
+ }
+ return cm, nil
+}
+
+func marshalControlMessage(cm *ControlMessage) (oob []byte) {
+ if cm == nil {
+ return
+ }
+ var l int
+ tclass := false
+ if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
+ tclass = true
+ l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
+ }
+ hoplimit := false
+ if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
+ hoplimit = true
+ l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
+ }
+ pktinfo := false
+ if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
+ pktinfo = true
+ l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
+ }
+ nexthop := false
+ if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
+ nexthop = true
+ l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length)
+ }
+ if l > 0 {
+ oob = make([]byte, l)
+ b := oob
+ if tclass {
+ b = ctlOpts[ctlTrafficClass].marshal(b, cm)
+ }
+ if hoplimit {
+ b = ctlOpts[ctlHopLimit].marshal(b, cm)
+ }
+ if pktinfo {
+ b = ctlOpts[ctlPacketInfo].marshal(b, cm)
+ }
+ if nexthop {
+ b = ctlOpts[ctlNextHop].marshal(b, cm)
+ }
+ }
+ return
+}