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.
15
// See /usr/include/linux/in6.h.
16
syscall_IPV6_RECVPATHMTU = syscall.IPV6_DSTOPTS + 1 + iota
21
const pktinfo = FlagDst | FlagInterface
23
func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
26
if cf&FlagTrafficClass != 0 {
27
if err := setIPv6ReceiveTrafficClass(fd, on); err != nil {
31
opt.set(FlagTrafficClass)
33
opt.clear(FlagTrafficClass)
36
if cf&FlagHopLimit != 0 {
37
if err := setIPv6ReceiveHopLimit(fd, on); err != nil {
43
opt.clear(FlagHopLimit)
47
if err := setIPv6ReceivePacketInfo(fd, on); err != nil {
53
opt.clear(cf & pktinfo)
56
if cf&FlagPathMTU != 0 {
57
if err := setIPv6ReceivePathMTU(fd, on); err != nil {
63
opt.clear(FlagPathMTU)
69
func newControlMessage(opt *rawOpt) (oob []byte) {
73
if opt.isset(FlagTrafficClass) {
74
l += syscall.CmsgSpace(4)
76
if opt.isset(FlagHopLimit) {
77
l += syscall.CmsgSpace(4)
79
if opt.isset(pktinfo) {
80
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
82
if opt.isset(FlagPathMTU) {
83
l += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
87
if opt.isset(FlagTrafficClass) {
88
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
89
m.Level = ianaProtocolIPv6
90
m.Type = syscall.IPV6_RECVTCLASS
91
m.SetLen(syscall.CmsgLen(4))
92
off += syscall.CmsgSpace(4)
94
if opt.isset(FlagHopLimit) {
95
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
96
m.Level = ianaProtocolIPv6
97
m.Type = syscall.IPV6_RECVHOPLIMIT
98
m.SetLen(syscall.CmsgLen(4))
99
off += syscall.CmsgSpace(4)
101
if opt.isset(pktinfo) {
102
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
103
m.Level = ianaProtocolIPv6
104
m.Type = syscall.IPV6_RECVPKTINFO
105
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
106
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
108
if opt.isset(FlagPathMTU) {
109
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
110
m.Level = ianaProtocolIPv6
111
m.Type = syscall_IPV6_RECVPATHMTU
112
m.SetLen(syscall.CmsgLen(syscall.SizeofIPv6MTUInfo))
113
off += syscall.CmsgSpace(syscall.SizeofIPv6MTUInfo)
119
func parseControlMessage(b []byte) (*ControlMessage, error) {
123
cmsgs, err := syscall.ParseSocketControlMessage(b)
125
return nil, os.NewSyscallError("parse socket control message", err)
127
cm := &ControlMessage{}
128
for _, m := range cmsgs {
129
if m.Header.Level != ianaProtocolIPv6 {
132
switch m.Header.Type {
133
case syscall.IPV6_TCLASS:
134
cm.TrafficClass = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
135
case syscall.IPV6_HOPLIMIT:
136
cm.HopLimit = int(*(*byte)(unsafe.Pointer(&m.Data[:1][0])))
137
case syscall.IPV6_PKTINFO:
138
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&m.Data[0]))
140
cm.IfIndex = int(pi.Ifindex)
141
case syscall_IPV6_PATHMTU:
142
mi := (*syscall.IPv6MTUInfo)(unsafe.Pointer(&m.Data[0]))
143
cm.Dst = mi.Addr.Addr[:]
144
cm.IfIndex = int(mi.Addr.Scope_id)
151
func marshalControlMessage(cm *ControlMessage) (oob []byte) {
156
if cm.TrafficClass > 0 {
157
l += syscall.CmsgSpace(4)
160
l += syscall.CmsgSpace(4)
163
if cm.Src.To4() == nil && cm.Src.To16() != nil || cm.IfIndex != 0 {
165
l += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
167
if len(cm.NextHop) == net.IPv6len {
168
l += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)
171
oob = make([]byte, l)
172
if cm.TrafficClass > 0 {
173
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
174
m.Level = ianaProtocolIPv6
175
m.Type = syscall.IPV6_TCLASS
176
m.SetLen(syscall.CmsgLen(4))
177
data := oob[off+syscall.CmsgLen(0):]
178
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.TrafficClass)
179
off += syscall.CmsgSpace(4)
182
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
183
m.Level = ianaProtocolIPv6
184
m.Type = syscall.IPV6_HOPLIMIT
185
m.SetLen(syscall.CmsgLen(4))
186
data := oob[off+syscall.CmsgLen(0):]
187
*(*byte)(unsafe.Pointer(&data[:1][0])) = byte(cm.HopLimit)
188
off += syscall.CmsgSpace(4)
191
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
192
m.Level = ianaProtocolIPv6
193
m.Type = syscall.IPV6_PKTINFO
194
m.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo))
195
pi := (*syscall.Inet6Pktinfo)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
196
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
200
pi.Ifindex = uint32(cm.IfIndex)
202
off += syscall.CmsgSpace(syscall.SizeofInet6Pktinfo)
204
if len(cm.NextHop) == net.IPv6len {
205
m := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[off]))
206
m.Level = ianaProtocolIPv6
207
m.Type = syscall.IPV6_NEXTHOP
208
m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrInet6))
209
sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&oob[off+syscall.CmsgLen(0)]))
210
sa.Family = syscall.AF_INET6
211
copy(sa.Addr[:], cm.NextHop)
212
sa.Scope_id = uint32(cm.IfIndex)
213
off += syscall.CmsgSpace(syscall.SizeofSockaddrInet6)