| // Copyright 2016 The Netstack Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package ipv6 contains the implementation of the ipv6 network protocol. To use |
| // it in the networking stack, this package must be added to the project, and |
| // activated on the stack by passing ipv6.ProtocolName (or "ipv6") as one of the |
| // network protocols when calling stack.New(). Then endpoints can be created |
| // by passing ipv6.ProtocolNumber as the network protocol number when calling |
| // Stack.NewEndpoint(). |
| package ipv6 |
| |
| import ( |
| "sync/atomic" |
| |
| "github.com/google/netstack/tcpip" |
| "github.com/google/netstack/tcpip/buffer" |
| "github.com/google/netstack/tcpip/header" |
| "github.com/google/netstack/tcpip/stack" |
| ) |
| |
| const ( |
| // ProtocolName is the string representation of the ipv6 protocol name. |
| ProtocolName = "ipv6" |
| |
| // ProtocolNumber is the ipv6 protocol number. |
| ProtocolNumber = header.IPv6ProtocolNumber |
| |
| // maxTotalSize is maximum size that can be encoded in the 16-bit |
| // PayloadLength field of the ipv6 header. |
| maxPayloadSize = 0xffff |
| ) |
| |
| type address [header.IPv6AddressSize]byte |
| |
| type endpoint struct { |
| nicid tcpip.NICID |
| id stack.NetworkEndpointID |
| address address |
| linkEP stack.LinkEndpoint |
| linkAddrCache stack.LinkAddressCache |
| dispatcher stack.TransportDispatcher |
| } |
| |
| func (e *endpoint) DefaultTTL() uint8 { |
| return header.IPv6DefaultHopLimit |
| } |
| |
| // MTU implements stack.NetworkEndpoint.MTU. It returns the link-layer MTU minus |
| // the network layer max header length. |
| func (e *endpoint) MTU() uint32 { |
| mtu := e.linkEP.MTU() - uint32(e.MaxHeaderLength()) |
| if mtu <= maxPayloadSize { |
| return mtu |
| } |
| return maxPayloadSize |
| } |
| |
| // NICID returns the ID of the NIC this endpoint belongs to. |
| func (e *endpoint) NICID() tcpip.NICID { |
| return e.nicid |
| } |
| |
| // ID returns the ipv6 endpoint ID. |
| func (e *endpoint) ID() *stack.NetworkEndpointID { |
| return &e.id |
| } |
| |
| // MaxHeaderLength returns the maximum length needed by ipv6 headers (and |
| // underlying protocols). |
| func (e *endpoint) MaxHeaderLength() uint16 { |
| return e.linkEP.MaxHeaderLength() + header.IPv6MinimumSize |
| } |
| |
| // WritePacket writes a packet to the given destination address and protocol. |
| func (e *endpoint) WritePacket(r *stack.Route, hdr *buffer.Prependable, payload buffer.View, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error { |
| length := uint16(hdr.UsedLength()) |
| if payload != nil { |
| length += uint16(len(payload)) |
| } |
| ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) |
| ip.Encode(&header.IPv6Fields{ |
| PayloadLength: length, |
| NextHeader: uint8(protocol), |
| HopLimit: ttl, |
| SrcAddr: r.LocalAddress, |
| DstAddr: r.RemoteAddress, |
| }) |
| atomic.AddUint64(&r.MutableStats().IP.PacketsSent, 1) |
| |
| return e.linkEP.WritePacket(r, hdr, payload, ProtocolNumber) |
| } |
| |
| // HandlePacket is called by the link layer when new ipv6 packets arrive for |
| // this endpoint. |
| func (e *endpoint) HandlePacket(r *stack.Route, vv *buffer.VectorisedView) { |
| h := header.IPv6(vv.First()) |
| if !h.IsValid(vv.Size()) { |
| return |
| } |
| |
| vv.TrimFront(header.IPv6MinimumSize) |
| vv.CapLength(int(h.PayloadLength())) |
| p := tcpip.TransportProtocolNumber(h.NextHeader()) |
| if p == header.ICMPv6ProtocolNumber { |
| e.handleICMP(r, vv) |
| return |
| } |
| atomic.AddUint64(&r.MutableStats().IP.PacketsReceived, 1) |
| e.dispatcher.DeliverTransportPacket(r, p, vv) |
| } |
| |
| // Close cleans up resources associated with the endpoint. |
| func (*endpoint) Close() {} |
| |
| type protocol struct{} |
| |
| // NewProtocol creates a new protocol ipv6 protocol descriptor. This is exported |
| // only for tests that short-circuit the stack. Regular use of the protocol is |
| // done via the stack, which gets a protocol descriptor from the init() function |
| // below. |
| func NewProtocol() stack.NetworkProtocol { |
| return &protocol{} |
| } |
| |
| // Number returns the ipv6 protocol number. |
| func (p *protocol) Number() tcpip.NetworkProtocolNumber { |
| return ProtocolNumber |
| } |
| |
| // MinimumPacketSize returns the minimum valid ipv6 packet size. |
| func (p *protocol) MinimumPacketSize() int { |
| return header.IPv6MinimumSize |
| } |
| |
| // ParseAddresses implements NetworkProtocol.ParseAddresses. |
| func (*protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address) { |
| h := header.IPv6(v) |
| return h.SourceAddress(), h.DestinationAddress() |
| } |
| |
| // NewEndpoint creates a new ipv6 endpoint. |
| func (p *protocol) NewEndpoint(nicid tcpip.NICID, addr tcpip.Address, linkAddrCache stack.LinkAddressCache, dispatcher stack.TransportDispatcher, linkEP stack.LinkEndpoint) (stack.NetworkEndpoint, *tcpip.Error) { |
| e := &endpoint{ |
| nicid: nicid, |
| linkEP: linkEP, |
| linkAddrCache: linkAddrCache, |
| dispatcher: dispatcher, |
| } |
| copy(e.address[:], addr) |
| e.id = stack.NetworkEndpointID{tcpip.Address(e.address[:])} |
| return e, nil |
| } |
| |
| // SetOption implements NetworkProtocol.SetOption. |
| func (p *protocol) SetOption(option interface{}) *tcpip.Error { |
| return tcpip.ErrUnknownProtocolOption |
| } |
| |
| func init() { |
| stack.RegisterNetworkProtocolFactory(ProtocolName, func() stack.NetworkProtocol { |
| return &protocol{} |
| }) |
| } |
| |
| // LinkLocalAddr computes the default IPv6 link-local address from |
| // a link-layer (MAC) address. |
| func LinkLocalAddr(linkAddr tcpip.LinkAddress) tcpip.Address { |
| // Convert a 48-bit MAC to an EUI-64 and then prepend the |
| // link-local header, FE80::. |
| // |
| // The conversion is very nearly: |
| // aa:bb:cc:dd:ee:ff => FE80::Aabb:ccFF:FEdd:eeff |
| // Note the capital A. The conversion aa->Aa involves a bit flip. |
| lladdrb := [16]byte{ |
| 0: 0xFE, |
| 1: 0x80, |
| 8: linkAddr[0] ^ 2, |
| 9: linkAddr[1], |
| 10: linkAddr[2], |
| 11: 0xFF, |
| 12: 0xFE, |
| 13: linkAddr[3], |
| 14: linkAddr[4], |
| 15: linkAddr[5], |
| } |
| return tcpip.Address(lladdrb[:]) |
| } |
| |
| // SolicitedNodeAddr computes the solicited-node multicast address. |
| // This is used for NDP. Described in RFC 4291. |
| func SolicitedNodeAddr(addr tcpip.Address) tcpip.Address { |
| return "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff" + addr[len(addr)-3:] |
| } |