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.
12 "golang.org/x/net/internal/iana"
13 "golang.org/x/net/internal/socket"
16 // Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the
17 // former still support RFC 2292 only. Please be aware that almost
18 // all protocol implementations prohibit using a combination of RFC
19 // 2292 and RFC 3542 for some practical reasons.
26 func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
27 func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
28 func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
30 // A ControlFlags represents per packet basis IP-level socket option
32 type ControlFlags uint
35 FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet
36 FlagHopLimit // pass the hop limit on the received packet
37 FlagSrc // pass the source address on the received packet
38 FlagDst // pass the destination address on the received packet
39 FlagInterface // pass the interface index on the received packet
40 FlagPathMTU // pass the path MTU on the received packet path
43 const flagPacketInfo = FlagDst | FlagInterface
45 // A ControlMessage represents per packet basis IP-level socket
47 type ControlMessage struct {
48 // Receiving socket options: SetControlMessage allows to
49 // receive the options from the protocol stack using ReadFrom
50 // method of PacketConn.
52 // Specifying socket options: ControlMessage for WriteTo
53 // method of PacketConn allows to send the options to the
56 TrafficClass int // traffic class, must be 1 <= value <= 255 when specifying
57 HopLimit int // hop limit, must be 1 <= value <= 255 when specifying
58 Src net.IP // source address, specifying only
59 Dst net.IP // destination address, receiving only
60 IfIndex int // interface index, must be 1 <= value when specifying
61 NextHop net.IP // next hop address, specifying only
62 MTU int // path MTU, receiving only
65 func (cm *ControlMessage) String() string {
69 return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
72 // Marshal returns the binary encoding of cm.
73 func (cm *ControlMessage) Marshal() []byte {
79 if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
81 l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
84 if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
86 l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
89 if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
91 l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
94 if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
96 l += socket.ControlMessageSpace(ctlOpts[ctlNextHop].length)
103 bb = ctlOpts[ctlTrafficClass].marshal(bb, cm)
106 bb = ctlOpts[ctlHopLimit].marshal(bb, cm)
109 bb = ctlOpts[ctlPacketInfo].marshal(bb, cm)
112 bb = ctlOpts[ctlNextHop].marshal(bb, cm)
118 // Parse parses b as a control message and stores the result in cm.
119 func (cm *ControlMessage) Parse(b []byte) error {
120 ms, err := socket.ControlMessage(b).Parse()
124 for _, m := range ms {
125 lvl, typ, l, err := m.ParseHeader()
129 if lvl != iana.ProtocolIPv6 {
133 case typ == ctlOpts[ctlTrafficClass].name && l >= ctlOpts[ctlTrafficClass].length:
134 ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
135 case typ == ctlOpts[ctlHopLimit].name && l >= ctlOpts[ctlHopLimit].length:
136 ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
137 case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
138 ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
139 case typ == ctlOpts[ctlPathMTU].name && l >= ctlOpts[ctlPathMTU].length:
140 ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
146 // NewControlMessage returns a new control message.
148 // The returned message is large enough for options specified by cf.
149 func NewControlMessage(cf ControlFlags) []byte {
150 opt := rawOpt{cflags: cf}
152 if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
153 l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
155 if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
156 l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
158 if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
159 l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
161 if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
162 l += socket.ControlMessageSpace(ctlOpts[ctlPathMTU].length)
171 // Ancillary data socket options
173 ctlTrafficClass = iota // header field
174 ctlHopLimit // header field
175 ctlPacketInfo // inbound or outbound packet path
176 ctlNextHop // nexthop
177 ctlPathMTU // path mtu
181 // A ctlOpt represents a binding for ancillary data socket option.
183 name int // option name, must be equal or greater than 1
184 length int // option length
185 marshal func([]byte, *ControlMessage) []byte
186 parse func(*ControlMessage, []byte)