github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/ipv6/control_unix.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd linux netbsd openbsd 6 7 package ipv6 8 9 import ( 10 "os" 11 "syscall" 12 13 "golang.org/x/net/internal/iana" 14 ) 15 16 func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { 17 opt.Lock() 18 defer opt.Unlock() 19 if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 { 20 if err := setInt(fd, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil { 21 return err 22 } 23 if on { 24 opt.set(FlagTrafficClass) 25 } else { 26 opt.clear(FlagTrafficClass) 27 } 28 } 29 if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 { 30 if err := setInt(fd, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil { 31 return err 32 } 33 if on { 34 opt.set(FlagHopLimit) 35 } else { 36 opt.clear(FlagHopLimit) 37 } 38 } 39 if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 { 40 if err := setInt(fd, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil { 41 return err 42 } 43 if on { 44 opt.set(cf & flagPacketInfo) 45 } else { 46 opt.clear(cf & flagPacketInfo) 47 } 48 } 49 if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 { 50 if err := setInt(fd, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil { 51 return err 52 } 53 if on { 54 opt.set(FlagPathMTU) 55 } else { 56 opt.clear(FlagPathMTU) 57 } 58 } 59 return nil 60 } 61 62 func newControlMessage(opt *rawOpt) (oob []byte) { 63 opt.RLock() 64 var l int 65 if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 { 66 l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length) 67 } 68 if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 { 69 l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length) 70 } 71 if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 { 72 l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length) 73 } 74 if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 { 75 l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length) 76 } 77 if l > 0 { 78 oob = make([]byte, l) 79 b := oob 80 if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 { 81 b = ctlOpts[ctlTrafficClass].marshal(b, nil) 82 } 83 if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 { 84 b = ctlOpts[ctlHopLimit].marshal(b, nil) 85 } 86 if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 { 87 b = ctlOpts[ctlPacketInfo].marshal(b, nil) 88 } 89 if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 { 90 b = ctlOpts[ctlPathMTU].marshal(b, nil) 91 } 92 } 93 opt.RUnlock() 94 return 95 } 96 97 func parseControlMessage(b []byte) (*ControlMessage, error) { 98 if len(b) == 0 { 99 return nil, nil 100 } 101 cmsgs, err := syscall.ParseSocketControlMessage(b) 102 if err != nil { 103 return nil, os.NewSyscallError("parse socket control message", err) 104 } 105 cm := &ControlMessage{} 106 for _, m := range cmsgs { 107 if m.Header.Level != iana.ProtocolIPv6 { 108 continue 109 } 110 switch int(m.Header.Type) { 111 case ctlOpts[ctlTrafficClass].name: 112 ctlOpts[ctlTrafficClass].parse(cm, m.Data[:]) 113 case ctlOpts[ctlHopLimit].name: 114 ctlOpts[ctlHopLimit].parse(cm, m.Data[:]) 115 case ctlOpts[ctlPacketInfo].name: 116 ctlOpts[ctlPacketInfo].parse(cm, m.Data[:]) 117 case ctlOpts[ctlPathMTU].name: 118 ctlOpts[ctlPathMTU].parse(cm, m.Data[:]) 119 } 120 } 121 return cm, nil 122 } 123 124 func marshalControlMessage(cm *ControlMessage) (oob []byte) { 125 if cm == nil { 126 return 127 } 128 var l int 129 tclass := false 130 if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 { 131 tclass = true 132 l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length) 133 } 134 hoplimit := false 135 if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 { 136 hoplimit = true 137 l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length) 138 } 139 pktinfo := false 140 if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) { 141 pktinfo = true 142 l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length) 143 } 144 nexthop := false 145 if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil { 146 nexthop = true 147 l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length) 148 } 149 if l > 0 { 150 oob = make([]byte, l) 151 b := oob 152 if tclass { 153 b = ctlOpts[ctlTrafficClass].marshal(b, cm) 154 } 155 if hoplimit { 156 b = ctlOpts[ctlHopLimit].marshal(b, cm) 157 } 158 if pktinfo { 159 b = ctlOpts[ctlPacketInfo].marshal(b, cm) 160 } 161 if nexthop { 162 b = ctlOpts[ctlNextHop].marshal(b, cm) 163 } 164 } 165 return 166 }