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.
5
// +build freebsd netbsd openbsd
16
const pktinfo = FlagDst | FlagInterface
18
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
21
if cf&FlagTrafficClass != 0 {
22
if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
26
opt.set(FlagTrafficClass)
28
opt.clear(FlagTrafficClass)
31
if cf&FlagHopLimit != 0 {
32
if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
38
opt.clear(FlagHopLimit)
42
if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
48
opt.clear(cf & pktinfo)
51
if cf&FlagPathMTU != 0 {
52
if err := setIPv6ReceivePathMTU(fd, on); err != nil {
58
opt.clear(FlagPathMTU)
64
func newControlMessage(opt *rawOpt) (oob []byte) {
68
if opt.isset(FlagTrafficClass) {
69
l += syscall.CmsgSpace(4)
71
if opt.isset(FlagHopLimit) {
72
l += syscall.CmsgSpace(4)
74
if opt.isset(pktinfo) {
75
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
77
if opt.isset(FlagPathMTU) {
78
l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
82
if opt.isset(FlagTrafficClass) {
83
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
84
m.Level = ianaProtocolIPv6
85
m.Type = syscall.IPV6_RECVTCLASS
86
m.SetLen(syscall.CmsgLen(4))
87
off += syscall.CmsgSpace(4)
89
if opt.isset(FlagHopLimit) {
90
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
91
m.Level = ianaProtocolIPv6
92
m.Type = syscall.IPV6_RECVHOPLIMIT
93
m.SetLen(syscall.CmsgLen(4))
94
off += syscall.CmsgSpace(4)
96
if opt.isset(pktinfo) {
97
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
98
m.Level = ianaProtocolIPv6
99
m.Type = syscall.IPV6_RECVPKTINFO
100
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
101
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
103
if opt.isset(FlagPathMTU) {
104
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
105
m.Level = ianaProtocolIPv6
106
m.Type = syscall.IPV6_RECVPATHMTU
107
m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo))
108
off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
114
func parseControlMessage(b []byte) (*ControlMessage, error) {
118
cmsgs, err := syscall.ParseSocketControlMessage(b)
120
return nil, os.NewSyscallError("parse socket control message", err)
122
cm := &ControlMessage{}
123
for _, m := range cmsgs {
124
if m.Header.Level != ianaProtocolIPv6 {
127
switch m.Header.Type {
128
case syscall.IPV6_TCLASS:
129
cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
130
case syscall.IPV6_HOPLIMIT:
131
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
132
case syscall.IPV6_PKTINFO:
133
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0]))
135
cm.IfIndex = int(pi.Ifindex)
136
case syscall.IPV6_PATHMTU:
137
mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0]))
138
cm.Dst = mi.Addr.Addr[:]
139
cm.IfIndex = int(mi.Addr.Scope_id)
146
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
151
if cm.TrafficClass > 0 {
152
l += syscall.CmsgSpace(4)
155
l += syscall.CmsgSpace(4)
158
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
160
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
162
if len(cm.NextHop) == net.IPv6len {
163
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
166
oob = make([]byte, l)
167
if cm.TrafficClass > 0 {
168
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
169
m.Level = ianaProtocolIPv6
170
m.Type = syscall.IPV6_TCLASS
171
m.SetLen(syscall.CmsgLen(4))
172
data := oob[off+syscall.CmsgLen(0):]
173
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
174
off += syscall.CmsgSpace(4)
177
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
178
m.Level = ianaProtocolIPv6
179
m.Type = syscall.IPV6_HOPLIMIT
180
m.SetLen(syscall.CmsgLen(4))
181
data := oob[off+syscall.CmsgLen(0):]
182
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
183
off += syscall.CmsgSpace(4)
186
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
187
m.Level = ianaProtocolIPv6
188
m.Type = syscall.IPV6_PKTINFO
189
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
190
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
191
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
195
pi.Ifindex = uint32(cm.IfIndex)
197
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
199
if len(cm.NextHop) == net.IPv6len {
200
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
201
m.Level = ianaProtocolIPv6
202
m.Type = syscall.IPV6_NEXTHOP
203
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
204
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
205
sa.Len = syscall.SizeofSockaddrInet6
206
sa.Family = syscall.AF_INET6
207
copy(sa.Addr[:], cm.NextHop)
208
sa.Scope_id = uint32(cm.IfIndex)
209
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)