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