github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/network/ipv6/icmp_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ipv6
    16  
    17  import (
    18  	"bytes"
    19  	"net"
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/SagerNet/gvisor/pkg/tcpip"
    26  	"github.com/SagerNet/gvisor/pkg/tcpip/buffer"
    27  	"github.com/SagerNet/gvisor/pkg/tcpip/checker"
    28  	"github.com/SagerNet/gvisor/pkg/tcpip/faketime"
    29  	"github.com/SagerNet/gvisor/pkg/tcpip/header"
    30  	"github.com/SagerNet/gvisor/pkg/tcpip/link/channel"
    31  	"github.com/SagerNet/gvisor/pkg/tcpip/link/sniffer"
    32  	"github.com/SagerNet/gvisor/pkg/tcpip/stack"
    33  	"github.com/SagerNet/gvisor/pkg/tcpip/transport/icmp"
    34  	"github.com/SagerNet/gvisor/pkg/tcpip/transport/udp"
    35  	"github.com/SagerNet/gvisor/pkg/waiter"
    36  )
    37  
    38  const (
    39  	nicID = 1
    40  
    41  	linkAddr0 = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
    42  	linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
    43  	linkAddr2 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0f")
    44  
    45  	defaultChannelSize = 1
    46  	defaultMTU         = 65536
    47  
    48  	arbitraryHopLimit = 42
    49  )
    50  
    51  var (
    52  	lladdr0 = header.LinkLocalAddr(linkAddr0)
    53  	lladdr1 = header.LinkLocalAddr(linkAddr1)
    54  )
    55  
    56  type stubLinkEndpoint struct {
    57  	stack.LinkEndpoint
    58  }
    59  
    60  func (*stubLinkEndpoint) MTU() uint32 {
    61  	return defaultMTU
    62  }
    63  
    64  func (*stubLinkEndpoint) Capabilities() stack.LinkEndpointCapabilities {
    65  	// Indicate that resolution for link layer addresses is required to send
    66  	// packets over this link. This is needed so the NIC knows to allocate a
    67  	// neighbor table.
    68  	return stack.CapabilityResolutionRequired
    69  }
    70  
    71  func (*stubLinkEndpoint) MaxHeaderLength() uint16 {
    72  	return 0
    73  }
    74  
    75  func (*stubLinkEndpoint) LinkAddress() tcpip.LinkAddress {
    76  	return ""
    77  }
    78  
    79  func (*stubLinkEndpoint) WritePacket(stack.RouteInfo, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) tcpip.Error {
    80  	return nil
    81  }
    82  
    83  func (*stubLinkEndpoint) Attach(stack.NetworkDispatcher) {}
    84  
    85  type stubDispatcher struct {
    86  	stack.TransportDispatcher
    87  }
    88  
    89  func (*stubDispatcher) DeliverTransportPacket(tcpip.TransportProtocolNumber, *stack.PacketBuffer) stack.TransportPacketDisposition {
    90  	return stack.TransportPacketHandled
    91  }
    92  
    93  func (*stubDispatcher) DeliverRawPacket(tcpip.TransportProtocolNumber, *stack.PacketBuffer) {
    94  	// No-op.
    95  }
    96  
    97  var _ stack.NetworkInterface = (*testInterface)(nil)
    98  
    99  type testInterface struct {
   100  	stack.LinkEndpoint
   101  
   102  	probeCount        int
   103  	confirmationCount int
   104  
   105  	nicID tcpip.NICID
   106  }
   107  
   108  func (*testInterface) ID() tcpip.NICID {
   109  	return nicID
   110  }
   111  
   112  func (*testInterface) IsLoopback() bool {
   113  	return false
   114  }
   115  
   116  func (*testInterface) Name() string {
   117  	return ""
   118  }
   119  
   120  func (*testInterface) Enabled() bool {
   121  	return true
   122  }
   123  
   124  func (*testInterface) Promiscuous() bool {
   125  	return false
   126  }
   127  
   128  func (*testInterface) Spoofing() bool {
   129  	return false
   130  }
   131  
   132  func (t *testInterface) WritePacket(r *stack.Route, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
   133  	return t.LinkEndpoint.WritePacket(r.Fields(), protocol, pkt)
   134  }
   135  
   136  func (t *testInterface) WritePackets(r *stack.Route, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
   137  	return t.LinkEndpoint.WritePackets(r.Fields(), pkts, protocol)
   138  }
   139  
   140  func (t *testInterface) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
   141  	var r stack.RouteInfo
   142  	r.NetProto = protocol
   143  	r.RemoteLinkAddress = remoteLinkAddr
   144  	return t.LinkEndpoint.WritePacket(r, protocol, pkt)
   145  }
   146  
   147  func (t *testInterface) HandleNeighborProbe(tcpip.NetworkProtocolNumber, tcpip.Address, tcpip.LinkAddress) tcpip.Error {
   148  	t.probeCount++
   149  	return nil
   150  }
   151  
   152  func (t *testInterface) HandleNeighborConfirmation(tcpip.NetworkProtocolNumber, tcpip.Address, tcpip.LinkAddress, stack.ReachabilityConfirmationFlags) tcpip.Error {
   153  	t.confirmationCount++
   154  	return nil
   155  }
   156  
   157  func (*testInterface) PrimaryAddress(tcpip.NetworkProtocolNumber) (tcpip.AddressWithPrefix, tcpip.Error) {
   158  	return tcpip.AddressWithPrefix{}, nil
   159  }
   160  
   161  func (*testInterface) CheckLocalAddress(tcpip.NetworkProtocolNumber, tcpip.Address) bool {
   162  	return false
   163  }
   164  
   165  func handleICMPInIPv6(ep stack.NetworkEndpoint, src, dst tcpip.Address, icmp header.ICMPv6, hopLimit uint8, includeRouterAlert bool) {
   166  	var extensionHeaders header.IPv6ExtHdrSerializer
   167  	if includeRouterAlert {
   168  		extensionHeaders = header.IPv6ExtHdrSerializer{
   169  			header.IPv6SerializableHopByHopExtHdr{
   170  				&header.IPv6RouterAlertOption{Value: header.IPv6RouterAlertMLD},
   171  			},
   172  		}
   173  	}
   174  	ip := buffer.NewView(header.IPv6MinimumSize + extensionHeaders.Length())
   175  	header.IPv6(ip).Encode(&header.IPv6Fields{
   176  		PayloadLength:     uint16(len(icmp)),
   177  		TransportProtocol: header.ICMPv6ProtocolNumber,
   178  		HopLimit:          hopLimit,
   179  		SrcAddr:           src,
   180  		DstAddr:           dst,
   181  		ExtensionHeaders:  extensionHeaders,
   182  	})
   183  
   184  	vv := ip.ToVectorisedView()
   185  	vv.AppendView(buffer.View(icmp))
   186  	ep.HandlePacket(stack.NewPacketBuffer(stack.PacketBufferOptions{
   187  		Data: vv,
   188  	}))
   189  }
   190  
   191  func TestICMPCounts(t *testing.T) {
   192  	s := stack.New(stack.Options{
   193  		NetworkProtocols:   []stack.NetworkProtocolFactory{NewProtocol},
   194  		TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6},
   195  	})
   196  	if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil {
   197  		t.Fatalf("CreateNIC(_, _) = %s", err)
   198  	}
   199  	{
   200  		subnet, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
   201  		if err != nil {
   202  			t.Fatal(err)
   203  		}
   204  		s.SetRouteTable(
   205  			[]tcpip.Route{{
   206  				Destination: subnet,
   207  				NIC:         nicID,
   208  			}},
   209  		)
   210  	}
   211  
   212  	netProto := s.NetworkProtocolInstance(ProtocolNumber)
   213  	if netProto == nil {
   214  		t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber)
   215  	}
   216  	ep := netProto.NewEndpoint(&testInterface{}, &stubDispatcher{})
   217  	defer ep.Close()
   218  
   219  	if err := ep.Enable(); err != nil {
   220  		t.Fatalf("ep.Enable(): %s", err)
   221  	}
   222  
   223  	addressableEndpoint, ok := ep.(stack.AddressableEndpoint)
   224  	if !ok {
   225  		t.Fatalf("expected network endpoint to implement stack.AddressableEndpoint")
   226  	}
   227  	addr := lladdr0.WithPrefix()
   228  	if ep, err := addressableEndpoint.AddAndAcquirePermanentAddress(addr, stack.CanBePrimaryEndpoint, stack.AddressConfigStatic, false /* deprecated */); err != nil {
   229  		t.Fatalf("addressableEndpoint.AddAndAcquirePermanentAddress(%s, CanBePrimaryEndpoint, AddressConfigStatic, false): %s", addr, err)
   230  	} else {
   231  		ep.DecRef()
   232  	}
   233  
   234  	var tllData [header.NDPLinkLayerAddressSize]byte
   235  	header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{
   236  		header.NDPTargetLinkLayerAddressOption(linkAddr1),
   237  	})
   238  
   239  	types := []struct {
   240  		typ                header.ICMPv6Type
   241  		hopLimit           uint8
   242  		includeRouterAlert bool
   243  		size               int
   244  		extraData          []byte
   245  	}{
   246  		{
   247  			typ:      header.ICMPv6DstUnreachable,
   248  			hopLimit: arbitraryHopLimit,
   249  			size:     header.ICMPv6DstUnreachableMinimumSize,
   250  		},
   251  		{
   252  			typ:      header.ICMPv6PacketTooBig,
   253  			hopLimit: arbitraryHopLimit,
   254  			size:     header.ICMPv6PacketTooBigMinimumSize,
   255  		},
   256  		{
   257  			typ:      header.ICMPv6TimeExceeded,
   258  			hopLimit: arbitraryHopLimit,
   259  			size:     header.ICMPv6MinimumSize,
   260  		},
   261  		{
   262  			typ:      header.ICMPv6ParamProblem,
   263  			hopLimit: arbitraryHopLimit,
   264  			size:     header.ICMPv6MinimumSize,
   265  		},
   266  		{
   267  			typ:      header.ICMPv6EchoRequest,
   268  			hopLimit: arbitraryHopLimit,
   269  			size:     header.ICMPv6EchoMinimumSize,
   270  		},
   271  		{
   272  			typ:      header.ICMPv6EchoReply,
   273  			hopLimit: arbitraryHopLimit,
   274  			size:     header.ICMPv6EchoMinimumSize,
   275  		},
   276  		{
   277  			typ:      header.ICMPv6RouterSolicit,
   278  			hopLimit: header.NDPHopLimit,
   279  			size:     header.ICMPv6MinimumSize,
   280  		},
   281  		{
   282  			typ:      header.ICMPv6RouterAdvert,
   283  			hopLimit: header.NDPHopLimit,
   284  			size:     header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
   285  		},
   286  		{
   287  			typ:      header.ICMPv6NeighborSolicit,
   288  			hopLimit: header.NDPHopLimit,
   289  			size:     header.ICMPv6NeighborSolicitMinimumSize,
   290  		},
   291  		{
   292  			typ:       header.ICMPv6NeighborAdvert,
   293  			hopLimit:  header.NDPHopLimit,
   294  			size:      header.ICMPv6NeighborAdvertMinimumSize,
   295  			extraData: tllData[:],
   296  		},
   297  		{
   298  			typ:      header.ICMPv6RedirectMsg,
   299  			hopLimit: header.NDPHopLimit,
   300  			size:     header.ICMPv6MinimumSize,
   301  		},
   302  		{
   303  			typ:                header.ICMPv6MulticastListenerQuery,
   304  			hopLimit:           header.MLDHopLimit,
   305  			includeRouterAlert: true,
   306  			size:               header.MLDMinimumSize + header.ICMPv6HeaderSize,
   307  		},
   308  		{
   309  			typ:                header.ICMPv6MulticastListenerReport,
   310  			hopLimit:           header.MLDHopLimit,
   311  			includeRouterAlert: true,
   312  			size:               header.MLDMinimumSize + header.ICMPv6HeaderSize,
   313  		},
   314  		{
   315  			typ:                header.ICMPv6MulticastListenerDone,
   316  			hopLimit:           header.MLDHopLimit,
   317  			includeRouterAlert: true,
   318  			size:               header.MLDMinimumSize + header.ICMPv6HeaderSize,
   319  		},
   320  		{
   321  			typ:  255, /* Unrecognized */
   322  			size: 50,
   323  		},
   324  	}
   325  
   326  	for _, typ := range types {
   327  		icmp := header.ICMPv6(buffer.NewView(typ.size + len(typ.extraData)))
   328  		copy(icmp[typ.size:], typ.extraData)
   329  		icmp.SetType(typ.typ)
   330  		icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   331  			Header:      icmp[:typ.size],
   332  			Src:         lladdr0,
   333  			Dst:         lladdr1,
   334  			PayloadCsum: header.Checksum(typ.extraData, 0 /* initial */),
   335  			PayloadLen:  len(typ.extraData),
   336  		}))
   337  		handleICMPInIPv6(ep, lladdr1, lladdr0, icmp, typ.hopLimit, typ.includeRouterAlert)
   338  	}
   339  
   340  	// Construct an empty ICMP packet so that
   341  	// Stats().ICMP.ICMPv6ReceivedPacketStats.Invalid is incremented.
   342  	handleICMPInIPv6(ep, lladdr1, lladdr0, header.ICMPv6(buffer.NewView(header.IPv6MinimumSize)), arbitraryHopLimit, false)
   343  
   344  	icmpv6Stats := s.Stats().ICMP.V6.PacketsReceived
   345  	visitStats(reflect.ValueOf(&icmpv6Stats).Elem(), func(name string, s *tcpip.StatCounter) {
   346  		if got, want := s.Value(), uint64(1); got != want {
   347  			t.Errorf("got %s = %d, want = %d", name, got, want)
   348  		}
   349  	})
   350  	if t.Failed() {
   351  		t.Logf("stats:\n%+v", s.Stats())
   352  	}
   353  }
   354  
   355  func visitStats(v reflect.Value, f func(string, *tcpip.StatCounter)) {
   356  	t := v.Type()
   357  	for i := 0; i < v.NumField(); i++ {
   358  		v := v.Field(i)
   359  		if s, ok := v.Interface().(*tcpip.StatCounter); ok {
   360  			f(t.Field(i).Name, s)
   361  		} else {
   362  			visitStats(v, f)
   363  		}
   364  	}
   365  }
   366  
   367  type testContext struct {
   368  	s0 *stack.Stack
   369  	s1 *stack.Stack
   370  
   371  	linkEP0 *channel.Endpoint
   372  	linkEP1 *channel.Endpoint
   373  
   374  	clock *faketime.ManualClock
   375  }
   376  
   377  type endpointWithResolutionCapability struct {
   378  	stack.LinkEndpoint
   379  }
   380  
   381  func (e endpointWithResolutionCapability) Capabilities() stack.LinkEndpointCapabilities {
   382  	return e.LinkEndpoint.Capabilities() | stack.CapabilityResolutionRequired
   383  }
   384  
   385  func newTestContext(t *testing.T) *testContext {
   386  	clock := faketime.NewManualClock()
   387  	c := &testContext{
   388  		s0: stack.New(stack.Options{
   389  			NetworkProtocols:   []stack.NetworkProtocolFactory{NewProtocol},
   390  			TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6},
   391  			Clock:              clock,
   392  		}),
   393  		s1: stack.New(stack.Options{
   394  			NetworkProtocols:   []stack.NetworkProtocolFactory{NewProtocol},
   395  			TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6},
   396  			Clock:              clock,
   397  		}),
   398  		clock: clock,
   399  	}
   400  
   401  	c.linkEP0 = channel.New(defaultChannelSize, defaultMTU, linkAddr0)
   402  
   403  	wrappedEP0 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP0})
   404  	if testing.Verbose() {
   405  		wrappedEP0 = sniffer.New(wrappedEP0)
   406  	}
   407  	if err := c.s0.CreateNIC(nicID, wrappedEP0); err != nil {
   408  		t.Fatalf("CreateNIC s0: %v", err)
   409  	}
   410  	if err := c.s0.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
   411  		t.Fatalf("AddAddress lladdr0: %v", err)
   412  	}
   413  
   414  	c.linkEP1 = channel.New(defaultChannelSize, defaultMTU, linkAddr1)
   415  	wrappedEP1 := stack.LinkEndpoint(endpointWithResolutionCapability{LinkEndpoint: c.linkEP1})
   416  	if err := c.s1.CreateNIC(nicID, wrappedEP1); err != nil {
   417  		t.Fatalf("CreateNIC failed: %v", err)
   418  	}
   419  	if err := c.s1.AddAddress(nicID, ProtocolNumber, lladdr1); err != nil {
   420  		t.Fatalf("AddAddress lladdr1: %v", err)
   421  	}
   422  
   423  	subnet0, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
   424  	if err != nil {
   425  		t.Fatal(err)
   426  	}
   427  	c.s0.SetRouteTable(
   428  		[]tcpip.Route{{
   429  			Destination: subnet0,
   430  			NIC:         nicID,
   431  		}},
   432  	)
   433  	subnet1, err := tcpip.NewSubnet(lladdr0, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr0))))
   434  	if err != nil {
   435  		t.Fatal(err)
   436  	}
   437  	c.s1.SetRouteTable(
   438  		[]tcpip.Route{{
   439  			Destination: subnet1,
   440  			NIC:         nicID,
   441  		}},
   442  	)
   443  
   444  	t.Cleanup(func() {
   445  		if err := c.s0.RemoveNIC(nicID); err != nil {
   446  			t.Errorf("c.s0.RemoveNIC(%d): %s", nicID, err)
   447  		}
   448  		if err := c.s1.RemoveNIC(nicID); err != nil {
   449  			t.Errorf("c.s1.RemoveNIC(%d): %s", nicID, err)
   450  		}
   451  
   452  		c.linkEP0.Close()
   453  		c.linkEP1.Close()
   454  	})
   455  
   456  	return c
   457  }
   458  
   459  type routeArgs struct {
   460  	src, dst       *channel.Endpoint
   461  	typ            header.ICMPv6Type
   462  	remoteLinkAddr tcpip.LinkAddress
   463  }
   464  
   465  func routeICMPv6Packet(t *testing.T, clock *faketime.ManualClock, args routeArgs, fn func(*testing.T, header.ICMPv6)) {
   466  	t.Helper()
   467  
   468  	clock.RunImmediatelyScheduledJobs()
   469  	pi, ok := args.src.Read()
   470  	if !ok {
   471  		t.Fatal("packet didn't arrive")
   472  	}
   473  
   474  	{
   475  		pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   476  			Data: buffer.NewVectorisedView(pi.Pkt.Size(), pi.Pkt.Views()),
   477  		})
   478  		args.dst.InjectLinkAddr(pi.Proto, args.dst.LinkAddress(), pkt)
   479  	}
   480  
   481  	if pi.Proto != ProtocolNumber {
   482  		t.Errorf("unexpected protocol number %d", pi.Proto)
   483  		return
   484  	}
   485  
   486  	if len(args.remoteLinkAddr) != 0 && pi.Route.RemoteLinkAddress != args.remoteLinkAddr {
   487  		t.Errorf("got remote link address = %s, want = %s", pi.Route.RemoteLinkAddress, args.remoteLinkAddr)
   488  	}
   489  
   490  	// Pull the full payload since network header. Needed for header.IPv6 to
   491  	// extract its payload.
   492  	ipv6 := header.IPv6(stack.PayloadSince(pi.Pkt.NetworkHeader()))
   493  	transProto := tcpip.TransportProtocolNumber(ipv6.NextHeader())
   494  	if transProto != header.ICMPv6ProtocolNumber {
   495  		t.Errorf("unexpected transport protocol number %d", transProto)
   496  		return
   497  	}
   498  	icmpv6 := header.ICMPv6(ipv6.Payload())
   499  	if got, want := icmpv6.Type(), args.typ; got != want {
   500  		t.Errorf("got ICMPv6 type = %d, want = %d", got, want)
   501  		return
   502  	}
   503  	if fn != nil {
   504  		fn(t, icmpv6)
   505  	}
   506  }
   507  
   508  func TestLinkResolution(t *testing.T) {
   509  	c := newTestContext(t)
   510  
   511  	r, err := c.s0.FindRoute(nicID, lladdr0, lladdr1, ProtocolNumber, false /* multicastLoop */)
   512  	if err != nil {
   513  		t.Fatalf("FindRoute(%d, %s, %s, _, false) = (_, %s), want = (_, nil)", nicID, lladdr0, lladdr1, err)
   514  	}
   515  	defer r.Release()
   516  
   517  	hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6EchoMinimumSize)
   518  	pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize))
   519  	pkt.SetType(header.ICMPv6EchoRequest)
   520  	pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   521  		Header: pkt,
   522  		Src:    r.LocalAddress(),
   523  		Dst:    r.RemoteAddress(),
   524  	}))
   525  
   526  	// We can't send our payload directly over the route because that
   527  	// doesn't provoke NDP discovery.
   528  	var wq waiter.Queue
   529  	ep, err := c.s0.NewEndpoint(header.ICMPv6ProtocolNumber, ProtocolNumber, &wq)
   530  	if err != nil {
   531  		t.Fatalf("NewEndpoint(_) = (_, %s), want = (_, nil)", err)
   532  	}
   533  
   534  	{
   535  		var r bytes.Reader
   536  		r.Reset(hdr.View())
   537  		if _, err := ep.Write(&r, tcpip.WriteOptions{To: &tcpip.FullAddress{NIC: nicID, Addr: lladdr1}}); err != nil {
   538  			t.Fatalf("ep.Write(_): %s", err)
   539  		}
   540  	}
   541  	for _, args := range []routeArgs{
   542  		{src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6NeighborSolicit, remoteLinkAddr: header.EthernetAddressFromMulticastIPv6Address(header.SolicitedNodeAddr(lladdr1))},
   543  		{src: c.linkEP1, dst: c.linkEP0, typ: header.ICMPv6NeighborAdvert},
   544  	} {
   545  		routeICMPv6Packet(t, c.clock, args, func(t *testing.T, icmpv6 header.ICMPv6) {
   546  			if got, want := tcpip.Address(icmpv6[8:][:16]), lladdr1; got != want {
   547  				t.Errorf("%d: got target = %s, want = %s", icmpv6.Type(), got, want)
   548  			}
   549  		})
   550  	}
   551  
   552  	for _, args := range []routeArgs{
   553  		{src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6EchoRequest},
   554  		{src: c.linkEP1, dst: c.linkEP0, typ: header.ICMPv6EchoReply},
   555  	} {
   556  		routeICMPv6Packet(t, c.clock, args, nil)
   557  	}
   558  }
   559  
   560  func TestICMPChecksumValidationSimple(t *testing.T) {
   561  	var tllData [header.NDPLinkLayerAddressSize]byte
   562  	header.NDPOptions(tllData[:]).Serialize(header.NDPOptionsSerializer{
   563  		header.NDPTargetLinkLayerAddressOption(linkAddr1),
   564  	})
   565  
   566  	types := []struct {
   567  		name        string
   568  		typ         header.ICMPv6Type
   569  		size        int
   570  		extraData   []byte
   571  		statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
   572  		routerOnly  bool
   573  	}{
   574  		{
   575  			name: "DstUnreachable",
   576  			typ:  header.ICMPv6DstUnreachable,
   577  			size: header.ICMPv6DstUnreachableMinimumSize,
   578  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   579  				return stats.DstUnreachable
   580  			},
   581  		},
   582  		{
   583  			name: "PacketTooBig",
   584  			typ:  header.ICMPv6PacketTooBig,
   585  			size: header.ICMPv6PacketTooBigMinimumSize,
   586  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   587  				return stats.PacketTooBig
   588  			},
   589  		},
   590  		{
   591  			name: "TimeExceeded",
   592  			typ:  header.ICMPv6TimeExceeded,
   593  			size: header.ICMPv6MinimumSize,
   594  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   595  				return stats.TimeExceeded
   596  			},
   597  		},
   598  		{
   599  			name: "ParamProblem",
   600  			typ:  header.ICMPv6ParamProblem,
   601  			size: header.ICMPv6MinimumSize,
   602  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   603  				return stats.ParamProblem
   604  			},
   605  		},
   606  		{
   607  			name: "EchoRequest",
   608  			typ:  header.ICMPv6EchoRequest,
   609  			size: header.ICMPv6EchoMinimumSize,
   610  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   611  				return stats.EchoRequest
   612  			},
   613  		},
   614  		{
   615  			name: "EchoReply",
   616  			typ:  header.ICMPv6EchoReply,
   617  			size: header.ICMPv6EchoMinimumSize,
   618  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   619  				return stats.EchoReply
   620  			},
   621  		},
   622  		{
   623  			name: "RouterSolicit",
   624  			typ:  header.ICMPv6RouterSolicit,
   625  			size: header.ICMPv6MinimumSize,
   626  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   627  				return stats.RouterSolicit
   628  			},
   629  			// Hosts MUST silently discard any received Router Solicitation messages.
   630  			routerOnly: true,
   631  		},
   632  		{
   633  			name: "RouterAdvert",
   634  			typ:  header.ICMPv6RouterAdvert,
   635  			size: header.ICMPv6HeaderSize + header.NDPRAMinimumSize,
   636  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   637  				return stats.RouterAdvert
   638  			},
   639  		},
   640  		{
   641  			name: "NeighborSolicit",
   642  			typ:  header.ICMPv6NeighborSolicit,
   643  			size: header.ICMPv6NeighborSolicitMinimumSize,
   644  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   645  				return stats.NeighborSolicit
   646  			},
   647  		},
   648  		{
   649  			name:      "NeighborAdvert",
   650  			typ:       header.ICMPv6NeighborAdvert,
   651  			size:      header.ICMPv6NeighborAdvertMinimumSize,
   652  			extraData: tllData[:],
   653  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   654  				return stats.NeighborAdvert
   655  			},
   656  		},
   657  		{
   658  			name: "RedirectMsg",
   659  			typ:  header.ICMPv6RedirectMsg,
   660  			size: header.ICMPv6MinimumSize,
   661  			statCounter: func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   662  				return stats.RedirectMsg
   663  			},
   664  		},
   665  	}
   666  
   667  	for _, typ := range types {
   668  		for _, isRouter := range []bool{false, true} {
   669  			name := typ.name
   670  			if isRouter {
   671  				name += " (Router)"
   672  			}
   673  			t.Run(name, func(t *testing.T) {
   674  				e := channel.New(0, 1280, linkAddr0)
   675  
   676  				// Indicate that resolution for link layer addresses is required to
   677  				// send packets over this link. This is needed so the NIC knows to
   678  				// allocate a neighbor table.
   679  				e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
   680  
   681  				s := stack.New(stack.Options{
   682  					NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
   683  				})
   684  				if isRouter {
   685  					if err := s.SetForwardingDefaultAndAllNICs(ProtocolNumber, true); err != nil {
   686  						t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ProtocolNumber, err)
   687  					}
   688  				}
   689  				if err := s.CreateNIC(nicID, e); err != nil {
   690  					t.Fatalf("CreateNIC(_, _) = %s", err)
   691  				}
   692  
   693  				if err := s.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
   694  					t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, lladdr0, err)
   695  				}
   696  				{
   697  					subnet, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
   698  					if err != nil {
   699  						t.Fatal(err)
   700  					}
   701  					s.SetRouteTable(
   702  						[]tcpip.Route{{
   703  							Destination: subnet,
   704  							NIC:         nicID,
   705  						}},
   706  					)
   707  				}
   708  
   709  				handleIPv6Payload := func(checksum bool) {
   710  					icmp := header.ICMPv6(buffer.NewView(typ.size + len(typ.extraData)))
   711  					copy(icmp[typ.size:], typ.extraData)
   712  					icmp.SetType(typ.typ)
   713  					if checksum {
   714  						icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   715  							Header: icmp,
   716  							Src:    lladdr1,
   717  							Dst:    lladdr0,
   718  						}))
   719  					}
   720  					ip := header.IPv6(buffer.NewView(header.IPv6MinimumSize))
   721  					ip.Encode(&header.IPv6Fields{
   722  						PayloadLength:     uint16(len(icmp)),
   723  						TransportProtocol: header.ICMPv6ProtocolNumber,
   724  						HopLimit:          header.NDPHopLimit,
   725  						SrcAddr:           lladdr1,
   726  						DstAddr:           lladdr0,
   727  					})
   728  					pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   729  						Data: buffer.NewVectorisedView(len(ip)+len(icmp), []buffer.View{buffer.View(ip), buffer.View(icmp)}),
   730  					})
   731  					e.InjectInbound(ProtocolNumber, pkt)
   732  				}
   733  
   734  				stats := s.Stats().ICMP.V6.PacketsReceived
   735  				invalid := stats.Invalid
   736  				routerOnly := stats.RouterOnlyPacketsDroppedByHost
   737  				typStat := typ.statCounter(stats)
   738  
   739  				// Initial stat counts should be 0.
   740  				if got := invalid.Value(); got != 0 {
   741  					t.Fatalf("got invalid = %d, want = 0", got)
   742  				}
   743  				if got := routerOnly.Value(); got != 0 {
   744  					t.Fatalf("got RouterOnlyPacketsReceivedByHost = %d, want = 0", got)
   745  				}
   746  				if got := typStat.Value(); got != 0 {
   747  					t.Fatalf("got %s = %d, want = 0", typ.name, got)
   748  				}
   749  
   750  				// Without setting checksum, the incoming packet should
   751  				// be invalid.
   752  				handleIPv6Payload(false)
   753  				if got := invalid.Value(); got != 1 {
   754  					t.Fatalf("got invalid = %d, want = 1", got)
   755  				}
   756  				// Router only count should not have increased.
   757  				if got := routerOnly.Value(); got != 0 {
   758  					t.Fatalf("got RouterOnlyPacketsReceivedByHost = %d, want = 0", got)
   759  				}
   760  				// Rx count of type typ.typ should not have increased.
   761  				if got := typStat.Value(); got != 0 {
   762  					t.Fatalf("got %s = %d, want = 0", typ.name, got)
   763  				}
   764  
   765  				// When checksum is set, it should be received.
   766  				handleIPv6Payload(true)
   767  				if got := typStat.Value(); got != 1 {
   768  					t.Fatalf("got %s = %d, want = 1", typ.name, got)
   769  				}
   770  				// Invalid count should not have increased again.
   771  				if got := invalid.Value(); got != 1 {
   772  					t.Fatalf("got invalid = %d, want = 1", got)
   773  				}
   774  				if !isRouter && typ.routerOnly {
   775  					// Router only count should have increased.
   776  					if got := routerOnly.Value(); got != 1 {
   777  						t.Fatalf("got RouterOnlyPacketsReceivedByHost = %d, want = 1", got)
   778  					}
   779  				}
   780  			})
   781  		}
   782  	}
   783  }
   784  
   785  func TestICMPChecksumValidationWithPayload(t *testing.T) {
   786  	const simpleBodySize = 64
   787  	simpleBody := func(view buffer.View) {
   788  		for i := 0; i < simpleBodySize; i++ {
   789  			view[i] = uint8(i)
   790  		}
   791  	}
   792  
   793  	const errorICMPBodySize = header.IPv6MinimumSize + simpleBodySize
   794  	errorICMPBody := func(view buffer.View) {
   795  		ip := header.IPv6(view)
   796  		ip.Encode(&header.IPv6Fields{
   797  			PayloadLength:     simpleBodySize,
   798  			TransportProtocol: 10,
   799  			HopLimit:          20,
   800  			SrcAddr:           lladdr0,
   801  			DstAddr:           lladdr1,
   802  		})
   803  		simpleBody(view[header.IPv6MinimumSize:])
   804  	}
   805  
   806  	types := []struct {
   807  		name        string
   808  		typ         header.ICMPv6Type
   809  		size        int
   810  		statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
   811  		payloadSize int
   812  		payload     func(buffer.View)
   813  	}{
   814  		{
   815  			"DstUnreachable",
   816  			header.ICMPv6DstUnreachable,
   817  			header.ICMPv6DstUnreachableMinimumSize,
   818  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   819  				return stats.DstUnreachable
   820  			},
   821  			errorICMPBodySize,
   822  			errorICMPBody,
   823  		},
   824  		{
   825  			"PacketTooBig",
   826  			header.ICMPv6PacketTooBig,
   827  			header.ICMPv6PacketTooBigMinimumSize,
   828  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   829  				return stats.PacketTooBig
   830  			},
   831  			errorICMPBodySize,
   832  			errorICMPBody,
   833  		},
   834  		{
   835  			"TimeExceeded",
   836  			header.ICMPv6TimeExceeded,
   837  			header.ICMPv6MinimumSize,
   838  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   839  				return stats.TimeExceeded
   840  			},
   841  			errorICMPBodySize,
   842  			errorICMPBody,
   843  		},
   844  		{
   845  			"ParamProblem",
   846  			header.ICMPv6ParamProblem,
   847  			header.ICMPv6MinimumSize,
   848  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   849  				return stats.ParamProblem
   850  			},
   851  			errorICMPBodySize,
   852  			errorICMPBody,
   853  		},
   854  		{
   855  			"EchoRequest",
   856  			header.ICMPv6EchoRequest,
   857  			header.ICMPv6EchoMinimumSize,
   858  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   859  				return stats.EchoRequest
   860  			},
   861  			simpleBodySize,
   862  			simpleBody,
   863  		},
   864  		{
   865  			"EchoReply",
   866  			header.ICMPv6EchoReply,
   867  			header.ICMPv6EchoMinimumSize,
   868  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   869  				return stats.EchoReply
   870  			},
   871  			simpleBodySize,
   872  			simpleBody,
   873  		},
   874  	}
   875  
   876  	for _, typ := range types {
   877  		t.Run(typ.name, func(t *testing.T) {
   878  			e := channel.New(10, 1280, linkAddr0)
   879  			s := stack.New(stack.Options{
   880  				NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
   881  			})
   882  			if err := s.CreateNIC(nicID, e); err != nil {
   883  				t.Fatalf("CreateNIC(_, _) = %s", err)
   884  			}
   885  
   886  			if err := s.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
   887  				t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, lladdr0, err)
   888  			}
   889  			{
   890  				subnet, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
   891  				if err != nil {
   892  					t.Fatal(err)
   893  				}
   894  				s.SetRouteTable(
   895  					[]tcpip.Route{{
   896  						Destination: subnet,
   897  						NIC:         nicID,
   898  					}},
   899  				)
   900  			}
   901  
   902  			handleIPv6Payload := func(typ header.ICMPv6Type, size, payloadSize int, payloadFn func(buffer.View), checksum bool) {
   903  				icmpSize := size + payloadSize
   904  				hdr := buffer.NewPrependable(header.IPv6MinimumSize + icmpSize)
   905  				icmpHdr := header.ICMPv6(hdr.Prepend(icmpSize))
   906  				icmpHdr.SetType(typ)
   907  				payloadFn(icmpHdr.Payload())
   908  
   909  				if checksum {
   910  					icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
   911  						Header: icmpHdr,
   912  						Src:    lladdr1,
   913  						Dst:    lladdr0,
   914  					}))
   915  				}
   916  
   917  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   918  				ip.Encode(&header.IPv6Fields{
   919  					PayloadLength:     uint16(icmpSize),
   920  					TransportProtocol: header.ICMPv6ProtocolNumber,
   921  					HopLimit:          header.NDPHopLimit,
   922  					SrcAddr:           lladdr1,
   923  					DstAddr:           lladdr0,
   924  				})
   925  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   926  					Data: hdr.View().ToVectorisedView(),
   927  				})
   928  				e.InjectInbound(ProtocolNumber, pkt)
   929  			}
   930  
   931  			stats := s.Stats().ICMP.V6.PacketsReceived
   932  			invalid := stats.Invalid
   933  			typStat := typ.statCounter(stats)
   934  
   935  			// Initial stat counts should be 0.
   936  			if got := invalid.Value(); got != 0 {
   937  				t.Fatalf("got invalid = %d, want = 0", got)
   938  			}
   939  			if got := typStat.Value(); got != 0 {
   940  				t.Fatalf("got = %d, want = 0", got)
   941  			}
   942  
   943  			// Without setting checksum, the incoming packet should
   944  			// be invalid.
   945  			handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, false)
   946  			if got := invalid.Value(); got != 1 {
   947  				t.Fatalf("got invalid = %d, want = 1", got)
   948  			}
   949  			// Rx count of type typ.typ should not have increased.
   950  			if got := typStat.Value(); got != 0 {
   951  				t.Fatalf("got = %d, want = 0", got)
   952  			}
   953  
   954  			// When checksum is set, it should be received.
   955  			handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, true)
   956  			if got := typStat.Value(); got != 1 {
   957  				t.Fatalf("got = %d, want = 0", got)
   958  			}
   959  			// Invalid count should not have increased again.
   960  			if got := invalid.Value(); got != 1 {
   961  				t.Fatalf("got invalid = %d, want = 1", got)
   962  			}
   963  		})
   964  	}
   965  }
   966  
   967  func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) {
   968  	const simpleBodySize = 64
   969  	simpleBody := func(view buffer.View) {
   970  		for i := 0; i < simpleBodySize; i++ {
   971  			view[i] = uint8(i)
   972  		}
   973  	}
   974  
   975  	const errorICMPBodySize = header.IPv6MinimumSize + simpleBodySize
   976  	errorICMPBody := func(view buffer.View) {
   977  		ip := header.IPv6(view)
   978  		ip.Encode(&header.IPv6Fields{
   979  			PayloadLength:     simpleBodySize,
   980  			TransportProtocol: 10,
   981  			HopLimit:          20,
   982  			SrcAddr:           lladdr0,
   983  			DstAddr:           lladdr1,
   984  		})
   985  		simpleBody(view[header.IPv6MinimumSize:])
   986  	}
   987  
   988  	types := []struct {
   989  		name        string
   990  		typ         header.ICMPv6Type
   991  		size        int
   992  		statCounter func(tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
   993  		payloadSize int
   994  		payload     func(buffer.View)
   995  	}{
   996  		{
   997  			"DstUnreachable",
   998  			header.ICMPv6DstUnreachable,
   999  			header.ICMPv6DstUnreachableMinimumSize,
  1000  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
  1001  				return stats.DstUnreachable
  1002  			},
  1003  			errorICMPBodySize,
  1004  			errorICMPBody,
  1005  		},
  1006  		{
  1007  			"PacketTooBig",
  1008  			header.ICMPv6PacketTooBig,
  1009  			header.ICMPv6PacketTooBigMinimumSize,
  1010  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
  1011  				return stats.PacketTooBig
  1012  			},
  1013  			errorICMPBodySize,
  1014  			errorICMPBody,
  1015  		},
  1016  		{
  1017  			"TimeExceeded",
  1018  			header.ICMPv6TimeExceeded,
  1019  			header.ICMPv6MinimumSize,
  1020  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
  1021  				return stats.TimeExceeded
  1022  			},
  1023  			errorICMPBodySize,
  1024  			errorICMPBody,
  1025  		},
  1026  		{
  1027  			"ParamProblem",
  1028  			header.ICMPv6ParamProblem,
  1029  			header.ICMPv6MinimumSize,
  1030  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
  1031  				return stats.ParamProblem
  1032  			},
  1033  			errorICMPBodySize,
  1034  			errorICMPBody,
  1035  		},
  1036  		{
  1037  			"EchoRequest",
  1038  			header.ICMPv6EchoRequest,
  1039  			header.ICMPv6EchoMinimumSize,
  1040  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
  1041  				return stats.EchoRequest
  1042  			},
  1043  			simpleBodySize,
  1044  			simpleBody,
  1045  		},
  1046  		{
  1047  			"EchoReply",
  1048  			header.ICMPv6EchoReply,
  1049  			header.ICMPv6EchoMinimumSize,
  1050  			func(stats tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
  1051  				return stats.EchoReply
  1052  			},
  1053  			simpleBodySize,
  1054  			simpleBody,
  1055  		},
  1056  	}
  1057  
  1058  	for _, typ := range types {
  1059  		t.Run(typ.name, func(t *testing.T) {
  1060  			e := channel.New(10, 1280, linkAddr0)
  1061  			s := stack.New(stack.Options{
  1062  				NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
  1063  			})
  1064  			if err := s.CreateNIC(nicID, e); err != nil {
  1065  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  1066  			}
  1067  
  1068  			if err := s.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
  1069  				t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, ProtocolNumber, lladdr0, err)
  1070  			}
  1071  			{
  1072  				subnet, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
  1073  				if err != nil {
  1074  					t.Fatal(err)
  1075  				}
  1076  				s.SetRouteTable(
  1077  					[]tcpip.Route{{
  1078  						Destination: subnet,
  1079  						NIC:         nicID,
  1080  					}},
  1081  				)
  1082  			}
  1083  
  1084  			handleIPv6Payload := func(typ header.ICMPv6Type, size, payloadSize int, payloadFn func(buffer.View), checksum bool) {
  1085  				hdr := buffer.NewPrependable(header.IPv6MinimumSize + size)
  1086  				icmpHdr := header.ICMPv6(hdr.Prepend(size))
  1087  				icmpHdr.SetType(typ)
  1088  
  1089  				payload := buffer.NewView(payloadSize)
  1090  				payloadFn(payload)
  1091  
  1092  				if checksum {
  1093  					icmpHdr.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  1094  						Header:      icmpHdr,
  1095  						Src:         lladdr1,
  1096  						Dst:         lladdr0,
  1097  						PayloadCsum: header.Checksum(payload, 0 /* initial */),
  1098  						PayloadLen:  len(payload),
  1099  					}))
  1100  				}
  1101  
  1102  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1103  				ip.Encode(&header.IPv6Fields{
  1104  					PayloadLength:     uint16(size + payloadSize),
  1105  					TransportProtocol: header.ICMPv6ProtocolNumber,
  1106  					HopLimit:          header.NDPHopLimit,
  1107  					SrcAddr:           lladdr1,
  1108  					DstAddr:           lladdr0,
  1109  				})
  1110  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  1111  					Data: buffer.NewVectorisedView(header.IPv6MinimumSize+size+payloadSize, []buffer.View{hdr.View(), payload}),
  1112  				})
  1113  				e.InjectInbound(ProtocolNumber, pkt)
  1114  			}
  1115  
  1116  			stats := s.Stats().ICMP.V6.PacketsReceived
  1117  			invalid := stats.Invalid
  1118  			typStat := typ.statCounter(stats)
  1119  
  1120  			// Initial stat counts should be 0.
  1121  			if got := invalid.Value(); got != 0 {
  1122  				t.Fatalf("got invalid = %d, want = 0", got)
  1123  			}
  1124  			if got := typStat.Value(); got != 0 {
  1125  				t.Fatalf("got = %d, want = 0", got)
  1126  			}
  1127  
  1128  			// Without setting checksum, the incoming packet should
  1129  			// be invalid.
  1130  			handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, false)
  1131  			if got := invalid.Value(); got != 1 {
  1132  				t.Fatalf("got invalid = %d, want = 1", got)
  1133  			}
  1134  			// Rx count of type typ.typ should not have increased.
  1135  			if got := typStat.Value(); got != 0 {
  1136  				t.Fatalf("got = %d, want = 0", got)
  1137  			}
  1138  
  1139  			// When checksum is set, it should be received.
  1140  			handleIPv6Payload(typ.typ, typ.size, typ.payloadSize, typ.payload, true)
  1141  			if got := typStat.Value(); got != 1 {
  1142  				t.Fatalf("got = %d, want = 0", got)
  1143  			}
  1144  			// Invalid count should not have increased again.
  1145  			if got := invalid.Value(); got != 1 {
  1146  				t.Fatalf("got invalid = %d, want = 1", got)
  1147  			}
  1148  		})
  1149  	}
  1150  }
  1151  
  1152  func TestLinkAddressRequest(t *testing.T) {
  1153  	const nicID = 1
  1154  
  1155  	snaddr := header.SolicitedNodeAddr(lladdr0)
  1156  	mcaddr := header.EthernetAddressFromMulticastIPv6Address(snaddr)
  1157  
  1158  	tests := []struct {
  1159  		name           string
  1160  		nicAddr        tcpip.Address
  1161  		localAddr      tcpip.Address
  1162  		remoteLinkAddr tcpip.LinkAddress
  1163  
  1164  		expectedErr            tcpip.Error
  1165  		expectedRemoteAddr     tcpip.Address
  1166  		expectedRemoteLinkAddr tcpip.LinkAddress
  1167  	}{
  1168  		{
  1169  			name:                   "Unicast",
  1170  			nicAddr:                lladdr1,
  1171  			localAddr:              lladdr1,
  1172  			remoteLinkAddr:         linkAddr1,
  1173  			expectedRemoteAddr:     lladdr0,
  1174  			expectedRemoteLinkAddr: linkAddr1,
  1175  		},
  1176  		{
  1177  			name:                   "Multicast",
  1178  			nicAddr:                lladdr1,
  1179  			localAddr:              lladdr1,
  1180  			remoteLinkAddr:         "",
  1181  			expectedRemoteAddr:     snaddr,
  1182  			expectedRemoteLinkAddr: mcaddr,
  1183  		},
  1184  		{
  1185  			name:                   "Unicast with unspecified source",
  1186  			nicAddr:                lladdr1,
  1187  			remoteLinkAddr:         linkAddr1,
  1188  			expectedRemoteAddr:     lladdr0,
  1189  			expectedRemoteLinkAddr: linkAddr1,
  1190  		},
  1191  		{
  1192  			name:                   "Multicast with unspecified source",
  1193  			nicAddr:                lladdr1,
  1194  			remoteLinkAddr:         "",
  1195  			expectedRemoteAddr:     snaddr,
  1196  			expectedRemoteLinkAddr: mcaddr,
  1197  		},
  1198  		{
  1199  			name:           "Unicast with unassigned address",
  1200  			localAddr:      lladdr1,
  1201  			remoteLinkAddr: linkAddr1,
  1202  			expectedErr:    &tcpip.ErrBadLocalAddress{},
  1203  		},
  1204  		{
  1205  			name:           "Multicast with unassigned address",
  1206  			localAddr:      lladdr1,
  1207  			remoteLinkAddr: "",
  1208  			expectedErr:    &tcpip.ErrBadLocalAddress{},
  1209  		},
  1210  		{
  1211  			name:           "Unicast with no local address available",
  1212  			remoteLinkAddr: linkAddr1,
  1213  			expectedErr:    &tcpip.ErrNetworkUnreachable{},
  1214  		},
  1215  		{
  1216  			name:           "Multicast with no local address available",
  1217  			remoteLinkAddr: "",
  1218  			expectedErr:    &tcpip.ErrNetworkUnreachable{},
  1219  		},
  1220  	}
  1221  
  1222  	for _, test := range tests {
  1223  		t.Run(test.name, func(t *testing.T) {
  1224  			s := stack.New(stack.Options{
  1225  				NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
  1226  			})
  1227  
  1228  			linkEP := channel.New(defaultChannelSize, defaultMTU, linkAddr0)
  1229  			if err := s.CreateNIC(nicID, linkEP); err != nil {
  1230  				t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  1231  			}
  1232  
  1233  			ep, err := s.GetNetworkEndpoint(nicID, ProtocolNumber)
  1234  			if err != nil {
  1235  				t.Fatalf("s.GetNetworkEndpoint(%d, %d): %s", nicID, ProtocolNumber, err)
  1236  			}
  1237  			linkRes, ok := ep.(stack.LinkAddressResolver)
  1238  			if !ok {
  1239  				t.Fatalf("expected %T to implement stack.LinkAddressResolver", ep)
  1240  			}
  1241  
  1242  			if len(test.nicAddr) != 0 {
  1243  				if err := s.AddAddress(nicID, ProtocolNumber, test.nicAddr); err != nil {
  1244  					t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, ProtocolNumber, test.nicAddr, err)
  1245  				}
  1246  			}
  1247  
  1248  			{
  1249  				err := linkRes.LinkAddressRequest(lladdr0, test.localAddr, test.remoteLinkAddr)
  1250  				if diff := cmp.Diff(test.expectedErr, err); diff != "" {
  1251  					t.Fatalf("unexpected error from p.LinkAddressRequest(%s, %s, %s, _), (-want, +got):\n%s", lladdr0, test.localAddr, test.remoteLinkAddr, diff)
  1252  				}
  1253  			}
  1254  
  1255  			if test.expectedErr != nil {
  1256  				return
  1257  			}
  1258  
  1259  			pkt, ok := linkEP.Read()
  1260  			if !ok {
  1261  				t.Fatal("expected to send a link address request")
  1262  			}
  1263  
  1264  			var want stack.RouteInfo
  1265  			want.NetProto = ProtocolNumber
  1266  			want.RemoteLinkAddress = test.expectedRemoteLinkAddr
  1267  			if diff := cmp.Diff(want, pkt.Route, cmp.AllowUnexported(want)); diff != "" {
  1268  				t.Errorf("route info mismatch (-want +got):\n%s", diff)
  1269  			}
  1270  			checker.IPv6(t, stack.PayloadSince(pkt.Pkt.NetworkHeader()),
  1271  				checker.SrcAddr(lladdr1),
  1272  				checker.DstAddr(test.expectedRemoteAddr),
  1273  				checker.TTL(header.NDPHopLimit),
  1274  				checker.NDPNS(
  1275  					checker.NDPNSTargetAddress(lladdr0),
  1276  					checker.NDPNSOptions([]header.NDPOption{header.NDPSourceLinkLayerAddressOption(linkAddr0)}),
  1277  				))
  1278  		})
  1279  	}
  1280  }
  1281  
  1282  func TestPacketQueing(t *testing.T) {
  1283  	const nicID = 1
  1284  
  1285  	var (
  1286  		host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
  1287  		host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
  1288  
  1289  		host1IPv6Addr = tcpip.ProtocolAddress{
  1290  			Protocol: ProtocolNumber,
  1291  			AddressWithPrefix: tcpip.AddressWithPrefix{
  1292  				Address:   tcpip.Address(net.ParseIP("a::1").To16()),
  1293  				PrefixLen: 64,
  1294  			},
  1295  		}
  1296  		host2IPv6Addr = tcpip.ProtocolAddress{
  1297  			Protocol: ProtocolNumber,
  1298  			AddressWithPrefix: tcpip.AddressWithPrefix{
  1299  				Address:   tcpip.Address(net.ParseIP("a::2").To16()),
  1300  				PrefixLen: 64,
  1301  			},
  1302  		}
  1303  	)
  1304  
  1305  	tests := []struct {
  1306  		name      string
  1307  		rxPkt     func(*channel.Endpoint)
  1308  		checkResp func(*testing.T, *channel.Endpoint)
  1309  	}{
  1310  		{
  1311  			name: "ICMP Error",
  1312  			rxPkt: func(e *channel.Endpoint) {
  1313  				hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.UDPMinimumSize)
  1314  				u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
  1315  				u.Encode(&header.UDPFields{
  1316  					SrcPort: 5555,
  1317  					DstPort: 80,
  1318  					Length:  header.UDPMinimumSize,
  1319  				})
  1320  				sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, header.UDPMinimumSize)
  1321  				sum = header.Checksum(nil, sum)
  1322  				u.SetChecksum(^u.CalculateChecksum(sum))
  1323  				payloadLength := hdr.UsedLength()
  1324  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1325  				ip.Encode(&header.IPv6Fields{
  1326  					PayloadLength:     uint16(payloadLength),
  1327  					TransportProtocol: udp.ProtocolNumber,
  1328  					HopLimit:          DefaultTTL,
  1329  					SrcAddr:           host2IPv6Addr.AddressWithPrefix.Address,
  1330  					DstAddr:           host1IPv6Addr.AddressWithPrefix.Address,
  1331  				})
  1332  				e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
  1333  					Data: hdr.View().ToVectorisedView(),
  1334  				}))
  1335  			},
  1336  			checkResp: func(t *testing.T, e *channel.Endpoint) {
  1337  				p, ok := e.Read()
  1338  				if !ok {
  1339  					t.Fatalf("timed out waiting for packet")
  1340  				}
  1341  				if p.Proto != ProtocolNumber {
  1342  					t.Errorf("got p.Proto = %d, want = %d", p.Proto, ProtocolNumber)
  1343  				}
  1344  				if p.Route.RemoteLinkAddress != host2NICLinkAddr {
  1345  					t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, host2NICLinkAddr)
  1346  				}
  1347  				checker.IPv6(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
  1348  					checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
  1349  					checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address),
  1350  					checker.ICMPv6(
  1351  						checker.ICMPv6Type(header.ICMPv6DstUnreachable),
  1352  						checker.ICMPv6Code(header.ICMPv6PortUnreachable)))
  1353  			},
  1354  		},
  1355  
  1356  		{
  1357  			name: "Ping",
  1358  			rxPkt: func(e *channel.Endpoint) {
  1359  				totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize
  1360  				hdr := buffer.NewPrependable(totalLen)
  1361  				pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize))
  1362  				pkt.SetType(header.ICMPv6EchoRequest)
  1363  				pkt.SetCode(0)
  1364  				pkt.SetChecksum(0)
  1365  				pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  1366  					Header: pkt,
  1367  					Src:    host2IPv6Addr.AddressWithPrefix.Address,
  1368  					Dst:    host1IPv6Addr.AddressWithPrefix.Address,
  1369  				}))
  1370  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1371  				ip.Encode(&header.IPv6Fields{
  1372  					PayloadLength:     header.ICMPv6MinimumSize,
  1373  					TransportProtocol: icmp.ProtocolNumber6,
  1374  					HopLimit:          DefaultTTL,
  1375  					SrcAddr:           host2IPv6Addr.AddressWithPrefix.Address,
  1376  					DstAddr:           host1IPv6Addr.AddressWithPrefix.Address,
  1377  				})
  1378  				e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
  1379  					Data: hdr.View().ToVectorisedView(),
  1380  				}))
  1381  			},
  1382  			checkResp: func(t *testing.T, e *channel.Endpoint) {
  1383  				p, ok := e.Read()
  1384  				if !ok {
  1385  					t.Fatalf("timed out waiting for packet")
  1386  				}
  1387  				if p.Proto != ProtocolNumber {
  1388  					t.Errorf("got p.Proto = %d, want = %d", p.Proto, ProtocolNumber)
  1389  				}
  1390  				if p.Route.RemoteLinkAddress != host2NICLinkAddr {
  1391  					t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, host2NICLinkAddr)
  1392  				}
  1393  				checker.IPv6(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
  1394  					checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
  1395  					checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address),
  1396  					checker.ICMPv6(
  1397  						checker.ICMPv6Type(header.ICMPv6EchoReply),
  1398  						checker.ICMPv6Code(header.ICMPv6UnusedCode)))
  1399  			},
  1400  		},
  1401  	}
  1402  
  1403  	for _, test := range tests {
  1404  		t.Run(test.name, func(t *testing.T) {
  1405  
  1406  			e := channel.New(1, header.IPv6MinimumMTU, host1NICLinkAddr)
  1407  			e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
  1408  			clock := faketime.NewManualClock()
  1409  			s := stack.New(stack.Options{
  1410  				NetworkProtocols:   []stack.NetworkProtocolFactory{NewProtocol},
  1411  				TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
  1412  				Clock:              clock,
  1413  			})
  1414  
  1415  			if err := s.CreateNIC(nicID, e); err != nil {
  1416  				t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  1417  			}
  1418  			if err := s.AddProtocolAddress(nicID, host1IPv6Addr); err != nil {
  1419  				t.Fatalf("s.AddProtocolAddress(%d, %#v): %s", nicID, host1IPv6Addr, err)
  1420  			}
  1421  
  1422  			s.SetRouteTable([]tcpip.Route{
  1423  				{
  1424  					Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
  1425  					NIC:         nicID,
  1426  				},
  1427  			})
  1428  
  1429  			// Receive a packet to trigger link resolution before a response is sent.
  1430  			test.rxPkt(e)
  1431  
  1432  			// Wait for a neighbor solicitation since link address resolution should
  1433  			// be performed.
  1434  			{
  1435  				clock.RunImmediatelyScheduledJobs()
  1436  				p, ok := e.Read()
  1437  				if !ok {
  1438  					t.Fatalf("timed out waiting for packet")
  1439  				}
  1440  				if p.Proto != ProtocolNumber {
  1441  					t.Errorf("got Proto = %d, want = %d", p.Proto, ProtocolNumber)
  1442  				}
  1443  				snmc := header.SolicitedNodeAddr(host2IPv6Addr.AddressWithPrefix.Address)
  1444  				if want := header.EthernetAddressFromMulticastIPv6Address(snmc); p.Route.RemoteLinkAddress != want {
  1445  					t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, want)
  1446  				}
  1447  				checker.IPv6(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
  1448  					checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
  1449  					checker.DstAddr(snmc),
  1450  					checker.TTL(header.NDPHopLimit),
  1451  					checker.NDPNS(
  1452  						checker.NDPNSTargetAddress(host2IPv6Addr.AddressWithPrefix.Address),
  1453  						checker.NDPNSOptions([]header.NDPOption{header.NDPSourceLinkLayerAddressOption(host1NICLinkAddr)}),
  1454  					))
  1455  			}
  1456  
  1457  			// Send a neighbor advertisement to complete link address resolution.
  1458  			{
  1459  				naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize
  1460  				hdr := buffer.NewPrependable(header.IPv6MinimumSize + naSize)
  1461  				pkt := header.ICMPv6(hdr.Prepend(naSize))
  1462  				pkt.SetType(header.ICMPv6NeighborAdvert)
  1463  				na := header.NDPNeighborAdvert(pkt.MessageBody())
  1464  				na.SetSolicitedFlag(true)
  1465  				na.SetOverrideFlag(true)
  1466  				na.SetTargetAddress(host2IPv6Addr.AddressWithPrefix.Address)
  1467  				na.Options().Serialize(header.NDPOptionsSerializer{
  1468  					header.NDPTargetLinkLayerAddressOption(host2NICLinkAddr),
  1469  				})
  1470  				pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  1471  					Header: pkt,
  1472  					Src:    host2IPv6Addr.AddressWithPrefix.Address,
  1473  					Dst:    host1IPv6Addr.AddressWithPrefix.Address,
  1474  				}))
  1475  				payloadLength := hdr.UsedLength()
  1476  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1477  				ip.Encode(&header.IPv6Fields{
  1478  					PayloadLength:     uint16(payloadLength),
  1479  					TransportProtocol: icmp.ProtocolNumber6,
  1480  					HopLimit:          header.NDPHopLimit,
  1481  					SrcAddr:           host2IPv6Addr.AddressWithPrefix.Address,
  1482  					DstAddr:           host1IPv6Addr.AddressWithPrefix.Address,
  1483  				})
  1484  				e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
  1485  					Data: hdr.View().ToVectorisedView(),
  1486  				}))
  1487  			}
  1488  
  1489  			// Expect the response now that the link address has resolved.
  1490  			clock.RunImmediatelyScheduledJobs()
  1491  			test.checkResp(t, e)
  1492  
  1493  			// Since link resolution was already performed, it shouldn't be performed
  1494  			// again.
  1495  			test.rxPkt(e)
  1496  			test.checkResp(t, e)
  1497  		})
  1498  	}
  1499  }
  1500  
  1501  func TestCallsToNeighborCache(t *testing.T) {
  1502  	tests := []struct {
  1503  		name                  string
  1504  		createPacket          func() header.ICMPv6
  1505  		multicast             bool
  1506  		source                tcpip.Address
  1507  		destination           tcpip.Address
  1508  		wantProbeCount        int
  1509  		wantConfirmationCount int
  1510  	}{
  1511  		{
  1512  			name: "Unicast Neighbor Solicitation without source link-layer address option",
  1513  			createPacket: func() header.ICMPv6 {
  1514  				nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize
  1515  				icmp := header.ICMPv6(buffer.NewView(nsSize))
  1516  				icmp.SetType(header.ICMPv6NeighborSolicit)
  1517  				ns := header.NDPNeighborSolicit(icmp.MessageBody())
  1518  				ns.SetTargetAddress(lladdr0)
  1519  				return icmp
  1520  			},
  1521  			source:      lladdr1,
  1522  			destination: lladdr0,
  1523  			// "The source link-layer address option SHOULD be included in unicast
  1524  			//  solicitations." - RFC 4861 section 4.3
  1525  			//
  1526  			// A Neighbor Advertisement needs to be sent in response, but the
  1527  			// Neighbor Cache shouldn't be updated since we have no useful
  1528  			// information about the sender.
  1529  			wantProbeCount: 0,
  1530  		},
  1531  		{
  1532  			name: "Unicast Neighbor Solicitation with source link-layer address option",
  1533  			createPacket: func() header.ICMPv6 {
  1534  				nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize
  1535  				icmp := header.ICMPv6(buffer.NewView(nsSize))
  1536  				icmp.SetType(header.ICMPv6NeighborSolicit)
  1537  				ns := header.NDPNeighborSolicit(icmp.MessageBody())
  1538  				ns.SetTargetAddress(lladdr0)
  1539  				ns.Options().Serialize(header.NDPOptionsSerializer{
  1540  					header.NDPSourceLinkLayerAddressOption(linkAddr1),
  1541  				})
  1542  				return icmp
  1543  			},
  1544  			source:         lladdr1,
  1545  			destination:    lladdr0,
  1546  			wantProbeCount: 1,
  1547  		},
  1548  		{
  1549  			name: "Multicast Neighbor Solicitation without source link-layer address option",
  1550  			createPacket: func() header.ICMPv6 {
  1551  				nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize
  1552  				icmp := header.ICMPv6(buffer.NewView(nsSize))
  1553  				icmp.SetType(header.ICMPv6NeighborSolicit)
  1554  				ns := header.NDPNeighborSolicit(icmp.MessageBody())
  1555  				ns.SetTargetAddress(lladdr0)
  1556  				return icmp
  1557  			},
  1558  			source:      lladdr1,
  1559  			destination: header.SolicitedNodeAddr(lladdr0),
  1560  			// "The source link-layer address option MUST be included in multicast
  1561  			//  solicitations." - RFC 4861 section 4.3
  1562  			wantProbeCount: 0,
  1563  		},
  1564  		{
  1565  			name: "Multicast Neighbor Solicitation with source link-layer address option",
  1566  			createPacket: func() header.ICMPv6 {
  1567  				nsSize := header.ICMPv6NeighborSolicitMinimumSize + header.NDPLinkLayerAddressSize
  1568  				icmp := header.ICMPv6(buffer.NewView(nsSize))
  1569  				icmp.SetType(header.ICMPv6NeighborSolicit)
  1570  				ns := header.NDPNeighborSolicit(icmp.MessageBody())
  1571  				ns.SetTargetAddress(lladdr0)
  1572  				ns.Options().Serialize(header.NDPOptionsSerializer{
  1573  					header.NDPSourceLinkLayerAddressOption(linkAddr1),
  1574  				})
  1575  				return icmp
  1576  			},
  1577  			source:         lladdr1,
  1578  			destination:    header.SolicitedNodeAddr(lladdr0),
  1579  			wantProbeCount: 1,
  1580  		},
  1581  		{
  1582  			name: "Unicast Neighbor Advertisement without target link-layer address option",
  1583  			createPacket: func() header.ICMPv6 {
  1584  				naSize := header.ICMPv6NeighborAdvertMinimumSize
  1585  				icmp := header.ICMPv6(buffer.NewView(naSize))
  1586  				icmp.SetType(header.ICMPv6NeighborAdvert)
  1587  				na := header.NDPNeighborAdvert(icmp.MessageBody())
  1588  				na.SetSolicitedFlag(true)
  1589  				na.SetOverrideFlag(false)
  1590  				na.SetTargetAddress(lladdr1)
  1591  				return icmp
  1592  			},
  1593  			source:      lladdr1,
  1594  			destination: lladdr0,
  1595  			// "When responding to unicast solicitations, the target link-layer
  1596  			//  address option can be omitted since the sender of the solicitation has
  1597  			//  the correct link-layer address; otherwise, it would not be able to
  1598  			//  send the unicast solicitation in the first place."
  1599  			//   - RFC 4861 section 4.4
  1600  			wantConfirmationCount: 1,
  1601  		},
  1602  		{
  1603  			name: "Unicast Neighbor Advertisement with target link-layer address option",
  1604  			createPacket: func() header.ICMPv6 {
  1605  				naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize
  1606  				icmp := header.ICMPv6(buffer.NewView(naSize))
  1607  				icmp.SetType(header.ICMPv6NeighborAdvert)
  1608  				na := header.NDPNeighborAdvert(icmp.MessageBody())
  1609  				na.SetSolicitedFlag(true)
  1610  				na.SetOverrideFlag(false)
  1611  				na.SetTargetAddress(lladdr1)
  1612  				na.Options().Serialize(header.NDPOptionsSerializer{
  1613  					header.NDPTargetLinkLayerAddressOption(linkAddr1),
  1614  				})
  1615  				return icmp
  1616  			},
  1617  			source:                lladdr1,
  1618  			destination:           lladdr0,
  1619  			wantConfirmationCount: 1,
  1620  		},
  1621  		{
  1622  			name: "Multicast Neighbor Advertisement without target link-layer address option",
  1623  			createPacket: func() header.ICMPv6 {
  1624  				naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize
  1625  				icmp := header.ICMPv6(buffer.NewView(naSize))
  1626  				icmp.SetType(header.ICMPv6NeighborAdvert)
  1627  				na := header.NDPNeighborAdvert(icmp.MessageBody())
  1628  				na.SetSolicitedFlag(false)
  1629  				na.SetOverrideFlag(false)
  1630  				na.SetTargetAddress(lladdr1)
  1631  				return icmp
  1632  			},
  1633  			source:      lladdr1,
  1634  			destination: header.IPv6AllNodesMulticastAddress,
  1635  			// "Target link-layer address MUST be included for multicast solicitations
  1636  			//  in order to avoid infinite Neighbor Solicitation "recursion" when the
  1637  			//  peer node does not have a cache entry to return a Neighbor
  1638  			//  Advertisements message." - RFC 4861 section 4.4
  1639  			wantConfirmationCount: 0,
  1640  		},
  1641  		{
  1642  			name: "Multicast Neighbor Advertisement with target link-layer address option",
  1643  			createPacket: func() header.ICMPv6 {
  1644  				naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize
  1645  				icmp := header.ICMPv6(buffer.NewView(naSize))
  1646  				icmp.SetType(header.ICMPv6NeighborAdvert)
  1647  				na := header.NDPNeighborAdvert(icmp.MessageBody())
  1648  				na.SetSolicitedFlag(false)
  1649  				na.SetOverrideFlag(false)
  1650  				na.SetTargetAddress(lladdr1)
  1651  				na.Options().Serialize(header.NDPOptionsSerializer{
  1652  					header.NDPTargetLinkLayerAddressOption(linkAddr1),
  1653  				})
  1654  				return icmp
  1655  			},
  1656  			source:                lladdr1,
  1657  			destination:           header.IPv6AllNodesMulticastAddress,
  1658  			wantConfirmationCount: 1,
  1659  		},
  1660  	}
  1661  
  1662  	for _, test := range tests {
  1663  		t.Run(test.name, func(t *testing.T) {
  1664  			s := stack.New(stack.Options{
  1665  				NetworkProtocols:   []stack.NetworkProtocolFactory{NewProtocol},
  1666  				TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol6},
  1667  			})
  1668  			{
  1669  				if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil {
  1670  					t.Fatalf("CreateNIC(_, _) = %s", err)
  1671  				}
  1672  				if err := s.AddAddress(nicID, ProtocolNumber, lladdr0); err != nil {
  1673  					t.Fatalf("AddAddress(_, %d, %s) = %s", ProtocolNumber, lladdr0, err)
  1674  				}
  1675  			}
  1676  			{
  1677  				subnet, err := tcpip.NewSubnet(lladdr1, tcpip.AddressMask(strings.Repeat("\xff", len(lladdr1))))
  1678  				if err != nil {
  1679  					t.Fatal(err)
  1680  				}
  1681  				s.SetRouteTable(
  1682  					[]tcpip.Route{{
  1683  						Destination: subnet,
  1684  						NIC:         nicID,
  1685  					}},
  1686  				)
  1687  			}
  1688  
  1689  			netProto := s.NetworkProtocolInstance(ProtocolNumber)
  1690  			if netProto == nil {
  1691  				t.Fatalf("cannot find protocol instance for network protocol %d", ProtocolNumber)
  1692  			}
  1693  
  1694  			testInterface := testInterface{LinkEndpoint: channel.New(0, header.IPv6MinimumMTU, linkAddr0)}
  1695  			ep := netProto.NewEndpoint(&testInterface, &stubDispatcher{})
  1696  			defer ep.Close()
  1697  
  1698  			if err := ep.Enable(); err != nil {
  1699  				t.Fatalf("ep.Enable(): %s", err)
  1700  			}
  1701  
  1702  			addressableEndpoint, ok := ep.(stack.AddressableEndpoint)
  1703  			if !ok {
  1704  				t.Fatalf("expected network endpoint to implement stack.AddressableEndpoint")
  1705  			}
  1706  			addr := lladdr0.WithPrefix()
  1707  			if ep, err := addressableEndpoint.AddAndAcquirePermanentAddress(addr, stack.CanBePrimaryEndpoint, stack.AddressConfigStatic, false /* deprecated */); err != nil {
  1708  				t.Fatalf("addressableEndpoint.AddAndAcquirePermanentAddress(%s, CanBePrimaryEndpoint, AddressConfigStatic, false): %s", addr, err)
  1709  			} else {
  1710  				ep.DecRef()
  1711  			}
  1712  
  1713  			icmp := test.createPacket()
  1714  			icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  1715  				Header: icmp,
  1716  				Src:    test.source,
  1717  				Dst:    test.destination,
  1718  			}))
  1719  			handleICMPInIPv6(ep, test.source, test.destination, icmp, header.NDPHopLimit, false)
  1720  
  1721  			// Confirm the endpoint calls the correct NUDHandler method.
  1722  			if testInterface.probeCount != test.wantProbeCount {
  1723  				t.Errorf("got testInterface.probeCount = %d, want = %d", testInterface.probeCount, test.wantProbeCount)
  1724  			}
  1725  			if testInterface.confirmationCount != test.wantConfirmationCount {
  1726  				t.Errorf("got testInterface.confirmationCount = %d, want = %d", testInterface.confirmationCount, test.wantConfirmationCount)
  1727  			}
  1728  		})
  1729  	}
  1730  }