1 // Copyright 2015 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"
16 classInterfaceInfo = 2
29 // An InterfaceInfo represents interface and next-hop identification.
30 type InterfaceInfo struct {
31 Class int // extension object class number
32 Type int // extension object sub-type
33 Interface *net.Interface
37 func (ifi *InterfaceInfo) nameLen() int {
38 if len(ifi.Interface.Name) > 63 {
41 l := 1 + len(ifi.Interface.Name)
45 func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) {
47 if ifi.Interface != nil && ifi.Interface.Index > 0 {
50 if len(ifi.Interface.Name) > 0 {
54 if ifi.Interface.MTU > 0 {
61 case iana.ProtocolICMP:
62 if ifi.Addr.IP.To4() != nil {
66 case iana.ProtocolIPv6ICMP:
67 if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {
76 // Len implements the Len method of Extension interface.
77 func (ifi *InterfaceInfo) Len(proto int) int {
78 _, l := ifi.attrsAndLen(proto)
82 // Marshal implements the Marshal method of Extension interface.
83 func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) {
84 attrs, l := ifi.attrsAndLen(proto)
86 if err := ifi.marshal(proto, b, attrs, l); err != nil {
92 func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error {
93 binary.BigEndian.PutUint16(b[:2], uint16(l))
94 b[2], b[3] = classInterfaceInfo, byte(ifi.Type)
95 for b = b[4:]; len(b) > 0 && attrs != 0; {
97 case attrs&attrIfIndex != 0:
98 b = ifi.marshalIfIndex(proto, b)
100 case attrs&attrIPAddr != 0:
101 b = ifi.marshalIPAddr(proto, b)
103 case attrs&attrName != 0:
104 b = ifi.marshalName(proto, b)
106 case attrs&attrMTU != 0:
107 b = ifi.marshalMTU(proto, b)
114 func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte {
115 binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.Index))
119 func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {
121 return nil, errMessageTooShort
123 ifi.Interface.Index = int(binary.BigEndian.Uint32(b[:4]))
127 func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {
129 case iana.ProtocolICMP:
130 binary.BigEndian.PutUint16(b[:2], uint16(afiIPv4))
131 copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
132 b = b[4+net.IPv4len:]
133 case iana.ProtocolIPv6ICMP:
134 binary.BigEndian.PutUint16(b[:2], uint16(afiIPv6))
135 copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())
136 b = b[4+net.IPv6len:]
141 func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {
143 return nil, errMessageTooShort
145 afi := int(binary.BigEndian.Uint16(b[:2]))
149 if len(b) < net.IPv4len {
150 return nil, errMessageTooShort
152 ifi.Addr.IP = make(net.IP, net.IPv4len)
153 copy(ifi.Addr.IP, b[:net.IPv4len])
156 if len(b) < net.IPv6len {
157 return nil, errMessageTooShort
159 ifi.Addr.IP = make(net.IP, net.IPv6len)
160 copy(ifi.Addr.IP, b[:net.IPv6len])
166 func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte {
167 l := byte(ifi.nameLen())
169 copy(b[1:], []byte(ifi.Interface.Name))
173 func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) {
174 if 4 > len(b) || len(b) < int(b[0]) {
175 return nil, errMessageTooShort
178 if l%4 != 0 || 4 > l || l > 64 {
179 return nil, errInvalidExtension
182 copy(name[:], b[1:l])
183 ifi.Interface.Name = strings.Trim(string(name[:]), "\000")
187 func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte {
188 binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.MTU))
192 func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) {
194 return nil, errMessageTooShort
196 ifi.Interface.MTU = int(binary.BigEndian.Uint32(b[:4]))
200 func parseInterfaceInfo(b []byte) (Extension, error) {
201 ifi := &InterfaceInfo{
205 if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 {
206 ifi.Interface = &net.Interface{}
208 if ifi.Type&attrIPAddr != 0 {
209 ifi.Addr = &net.IPAddr{}
211 attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU)
212 for b = b[4:]; len(b) > 0 && attrs != 0; {
215 case attrs&attrIfIndex != 0:
216 b, err = ifi.parseIfIndex(b)
217 attrs &^= attrIfIndex
218 case attrs&attrIPAddr != 0:
219 b, err = ifi.parseIPAddr(b)
221 case attrs&attrName != 0:
222 b, err = ifi.parseName(b)
224 case attrs&attrMTU != 0:
225 b, err = ifi.parseMTU(b)
232 if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil {
233 ifi.Addr.Zone = ifi.Interface.Name