gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/ipv6/ipv6_test.go (about)

     1  // Copyright 2019 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  	"encoding/hex"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"math"
    23  	"net"
    24  	"reflect"
    25  	"testing"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  	"gvisor.dev/gvisor/pkg/buffer"
    29  	"gvisor.dev/gvisor/pkg/sync"
    30  	"gvisor.dev/gvisor/pkg/tcpip"
    31  	"gvisor.dev/gvisor/pkg/tcpip/checker"
    32  	"gvisor.dev/gvisor/pkg/tcpip/checksum"
    33  	"gvisor.dev/gvisor/pkg/tcpip/header"
    34  	"gvisor.dev/gvisor/pkg/tcpip/link/channel"
    35  	iptestutil "gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil"
    36  	"gvisor.dev/gvisor/pkg/tcpip/prependable"
    37  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    38  	"gvisor.dev/gvisor/pkg/tcpip/testutil"
    39  	"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
    40  	"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
    41  	"gvisor.dev/gvisor/pkg/waiter"
    42  )
    43  
    44  var (
    45  	addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"))
    46  	addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"))
    47  	// The least significant 3 bytes are the same as addr2 so both addr2 and
    48  	// addr3 will have the same solicited-node address.
    49  	addr3 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x02"))
    50  	addr4 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x03"))
    51  )
    52  
    53  const (
    54  	// Tests use the extension header identifier values as uint8 instead of
    55  	// header.IPv6ExtensionHeaderIdentifier.
    56  	hopByHopExtHdrID    = uint8(header.IPv6HopByHopOptionsExtHdrIdentifier)
    57  	routingExtHdrID     = uint8(header.IPv6RoutingExtHdrIdentifier)
    58  	fragmentExtHdrID    = uint8(header.IPv6FragmentExtHdrIdentifier)
    59  	destinationExtHdrID = uint8(header.IPv6DestinationOptionsExtHdrIdentifier)
    60  	noNextHdrID         = uint8(header.IPv6NoNextHeaderIdentifier)
    61  	unknownHdrID        = uint8(header.IPv6UnknownExtHdrIdentifier)
    62  
    63  	extraHeaderReserve = 50
    64  )
    65  
    66  var _ stack.MulticastForwardingEventDispatcher = (*fakeMulticastEventDispatcher)(nil)
    67  
    68  type fakeMulticastEventDispatcher struct{}
    69  
    70  func (m *fakeMulticastEventDispatcher) OnMissingRoute(context stack.MulticastPacketContext) {}
    71  
    72  func (m *fakeMulticastEventDispatcher) OnUnexpectedInputInterface(context stack.MulticastPacketContext, expectedInputInterface tcpip.NICID) {
    73  }
    74  
    75  // testReceiveICMP tests receiving an ICMP packet from src to dst. want is the
    76  // expected Neighbor Advertisement received count after receiving the packet.
    77  func testReceiveICMP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) {
    78  	t.Helper()
    79  
    80  	// Receive ICMP packet.
    81  	hdr := prependable.New(header.IPv6MinimumSize + header.ICMPv6NeighborAdvertMinimumSize)
    82  	pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertMinimumSize))
    83  	pkt.SetType(header.ICMPv6NeighborAdvert)
    84  	pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
    85  		Header: pkt,
    86  		Src:    src,
    87  		Dst:    dst,
    88  	}))
    89  	payloadLength := hdr.UsedLength()
    90  	ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
    91  	ip.Encode(&header.IPv6Fields{
    92  		PayloadLength:     uint16(payloadLength),
    93  		TransportProtocol: header.ICMPv6ProtocolNumber,
    94  		HopLimit:          255,
    95  		SrcAddr:           src,
    96  		DstAddr:           dst,
    97  	})
    98  
    99  	pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
   100  		Payload: buffer.MakeWithData(hdr.View()),
   101  	})
   102  	e.InjectInbound(ProtocolNumber, pktBuf)
   103  	pktBuf.DecRef()
   104  
   105  	stats := s.Stats().ICMP.V6.PacketsReceived
   106  
   107  	if got := stats.NeighborAdvert.Value(); got != want {
   108  		t.Fatalf("got NeighborAdvert = %d, want = %d", got, want)
   109  	}
   110  }
   111  
   112  // testReceiveUDP tests receiving a UDP packet from src to dst. want is the
   113  // expected UDP received count after receiving the packet.
   114  func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64) {
   115  	t.Helper()
   116  
   117  	wq := waiter.Queue{}
   118  	we, ch := waiter.NewChannelEntry(waiter.ReadableEvents)
   119  	wq.EventRegister(&we)
   120  	defer wq.EventUnregister(&we)
   121  	defer close(ch)
   122  
   123  	ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq)
   124  	if err != nil {
   125  		t.Fatalf("NewEndpoint failed: %v", err)
   126  	}
   127  	defer ep.Close()
   128  
   129  	if err := ep.Bind(tcpip.FullAddress{Addr: dst, Port: 80}); err != nil {
   130  		t.Fatalf("ep.Bind(...) failed: %v", err)
   131  	}
   132  
   133  	// Receive UDP Packet.
   134  	hdr := prependable.New(header.IPv6MinimumSize + header.UDPMinimumSize)
   135  	u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
   136  	u.Encode(&header.UDPFields{
   137  		SrcPort: 5555,
   138  		DstPort: 80,
   139  		Length:  header.UDPMinimumSize,
   140  	})
   141  
   142  	// UDP pseudo-header checksum.
   143  	sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, header.UDPMinimumSize)
   144  
   145  	// UDP checksum
   146  	sum = checksum.Checksum(nil, sum)
   147  	u.SetChecksum(^u.CalculateChecksum(sum))
   148  
   149  	payloadLength := hdr.UsedLength()
   150  	ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   151  	ip.Encode(&header.IPv6Fields{
   152  		PayloadLength:     uint16(payloadLength),
   153  		TransportProtocol: udp.ProtocolNumber,
   154  		HopLimit:          255,
   155  		SrcAddr:           src,
   156  		DstAddr:           dst,
   157  	})
   158  
   159  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   160  		Payload: buffer.MakeWithData(hdr.View()),
   161  	})
   162  	e.InjectInbound(ProtocolNumber, pkt)
   163  	pkt.DecRef()
   164  
   165  	stat := s.Stats().UDP.PacketsReceived
   166  
   167  	if got := stat.Value(); got != want {
   168  		t.Fatalf("got UDPPacketsReceived = %d, want = %d", got, want)
   169  	}
   170  }
   171  
   172  func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketBuffer, mtu uint32, wantFragments []fragmentInfo, proto tcpip.TransportProtocolNumber) error {
   173  	// sourcePacket does not have its IP Header populated. Let's copy the one
   174  	// from the first fragment.
   175  	source := header.IPv6(packets[0].NetworkHeader().Slice())
   176  	sourceIPHeadersLen := len(source)
   177  	view := sourcePacket.ToView()
   178  	defer view.Release()
   179  	source = append(source, view.AsSlice()...)
   180  
   181  	var reassembledPayload buffer.Buffer
   182  	defer reassembledPayload.Release()
   183  	for i, fragment := range packets {
   184  		// Confirm that the packet is valid.
   185  		allBytes := fragment.ToBuffer()
   186  		defer allBytes.Release()
   187  		fragmentIPHeaders := header.IPv6(allBytes.Flatten())
   188  		if !fragmentIPHeaders.IsValid(len(fragmentIPHeaders)) {
   189  			return fmt.Errorf("fragment #%d: IP packet is invalid:\n%s", i, hex.Dump(fragmentIPHeaders))
   190  		}
   191  
   192  		fragmentIPHeadersLength := len(fragment.NetworkHeader().Slice())
   193  		if fragmentIPHeadersLength != sourceIPHeadersLen {
   194  			return fmt.Errorf("fragment #%d: got fragmentIPHeadersLength = %d, want = %d", i, fragmentIPHeadersLength, sourceIPHeadersLen)
   195  		}
   196  
   197  		if got := len(fragmentIPHeaders); got > int(mtu) {
   198  			return fmt.Errorf("fragment #%d: got len(fragmentIPHeaders) = %d, want <= %d", i, got, mtu)
   199  		}
   200  
   201  		sourceIPHeader := source[:header.IPv6MinimumSize]
   202  		fragmentIPHeader := fragmentIPHeaders[:header.IPv6MinimumSize]
   203  
   204  		if got := fragmentIPHeaders.PayloadLength(); got != wantFragments[i].payloadSize {
   205  			return fmt.Errorf("fragment #%d: got fragmentIPHeaders.PayloadLength() = %d, want = %d", i, got, wantFragments[i].payloadSize)
   206  		}
   207  
   208  		// We expect the IPv6 Header to be similar across each fragment, besides the
   209  		// payload length.
   210  		sourceIPHeader.SetPayloadLength(0)
   211  		fragmentIPHeader.SetPayloadLength(0)
   212  		if diff := cmp.Diff(fragmentIPHeader, sourceIPHeader); diff != "" {
   213  			return fmt.Errorf("fragment #%d: fragmentIPHeader mismatch (-want +got):\n%s", i, diff)
   214  		}
   215  
   216  		if got := fragment.AvailableHeaderBytes(); got != extraHeaderReserve {
   217  			return fmt.Errorf("fragment #%d: got packet.AvailableHeaderBytes() = %d, want = %d", i, got, extraHeaderReserve)
   218  		}
   219  		if fragment.NetworkProtocolNumber != sourcePacket.NetworkProtocolNumber {
   220  			return fmt.Errorf("fragment #%d: got fragment.NetworkProtocolNumber = %d, want = %d", i, fragment.NetworkProtocolNumber, sourcePacket.NetworkProtocolNumber)
   221  		}
   222  
   223  		if len(packets) > 1 {
   224  			// If the source packet was big enough that it needed fragmentation, let's
   225  			// inspect the fragment header. Because no other extension headers are
   226  			// supported, it will always be the last extension header.
   227  			fragmentHeader := header.IPv6Fragment(fragmentIPHeaders[fragmentIPHeadersLength-header.IPv6FragmentHeaderSize : fragmentIPHeadersLength])
   228  
   229  			if got := fragmentHeader.More(); got != wantFragments[i].more {
   230  				return fmt.Errorf("fragment #%d: got fragmentHeader.More() = %t, want = %t", i, got, wantFragments[i].more)
   231  			}
   232  			if got := fragmentHeader.FragmentOffset(); got != wantFragments[i].offset {
   233  				return fmt.Errorf("fragment #%d: got fragmentHeader.FragmentOffset() = %d, want = %d", i, got, wantFragments[i].offset)
   234  			}
   235  			if got := fragmentHeader.NextHeader(); got != uint8(proto) {
   236  				return fmt.Errorf("fragment #%d: got fragmentHeader.NextHeader() = %d, want = %d", i, got, uint8(proto))
   237  			}
   238  		}
   239  
   240  		// Store the reassembled payload as we parse each fragment. The payload
   241  		// includes the Transport header and everything after.
   242  		reassembledPayload.Append(fragment.TransportHeader().View())
   243  		reassembledPayload.Append(fragment.Data().AsRange().ToView())
   244  	}
   245  
   246  	if diff := cmp.Diff([]byte(source[sourceIPHeadersLen:]), reassembledPayload.Flatten()); diff != "" {
   247  		return fmt.Errorf("reassembledPayload mismatch (-want +got):\n%s", diff)
   248  	}
   249  
   250  	return nil
   251  }
   252  
   253  // TestReceiveOnAllNodesMulticastAddr tests that IPv6 endpoints receive ICMP and
   254  // UDP packets destined to the IPv6 link-local all-nodes multicast address.
   255  func TestReceiveOnAllNodesMulticastAddr(t *testing.T) {
   256  	tests := []struct {
   257  		name string
   258  		rxf  func(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64)
   259  	}{
   260  		{"ICMP", testReceiveICMP},
   261  		{"UDP", testReceiveUDP},
   262  	}
   263  
   264  	for _, test := range tests {
   265  		t.Run(test.name, func(t *testing.T) {
   266  			c := newTestContext()
   267  			defer c.cleanup()
   268  			s := c.s
   269  
   270  			e := channel.New(10, header.IPv6MinimumMTU, linkAddr1)
   271  			defer e.Close()
   272  			if err := s.CreateNIC(1, e); err != nil {
   273  				t.Fatalf("CreateNIC(_) = %s", err)
   274  			}
   275  
   276  			// Should receive a packet destined to the all-nodes
   277  			// multicast address.
   278  			test.rxf(t, s, e, addr1, header.IPv6AllNodesMulticastAddress, 1)
   279  		})
   280  	}
   281  }
   282  
   283  // TestReceiveOnSolicitedNodeAddr tests that IPv6 endpoints receive ICMP and UDP
   284  // packets destined to the IPv6 solicited-node address of an assigned IPv6
   285  // address.
   286  func TestReceiveOnSolicitedNodeAddr(t *testing.T) {
   287  	tests := []struct {
   288  		name string
   289  		rxf  func(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst tcpip.Address, want uint64)
   290  	}{
   291  		{"ICMP", testReceiveICMP},
   292  		{"UDP", testReceiveUDP},
   293  	}
   294  
   295  	snmc := header.SolicitedNodeAddr(addr2)
   296  
   297  	for _, test := range tests {
   298  		t.Run(test.name, func(t *testing.T) {
   299  			c := newTestContext()
   300  			defer c.cleanup()
   301  			s := c.s
   302  
   303  			e := channel.New(1, header.IPv6MinimumMTU, linkAddr1)
   304  			defer e.Close()
   305  			if err := s.CreateNIC(nicID, e); err != nil {
   306  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
   307  			}
   308  
   309  			s.SetRouteTable([]tcpip.Route{
   310  				{
   311  					Destination: header.IPv6EmptySubnet,
   312  					NIC:         nicID,
   313  				},
   314  			})
   315  
   316  			// Should not receive a packet destined to the solicited node address of
   317  			// addr2/addr3 yet as we haven't added those addresses.
   318  			test.rxf(t, s, e, addr1, snmc, 0)
   319  
   320  			protocolAddr2 := tcpip.ProtocolAddress{
   321  				Protocol:          ProtocolNumber,
   322  				AddressWithPrefix: addr2.WithPrefix(),
   323  			}
   324  			if err := s.AddProtocolAddress(nicID, protocolAddr2, stack.AddressProperties{}); err != nil {
   325  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr2, err)
   326  			}
   327  
   328  			// Should receive a packet destined to the solicited node address of
   329  			// addr2/addr3 now that we have added added addr2.
   330  			test.rxf(t, s, e, addr1, snmc, 1)
   331  
   332  			protocolAddr3 := tcpip.ProtocolAddress{
   333  				Protocol:          ProtocolNumber,
   334  				AddressWithPrefix: addr3.WithPrefix(),
   335  			}
   336  			if err := s.AddProtocolAddress(nicID, protocolAddr3, stack.AddressProperties{}); err != nil {
   337  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr3, err)
   338  			}
   339  
   340  			// Should still receive a packet destined to the solicited node address of
   341  			// addr2/addr3 now that we have added addr3.
   342  			test.rxf(t, s, e, addr1, snmc, 2)
   343  
   344  			if err := s.RemoveAddress(nicID, addr2); err != nil {
   345  				t.Fatalf("RemoveAddress(%d, %s) = %s", nicID, addr2, err)
   346  			}
   347  
   348  			// Should still receive a packet destined to the solicited node address of
   349  			// addr2/addr3 now that we have removed addr2.
   350  			test.rxf(t, s, e, addr1, snmc, 3)
   351  
   352  			// Make sure addr3's endpoint does not get removed from the NIC by
   353  			// incrementing its reference count with a route.
   354  			r, err := s.FindRoute(nicID, addr3, addr4, ProtocolNumber, false)
   355  			if err != nil {
   356  				t.Fatalf("FindRoute(%d, %s, %s, %d, false): %s", nicID, addr3, addr4, ProtocolNumber, err)
   357  			}
   358  			defer r.Release()
   359  
   360  			if err := s.RemoveAddress(nicID, addr3); err != nil {
   361  				t.Fatalf("RemoveAddress(%d, %s) = %s", nicID, addr3, err)
   362  			}
   363  
   364  			// Should not receive a packet destined to the solicited node address of
   365  			// addr2/addr3 yet as both of them got removed, even though a route using
   366  			// addr3 exists.
   367  			test.rxf(t, s, e, addr1, snmc, 3)
   368  		})
   369  	}
   370  }
   371  
   372  // TestAddIpv6Address tests adding IPv6 addresses.
   373  func TestAddIpv6Address(t *testing.T) {
   374  	const nicID = 1
   375  
   376  	tests := []struct {
   377  		name string
   378  		addr tcpip.Address
   379  	}{
   380  		// This test is in response to b/140943433.
   381  		{
   382  			"Nil",
   383  			tcpip.Address{},
   384  		},
   385  		{
   386  			"ValidUnicast",
   387  			addr1,
   388  		},
   389  		{
   390  			"ValidLinkLocalUnicast",
   391  			lladdr0,
   392  		},
   393  	}
   394  
   395  	for _, test := range tests {
   396  		t.Run(test.name, func(t *testing.T) {
   397  			c := newTestContext()
   398  			defer c.cleanup()
   399  			s := c.s
   400  
   401  			if err := s.CreateNIC(nicID, &stubLinkEndpoint{}); err != nil {
   402  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
   403  			}
   404  
   405  			protocolAddr := tcpip.ProtocolAddress{
   406  				Protocol:          ProtocolNumber,
   407  				AddressWithPrefix: test.addr.WithPrefix(),
   408  			}
   409  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   410  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   411  			}
   412  
   413  			if addr, err := s.GetMainNICAddress(nicID, ProtocolNumber); err != nil {
   414  				t.Fatalf("stack.GetMainNICAddress(%d, %d): %s", nicID, ProtocolNumber, err)
   415  			} else if addr.Address != test.addr {
   416  				t.Fatalf("got stack.GetMainNICAddress(%d, %d) = %s, want = %s", nicID, ProtocolNumber, addr.Address, test.addr)
   417  			}
   418  		})
   419  	}
   420  }
   421  
   422  func TestReceiveIPv6ExtHdrs(t *testing.T) {
   423  	tests := []struct {
   424  		name                    string
   425  		extHdr                  func(nextHdr uint8) ([]byte, uint8)
   426  		shouldAccept            bool
   427  		countersToBeIncremented func(*tcpip.Stats) []*tcpip.StatCounter
   428  		// Should we expect an ICMP response and if so, with what contents?
   429  		expectICMP bool
   430  		ICMPType   header.ICMPv6Type
   431  		ICMPCode   header.ICMPv6Code
   432  		pointer    uint32
   433  		multicast  bool
   434  	}{
   435  		{
   436  			name:         "None",
   437  			extHdr:       func(nextHdr uint8) ([]byte, uint8) { return nil, nextHdr },
   438  			shouldAccept: true,
   439  			expectICMP:   false,
   440  		},
   441  		{
   442  			name: "hopbyhop with router alert option",
   443  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   444  				return []byte{
   445  					nextHdr, 0,
   446  
   447  					// Router Alert option.
   448  					5, 2, 0, 0, 0, 0,
   449  				}, hopByHopExtHdrID
   450  			},
   451  			shouldAccept: true,
   452  			countersToBeIncremented: func(stats *tcpip.Stats) []*tcpip.StatCounter {
   453  				return []*tcpip.StatCounter{stats.IP.OptionRouterAlertReceived}
   454  			},
   455  		},
   456  		{
   457  			name: "hopbyhop with two router alert options",
   458  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   459  				return []byte{
   460  					nextHdr, 1,
   461  
   462  					// Router Alert option.
   463  					5, 2, 0, 0, 0, 0,
   464  
   465  					// Router Alert option.
   466  					5, 2, 0, 0, 0, 0, 0, 0,
   467  				}, hopByHopExtHdrID
   468  			},
   469  			shouldAccept: false,
   470  			countersToBeIncremented: func(stats *tcpip.Stats) []*tcpip.StatCounter {
   471  				return []*tcpip.StatCounter{
   472  					stats.IP.OptionRouterAlertReceived,
   473  					stats.IP.MalformedPacketsReceived,
   474  				}
   475  			},
   476  		},
   477  		{
   478  			name: "hopbyhop with unknown option skippable action",
   479  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   480  				return []byte{
   481  					nextHdr, 1,
   482  
   483  					// Skippable unknown.
   484  					63, 4, 1, 2, 3, 4,
   485  
   486  					// Skippable unknown.
   487  					62, 6, 1, 2, 3, 4, 5, 6,
   488  				}, hopByHopExtHdrID
   489  			},
   490  			shouldAccept: true,
   491  		},
   492  		{
   493  			name: "hopbyhop with unknown option discard action",
   494  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   495  				return []byte{
   496  					nextHdr, 1,
   497  
   498  					// Skippable unknown.
   499  					63, 4, 1, 2, 3, 4,
   500  
   501  					// Discard unknown.
   502  					127, 6, 1, 2, 3, 4, 5, 6,
   503  				}, hopByHopExtHdrID
   504  			},
   505  			shouldAccept: false,
   506  			expectICMP:   false,
   507  		},
   508  		{
   509  			name: "hopbyhop with unknown option discard and send icmp action (unicast)",
   510  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   511  				return []byte{
   512  					nextHdr, 1,
   513  
   514  					// Skippable unknown.
   515  					63, 4, 1, 2, 3, 4,
   516  
   517  					// Discard & send ICMP if option is unknown.
   518  					191, 6, 1, 2, 3, 4, 5, 6,
   519  					//^ Unknown option.
   520  				}, hopByHopExtHdrID
   521  			},
   522  			shouldAccept: false,
   523  			expectICMP:   true,
   524  			ICMPType:     header.ICMPv6ParamProblem,
   525  			ICMPCode:     header.ICMPv6UnknownOption,
   526  			pointer:      header.IPv6FixedHeaderSize + 8,
   527  		},
   528  		{
   529  			name: "hopbyhop with unknown option discard and send icmp action (multicast)",
   530  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   531  				return []byte{
   532  					nextHdr, 1,
   533  
   534  					// Skippable unknown.
   535  					63, 4, 1, 2, 3, 4,
   536  
   537  					// Discard & send ICMP if option is unknown.
   538  					191, 6, 1, 2, 3, 4, 5, 6,
   539  					//^ Unknown option.
   540  				}, hopByHopExtHdrID
   541  			},
   542  			multicast:    true,
   543  			shouldAccept: false,
   544  			expectICMP:   true,
   545  			ICMPType:     header.ICMPv6ParamProblem,
   546  			ICMPCode:     header.ICMPv6UnknownOption,
   547  			pointer:      header.IPv6FixedHeaderSize + 8,
   548  		},
   549  		{
   550  			name: "hopbyhop with unknown option discard and send icmp action unless multicast dest (unicast)",
   551  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   552  				return []byte{
   553  					nextHdr, 1,
   554  
   555  					// Skippable unknown.
   556  					63, 4, 1, 2, 3, 4,
   557  
   558  					// Discard & send ICMP unless packet is for multicast destination if
   559  					// option is unknown.
   560  					255, 6, 1, 2, 3, 4, 5, 6,
   561  					//^ Unknown option.
   562  				}, hopByHopExtHdrID
   563  			},
   564  			expectICMP: true,
   565  			ICMPType:   header.ICMPv6ParamProblem,
   566  			ICMPCode:   header.ICMPv6UnknownOption,
   567  			pointer:    header.IPv6FixedHeaderSize + 8,
   568  		},
   569  		{
   570  			name: "hopbyhop with unknown option discard and send icmp action unless multicast dest (multicast)",
   571  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   572  				return []byte{
   573  					nextHdr, 1,
   574  
   575  					// Skippable unknown.
   576  					63, 4, 1, 2, 3, 4,
   577  
   578  					// Discard & send ICMP unless packet is for multicast destination if
   579  					// option is unknown.
   580  					255, 6, 1, 2, 3, 4, 5, 6,
   581  					//^ Unknown option.
   582  				}, hopByHopExtHdrID
   583  			},
   584  			multicast:    true,
   585  			shouldAccept: false,
   586  			expectICMP:   false,
   587  		},
   588  		{
   589  			name: "routing with zero segments left",
   590  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   591  				return []byte{
   592  					nextHdr, 0,
   593  					1, 0, 2, 3, 4, 5,
   594  				}, routingExtHdrID
   595  			},
   596  			shouldAccept: true,
   597  		},
   598  		{
   599  			name: "routing with non-zero segments left",
   600  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   601  				return []byte{
   602  					nextHdr, 0,
   603  					1, 1, 2, 3, 4, 5,
   604  				}, routingExtHdrID
   605  			},
   606  			shouldAccept: false,
   607  			expectICMP:   true,
   608  			ICMPType:     header.ICMPv6ParamProblem,
   609  			ICMPCode:     header.ICMPv6ErroneousHeader,
   610  			pointer:      header.IPv6FixedHeaderSize + 2,
   611  		},
   612  		{
   613  			name: "atomic fragment with zero ID",
   614  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   615  				return []byte{
   616  					nextHdr, 0,
   617  					0, 0, 0, 0, 0, 0,
   618  				}, fragmentExtHdrID
   619  			},
   620  			shouldAccept: true,
   621  		},
   622  		{
   623  			name: "atomic fragment with non-zero ID",
   624  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   625  				return []byte{
   626  					nextHdr, 0,
   627  					0, 0, 1, 2, 3, 4,
   628  				}, fragmentExtHdrID
   629  			},
   630  			shouldAccept: true,
   631  			expectICMP:   false,
   632  		},
   633  		{
   634  			name: "fragment",
   635  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   636  				return []byte{
   637  					nextHdr, 0,
   638  					1, 0, 1, 2, 3, 4,
   639  				}, fragmentExtHdrID
   640  			},
   641  			shouldAccept: false,
   642  			expectICMP:   false,
   643  		},
   644  		{
   645  			name: "No next header",
   646  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   647  				return nil, noNextHdrID
   648  			},
   649  			shouldAccept: false,
   650  			expectICMP:   false,
   651  		},
   652  		{
   653  			name: "unknown next header (first)",
   654  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   655  				return []byte{
   656  					nextHdr, 0, 63, 4, 1, 2, 3, 4,
   657  				}, unknownHdrID
   658  			},
   659  			shouldAccept: false,
   660  			expectICMP:   true,
   661  			ICMPType:     header.ICMPv6ParamProblem,
   662  			ICMPCode:     header.ICMPv6UnknownHeader,
   663  			pointer:      header.IPv6NextHeaderOffset,
   664  		},
   665  		{
   666  			name: "unknown next header (not first)",
   667  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   668  				return []byte{
   669  					unknownHdrID, 0,
   670  					63, 4, 1, 2, 3, 4,
   671  				}, hopByHopExtHdrID
   672  			},
   673  			shouldAccept: false,
   674  			expectICMP:   true,
   675  			ICMPType:     header.ICMPv6ParamProblem,
   676  			ICMPCode:     header.ICMPv6UnknownHeader,
   677  			pointer:      header.IPv6FixedHeaderSize,
   678  		},
   679  		{
   680  			name: "destination with unknown option skippable action",
   681  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   682  				return []byte{
   683  					nextHdr, 1,
   684  
   685  					// Skippable unknown.
   686  					63, 4, 1, 2, 3, 4,
   687  
   688  					// Skippable unknown.
   689  					62, 6, 1, 2, 3, 4, 5, 6,
   690  				}, destinationExtHdrID
   691  			},
   692  			shouldAccept: true,
   693  			expectICMP:   false,
   694  		},
   695  		{
   696  			name: "destination with unknown option discard action",
   697  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   698  				return []byte{
   699  					nextHdr, 1,
   700  
   701  					// Skippable unknown.
   702  					63, 4, 1, 2, 3, 4,
   703  
   704  					// Discard unknown.
   705  					127, 6, 1, 2, 3, 4, 5, 6,
   706  				}, destinationExtHdrID
   707  			},
   708  			shouldAccept: false,
   709  			expectICMP:   false,
   710  		},
   711  		{
   712  			name: "destination with unknown option discard and send icmp action (unicast)",
   713  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   714  				return []byte{
   715  					nextHdr, 1,
   716  
   717  					// Skippable unknown.
   718  					63, 4, 1, 2, 3, 4,
   719  
   720  					// Discard & send ICMP if option is unknown.
   721  					191, 6, 1, 2, 3, 4, 5, 6,
   722  					//^  191 is an unknown option.
   723  				}, destinationExtHdrID
   724  			},
   725  			shouldAccept: false,
   726  			expectICMP:   true,
   727  			ICMPType:     header.ICMPv6ParamProblem,
   728  			ICMPCode:     header.ICMPv6UnknownOption,
   729  			pointer:      header.IPv6FixedHeaderSize + 8,
   730  		},
   731  		{
   732  			name: "destination with unknown option discard and send icmp action (multicast)",
   733  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   734  				return []byte{
   735  					nextHdr, 1,
   736  
   737  					// Skippable unknown.
   738  					63, 4, 1, 2, 3, 4,
   739  
   740  					// Discard & send ICMP if option is unknown.
   741  					191, 6, 1, 2, 3, 4, 5, 6,
   742  					//^  191 is an unknown option.
   743  				}, destinationExtHdrID
   744  			},
   745  			multicast:    true,
   746  			shouldAccept: false,
   747  			expectICMP:   true,
   748  			ICMPType:     header.ICMPv6ParamProblem,
   749  			ICMPCode:     header.ICMPv6UnknownOption,
   750  			pointer:      header.IPv6FixedHeaderSize + 8,
   751  		},
   752  		{
   753  			name: "destination with unknown option discard and send icmp action unless multicast dest (unicast)",
   754  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   755  				return []byte{
   756  					nextHdr, 1,
   757  
   758  					// Skippable unknown.
   759  					63, 4, 1, 2, 3, 4,
   760  
   761  					// Discard & send ICMP unless packet is for multicast destination if
   762  					// option is unknown.
   763  					255, 6, 1, 2, 3, 4, 5, 6,
   764  					//^ 255 is unknown.
   765  				}, destinationExtHdrID
   766  			},
   767  			shouldAccept: false,
   768  			expectICMP:   true,
   769  			ICMPType:     header.ICMPv6ParamProblem,
   770  			ICMPCode:     header.ICMPv6UnknownOption,
   771  			pointer:      header.IPv6FixedHeaderSize + 8,
   772  		},
   773  		{
   774  			name: "destination with unknown option discard and send icmp action unless multicast dest (multicast)",
   775  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   776  				return []byte{
   777  					nextHdr, 1,
   778  
   779  					// Skippable unknown.
   780  					63, 4, 1, 2, 3, 4,
   781  
   782  					// Discard & send ICMP unless packet is for multicast destination if
   783  					// option is unknown.
   784  					255, 6, 1, 2, 3, 4, 5, 6,
   785  					//^ 255 is unknown.
   786  				}, destinationExtHdrID
   787  			},
   788  			shouldAccept: false,
   789  			expectICMP:   false,
   790  			multicast:    true,
   791  		},
   792  		{
   793  			name: "atomic fragment - routing",
   794  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   795  				return []byte{
   796  					// Fragment extension header.
   797  					routingExtHdrID, 0, 0, 0, 1, 2, 3, 4,
   798  
   799  					// Routing extension header.
   800  					nextHdr, 0, 1, 0, 2, 3, 4, 5,
   801  				}, fragmentExtHdrID
   802  			},
   803  			shouldAccept: true,
   804  		},
   805  		{
   806  			name: "hop by hop (with skippable unknown) - routing",
   807  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   808  				return []byte{
   809  					// Hop By Hop extension header with skippable unknown option.
   810  					routingExtHdrID, 0, 62, 4, 1, 2, 3, 4,
   811  
   812  					// Routing extension header.
   813  					nextHdr, 0, 1, 0, 2, 3, 4, 5,
   814  				}, hopByHopExtHdrID
   815  			},
   816  			shouldAccept: true,
   817  		},
   818  		{
   819  			name: "routing - hop by hop (with skippable unknown)",
   820  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   821  				return []byte{
   822  					// Routing extension header.
   823  					hopByHopExtHdrID, 0, 1, 0, 2, 3, 4, 5,
   824  					// ^^^   The HopByHop extension header may not appear after the first
   825  					// extension header.
   826  
   827  					// Hop By Hop extension header with skippable unknown option.
   828  					nextHdr, 0, 62, 4, 1, 2, 3, 4,
   829  				}, routingExtHdrID
   830  			},
   831  			shouldAccept: false,
   832  			expectICMP:   true,
   833  			ICMPType:     header.ICMPv6ParamProblem,
   834  			ICMPCode:     header.ICMPv6UnknownHeader,
   835  			pointer:      header.IPv6FixedHeaderSize,
   836  		},
   837  		{
   838  			name: "routing - hop by hop (with send icmp unknown)",
   839  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   840  				return []byte{
   841  					// Routing extension header.
   842  					hopByHopExtHdrID, 0, 1, 0, 2, 3, 4, 5,
   843  					// ^^^   The HopByHop extension header may not appear after the first
   844  					// extension header.
   845  
   846  					nextHdr, 1,
   847  
   848  					// Skippable unknown.
   849  					63, 4, 1, 2, 3, 4,
   850  
   851  					// Skippable unknown.
   852  					191, 6, 1, 2, 3, 4, 5, 6,
   853  				}, routingExtHdrID
   854  			},
   855  			shouldAccept: false,
   856  			expectICMP:   true,
   857  			ICMPType:     header.ICMPv6ParamProblem,
   858  			ICMPCode:     header.ICMPv6UnknownHeader,
   859  			pointer:      header.IPv6FixedHeaderSize,
   860  		},
   861  		{
   862  			name: "hopbyhop (with skippable unknown) - routing - atomic fragment - destination (with skippable unknown)",
   863  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   864  				return []byte{
   865  					// Hop By Hop extension header with skippable unknown option.
   866  					routingExtHdrID, 0, 62, 4, 1, 2, 3, 4,
   867  
   868  					// Routing extension header.
   869  					fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5,
   870  
   871  					// Fragment extension header.
   872  					destinationExtHdrID, 0, 0, 0, 1, 2, 3, 4,
   873  
   874  					// Destination extension header with skippable unknown option.
   875  					nextHdr, 0, 63, 4, 1, 2, 3, 4,
   876  				}, hopByHopExtHdrID
   877  			},
   878  			shouldAccept: true,
   879  		},
   880  		{
   881  			name: "hopbyhop (with discard unknown) - routing - atomic fragment - destination (with skippable unknown)",
   882  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   883  				return []byte{
   884  					// Hop By Hop extension header with discard action for unknown option.
   885  					routingExtHdrID, 0, 65, 4, 1, 2, 3, 4,
   886  
   887  					// Routing extension header.
   888  					fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5,
   889  
   890  					// Fragment extension header.
   891  					destinationExtHdrID, 0, 0, 0, 1, 2, 3, 4,
   892  
   893  					// Destination extension header with skippable unknown option.
   894  					nextHdr, 0, 63, 4, 1, 2, 3, 4,
   895  				}, hopByHopExtHdrID
   896  			},
   897  			shouldAccept: false,
   898  			expectICMP:   false,
   899  		},
   900  		{
   901  			name: "hopbyhop (with skippable unknown) - routing - atomic fragment - destination (with discard unknown)",
   902  			extHdr: func(nextHdr uint8) ([]byte, uint8) {
   903  				return []byte{
   904  					// Hop By Hop extension header with skippable unknown option.
   905  					routingExtHdrID, 0, 62, 4, 1, 2, 3, 4,
   906  
   907  					// Routing extension header.
   908  					fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5,
   909  
   910  					// Fragment extension header.
   911  					destinationExtHdrID, 0, 0, 0, 1, 2, 3, 4,
   912  
   913  					// Destination extension header with discard action for unknown
   914  					// option.
   915  					nextHdr, 0, 65, 4, 1, 2, 3, 4,
   916  				}, hopByHopExtHdrID
   917  			},
   918  			shouldAccept: false,
   919  			expectICMP:   false,
   920  		},
   921  	}
   922  
   923  	for _, test := range tests {
   924  		t.Run(test.name, func(t *testing.T) {
   925  			c := newTestContext()
   926  			defer c.cleanup()
   927  			s := c.s
   928  
   929  			e := channel.New(1, header.IPv6MinimumMTU, linkAddr1)
   930  			defer e.Close()
   931  			if err := s.CreateNIC(nicID, e); err != nil {
   932  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
   933  			}
   934  			protocolAddr := tcpip.ProtocolAddress{
   935  				Protocol:          ProtocolNumber,
   936  				AddressWithPrefix: addr2.WithPrefix(),
   937  			}
   938  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   939  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   940  			}
   941  
   942  			// Add a default route so that a return packet knows where to go.
   943  			s.SetRouteTable([]tcpip.Route{
   944  				{
   945  					Destination: header.IPv6EmptySubnet,
   946  					NIC:         nicID,
   947  				},
   948  			})
   949  
   950  			wq := waiter.Queue{}
   951  			we, ch := waiter.NewChannelEntry(waiter.WritableEvents)
   952  			wq.EventRegister(&we)
   953  			defer wq.EventUnregister(&we)
   954  			defer close(ch)
   955  			ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq)
   956  			if err != nil {
   957  				t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, ProtocolNumber, err)
   958  			}
   959  			defer ep.Close()
   960  
   961  			bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80}
   962  			if err := ep.Bind(bindAddr); err != nil {
   963  				t.Fatalf("Bind(%+v): %s", bindAddr, err)
   964  			}
   965  
   966  			udpPayload := []byte{1, 2, 3, 4, 5, 6, 7, 8}
   967  			udpLength := header.UDPMinimumSize + len(udpPayload)
   968  			extHdrBytes, ipv6NextHdr := test.extHdr(uint8(header.UDPProtocolNumber))
   969  			extHdrLen := len(extHdrBytes)
   970  			hdr := prependable.New(header.IPv6MinimumSize + extHdrLen + udpLength)
   971  
   972  			// Serialize UDP message.
   973  			u := header.UDP(hdr.Prepend(udpLength))
   974  			u.Encode(&header.UDPFields{
   975  				SrcPort: 5555,
   976  				DstPort: 80,
   977  				Length:  uint16(udpLength),
   978  			})
   979  			copy(u.Payload(), udpPayload)
   980  
   981  			dstAddr := tcpip.Address(addr2)
   982  			if test.multicast {
   983  				dstAddr = header.IPv6AllNodesMulticastAddress
   984  			}
   985  
   986  			sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, addr1, dstAddr, uint16(udpLength))
   987  			sum = checksum.Checksum(udpPayload, sum)
   988  			u.SetChecksum(^u.CalculateChecksum(sum))
   989  
   990  			// Copy extension header bytes between the UDP message and the IPv6
   991  			// fixed header.
   992  			copy(hdr.Prepend(extHdrLen), extHdrBytes)
   993  
   994  			// Serialize IPv6 fixed header.
   995  			payloadLength := hdr.UsedLength()
   996  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   997  			ip.Encode(&header.IPv6Fields{
   998  				PayloadLength: uint16(payloadLength),
   999  				// We're lying about transport protocol here to be able to generate
  1000  				// raw extension headers from the test definitions.
  1001  				TransportProtocol: tcpip.TransportProtocolNumber(ipv6NextHdr),
  1002  				HopLimit:          255,
  1003  				SrcAddr:           addr1,
  1004  				DstAddr:           dstAddr,
  1005  			})
  1006  
  1007  			stats := s.Stats()
  1008  			var counters []*tcpip.StatCounter
  1009  			// Make sure that the counters we expect to be incremented are initially
  1010  			// set to zero.
  1011  			if fn := test.countersToBeIncremented; fn != nil {
  1012  				counters = fn(&stats)
  1013  			}
  1014  			for i := range counters {
  1015  				if got := counters[i].Value(); got != 0 {
  1016  					t.Errorf("before writing packet: got test.countersToBeIncremented(&stats)[%d].Value() = %d, want = 0", i, got)
  1017  				}
  1018  			}
  1019  
  1020  			pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  1021  				Payload: buffer.MakeWithData(hdr.View()),
  1022  			})
  1023  			e.InjectInbound(ProtocolNumber, pkt)
  1024  			pkt.DecRef()
  1025  			for i := range counters {
  1026  				if got := counters[i].Value(); got != 1 {
  1027  					t.Errorf("after writing packet: got test.countersToBeIncremented(&stats)[%d].Value() = %d, want = 1", i, got)
  1028  				}
  1029  			}
  1030  
  1031  			udpReceiveStat := stats.UDP.PacketsReceived
  1032  			if !test.shouldAccept {
  1033  				if got := udpReceiveStat.Value(); got != 0 {
  1034  					t.Errorf("got UDP Rx Packets = %d, want = 0", got)
  1035  				}
  1036  
  1037  				if !test.expectICMP {
  1038  					if p := e.Read(); p != nil {
  1039  						t.Fatalf("unexpected packet received: %#v", p)
  1040  					}
  1041  					return
  1042  				}
  1043  
  1044  				// ICMP required.
  1045  				p := e.Read()
  1046  				if p == nil {
  1047  					t.Fatalf("expected packet wasn't written out")
  1048  				}
  1049  				defer p.DecRef()
  1050  
  1051  				// Pack the output packet into a single buffer.View as the checkers
  1052  				// assume that.
  1053  				v := p.ToView()
  1054  				defer v.Release()
  1055  				pkt := v.AsSlice()
  1056  				if got, want := len(pkt), header.IPv6FixedHeaderSize+header.ICMPv6MinimumSize+hdr.UsedLength(); got != want {
  1057  					t.Fatalf("got an ICMP packet of size = %d, want = %d", got, want)
  1058  				}
  1059  
  1060  				checker.IPv6(t, v, checker.ICMPv6(
  1061  					checker.ICMPv6Type(test.ICMPType),
  1062  					checker.ICMPv6Code(test.ICMPCode)))
  1063  
  1064  				// We know we are looking at no extension headers in the error ICMP
  1065  				// packets.
  1066  				icm := header.ICMPv6(header.IPv6(pkt).Payload())
  1067  				// We know we sent small packets that won't be truncated when reflected
  1068  				// back to us.
  1069  				originalPacket := icm.Payload()
  1070  				if got, want := icm.TypeSpecific(), test.pointer; got != want {
  1071  					t.Errorf("unexpected ICMPv6 pointer, got = %d, want = %d\n", got, want)
  1072  				}
  1073  				if diff := cmp.Diff([]byte(hdr.View()), originalPacket); diff != "" {
  1074  					t.Errorf("ICMPv6 payload mismatch (-want +got):\n%s", diff)
  1075  				}
  1076  				return
  1077  			}
  1078  
  1079  			// Expect a UDP packet.
  1080  			if got := udpReceiveStat.Value(); got != 1 {
  1081  				t.Errorf("got UDP Rx Packets = %d, want = 1", got)
  1082  			}
  1083  			var buf bytes.Buffer
  1084  			result, err := ep.Read(&buf, tcpip.ReadOptions{})
  1085  			if err != nil {
  1086  				t.Fatalf("Read: %s", err)
  1087  			}
  1088  			if diff := cmp.Diff(tcpip.ReadResult{
  1089  				Count: len(udpPayload),
  1090  				Total: len(udpPayload),
  1091  			}, result, checker.IgnoreCmpPath("ControlMessages")); diff != "" {
  1092  				t.Errorf("Read: unexpected result (-want +got):\n%s", diff)
  1093  			}
  1094  			if diff := cmp.Diff(udpPayload, buf.Bytes()); diff != "" {
  1095  				t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff)
  1096  			}
  1097  
  1098  			// Should not have any more UDP packets.
  1099  			res, err := ep.Read(ioutil.Discard, tcpip.ReadOptions{})
  1100  			if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
  1101  				t.Fatalf("got Read = (%v, %v), want = (_, %s)", res, err, &tcpip.ErrWouldBlock{})
  1102  			}
  1103  		})
  1104  	}
  1105  }
  1106  
  1107  // fragmentData holds the IPv6 payload for a fragmented IPv6 packet.
  1108  type fragmentData struct {
  1109  	srcAddr tcpip.Address
  1110  	dstAddr tcpip.Address
  1111  	nextHdr uint8
  1112  	data    []byte
  1113  }
  1114  
  1115  func udpGen(payload []byte, multiplier uint8, src, dst tcpip.Address) []byte {
  1116  	payloadLen := len(payload)
  1117  	for i := 0; i < payloadLen; i++ {
  1118  		payload[i] = uint8(i) * multiplier
  1119  	}
  1120  
  1121  	udpLength := header.UDPMinimumSize + payloadLen
  1122  
  1123  	hdr := prependable.New(udpLength)
  1124  	u := header.UDP(hdr.Prepend(udpLength))
  1125  	u.Encode(&header.UDPFields{
  1126  		SrcPort: 5555,
  1127  		DstPort: 80,
  1128  		Length:  uint16(udpLength),
  1129  	})
  1130  	copy(u.Payload(), payload)
  1131  	sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(udpLength))
  1132  	sum = checksum.Checksum(payload, sum)
  1133  	u.SetChecksum(^u.CalculateChecksum(sum))
  1134  	return hdr.View()
  1135  }
  1136  
  1137  func TestReceiveIPv6Fragments(t *testing.T) {
  1138  	const (
  1139  		udpPayload1Length = 256
  1140  		udpPayload2Length = 128
  1141  		// Used to test cases where the fragment blocks are not a multiple of
  1142  		// the fragment block size of 8 (RFC 8200 section 4.5).
  1143  		udpPayload3Length     = 127
  1144  		udpPayload4Length     = header.IPv6MaximumPayloadSize - header.UDPMinimumSize
  1145  		udpMaximumSizeMinus15 = header.UDPMaximumSize - 15
  1146  		fragmentExtHdrLen     = 8
  1147  		// Note, not all routing extension headers will be 8 bytes but this test
  1148  		// uses 8 byte routing extension headers for most sub tests.
  1149  		routingExtHdrLen = 8
  1150  	)
  1151  
  1152  	var udpPayload1Addr1ToAddr2Buf [udpPayload1Length]byte
  1153  	udpPayload1Addr1ToAddr2 := udpPayload1Addr1ToAddr2Buf[:]
  1154  	ipv6Payload1Addr1ToAddr2 := udpGen(udpPayload1Addr1ToAddr2, 1, addr1, addr2)
  1155  
  1156  	var udpPayload1Addr3ToAddr2Buf [udpPayload1Length]byte
  1157  	udpPayload1Addr3ToAddr2 := udpPayload1Addr3ToAddr2Buf[:]
  1158  	ipv6Payload1Addr3ToAddr2 := udpGen(udpPayload1Addr3ToAddr2, 4, addr3, addr2)
  1159  
  1160  	var udpPayload2Addr1ToAddr2Buf [udpPayload2Length]byte
  1161  	udpPayload2Addr1ToAddr2 := udpPayload2Addr1ToAddr2Buf[:]
  1162  	ipv6Payload2Addr1ToAddr2 := udpGen(udpPayload2Addr1ToAddr2, 2, addr1, addr2)
  1163  
  1164  	var udpPayload3Addr1ToAddr2Buf [udpPayload3Length]byte
  1165  	udpPayload3Addr1ToAddr2 := udpPayload3Addr1ToAddr2Buf[:]
  1166  	ipv6Payload3Addr1ToAddr2 := udpGen(udpPayload3Addr1ToAddr2, 3, addr1, addr2)
  1167  
  1168  	var udpPayload4Addr1ToAddr2Buf [udpPayload4Length]byte
  1169  	udpPayload4Addr1ToAddr2 := udpPayload4Addr1ToAddr2Buf[:]
  1170  	ipv6Payload4Addr1ToAddr2 := udpGen(udpPayload4Addr1ToAddr2, 4, addr1, addr2)
  1171  
  1172  	tests := []struct {
  1173  		name             string
  1174  		expectedPayload  []byte
  1175  		fragments        []fragmentData
  1176  		expectedPayloads [][]byte
  1177  	}{
  1178  		{
  1179  			name: "No fragmentation",
  1180  			fragments: []fragmentData{
  1181  				{
  1182  					srcAddr: addr1,
  1183  					dstAddr: addr2,
  1184  					nextHdr: uint8(header.UDPProtocolNumber),
  1185  					data:    ipv6Payload1Addr1ToAddr2,
  1186  				},
  1187  			},
  1188  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1189  		},
  1190  		{
  1191  			name: "Atomic fragment",
  1192  			fragments: []fragmentData{
  1193  				{
  1194  					srcAddr: addr1,
  1195  					dstAddr: addr2,
  1196  					nextHdr: fragmentExtHdrID,
  1197  					data: append(
  1198  						// Fragment extension header.
  1199  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0},
  1200  						ipv6Payload1Addr1ToAddr2...,
  1201  					),
  1202  				},
  1203  			},
  1204  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1205  		},
  1206  		{
  1207  			name: "Atomic fragment with size not a multiple of fragment block size",
  1208  			fragments: []fragmentData{
  1209  				{
  1210  					srcAddr: addr1,
  1211  					dstAddr: addr2,
  1212  					nextHdr: fragmentExtHdrID,
  1213  					data: append(
  1214  						// Fragment extension header.
  1215  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0},
  1216  						ipv6Payload3Addr1ToAddr2...,
  1217  					),
  1218  				},
  1219  			},
  1220  			expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2},
  1221  		},
  1222  		{
  1223  			name: "Two fragments",
  1224  			fragments: []fragmentData{
  1225  				{
  1226  					srcAddr: addr1,
  1227  					dstAddr: addr2,
  1228  					nextHdr: fragmentExtHdrID,
  1229  					data: append(
  1230  						// Fragment extension header.
  1231  						//
  1232  						// Fragment offset = 0, More = true, ID = 1
  1233  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1234  						ipv6Payload1Addr1ToAddr2[:64]...,
  1235  					),
  1236  				},
  1237  				{
  1238  					srcAddr: addr1,
  1239  					dstAddr: addr2,
  1240  					nextHdr: fragmentExtHdrID,
  1241  					data: append(
  1242  						// Fragment extension header.
  1243  						//
  1244  						// Fragment offset = 8, More = false, ID = 1
  1245  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1246  						ipv6Payload1Addr1ToAddr2[64:]...,
  1247  					),
  1248  				},
  1249  			},
  1250  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1251  		},
  1252  		{
  1253  			name: "Two fragments out of order",
  1254  			fragments: []fragmentData{
  1255  				{
  1256  					srcAddr: addr1,
  1257  					dstAddr: addr2,
  1258  					nextHdr: fragmentExtHdrID,
  1259  					data: append(
  1260  						// Fragment extension header.
  1261  						//
  1262  						// Fragment offset = 8, More = false, ID = 1
  1263  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1264  						ipv6Payload1Addr1ToAddr2[64:]...,
  1265  					),
  1266  				},
  1267  				{
  1268  					srcAddr: addr1,
  1269  					dstAddr: addr2,
  1270  					nextHdr: fragmentExtHdrID,
  1271  					data: append(
  1272  						// Fragment extension header.
  1273  						//
  1274  						// Fragment offset = 0, More = true, ID = 1
  1275  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1276  						ipv6Payload1Addr1ToAddr2[:64]...,
  1277  					),
  1278  				},
  1279  			},
  1280  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1281  		},
  1282  		{
  1283  			name: "Two fragments with different Next Header values",
  1284  			fragments: []fragmentData{
  1285  				{
  1286  					srcAddr: addr1,
  1287  					dstAddr: addr2,
  1288  					nextHdr: fragmentExtHdrID,
  1289  					data: append(
  1290  						// Fragment extension header.
  1291  						//
  1292  						// Fragment offset = 0, More = true, ID = 1
  1293  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1294  						ipv6Payload1Addr1ToAddr2[:64]...,
  1295  					),
  1296  				},
  1297  				{
  1298  					srcAddr: addr1,
  1299  					dstAddr: addr2,
  1300  					nextHdr: fragmentExtHdrID,
  1301  					data: append(
  1302  						// Fragment extension header.
  1303  						//
  1304  						// Fragment offset = 8, More = false, ID = 1
  1305  						// NextHeader value is different than the one in the first fragment, so
  1306  						// this NextHeader should be ignored.
  1307  						[]byte{uint8(header.IPv6NoNextHeaderIdentifier), 0, 0, 64, 0, 0, 0, 1},
  1308  						ipv6Payload1Addr1ToAddr2[64:]...,
  1309  					),
  1310  				},
  1311  			},
  1312  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1313  		},
  1314  		{
  1315  			name: "Two fragments with last fragment size not a multiple of fragment block size",
  1316  			fragments: []fragmentData{
  1317  				{
  1318  					srcAddr: addr1,
  1319  					dstAddr: addr2,
  1320  					nextHdr: fragmentExtHdrID,
  1321  					data: append(
  1322  						// Fragment extension header.
  1323  						//
  1324  						// Fragment offset = 0, More = true, ID = 1
  1325  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1326  						ipv6Payload3Addr1ToAddr2[:64]...,
  1327  					),
  1328  				},
  1329  				{
  1330  					srcAddr: addr1,
  1331  					dstAddr: addr2,
  1332  					nextHdr: fragmentExtHdrID,
  1333  					data: append(
  1334  						// Fragment extension header.
  1335  						//
  1336  						// Fragment offset = 8, More = false, ID = 1
  1337  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1338  						ipv6Payload3Addr1ToAddr2[64:]...,
  1339  					),
  1340  				},
  1341  			},
  1342  			expectedPayloads: [][]byte{udpPayload3Addr1ToAddr2},
  1343  		},
  1344  		{
  1345  			name: "Two fragments with first fragment size not a multiple of fragment block size",
  1346  			fragments: []fragmentData{
  1347  				{
  1348  					srcAddr: addr1,
  1349  					dstAddr: addr2,
  1350  					nextHdr: fragmentExtHdrID,
  1351  					data: append(
  1352  						// Fragment extension header.
  1353  						//
  1354  						// Fragment offset = 0, More = true, ID = 1
  1355  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1356  						ipv6Payload3Addr1ToAddr2[:63]...,
  1357  					),
  1358  				},
  1359  				{
  1360  					srcAddr: addr1,
  1361  					dstAddr: addr2,
  1362  					nextHdr: fragmentExtHdrID,
  1363  					data: append(
  1364  						// Fragment extension header.
  1365  						//
  1366  						// Fragment offset = 8, More = false, ID = 1
  1367  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1368  						ipv6Payload3Addr1ToAddr2[63:]...,
  1369  					),
  1370  				},
  1371  			},
  1372  			expectedPayloads: nil,
  1373  		},
  1374  		{
  1375  			name: "Two fragments with different IDs",
  1376  			fragments: []fragmentData{
  1377  				{
  1378  					srcAddr: addr1,
  1379  					dstAddr: addr2,
  1380  					nextHdr: fragmentExtHdrID,
  1381  					data: append(
  1382  						// Fragment extension header.
  1383  						//
  1384  						// Fragment offset = 0, More = true, ID = 1
  1385  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1386  						ipv6Payload1Addr1ToAddr2[:64]...,
  1387  					),
  1388  				},
  1389  				{
  1390  					srcAddr: addr1,
  1391  					dstAddr: addr2,
  1392  					nextHdr: fragmentExtHdrID,
  1393  					data: append(
  1394  						// Fragment extension header.
  1395  						//
  1396  						// Fragment offset = 8, More = false, ID = 2
  1397  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 2},
  1398  						ipv6Payload1Addr1ToAddr2[64:]...,
  1399  					),
  1400  				},
  1401  			},
  1402  			expectedPayloads: nil,
  1403  		},
  1404  		{
  1405  			name: "Two fragments reassembled into a maximum UDP packet",
  1406  			fragments: []fragmentData{
  1407  				{
  1408  					srcAddr: addr1,
  1409  					dstAddr: addr2,
  1410  					nextHdr: fragmentExtHdrID,
  1411  					data: append(
  1412  						// Fragment extension header.
  1413  						//
  1414  						// Fragment offset = 0, More = true, ID = 1
  1415  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1416  						ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15]...,
  1417  					),
  1418  				},
  1419  				{
  1420  					srcAddr: addr1,
  1421  					dstAddr: addr2,
  1422  					nextHdr: fragmentExtHdrID,
  1423  					data: append(
  1424  						// Fragment extension header.
  1425  						//
  1426  						// Fragment offset = udpMaximumSizeMinus15/8, More = false, ID = 1
  1427  						[]byte{uint8(header.UDPProtocolNumber), 0,
  1428  							udpMaximumSizeMinus15 >> 8,
  1429  							udpMaximumSizeMinus15 & 0xff,
  1430  							0, 0, 0, 1},
  1431  						ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:]...,
  1432  					),
  1433  				},
  1434  			},
  1435  			expectedPayloads: [][]byte{udpPayload4Addr1ToAddr2},
  1436  		},
  1437  		{
  1438  			name: "Two fragments with MF flag reassembled into a maximum UDP packet",
  1439  			fragments: []fragmentData{
  1440  				{
  1441  					srcAddr: addr1,
  1442  					dstAddr: addr2,
  1443  					nextHdr: fragmentExtHdrID,
  1444  					data: append(
  1445  						// Fragment extension header.
  1446  						//
  1447  						// Fragment offset = 0, More = true, ID = 1
  1448  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1449  						ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15]...,
  1450  					),
  1451  				},
  1452  				{
  1453  					srcAddr: addr1,
  1454  					dstAddr: addr2,
  1455  					nextHdr: fragmentExtHdrID,
  1456  					data: append(
  1457  						// Fragment extension header.
  1458  						//
  1459  						// Fragment offset = udpMaximumSizeMinus15/8, More = true, ID = 1
  1460  						[]byte{uint8(header.UDPProtocolNumber), 0,
  1461  							udpMaximumSizeMinus15 >> 8,
  1462  							(udpMaximumSizeMinus15 & 0xff) + 1,
  1463  							0, 0, 0, 1},
  1464  
  1465  						ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:]...,
  1466  					),
  1467  				},
  1468  			},
  1469  			expectedPayloads: nil,
  1470  		},
  1471  		{
  1472  			name: "Two fragments with per-fragment routing header with zero segments left",
  1473  			fragments: []fragmentData{
  1474  				{
  1475  					srcAddr: addr1,
  1476  					dstAddr: addr2,
  1477  					nextHdr: routingExtHdrID,
  1478  					data: append(
  1479  						// Routing extension header.
  1480  						//
  1481  						// Segments left = 0.
  1482  						[]byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5},
  1483  						append(
  1484  							// Fragment extension header.
  1485  							//
  1486  							// Fragment offset = 0, More = true, ID = 1
  1487  							[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1488  							ipv6Payload1Addr1ToAddr2[:64]...,
  1489  						)...,
  1490  					),
  1491  				},
  1492  				{
  1493  					srcAddr: addr1,
  1494  					dstAddr: addr2,
  1495  					nextHdr: routingExtHdrID,
  1496  					data: append(
  1497  						// Routing extension header.
  1498  						//
  1499  						// Segments left = 0.
  1500  						[]byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5},
  1501  						append(
  1502  							// Fragment extension header.
  1503  							//
  1504  							// Fragment offset = 8, More = false, ID = 1
  1505  							[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1506  							ipv6Payload1Addr1ToAddr2[64:]...,
  1507  						)...,
  1508  					),
  1509  				},
  1510  			},
  1511  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1512  		},
  1513  		{
  1514  			name: "Two fragments with per-fragment routing header with non-zero segments left",
  1515  			fragments: []fragmentData{
  1516  				{
  1517  					srcAddr: addr1,
  1518  					dstAddr: addr2,
  1519  					nextHdr: routingExtHdrID,
  1520  					data: append(
  1521  						// Routing extension header.
  1522  						//
  1523  						// Segments left = 1.
  1524  						[]byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5},
  1525  						append(
  1526  							// Fragment extension header.
  1527  							//
  1528  							// Fragment offset = 0, More = true, ID = 1
  1529  							[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1530  							ipv6Payload1Addr1ToAddr2[:64]...,
  1531  						)...,
  1532  					),
  1533  				},
  1534  				{
  1535  					srcAddr: addr1,
  1536  					dstAddr: addr2,
  1537  					nextHdr: routingExtHdrID,
  1538  					data: append(
  1539  						// Routing extension header.
  1540  						//
  1541  						// Segments left = 1.
  1542  						[]byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5},
  1543  
  1544  						append(
  1545  							// Fragment extension header.
  1546  							//
  1547  							// Fragment offset = 9, More = false, ID = 1
  1548  							[]byte{uint8(header.UDPProtocolNumber), 0, 0, 72, 0, 0, 0, 1},
  1549  							ipv6Payload1Addr1ToAddr2[64:]...,
  1550  						)...,
  1551  					),
  1552  				},
  1553  			},
  1554  			expectedPayloads: nil,
  1555  		},
  1556  		{
  1557  			name: "Two fragments with routing header with zero segments left",
  1558  			fragments: []fragmentData{
  1559  				{
  1560  					srcAddr: addr1,
  1561  					dstAddr: addr2,
  1562  					nextHdr: fragmentExtHdrID,
  1563  					data: append(
  1564  						// Fragment extension header.
  1565  						//
  1566  						// Fragment offset = 0, More = true, ID = 1
  1567  						[]byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1},
  1568  						append(
  1569  							// Routing extension header.
  1570  							//
  1571  							// Segments left = 0.
  1572  							[]byte{uint8(header.UDPProtocolNumber), 0, 1, 0, 2, 3, 4, 5},
  1573  							ipv6Payload1Addr1ToAddr2[:64]...,
  1574  						)...,
  1575  					),
  1576  				},
  1577  				{
  1578  					srcAddr: addr1,
  1579  					dstAddr: addr2,
  1580  					nextHdr: fragmentExtHdrID,
  1581  					data: append(
  1582  						// Fragment extension header.
  1583  						//
  1584  						// Fragment offset = 9, More = false, ID = 1
  1585  						[]byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1},
  1586  
  1587  						ipv6Payload1Addr1ToAddr2[64:]...,
  1588  					),
  1589  				},
  1590  			},
  1591  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2},
  1592  		},
  1593  		{
  1594  			name: "Two fragments with routing header with non-zero segments left",
  1595  			fragments: []fragmentData{
  1596  				{
  1597  					srcAddr: addr1,
  1598  					dstAddr: addr2,
  1599  					nextHdr: fragmentExtHdrID,
  1600  					data: append(
  1601  						// Fragment extension header.
  1602  						//
  1603  						// Fragment offset = 0, More = true, ID = 1
  1604  						[]byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1},
  1605  						append(
  1606  							// Routing extension header.
  1607  							//
  1608  							// Segments left = 1.
  1609  							[]byte{uint8(header.UDPProtocolNumber), 0, 1, 1, 2, 3, 4, 5},
  1610  							ipv6Payload1Addr1ToAddr2[:64]...,
  1611  						)...,
  1612  					),
  1613  				},
  1614  				{
  1615  					srcAddr: addr1,
  1616  					dstAddr: addr2,
  1617  					nextHdr: fragmentExtHdrID,
  1618  					data: append(
  1619  						// Fragment extension header.
  1620  						//
  1621  						// Fragment offset = 9, More = false, ID = 1
  1622  						[]byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1},
  1623  						ipv6Payload1Addr1ToAddr2[64:]...,
  1624  					),
  1625  				},
  1626  			},
  1627  			expectedPayloads: nil,
  1628  		},
  1629  		{
  1630  			name: "Two fragments with routing header with zero segments left across fragments",
  1631  			fragments: []fragmentData{
  1632  				{
  1633  					srcAddr: addr1,
  1634  					dstAddr: addr2,
  1635  					nextHdr: fragmentExtHdrID,
  1636  					data: append(
  1637  						// Fragment offset = 0, More = true, ID = 1
  1638  						[]byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1},
  1639  						// Routing extension header (part 1)
  1640  						//
  1641  						// Segments left = 0.
  1642  						[]byte{uint8(header.UDPProtocolNumber), 1, 1, 0, 2, 3, 4, 5}...,
  1643  					),
  1644  				},
  1645  				{
  1646  					srcAddr: addr1,
  1647  					dstAddr: addr2,
  1648  					nextHdr: fragmentExtHdrID,
  1649  					data: append(
  1650  						// Fragment extension header.
  1651  						//
  1652  						// Fragment offset = 1, More = false, ID = 1
  1653  						[]byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1},
  1654  						append(
  1655  							// Routing extension header (part 2)
  1656  							[]byte{6, 7, 8, 9, 10, 11, 12, 13},
  1657  							ipv6Payload1Addr1ToAddr2...,
  1658  						)...,
  1659  					),
  1660  				},
  1661  			},
  1662  			expectedPayloads: nil,
  1663  		},
  1664  		{
  1665  			name: "Two fragments with routing header with non-zero segments left across fragments",
  1666  			fragments: []fragmentData{
  1667  				{
  1668  					srcAddr: addr1,
  1669  					dstAddr: addr2,
  1670  					nextHdr: fragmentExtHdrID,
  1671  					data: append(
  1672  						// Fragment extension header.
  1673  						//
  1674  						// Fragment offset = 0, More = true, ID = 1
  1675  						[]byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1},
  1676  
  1677  						// Routing extension header (part 1)
  1678  						//
  1679  						// Segments left = 1.
  1680  						[]byte{uint8(header.UDPProtocolNumber), 1, 1, 1, 2, 3, 4, 5}...,
  1681  					),
  1682  				},
  1683  				{
  1684  					srcAddr: addr1,
  1685  					dstAddr: addr2,
  1686  					nextHdr: fragmentExtHdrID,
  1687  					data: append(
  1688  						// Fragment extension header.
  1689  						//
  1690  						// Fragment offset = 1, More = false, ID = 1
  1691  						[]byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1},
  1692  						append(
  1693  							// Routing extension header (part 2)
  1694  							[]byte{6, 7, 8, 9, 10, 11, 12, 13},
  1695  							ipv6Payload1Addr1ToAddr2...,
  1696  						)...,
  1697  					),
  1698  				},
  1699  			},
  1700  			expectedPayloads: nil,
  1701  		},
  1702  		// As per RFC 6946, IPv6 atomic fragments MUST NOT interfere with "normal"
  1703  		// fragmented traffic.
  1704  		{
  1705  			name: "Two fragments with atomic",
  1706  			fragments: []fragmentData{
  1707  				{
  1708  					srcAddr: addr1,
  1709  					dstAddr: addr2,
  1710  					nextHdr: fragmentExtHdrID,
  1711  					data: append(
  1712  						// Fragment extension header.
  1713  						//
  1714  						// Fragment offset = 0, More = true, ID = 1
  1715  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1716  						ipv6Payload1Addr1ToAddr2[:64]...,
  1717  					),
  1718  				},
  1719  				// This fragment has the same ID as the other fragments but is an atomic
  1720  				// fragment. It should not interfere with the other fragments.
  1721  				{
  1722  					srcAddr: addr1,
  1723  					dstAddr: addr2,
  1724  					nextHdr: fragmentExtHdrID,
  1725  					data: append(
  1726  						// Fragment extension header.
  1727  						//
  1728  						// Fragment offset = 0, More = false, ID = 1
  1729  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 1},
  1730  						ipv6Payload2Addr1ToAddr2...,
  1731  					),
  1732  				},
  1733  				{
  1734  					srcAddr: addr1,
  1735  					dstAddr: addr2,
  1736  					nextHdr: fragmentExtHdrID,
  1737  					data: append(
  1738  						// Fragment extension header.
  1739  						//
  1740  						// Fragment offset = 8, More = false, ID = 1
  1741  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1742  
  1743  						ipv6Payload1Addr1ToAddr2[64:]...,
  1744  					),
  1745  				},
  1746  			},
  1747  			expectedPayloads: [][]byte{udpPayload2Addr1ToAddr2, udpPayload1Addr1ToAddr2},
  1748  		},
  1749  		{
  1750  			name: "Two interleaved fragmented packets",
  1751  			fragments: []fragmentData{
  1752  				{
  1753  					srcAddr: addr1,
  1754  					dstAddr: addr2,
  1755  					nextHdr: fragmentExtHdrID,
  1756  					data: append(
  1757  						// Fragment extension header.
  1758  						//
  1759  						// Fragment offset = 0, More = true, ID = 1
  1760  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1761  						ipv6Payload1Addr1ToAddr2[:64]...,
  1762  					),
  1763  				},
  1764  				{
  1765  					srcAddr: addr1,
  1766  					dstAddr: addr2,
  1767  					nextHdr: fragmentExtHdrID,
  1768  					data: append(
  1769  						// Fragment extension header.
  1770  						//
  1771  						// Fragment offset = 0, More = true, ID = 2
  1772  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 2},
  1773  						ipv6Payload2Addr1ToAddr2[:32]...,
  1774  					),
  1775  				},
  1776  				{
  1777  					srcAddr: addr1,
  1778  					dstAddr: addr2,
  1779  					nextHdr: fragmentExtHdrID,
  1780  					data: append(
  1781  						// Fragment extension header.
  1782  						//
  1783  						// Fragment offset = 8, More = false, ID = 1
  1784  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1785  						ipv6Payload1Addr1ToAddr2[64:]...,
  1786  					),
  1787  				},
  1788  				{
  1789  					srcAddr: addr1,
  1790  					dstAddr: addr2,
  1791  					nextHdr: fragmentExtHdrID,
  1792  					data: append(
  1793  						// Fragment extension header.
  1794  						//
  1795  						// Fragment offset = 4, More = false, ID = 2
  1796  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 2},
  1797  						ipv6Payload2Addr1ToAddr2[32:]...,
  1798  					),
  1799  				},
  1800  			},
  1801  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload2Addr1ToAddr2},
  1802  		},
  1803  		{
  1804  			name: "Two interleaved fragmented packets from different sources but with same ID",
  1805  			fragments: []fragmentData{
  1806  				{
  1807  					srcAddr: addr1,
  1808  					dstAddr: addr2,
  1809  					nextHdr: fragmentExtHdrID,
  1810  					data: append(
  1811  						// Fragment extension header.
  1812  						//
  1813  						// Fragment offset = 0, More = true, ID = 1
  1814  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1815  
  1816  						ipv6Payload1Addr1ToAddr2[:64]...,
  1817  					),
  1818  				},
  1819  				{
  1820  					srcAddr: addr3,
  1821  					dstAddr: addr2,
  1822  					nextHdr: fragmentExtHdrID,
  1823  					data: append(
  1824  						// Fragment extension header.
  1825  						//
  1826  						// Fragment offset = 0, More = true, ID = 1
  1827  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1828  						ipv6Payload1Addr3ToAddr2[:32]...,
  1829  					),
  1830  				},
  1831  				{
  1832  					srcAddr: addr1,
  1833  					dstAddr: addr2,
  1834  					nextHdr: fragmentExtHdrID,
  1835  					data: append(
  1836  						// Fragment extension header.
  1837  						//
  1838  						// Fragment offset = 8, More = false, ID = 1
  1839  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1840  						ipv6Payload1Addr1ToAddr2[64:]...,
  1841  					),
  1842  				},
  1843  				{
  1844  					srcAddr: addr3,
  1845  					dstAddr: addr2,
  1846  					nextHdr: fragmentExtHdrID,
  1847  					data: append(
  1848  						// Fragment extension header.
  1849  						//
  1850  						// Fragment offset = 4, More = false, ID = 1
  1851  						[]byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 1},
  1852  						ipv6Payload1Addr3ToAddr2[32:]...,
  1853  					),
  1854  				},
  1855  			},
  1856  			expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2, udpPayload1Addr3ToAddr2},
  1857  		},
  1858  	}
  1859  
  1860  	for _, test := range tests {
  1861  		t.Run(test.name, func(t *testing.T) {
  1862  			c := newTestContext()
  1863  			defer c.cleanup()
  1864  			s := c.s
  1865  
  1866  			e := channel.New(0, header.IPv6MinimumMTU, linkAddr1)
  1867  			defer e.Close()
  1868  			if err := s.CreateNIC(nicID, e); err != nil {
  1869  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  1870  			}
  1871  			protocolAddr := tcpip.ProtocolAddress{
  1872  				Protocol:          ProtocolNumber,
  1873  				AddressWithPrefix: addr2.WithPrefix(),
  1874  			}
  1875  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  1876  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  1877  			}
  1878  
  1879  			wq := waiter.Queue{}
  1880  			we, ch := waiter.NewChannelEntry(waiter.ReadableEvents)
  1881  			wq.EventRegister(&we)
  1882  			defer wq.EventUnregister(&we)
  1883  			defer close(ch)
  1884  			ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq)
  1885  			if err != nil {
  1886  				t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, ProtocolNumber, err)
  1887  			}
  1888  			defer ep.Close()
  1889  
  1890  			bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80}
  1891  			if err := ep.Bind(bindAddr); err != nil {
  1892  				t.Fatalf("Bind(%+v): %s", bindAddr, err)
  1893  			}
  1894  
  1895  			for _, f := range test.fragments {
  1896  				hdr := prependable.New(header.IPv6MinimumSize)
  1897  
  1898  				// Serialize IPv6 fixed header.
  1899  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  1900  				ip.Encode(&header.IPv6Fields{
  1901  					PayloadLength: uint16(len(f.data)),
  1902  					// We're lying about transport protocol here so that we can generate
  1903  					// raw extension headers for the tests.
  1904  					TransportProtocol: tcpip.TransportProtocolNumber(f.nextHdr),
  1905  					HopLimit:          255,
  1906  					SrcAddr:           f.srcAddr,
  1907  					DstAddr:           f.dstAddr,
  1908  				})
  1909  
  1910  				buf := buffer.MakeWithData(hdr.View())
  1911  				buf.Append(buffer.NewViewWithData(f.data))
  1912  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  1913  					Payload: buf,
  1914  				})
  1915  				e.InjectInbound(ProtocolNumber, pkt)
  1916  				pkt.DecRef()
  1917  			}
  1918  
  1919  			if got, want := s.Stats().UDP.PacketsReceived.Value(), uint64(len(test.expectedPayloads)); got != want {
  1920  				t.Errorf("got UDP Rx Packets = %d, want = %d", got, want)
  1921  			}
  1922  
  1923  			for i, p := range test.expectedPayloads {
  1924  				var buf bytes.Buffer
  1925  				_, err := ep.Read(&buf, tcpip.ReadOptions{})
  1926  				if err != nil {
  1927  					t.Fatalf("(i=%d) Read: %s", i, err)
  1928  				}
  1929  				if diff := cmp.Diff(p, buf.Bytes()); diff != "" {
  1930  					t.Errorf("(i=%d) got UDP payload mismatch (-want +got):\n%s", i, diff)
  1931  				}
  1932  			}
  1933  
  1934  			res, err := ep.Read(ioutil.Discard, tcpip.ReadOptions{})
  1935  			if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
  1936  				t.Fatalf("(last) got Read = (%v, %v), want = (_, %s)", res, err, &tcpip.ErrWouldBlock{})
  1937  			}
  1938  		})
  1939  	}
  1940  }
  1941  
  1942  func TestConcurrentFragmentWrites(t *testing.T) {
  1943  	const udpPayload1Length = 256
  1944  	const udpPayload2Length = 128
  1945  	var udpPayload1Addr1ToAddr2Buf [udpPayload1Length]byte
  1946  	udpPayload1Addr1ToAddr2 := udpPayload1Addr1ToAddr2Buf[:]
  1947  	ipv6Payload1Addr1ToAddr2 := udpGen(udpPayload1Addr1ToAddr2, 1, addr1, addr2)
  1948  
  1949  	var udpPayload2Addr1ToAddr2Buf [udpPayload2Length]byte
  1950  	udpPayload2Addr1ToAddr2 := udpPayload2Addr1ToAddr2Buf[:]
  1951  	ipv6Payload2Addr1ToAddr2 := udpGen(udpPayload2Addr1ToAddr2, 2, addr1, addr2)
  1952  
  1953  	fragments := []fragmentData{
  1954  		{
  1955  			srcAddr: addr1,
  1956  			dstAddr: addr2,
  1957  			nextHdr: fragmentExtHdrID,
  1958  			data: append(
  1959  				// Fragment extension header.
  1960  				//
  1961  				// Fragment offset = 0, More = true, ID = 1
  1962  				[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1},
  1963  				ipv6Payload1Addr1ToAddr2[:64]...,
  1964  			),
  1965  		},
  1966  		{
  1967  			srcAddr: addr1,
  1968  			dstAddr: addr2,
  1969  			nextHdr: fragmentExtHdrID,
  1970  			data: append(
  1971  				// Fragment extension header.
  1972  				//
  1973  				// Fragment offset = 0, More = true, ID = 2
  1974  				[]byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 2},
  1975  				ipv6Payload2Addr1ToAddr2[:32]...,
  1976  			),
  1977  		},
  1978  		{
  1979  			srcAddr: addr1,
  1980  			dstAddr: addr2,
  1981  			nextHdr: fragmentExtHdrID,
  1982  			data: append(
  1983  				// Fragment extension header.
  1984  				//
  1985  				// Fragment offset = 8, More = false, ID = 1
  1986  				[]byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1},
  1987  				ipv6Payload1Addr1ToAddr2[64:]...,
  1988  			),
  1989  		},
  1990  	}
  1991  
  1992  	c := newTestContext()
  1993  	defer c.cleanup()
  1994  	s := c.s
  1995  
  1996  	e := channel.New(0, header.IPv6MinimumMTU, linkAddr1)
  1997  	defer e.Close()
  1998  	if err := s.CreateNIC(nicID, e); err != nil {
  1999  		t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  2000  	}
  2001  	protocolAddr := tcpip.ProtocolAddress{
  2002  		Protocol:          ProtocolNumber,
  2003  		AddressWithPrefix: addr2.WithPrefix(),
  2004  	}
  2005  	if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  2006  		t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  2007  	}
  2008  
  2009  	wq := waiter.Queue{}
  2010  	we, ch := waiter.NewChannelEntry(waiter.ReadableEvents)
  2011  	wq.EventRegister(&we)
  2012  	defer wq.EventUnregister(&we)
  2013  	defer close(ch)
  2014  	ep, err := s.NewEndpoint(udp.ProtocolNumber, ProtocolNumber, &wq)
  2015  	if err != nil {
  2016  		t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, ProtocolNumber, err)
  2017  	}
  2018  	defer ep.Close()
  2019  
  2020  	bindAddr := tcpip.FullAddress{Addr: addr2, Port: 80}
  2021  	if err := ep.Bind(bindAddr); err != nil {
  2022  		t.Fatalf("Bind(%+v): %s", bindAddr, err)
  2023  	}
  2024  
  2025  	var wg sync.WaitGroup
  2026  	defer wg.Wait()
  2027  	for i := 0; i < 3; i++ {
  2028  		wg.Add(1)
  2029  		go func() {
  2030  			defer wg.Done()
  2031  			for i := 0; i < 10; i++ {
  2032  				for _, f := range fragments {
  2033  					hdr := prependable.New(header.IPv6MinimumSize)
  2034  
  2035  					// Serialize IPv6 fixed header.
  2036  					ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  2037  					ip.Encode(&header.IPv6Fields{
  2038  						PayloadLength: uint16(len(f.data)),
  2039  						// We're lying about transport protocol here so that we can generate
  2040  						// raw extension headers for the tests.
  2041  						TransportProtocol: tcpip.TransportProtocolNumber(f.nextHdr),
  2042  						HopLimit:          255,
  2043  						SrcAddr:           f.srcAddr,
  2044  						DstAddr:           f.dstAddr,
  2045  					})
  2046  
  2047  					buf := buffer.MakeWithData(hdr.View())
  2048  					buf.Append(buffer.NewViewWithData(f.data))
  2049  					pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  2050  						Payload: buf,
  2051  					})
  2052  					e.InjectInbound(ProtocolNumber, pkt)
  2053  					pkt.DecRef()
  2054  				}
  2055  			}
  2056  		}()
  2057  	}
  2058  }
  2059  
  2060  func TestInvalidIPv6Fragments(t *testing.T) {
  2061  	const (
  2062  		linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
  2063  		nicID     = 1
  2064  		hoplimit  = 255
  2065  		ident     = 1
  2066  		data      = "TEST_INVALID_IPV6_FRAGMENTS"
  2067  	)
  2068  
  2069  	var (
  2070  		addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"))
  2071  		addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"))
  2072  	)
  2073  
  2074  	type fragmentData struct {
  2075  		ipv6Fields         header.IPv6Fields
  2076  		ipv6FragmentFields header.IPv6SerializableFragmentExtHdr
  2077  		payload            []byte
  2078  	}
  2079  
  2080  	tests := []struct {
  2081  		name                   string
  2082  		fragments              []fragmentData
  2083  		wantMalformedIPPackets uint64
  2084  		wantMalformedFragments uint64
  2085  		expectICMP             bool
  2086  		expectICMPType         header.ICMPv6Type
  2087  		expectICMPCode         header.ICMPv6Code
  2088  		expectICMPTypeSpecific uint32
  2089  	}{
  2090  		{
  2091  			name: "fragment size is not a multiple of 8 and the M flag is true",
  2092  			fragments: []fragmentData{
  2093  				{
  2094  					ipv6Fields: header.IPv6Fields{
  2095  						PayloadLength:     header.IPv6FragmentHeaderSize + 9,
  2096  						TransportProtocol: header.UDPProtocolNumber,
  2097  						HopLimit:          hoplimit,
  2098  						SrcAddr:           addr1,
  2099  						DstAddr:           addr2,
  2100  					},
  2101  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2102  						FragmentOffset: 0 >> 3,
  2103  						M:              true,
  2104  						Identification: ident,
  2105  					},
  2106  					payload: []byte(data)[:9],
  2107  				},
  2108  			},
  2109  			wantMalformedIPPackets: 1,
  2110  			wantMalformedFragments: 1,
  2111  			expectICMP:             true,
  2112  			expectICMPType:         header.ICMPv6ParamProblem,
  2113  			expectICMPCode:         header.ICMPv6ErroneousHeader,
  2114  			expectICMPTypeSpecific: header.IPv6PayloadLenOffset,
  2115  		},
  2116  		{
  2117  			name: "fragments reassembled into a payload exceeding the max IPv6 payload size",
  2118  			fragments: []fragmentData{
  2119  				{
  2120  					ipv6Fields: header.IPv6Fields{
  2121  						PayloadLength:     header.IPv6FragmentHeaderSize + 16,
  2122  						TransportProtocol: header.UDPProtocolNumber,
  2123  						HopLimit:          hoplimit,
  2124  						SrcAddr:           addr1,
  2125  						DstAddr:           addr2,
  2126  					},
  2127  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2128  						FragmentOffset: ((header.IPv6MaximumPayloadSize + 1) - 16) >> 3,
  2129  						M:              false,
  2130  						Identification: ident,
  2131  					},
  2132  					payload: []byte(data)[:16],
  2133  				},
  2134  			},
  2135  			wantMalformedIPPackets: 1,
  2136  			wantMalformedFragments: 1,
  2137  			expectICMP:             true,
  2138  			expectICMPType:         header.ICMPv6ParamProblem,
  2139  			expectICMPCode:         header.ICMPv6ErroneousHeader,
  2140  			expectICMPTypeSpecific: header.IPv6MinimumSize + 2, /* offset for 'Fragment Offset' in the fragment header */
  2141  		},
  2142  	}
  2143  
  2144  	for _, test := range tests {
  2145  		t.Run(test.name, func(t *testing.T) {
  2146  			c := newTestContext()
  2147  			defer c.cleanup()
  2148  			s := c.s
  2149  
  2150  			e := channel.New(1, 1500, linkAddr1)
  2151  			defer e.Close()
  2152  			if err := s.CreateNIC(nicID, e); err != nil {
  2153  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  2154  			}
  2155  			protocolAddr := tcpip.ProtocolAddress{
  2156  				Protocol:          ProtocolNumber,
  2157  				AddressWithPrefix: addr2.WithPrefix(),
  2158  			}
  2159  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  2160  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  2161  			}
  2162  			s.SetRouteTable([]tcpip.Route{{
  2163  				Destination: header.IPv6EmptySubnet,
  2164  				NIC:         nicID,
  2165  			}})
  2166  
  2167  			var expectICMPPayload []byte
  2168  			for _, f := range test.fragments {
  2169  				hdr := prependable.New(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize)
  2170  
  2171  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize))
  2172  				encodeArgs := f.ipv6Fields
  2173  				encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields)
  2174  				ip.Encode(&encodeArgs)
  2175  
  2176  				buf := buffer.MakeWithData(append(hdr.View(), f.payload...))
  2177  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  2178  					Payload: buf,
  2179  				})
  2180  
  2181  				if test.expectICMP {
  2182  					payload := stack.PayloadSince(pkt.NetworkHeader())
  2183  					defer payload.Release()
  2184  					expectICMPPayload = payload.AsSlice()
  2185  				}
  2186  
  2187  				e.InjectInbound(ProtocolNumber, pkt)
  2188  				pkt.DecRef()
  2189  			}
  2190  
  2191  			if got, want := s.Stats().IP.MalformedPacketsReceived.Value(), test.wantMalformedIPPackets; got != want {
  2192  				t.Errorf("got Stats.IP.MalformedPacketsReceived = %d, want = %d", got, want)
  2193  			}
  2194  			if got, want := s.Stats().IP.MalformedFragmentsReceived.Value(), test.wantMalformedFragments; got != want {
  2195  				t.Errorf("got Stats.IP.MalformedFragmentsReceived = %d, want = %d", got, want)
  2196  			}
  2197  
  2198  			reply := e.Read()
  2199  			if !test.expectICMP {
  2200  				if reply != nil {
  2201  					t.Fatalf("unexpected ICMP error message received: %#v", reply)
  2202  				}
  2203  				return
  2204  			}
  2205  			if reply == nil {
  2206  				t.Fatal("expected ICMP error message missing")
  2207  			}
  2208  
  2209  			payload := stack.PayloadSince(reply.NetworkHeader())
  2210  			defer payload.Release()
  2211  			checker.IPv6(t, payload,
  2212  				checker.SrcAddr(addr2),
  2213  				checker.DstAddr(addr1),
  2214  				checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+len(expectICMPPayload))),
  2215  				checker.ICMPv6(
  2216  					checker.ICMPv6Type(test.expectICMPType),
  2217  					checker.ICMPv6Code(test.expectICMPCode),
  2218  					checker.ICMPv6TypeSpecific(test.expectICMPTypeSpecific),
  2219  					checker.ICMPv6Payload(expectICMPPayload),
  2220  				),
  2221  			)
  2222  			reply.DecRef()
  2223  		})
  2224  	}
  2225  }
  2226  
  2227  func TestFragmentReassemblyTimeout(t *testing.T) {
  2228  	const (
  2229  		linkAddr1 = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
  2230  		nicID     = 1
  2231  		hoplimit  = 255
  2232  		ident     = 1
  2233  		data      = "TEST_FRAGMENT_REASSEMBLY_TIMEOUT"
  2234  	)
  2235  	var (
  2236  		addr1 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"))
  2237  		addr2 = tcpip.AddrFromSlice([]byte("\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"))
  2238  	)
  2239  
  2240  	type fragmentData struct {
  2241  		ipv6Fields         header.IPv6Fields
  2242  		ipv6FragmentFields header.IPv6SerializableFragmentExtHdr
  2243  		payload            []byte
  2244  	}
  2245  
  2246  	tests := []struct {
  2247  		name       string
  2248  		fragments  []fragmentData
  2249  		expectICMP bool
  2250  	}{
  2251  		{
  2252  			name: "first fragment only",
  2253  			fragments: []fragmentData{
  2254  				{
  2255  					ipv6Fields: header.IPv6Fields{
  2256  						PayloadLength:     header.IPv6FragmentHeaderSize + 16,
  2257  						TransportProtocol: header.UDPProtocolNumber,
  2258  						HopLimit:          hoplimit,
  2259  						SrcAddr:           addr1,
  2260  						DstAddr:           addr2,
  2261  					},
  2262  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2263  						FragmentOffset: 0,
  2264  						M:              true,
  2265  						Identification: ident,
  2266  					},
  2267  					payload: []byte(data)[:16],
  2268  				},
  2269  			},
  2270  			expectICMP: true,
  2271  		},
  2272  		{
  2273  			name: "two first fragments",
  2274  			fragments: []fragmentData{
  2275  				{
  2276  					ipv6Fields: header.IPv6Fields{
  2277  						PayloadLength:     header.IPv6FragmentHeaderSize + 16,
  2278  						TransportProtocol: header.UDPProtocolNumber,
  2279  						HopLimit:          hoplimit,
  2280  						SrcAddr:           addr1,
  2281  						DstAddr:           addr2,
  2282  					},
  2283  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2284  						FragmentOffset: 0,
  2285  						M:              true,
  2286  						Identification: ident,
  2287  					},
  2288  					payload: []byte(data)[:16],
  2289  				},
  2290  				{
  2291  					ipv6Fields: header.IPv6Fields{
  2292  						PayloadLength:     header.IPv6FragmentHeaderSize + 16,
  2293  						TransportProtocol: header.UDPProtocolNumber,
  2294  						HopLimit:          hoplimit,
  2295  						SrcAddr:           addr1,
  2296  						DstAddr:           addr2,
  2297  					},
  2298  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2299  						FragmentOffset: 0,
  2300  						M:              true,
  2301  						Identification: ident,
  2302  					},
  2303  					payload: []byte(data)[:16],
  2304  				},
  2305  			},
  2306  			expectICMP: true,
  2307  		},
  2308  		{
  2309  			name: "second fragment only",
  2310  			fragments: []fragmentData{
  2311  				{
  2312  					ipv6Fields: header.IPv6Fields{
  2313  						PayloadLength:     uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
  2314  						TransportProtocol: header.UDPProtocolNumber,
  2315  						HopLimit:          hoplimit,
  2316  						SrcAddr:           addr1,
  2317  						DstAddr:           addr2,
  2318  					},
  2319  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2320  						FragmentOffset: 8,
  2321  						M:              false,
  2322  						Identification: ident,
  2323  					},
  2324  					payload: []byte(data)[16:],
  2325  				},
  2326  			},
  2327  			expectICMP: false,
  2328  		},
  2329  		{
  2330  			name: "two fragments with a gap",
  2331  			fragments: []fragmentData{
  2332  				{
  2333  					ipv6Fields: header.IPv6Fields{
  2334  						PayloadLength:     header.IPv6FragmentHeaderSize + 16,
  2335  						TransportProtocol: header.UDPProtocolNumber,
  2336  						HopLimit:          hoplimit,
  2337  						SrcAddr:           addr1,
  2338  						DstAddr:           addr2,
  2339  					},
  2340  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2341  						FragmentOffset: 0,
  2342  						M:              true,
  2343  						Identification: ident,
  2344  					},
  2345  					payload: []byte(data)[:16],
  2346  				},
  2347  				{
  2348  					ipv6Fields: header.IPv6Fields{
  2349  						PayloadLength:     uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
  2350  						TransportProtocol: header.UDPProtocolNumber,
  2351  						HopLimit:          hoplimit,
  2352  						SrcAddr:           addr1,
  2353  						DstAddr:           addr2,
  2354  					},
  2355  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2356  						FragmentOffset: 8,
  2357  						M:              false,
  2358  						Identification: ident,
  2359  					},
  2360  					payload: []byte(data)[16:],
  2361  				},
  2362  			},
  2363  			expectICMP: true,
  2364  		},
  2365  		{
  2366  			name: "two fragments with a gap in reverse order",
  2367  			fragments: []fragmentData{
  2368  				{
  2369  					ipv6Fields: header.IPv6Fields{
  2370  						PayloadLength:     uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
  2371  						TransportProtocol: header.UDPProtocolNumber,
  2372  						HopLimit:          hoplimit,
  2373  						SrcAddr:           addr1,
  2374  						DstAddr:           addr2,
  2375  					},
  2376  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2377  						FragmentOffset: 8,
  2378  						M:              false,
  2379  						Identification: ident,
  2380  					},
  2381  					payload: []byte(data)[16:],
  2382  				},
  2383  				{
  2384  					ipv6Fields: header.IPv6Fields{
  2385  						PayloadLength:     header.IPv6FragmentHeaderSize + 16,
  2386  						TransportProtocol: header.UDPProtocolNumber,
  2387  						HopLimit:          hoplimit,
  2388  						SrcAddr:           addr1,
  2389  						DstAddr:           addr2,
  2390  					},
  2391  					ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
  2392  						FragmentOffset: 0,
  2393  						M:              true,
  2394  						Identification: ident,
  2395  					},
  2396  					payload: []byte(data)[:16],
  2397  				},
  2398  			},
  2399  			expectICMP: true,
  2400  		},
  2401  	}
  2402  
  2403  	for _, test := range tests {
  2404  		t.Run(test.name, func(t *testing.T) {
  2405  			c := newTestContext()
  2406  			defer c.cleanup()
  2407  			s := c.s
  2408  
  2409  			e := channel.New(1, 1500, linkAddr1)
  2410  			defer e.Close()
  2411  			if err := s.CreateNIC(nicID, e); err != nil {
  2412  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  2413  			}
  2414  			protocolAddr := tcpip.ProtocolAddress{
  2415  				Protocol:          ProtocolNumber,
  2416  				AddressWithPrefix: addr2.WithPrefix(),
  2417  			}
  2418  			if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  2419  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  2420  			}
  2421  			s.SetRouteTable([]tcpip.Route{{
  2422  				Destination: header.IPv6EmptySubnet,
  2423  				NIC:         nicID,
  2424  			}})
  2425  
  2426  			var firstFragmentSent []byte
  2427  			for _, f := range test.fragments {
  2428  				hdr := prependable.New(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize)
  2429  
  2430  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize))
  2431  				encodeArgs := f.ipv6Fields
  2432  				encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields)
  2433  				ip.Encode(&encodeArgs)
  2434  
  2435  				fragHDR := header.IPv6Fragment(hdr.View()[header.IPv6MinimumSize:])
  2436  
  2437  				buf := buffer.MakeWithData(append(hdr.View(), f.payload...))
  2438  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  2439  					Payload: buf,
  2440  				})
  2441  
  2442  				if firstFragmentSent == nil && fragHDR.FragmentOffset() == 0 {
  2443  					payload := stack.PayloadSince(pkt.NetworkHeader())
  2444  					defer payload.Release()
  2445  					firstFragmentSent = payload.AsSlice()
  2446  				}
  2447  
  2448  				e.InjectInbound(ProtocolNumber, pkt)
  2449  				pkt.DecRef()
  2450  			}
  2451  
  2452  			c.clock.Advance(ReassembleTimeout)
  2453  
  2454  			reply := e.Read()
  2455  			if !test.expectICMP {
  2456  				if reply != nil {
  2457  					t.Fatalf("unexpected ICMP error message received: %#v", reply)
  2458  				}
  2459  				return
  2460  			}
  2461  			if reply == nil {
  2462  				t.Fatal("expected ICMP error message missing")
  2463  			}
  2464  			if firstFragmentSent == nil {
  2465  				t.Fatalf("unexpected ICMP error message received: %#v", reply)
  2466  			}
  2467  
  2468  			payload := stack.PayloadSince(reply.NetworkHeader())
  2469  			defer payload.Release()
  2470  			checker.IPv6(t, payload,
  2471  				checker.SrcAddr(addr2),
  2472  				checker.DstAddr(addr1),
  2473  				checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+len(firstFragmentSent))),
  2474  				checker.ICMPv6(
  2475  					checker.ICMPv6Type(header.ICMPv6TimeExceeded),
  2476  					checker.ICMPv6Code(header.ICMPv6ReassemblyTimeout),
  2477  					checker.ICMPv6Payload(firstFragmentSent),
  2478  				),
  2479  			)
  2480  			reply.DecRef()
  2481  		})
  2482  	}
  2483  }
  2484  
  2485  func TestWriteStats(t *testing.T) {
  2486  	const nPackets = 3
  2487  	tests := []struct {
  2488  		name                     string
  2489  		setup                    func(*testing.T, *stack.Stack)
  2490  		allowPackets             int
  2491  		expectSent               int
  2492  		expectOutputDropped      int
  2493  		expectPostroutingDropped int
  2494  		expectWritten            int
  2495  	}{
  2496  		{
  2497  			name: "Accept all",
  2498  			// No setup needed, tables accept everything by default.
  2499  			setup:                    func(*testing.T, *stack.Stack) {},
  2500  			allowPackets:             math.MaxInt32,
  2501  			expectSent:               nPackets,
  2502  			expectOutputDropped:      0,
  2503  			expectPostroutingDropped: 0,
  2504  			expectWritten:            nPackets,
  2505  		}, {
  2506  			name: "Accept all with error",
  2507  			// No setup needed, tables accept everything by default.
  2508  			setup:                    func(*testing.T, *stack.Stack) {},
  2509  			allowPackets:             nPackets - 1,
  2510  			expectSent:               nPackets - 1,
  2511  			expectOutputDropped:      0,
  2512  			expectPostroutingDropped: 0,
  2513  			expectWritten:            nPackets - 1,
  2514  		}, {
  2515  			name: "Drop all with Output chain",
  2516  			setup: func(t *testing.T, stk *stack.Stack) {
  2517  				// Install Output DROP rule.
  2518  				ipt := stk.IPTables()
  2519  				filter := ipt.GetTable(stack.FilterID, true /* ipv6 */)
  2520  				ruleIdx := filter.BuiltinChains[stack.Output]
  2521  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  2522  				ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */)
  2523  			},
  2524  			allowPackets:             math.MaxInt32,
  2525  			expectSent:               0,
  2526  			expectOutputDropped:      nPackets,
  2527  			expectPostroutingDropped: 0,
  2528  			expectWritten:            nPackets,
  2529  		}, {
  2530  			name: "Drop all with Postrouting chain",
  2531  			setup: func(t *testing.T, stk *stack.Stack) {
  2532  				// Install Output DROP rule.
  2533  				ipt := stk.IPTables()
  2534  				filter := ipt.GetTable(stack.NATID, true /* ipv6 */)
  2535  				ruleIdx := filter.BuiltinChains[stack.Postrouting]
  2536  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  2537  				ipt.ForceReplaceTable(stack.NATID, filter, true /* ipv6 */)
  2538  			},
  2539  			allowPackets:             math.MaxInt32,
  2540  			expectSent:               0,
  2541  			expectOutputDropped:      0,
  2542  			expectPostroutingDropped: nPackets,
  2543  			expectWritten:            nPackets,
  2544  		}, {
  2545  			name: "Drop some with Output chain",
  2546  			setup: func(t *testing.T, stk *stack.Stack) {
  2547  				// Install Output DROP rule that matches only 1
  2548  				// of the 3 packets.
  2549  				ipt := stk.IPTables()
  2550  				filter := ipt.GetTable(stack.FilterID, true /* ipv6 */)
  2551  				// We'll match and DROP the last packet.
  2552  				ruleIdx := filter.BuiltinChains[stack.Output]
  2553  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  2554  				filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}}
  2555  				// Make sure the next rule is ACCEPT.
  2556  				filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
  2557  				ipt.ForceReplaceTable(stack.FilterID, filter, true /* ipv6 */)
  2558  			},
  2559  			allowPackets:             math.MaxInt32,
  2560  			expectSent:               nPackets - 1,
  2561  			expectOutputDropped:      1,
  2562  			expectPostroutingDropped: 0,
  2563  			expectWritten:            nPackets,
  2564  		}, {
  2565  			name: "Drop some with Postrouting chain",
  2566  			setup: func(t *testing.T, stk *stack.Stack) {
  2567  				// Install Postrouting DROP rule that matches only 1
  2568  				// of the 3 packets.
  2569  				ipt := stk.IPTables()
  2570  				filter := ipt.GetTable(stack.NATID, true /* ipv6 */)
  2571  				// We'll match and DROP the last packet.
  2572  				ruleIdx := filter.BuiltinChains[stack.Postrouting]
  2573  				filter.Rules[ruleIdx].Target = &stack.DropTarget{}
  2574  				filter.Rules[ruleIdx].Matchers = []stack.Matcher{&limitedMatcher{nPackets - 1}}
  2575  				// Make sure the next rule is ACCEPT.
  2576  				filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
  2577  				ipt.ForceReplaceTable(stack.NATID, filter, true /* ipv6 */)
  2578  			},
  2579  			allowPackets:             math.MaxInt32,
  2580  			expectSent:               nPackets - 1,
  2581  			expectOutputDropped:      0,
  2582  			expectPostroutingDropped: 1,
  2583  			expectWritten:            nPackets,
  2584  		},
  2585  	}
  2586  
  2587  	for _, test := range tests {
  2588  		t.Run(test.name, func(t *testing.T) {
  2589  			c := newTestContext()
  2590  			defer c.cleanup()
  2591  
  2592  			ep := iptestutil.NewMockLinkEndpoint(header.IPv6MinimumMTU, &tcpip.ErrInvalidEndpointState{}, test.allowPackets)
  2593  			defer ep.Close()
  2594  
  2595  			rt := buildRoute(t, c, ep)
  2596  			defer rt.Release()
  2597  			test.setup(t, rt.Stack())
  2598  
  2599  			nWritten := 0
  2600  			for i := 0; i < nPackets; i++ {
  2601  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  2602  					ReserveHeaderBytes: header.UDPMinimumSize + int(rt.MaxHeaderLength()),
  2603  					Payload:            buffer.Buffer{},
  2604  				})
  2605  				defer pkt.DecRef()
  2606  				pkt.TransportHeader().Push(header.UDPMinimumSize)
  2607  				if err := rt.WritePacket(stack.NetworkHeaderParams{}, pkt); err != nil {
  2608  					break
  2609  				}
  2610  				nWritten++
  2611  			}
  2612  
  2613  			if got := int(rt.Stats().IP.PacketsSent.Value()); got != test.expectSent {
  2614  				t.Errorf("got rt.Stats().IP.PacketsSent.Value() = %d, want = %d", got, test.expectSent)
  2615  			}
  2616  			if got := int(rt.Stats().IP.IPTablesOutputDropped.Value()); got != test.expectOutputDropped {
  2617  				t.Errorf("got rt.Stats().IP.IPTablesOutputDropped.Value() = %d, want = %d", got, test.expectOutputDropped)
  2618  			}
  2619  			if got := int(rt.Stats().IP.IPTablesPostroutingDropped.Value()); got != test.expectPostroutingDropped {
  2620  				t.Errorf("got r.Stats().IP.IPTablesPostroutingDropped.Value() = %d, want = %d", got, test.expectPostroutingDropped)
  2621  			}
  2622  			if nWritten != test.expectWritten {
  2623  				t.Errorf("got nWritten = %d, want = %d", nWritten, test.expectWritten)
  2624  			}
  2625  		})
  2626  	}
  2627  }
  2628  
  2629  func buildRoute(t *testing.T, c testContext, ep stack.LinkEndpoint) *stack.Route {
  2630  	s := c.s
  2631  	if err := s.CreateNIC(1, ep); err != nil {
  2632  		t.Fatalf("CreateNIC(1, _) failed: %s", err)
  2633  	}
  2634  	var (
  2635  		src = tcpip.AddrFromSlice([]byte("\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"))
  2636  		dst = tcpip.AddrFromSlice([]byte("\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"))
  2637  	)
  2638  	protocolAddr := tcpip.ProtocolAddress{
  2639  		Protocol:          ProtocolNumber,
  2640  		AddressWithPrefix: src.WithPrefix(),
  2641  	}
  2642  	if err := s.AddProtocolAddress(1, protocolAddr, stack.AddressProperties{}); err != nil {
  2643  		t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", 1, protocolAddr, err)
  2644  	}
  2645  	{
  2646  		mask := tcpip.MaskFrom("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")
  2647  		subnet, err := tcpip.NewSubnet(dst, mask)
  2648  		if err != nil {
  2649  			t.Fatalf("NewSubnet(%s, %s) failed: %v", dst, mask, err)
  2650  		}
  2651  		s.SetRouteTable([]tcpip.Route{{
  2652  			Destination: subnet,
  2653  			NIC:         1,
  2654  		}})
  2655  	}
  2656  	rt, err := s.FindRoute(1, src, dst, ProtocolNumber, false /* multicastLoop */)
  2657  	if err != nil {
  2658  		t.Fatalf("FindRoute(1, %s, %s, %d, false) = %s, want = nil", src, dst, ProtocolNumber, err)
  2659  	}
  2660  	return rt
  2661  }
  2662  
  2663  // limitedMatcher is an iptables matcher that matches after a certain number of
  2664  // packets are checked against it.
  2665  type limitedMatcher struct {
  2666  	limit int
  2667  }
  2668  
  2669  // Name implements Matcher.Name.
  2670  func (*limitedMatcher) Name() string {
  2671  	return "limitedMatcher"
  2672  }
  2673  
  2674  // Match implements Matcher.Match.
  2675  func (lm *limitedMatcher) Match(stack.Hook, *stack.PacketBuffer, string, string) (bool, bool) {
  2676  	if lm.limit == 0 {
  2677  		return true, false
  2678  	}
  2679  	lm.limit--
  2680  	return false, false
  2681  }
  2682  
  2683  func knownNICIDs(proto *protocol) []tcpip.NICID {
  2684  	var nicIDs []tcpip.NICID
  2685  
  2686  	for k := range proto.mu.eps {
  2687  		nicIDs = append(nicIDs, k)
  2688  	}
  2689  
  2690  	return nicIDs
  2691  }
  2692  
  2693  func TestClearEndpointFromProtocolOnClose(t *testing.T) {
  2694  	c := newTestContext()
  2695  	defer c.cleanup()
  2696  	s := c.s
  2697  
  2698  	proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol)
  2699  	var nic testInterface
  2700  	ep := proto.NewEndpoint(&nic, nil).(*endpoint)
  2701  	var nicIDs []tcpip.NICID
  2702  
  2703  	proto.mu.Lock()
  2704  	foundEP, hasEndpointBeforeClose := proto.mu.eps[nic.ID()]
  2705  	nicIDs = knownNICIDs(proto)
  2706  	proto.mu.Unlock()
  2707  	if !hasEndpointBeforeClose {
  2708  		t.Fatalf("expected to find the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
  2709  	}
  2710  	if foundEP != ep {
  2711  		t.Fatalf("found an incorrect endpoint mapped to nic id %d", nic.ID())
  2712  	}
  2713  
  2714  	ep.Close()
  2715  
  2716  	proto.mu.Lock()
  2717  	_, hasEndpointAfterClose := proto.mu.eps[nic.ID()]
  2718  	nicIDs = knownNICIDs(proto)
  2719  	proto.mu.Unlock()
  2720  	if hasEndpointAfterClose {
  2721  		t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
  2722  	}
  2723  }
  2724  
  2725  type fragmentInfo struct {
  2726  	offset      uint16
  2727  	more        bool
  2728  	payloadSize uint16
  2729  }
  2730  
  2731  var fragmentationTests = []struct {
  2732  	description   string
  2733  	mtu           uint32
  2734  	transHdrLen   int
  2735  	payloadSize   int
  2736  	wantFragments []fragmentInfo
  2737  }{
  2738  	{
  2739  		description: "No fragmentation",
  2740  		mtu:         header.IPv6MinimumMTU,
  2741  		transHdrLen: 0,
  2742  		payloadSize: 1000,
  2743  		wantFragments: []fragmentInfo{
  2744  			{offset: 0, payloadSize: 1000, more: false},
  2745  		},
  2746  	},
  2747  	{
  2748  		description: "Fragmented",
  2749  		mtu:         header.IPv6MinimumMTU,
  2750  		transHdrLen: 0,
  2751  		payloadSize: 2000,
  2752  		wantFragments: []fragmentInfo{
  2753  			{offset: 0, payloadSize: 1240, more: true},
  2754  			{offset: 154, payloadSize: 776, more: false},
  2755  		},
  2756  	},
  2757  	{
  2758  		description: "Fragmented with mtu not a multiple of 8",
  2759  		mtu:         header.IPv6MinimumMTU + 1,
  2760  		transHdrLen: 0,
  2761  		payloadSize: 2000,
  2762  		wantFragments: []fragmentInfo{
  2763  			{offset: 0, payloadSize: 1240, more: true},
  2764  			{offset: 154, payloadSize: 776, more: false},
  2765  		},
  2766  	},
  2767  	{
  2768  		description: "No fragmentation with big header",
  2769  		mtu:         2000,
  2770  		transHdrLen: 100,
  2771  		payloadSize: 1000,
  2772  		wantFragments: []fragmentInfo{
  2773  			{offset: 0, payloadSize: 1100, more: false},
  2774  		},
  2775  	},
  2776  	{
  2777  		description: "Fragmented with big header",
  2778  		mtu:         header.IPv6MinimumMTU,
  2779  		transHdrLen: 100,
  2780  		payloadSize: 1200,
  2781  		wantFragments: []fragmentInfo{
  2782  			{offset: 0, payloadSize: 1240, more: true},
  2783  			{offset: 154, payloadSize: 76, more: false},
  2784  		},
  2785  	},
  2786  }
  2787  
  2788  func TestFragmentationWritePacket(t *testing.T) {
  2789  	const ttl = 42
  2790  
  2791  	for _, ft := range fragmentationTests {
  2792  		t.Run(ft.description, func(t *testing.T) {
  2793  			c := newTestContext()
  2794  			defer c.cleanup()
  2795  
  2796  			pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
  2797  			defer pkt.DecRef()
  2798  			source := pkt.Clone()
  2799  			defer source.DecRef()
  2800  
  2801  			ep := iptestutil.NewMockLinkEndpoint(ft.mtu, nil, math.MaxInt32)
  2802  			defer ep.Close()
  2803  
  2804  			r := buildRoute(t, c, ep)
  2805  			defer r.Release()
  2806  			err := r.WritePacket(stack.NetworkHeaderParams{
  2807  				Protocol: tcp.ProtocolNumber,
  2808  				TTL:      ttl,
  2809  				TOS:      stack.DefaultTOS,
  2810  			}, pkt)
  2811  			if err != nil {
  2812  				t.Fatalf("WritePacket(_, _, _): = %s", err)
  2813  			}
  2814  			if got := len(ep.WrittenPackets); got != len(ft.wantFragments) {
  2815  				t.Errorf("got len(ep.WrittenPackets) = %d, want = %d", got, len(ft.wantFragments))
  2816  			}
  2817  			if got := int(r.Stats().IP.PacketsSent.Value()); got != len(ft.wantFragments) {
  2818  				t.Errorf("got c.Route.Stats().IP.PacketsSent.Value() = %d, want = %d", got, len(ft.wantFragments))
  2819  			}
  2820  			if got := r.Stats().IP.OutgoingPacketErrors.Value(); got != 0 {
  2821  				t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = 0", got)
  2822  			}
  2823  			if err := compareFragments(ep.WrittenPackets, source, ft.mtu, ft.wantFragments, tcp.ProtocolNumber); err != nil {
  2824  				t.Error(err)
  2825  			}
  2826  		})
  2827  	}
  2828  }
  2829  
  2830  // TestFragmentationErrors checks that errors are returned from WritePacket
  2831  // correctly.
  2832  func TestFragmentationErrors(t *testing.T) {
  2833  	const ttl = 42
  2834  
  2835  	tests := []struct {
  2836  		description    string
  2837  		mtu            uint32
  2838  		transHdrLen    int
  2839  		payloadSize    int
  2840  		allowPackets   int
  2841  		outgoingErrors int
  2842  		mockError      tcpip.Error
  2843  		wantError      tcpip.Error
  2844  	}{
  2845  		{
  2846  			description:    "No frag",
  2847  			mtu:            2000,
  2848  			payloadSize:    1000,
  2849  			transHdrLen:    0,
  2850  			allowPackets:   0,
  2851  			outgoingErrors: 1,
  2852  			mockError:      &tcpip.ErrAborted{},
  2853  			wantError:      &tcpip.ErrAborted{},
  2854  		},
  2855  		{
  2856  			description:    "Error on first frag",
  2857  			mtu:            1300,
  2858  			payloadSize:    3000,
  2859  			transHdrLen:    0,
  2860  			allowPackets:   0,
  2861  			outgoingErrors: 3,
  2862  			mockError:      &tcpip.ErrAborted{},
  2863  			wantError:      &tcpip.ErrAborted{},
  2864  		},
  2865  		{
  2866  			description:    "Error on second frag",
  2867  			mtu:            1500,
  2868  			payloadSize:    4000,
  2869  			transHdrLen:    0,
  2870  			allowPackets:   1,
  2871  			outgoingErrors: 2,
  2872  			mockError:      &tcpip.ErrAborted{},
  2873  			wantError:      &tcpip.ErrAborted{},
  2874  		},
  2875  		{
  2876  			description:    "Error when MTU is smaller than transport header",
  2877  			mtu:            header.IPv6MinimumMTU,
  2878  			transHdrLen:    1500,
  2879  			payloadSize:    500,
  2880  			allowPackets:   0,
  2881  			outgoingErrors: 1,
  2882  			mockError:      nil,
  2883  			wantError:      &tcpip.ErrMessageTooLong{},
  2884  		},
  2885  		{
  2886  			description:    "Error when MTU is smaller than IPv6 minimum MTU",
  2887  			mtu:            header.IPv6MinimumMTU - 1,
  2888  			transHdrLen:    0,
  2889  			payloadSize:    500,
  2890  			allowPackets:   0,
  2891  			outgoingErrors: 1,
  2892  			mockError:      nil,
  2893  			wantError:      &tcpip.ErrInvalidEndpointState{},
  2894  		},
  2895  	}
  2896  
  2897  	for _, ft := range tests {
  2898  		t.Run(ft.description, func(t *testing.T) {
  2899  			c := newTestContext()
  2900  			defer c.cleanup()
  2901  
  2902  			pkt := iptestutil.MakeRandPkt(ft.transHdrLen, extraHeaderReserve+header.IPv6MinimumSize, []int{ft.payloadSize}, header.IPv6ProtocolNumber)
  2903  			defer pkt.DecRef()
  2904  			ep := iptestutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets)
  2905  			defer ep.Close()
  2906  
  2907  			r := buildRoute(t, c, ep)
  2908  			defer r.Release()
  2909  			err := r.WritePacket(stack.NetworkHeaderParams{
  2910  				Protocol: tcp.ProtocolNumber,
  2911  				TTL:      ttl,
  2912  				TOS:      stack.DefaultTOS,
  2913  			}, pkt)
  2914  			if diff := cmp.Diff(ft.wantError, err); diff != "" {
  2915  				t.Errorf("unexpected error from WritePacket(_, _, _), (-want, +got):\n%s", diff)
  2916  			}
  2917  			if got := int(r.Stats().IP.PacketsSent.Value()); got != ft.allowPackets {
  2918  				t.Errorf("got r.Stats().IP.PacketsSent.Value() = %d, want = %d", got, ft.allowPackets)
  2919  			}
  2920  			if got := int(r.Stats().IP.OutgoingPacketErrors.Value()); got != ft.outgoingErrors {
  2921  				t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = %d", got, ft.outgoingErrors)
  2922  			}
  2923  		})
  2924  	}
  2925  }
  2926  
  2927  type icmpError struct {
  2928  	icmpType header.ICMPv6Type
  2929  	icmpCode header.ICMPv6Code
  2930  }
  2931  
  2932  const (
  2933  	incomingNICID  = 1
  2934  	outgoingNICID  = 2
  2935  	randomSequence = 123
  2936  	randomIdent    = 42
  2937  )
  2938  
  2939  var (
  2940  	incomingIPv6Addr = tcpip.AddressWithPrefix{
  2941  		Address:   tcpip.AddrFromSlice(net.ParseIP("10::1").To16()),
  2942  		PrefixLen: 64,
  2943  	}
  2944  	outgoingIPv6Addr = tcpip.AddressWithPrefix{
  2945  		Address:   tcpip.AddrFromSlice(net.ParseIP("11::1").To16()),
  2946  		PrefixLen: 64,
  2947  	}
  2948  	multicastIPv6Addr = tcpip.AddressWithPrefix{
  2949  		Address:   tcpip.AddrFromSlice(net.ParseIP("ff00::").To16()),
  2950  		PrefixLen: 64,
  2951  	}
  2952  	remoteIPv6Addr1        = tcpip.AddrFromSlice(net.ParseIP("10::2").To16())
  2953  	remoteIPv6Addr2        = tcpip.AddrFromSlice(net.ParseIP("11::2").To16())
  2954  	unreachableIPv6Addr    = tcpip.AddrFromSlice(net.ParseIP("12::2").To16())
  2955  	linkLocalIPv6Addr      = tcpip.AddrFromSlice(net.ParseIP("fe80::").To16())
  2956  	defaultEndpointConfigs = map[tcpip.NICID]tcpip.AddressWithPrefix{
  2957  		incomingNICID: incomingIPv6Addr,
  2958  		outgoingNICID: outgoingIPv6Addr,
  2959  	}
  2960  )
  2961  
  2962  func TestForwarding(t *testing.T) {
  2963  	tests := []struct {
  2964  		name                             string
  2965  		extHdr                           func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker)
  2966  		TTL                              uint8
  2967  		payloadLength                    int
  2968  		srcAddr                          tcpip.Address
  2969  		dstAddr                          tcpip.Address
  2970  		expectedPacketUnrouteableErrors  uint64
  2971  		expectedInitializingSourceErrors uint64
  2972  		expectedLinkLocalSourceErrors    uint64
  2973  		expectedLinkLocalDestErrors      uint64
  2974  		expectedExtensionHeaderErrors    uint64
  2975  		expectedPacketTooBigErrors       uint64
  2976  		expectedExhaustedTTLErrors       uint64
  2977  		expectPacketForwarded            bool
  2978  		expectedFragmentsForwarded       []fragmentInfo
  2979  		expectedICMPError                *icmpError
  2980  	}{
  2981  		{
  2982  			name:    "TTL of zero",
  2983  			TTL:     0,
  2984  			srcAddr: remoteIPv6Addr1,
  2985  			dstAddr: remoteIPv6Addr2,
  2986  			expectedICMPError: &icmpError{
  2987  				icmpType: header.ICMPv6TimeExceeded,
  2988  				icmpCode: header.ICMPv6HopLimitExceeded,
  2989  			},
  2990  			expectedExhaustedTTLErrors: 1,
  2991  			expectPacketForwarded:      false,
  2992  		},
  2993  		{
  2994  			name:    "TTL of one",
  2995  			TTL:     1,
  2996  			srcAddr: remoteIPv6Addr1,
  2997  			dstAddr: remoteIPv6Addr2,
  2998  			expectedICMPError: &icmpError{
  2999  				icmpType: header.ICMPv6TimeExceeded,
  3000  				icmpCode: header.ICMPv6HopLimitExceeded,
  3001  			},
  3002  			expectedExhaustedTTLErrors: 1,
  3003  			expectPacketForwarded:      false,
  3004  		},
  3005  		{
  3006  			name:                  "TTL of two",
  3007  			TTL:                   2,
  3008  			srcAddr:               remoteIPv6Addr1,
  3009  			dstAddr:               remoteIPv6Addr2,
  3010  			expectPacketForwarded: true,
  3011  		},
  3012  		{
  3013  			name:                  "TTL of three",
  3014  			TTL:                   3,
  3015  			srcAddr:               remoteIPv6Addr1,
  3016  			dstAddr:               remoteIPv6Addr2,
  3017  			expectPacketForwarded: true,
  3018  		},
  3019  		{
  3020  			name:                  "Max TTL",
  3021  			TTL:                   math.MaxUint8,
  3022  			srcAddr:               remoteIPv6Addr1,
  3023  			dstAddr:               remoteIPv6Addr2,
  3024  			expectPacketForwarded: true,
  3025  		},
  3026  		{
  3027  			name:    "Network unreachable",
  3028  			TTL:     2,
  3029  			srcAddr: remoteIPv6Addr1,
  3030  			dstAddr: unreachableIPv6Addr,
  3031  			expectedICMPError: &icmpError{
  3032  				icmpType: header.ICMPv6DstUnreachable,
  3033  				icmpCode: header.ICMPv6NetworkUnreachable,
  3034  			},
  3035  			expectedPacketUnrouteableErrors: 1,
  3036  			expectPacketForwarded:           false,
  3037  		},
  3038  		{
  3039  			name:                        "Link local destination",
  3040  			TTL:                         2,
  3041  			srcAddr:                     remoteIPv6Addr1,
  3042  			dstAddr:                     linkLocalIPv6Addr,
  3043  			expectedLinkLocalDestErrors: 1,
  3044  			expectPacketForwarded:       false,
  3045  		},
  3046  		{
  3047  			name:                          "Link local source",
  3048  			TTL:                           2,
  3049  			srcAddr:                       linkLocalIPv6Addr,
  3050  			dstAddr:                       remoteIPv6Addr2,
  3051  			expectedLinkLocalSourceErrors: 1,
  3052  			expectPacketForwarded:         false,
  3053  		},
  3054  		{
  3055  			name:                             "Unspecified source",
  3056  			TTL:                              2,
  3057  			srcAddr:                          header.IPv6Any,
  3058  			dstAddr:                          remoteIPv6Addr2,
  3059  			expectedInitializingSourceErrors: 1,
  3060  			expectPacketForwarded:            false,
  3061  		},
  3062  		{
  3063  			name:    "Hopbyhop with unknown option skippable action",
  3064  			TTL:     2,
  3065  			srcAddr: remoteIPv6Addr1,
  3066  			dstAddr: remoteIPv6Addr2,
  3067  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3068  				return []byte{
  3069  					nextHdr, 1,
  3070  
  3071  					// Skippable unknown.
  3072  					63, 4, 1, 2, 3, 4,
  3073  
  3074  					// Skippable unknown.
  3075  					62, 6, 1, 2, 3, 4, 5, 6,
  3076  				}, hopByHopExtHdrID, checker.IPv6ExtHdr(checker.IPv6HopByHopExtensionHeader(checker.IPv6UnknownOption(), checker.IPv6UnknownOption()))
  3077  			},
  3078  			expectPacketForwarded: true,
  3079  		},
  3080  		{
  3081  			name:    "Hopbyhop with unknown option discard action",
  3082  			TTL:     2,
  3083  			srcAddr: remoteIPv6Addr1,
  3084  			dstAddr: remoteIPv6Addr2,
  3085  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3086  				return []byte{
  3087  					nextHdr, 1,
  3088  
  3089  					// Skippable unknown.
  3090  					63, 4, 1, 2, 3, 4,
  3091  
  3092  					// Discard unknown.
  3093  					127, 6, 1, 2, 3, 4, 5, 6,
  3094  				}, hopByHopExtHdrID, nil
  3095  			},
  3096  			expectedExtensionHeaderErrors: 1,
  3097  			expectPacketForwarded:         false,
  3098  		},
  3099  		{
  3100  			name:    "Hopbyhop with unknown option discard and send icmp action",
  3101  			TTL:     2,
  3102  			srcAddr: remoteIPv6Addr1,
  3103  			dstAddr: remoteIPv6Addr2,
  3104  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3105  				return []byte{
  3106  					nextHdr, 1,
  3107  
  3108  					// Skippable unknown.
  3109  					63, 4, 1, 2, 3, 4,
  3110  
  3111  					// Discard & send ICMP if option is unknown.
  3112  					191, 6, 1, 2, 3, 4, 5, 6,
  3113  				}, hopByHopExtHdrID, nil
  3114  			},
  3115  			expectedICMPError: &icmpError{
  3116  				icmpType: header.ICMPv6ParamProblem,
  3117  				icmpCode: header.ICMPv6UnknownOption,
  3118  			},
  3119  			expectedExtensionHeaderErrors: 1,
  3120  			expectPacketForwarded:         false,
  3121  		},
  3122  		{
  3123  			name:    "Hopbyhop with unknown option discard and send icmp action",
  3124  			TTL:     2,
  3125  			srcAddr: remoteIPv6Addr1,
  3126  			dstAddr: remoteIPv6Addr2,
  3127  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3128  				return []byte{
  3129  					nextHdr, 1,
  3130  
  3131  					// Skippable unknown.
  3132  					63, 4, 1, 2, 3, 4,
  3133  
  3134  					// Discard & send ICMP unless packet is for multicast destination if
  3135  					// option is unknown.
  3136  					255, 6, 1, 2, 3, 4, 5, 6,
  3137  				}, hopByHopExtHdrID, nil
  3138  			},
  3139  			expectedICMPError: &icmpError{
  3140  				icmpType: header.ICMPv6ParamProblem,
  3141  				icmpCode: header.ICMPv6UnknownOption,
  3142  			},
  3143  			expectedExtensionHeaderErrors: 1,
  3144  			expectPacketForwarded:         false,
  3145  		},
  3146  		{
  3147  			name:    "Hopbyhop with router alert option",
  3148  			TTL:     2,
  3149  			srcAddr: remoteIPv6Addr1,
  3150  			dstAddr: remoteIPv6Addr2,
  3151  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3152  				return []byte{
  3153  					nextHdr, 0,
  3154  
  3155  					// Router Alert option.
  3156  					5, 2, 0, 0, 0, 0,
  3157  				}, hopByHopExtHdrID, checker.IPv6ExtHdr(checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD)))
  3158  			},
  3159  			expectPacketForwarded: true,
  3160  		},
  3161  		{
  3162  			name:    "Hopbyhop with two router alert options",
  3163  			TTL:     2,
  3164  			srcAddr: remoteIPv6Addr1,
  3165  			dstAddr: remoteIPv6Addr2,
  3166  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3167  				return []byte{
  3168  					nextHdr, 1,
  3169  
  3170  					// Router Alert option.
  3171  					5, 2, 0, 0, 0, 0,
  3172  
  3173  					// Router Alert option.
  3174  					5, 2, 0, 0, 0, 0,
  3175  				}, hopByHopExtHdrID, nil
  3176  			},
  3177  			expectedExtensionHeaderErrors: 1,
  3178  			expectPacketForwarded:         false,
  3179  		},
  3180  		{
  3181  			name:          "Can't fragment",
  3182  			TTL:           2,
  3183  			payloadLength: header.IPv6MinimumMTU + 1,
  3184  			srcAddr:       remoteIPv6Addr1,
  3185  			dstAddr:       remoteIPv6Addr2,
  3186  			expectedICMPError: &icmpError{
  3187  				icmpType: header.ICMPv6PacketTooBig,
  3188  				icmpCode: header.ICMPv6UnusedCode,
  3189  			},
  3190  			expectedPacketTooBigErrors: 1,
  3191  			expectPacketForwarded:      false,
  3192  		},
  3193  	}
  3194  
  3195  	for _, test := range tests {
  3196  		t.Run(test.name, func(t *testing.T) {
  3197  			c := newTestContext()
  3198  			defer c.cleanup()
  3199  			s := c.s
  3200  
  3201  			endpoints := make(map[tcpip.NICID]*channel.Endpoint)
  3202  			for nicID, addr := range defaultEndpointConfigs {
  3203  				ep := channel.New(1, header.IPv6MinimumMTU, "")
  3204  				defer ep.Close()
  3205  
  3206  				if err := s.CreateNIC(nicID, ep); err != nil {
  3207  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  3208  				}
  3209  				addr := tcpip.ProtocolAddress{Protocol: ProtocolNumber, AddressWithPrefix: addr}
  3210  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
  3211  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
  3212  				}
  3213  				s.SetNICMulticastForwarding(nicID, ProtocolNumber, true /* enabled */)
  3214  				endpoints[nicID] = ep
  3215  			}
  3216  
  3217  			s.SetRouteTable([]tcpip.Route{
  3218  				{
  3219  					Destination: incomingIPv6Addr.Subnet(),
  3220  					NIC:         incomingNICID,
  3221  				},
  3222  				{
  3223  					Destination: outgoingIPv6Addr.Subnet(),
  3224  					NIC:         outgoingNICID,
  3225  				},
  3226  				{
  3227  					Destination: multicastIPv6Addr.Subnet(),
  3228  					NIC:         outgoingNICID,
  3229  				},
  3230  			})
  3231  
  3232  			if err := s.SetForwardingDefaultAndAllNICs(ProtocolNumber, true); err != nil {
  3233  				t.Fatalf("s.SetForwardingDefaultAndAllNICs(%d, true): %s", ProtocolNumber, err)
  3234  			}
  3235  
  3236  			transportProtocol := header.ICMPv6ProtocolNumber
  3237  			var extHdrBytes []byte
  3238  			extHdrChecker := checker.IPv6ExtHdr()
  3239  			if test.extHdr != nil {
  3240  				nextHdrID := hopByHopExtHdrID
  3241  				extHdrBytes, nextHdrID, extHdrChecker = test.extHdr(uint8(header.ICMPv6ProtocolNumber))
  3242  				transportProtocol = tcpip.TransportProtocolNumber(nextHdrID)
  3243  			}
  3244  			extHdrLen := len(extHdrBytes)
  3245  
  3246  			ipHeaderLength := header.IPv6MinimumSize
  3247  			icmpHeaderLength := header.ICMPv6MinimumSize
  3248  			payloadLength := icmpHeaderLength + test.payloadLength + extHdrLen
  3249  			totalLength := ipHeaderLength + payloadLength
  3250  			hdr := prependable.New(totalLength)
  3251  			hdr.Prepend(test.payloadLength)
  3252  			icmpH := header.ICMPv6(hdr.Prepend(icmpHeaderLength))
  3253  
  3254  			icmpH.SetIdent(randomIdent)
  3255  			icmpH.SetSequence(randomSequence)
  3256  			icmpH.SetType(header.ICMPv6EchoRequest)
  3257  			icmpH.SetCode(header.ICMPv6UnusedCode)
  3258  			icmpH.SetChecksum(0)
  3259  			icmpH.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  3260  				Header: icmpH,
  3261  				Src:    test.srcAddr,
  3262  				Dst:    test.dstAddr,
  3263  			}))
  3264  			copy(hdr.Prepend(extHdrLen), extHdrBytes)
  3265  			ip := header.IPv6(hdr.Prepend(ipHeaderLength))
  3266  			ip.Encode(&header.IPv6Fields{
  3267  				PayloadLength:     uint16(payloadLength),
  3268  				TransportProtocol: transportProtocol,
  3269  				HopLimit:          test.TTL,
  3270  				SrcAddr:           test.srcAddr,
  3271  				DstAddr:           test.dstAddr,
  3272  			})
  3273  			request := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3274  				Payload: buffer.MakeWithData(hdr.View()),
  3275  			})
  3276  
  3277  			incomingEndpoint, ok := endpoints[incomingNICID]
  3278  			if !ok {
  3279  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID)
  3280  			}
  3281  
  3282  			incomingEndpoint.InjectInbound(ProtocolNumber, request)
  3283  			request.DecRef()
  3284  
  3285  			reply := incomingEndpoint.Read()
  3286  
  3287  			outgoingEndpoint, ok := endpoints[outgoingNICID]
  3288  			if !ok {
  3289  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
  3290  			}
  3291  
  3292  			if test.expectedICMPError != nil {
  3293  				if reply == nil {
  3294  					t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.expectedICMPError.icmpType)
  3295  				}
  3296  
  3297  				// As per RFC 4443, page 9:
  3298  				//
  3299  				//   The returned ICMP packet will contain as much of invoking packet
  3300  				//   as possible without the ICMPv6 packet exceeding the minimum IPv6
  3301  				//   MTU.
  3302  				expectedICMPPayloadLength := func() int {
  3303  					maxICMPPayloadLength := header.IPv6MinimumMTU - ipHeaderLength - icmpHeaderLength
  3304  					if len(hdr.View()) > maxICMPPayloadLength {
  3305  						return maxICMPPayloadLength
  3306  					}
  3307  					return len(hdr.View())
  3308  				}
  3309  
  3310  				payload := stack.PayloadSince(reply.NetworkHeader())
  3311  				defer payload.Release()
  3312  				checker.IPv6(t, payload,
  3313  					checker.SrcAddr(incomingIPv6Addr.Address),
  3314  					checker.DstAddr(test.srcAddr),
  3315  					checker.TTL(DefaultTTL),
  3316  					checker.ICMPv6(
  3317  						checker.ICMPv6Type(test.expectedICMPError.icmpType),
  3318  						checker.ICMPv6Code(test.expectedICMPError.icmpCode),
  3319  						checker.ICMPv6Payload(hdr.View()[:expectedICMPPayloadLength()]),
  3320  					),
  3321  				)
  3322  				reply.DecRef()
  3323  
  3324  				if n := outgoingEndpoint.Drain(); n != 0 {
  3325  					t.Fatalf("e2.Drain() = %d, want = 0", n)
  3326  				}
  3327  			} else if reply != nil {
  3328  				t.Fatalf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply)
  3329  			}
  3330  
  3331  			reply = outgoingEndpoint.Read()
  3332  			if test.expectPacketForwarded {
  3333  				if reply == nil {
  3334  					t.Fatal("Expected ICMP Echo Request packet through outgoing NIC")
  3335  				}
  3336  
  3337  				payload := stack.PayloadSince(reply.NetworkHeader())
  3338  				defer payload.Release()
  3339  				checker.IPv6WithExtHdr(t, payload,
  3340  					checker.SrcAddr(test.srcAddr),
  3341  					checker.DstAddr(test.dstAddr),
  3342  					checker.TTL(test.TTL-1),
  3343  					extHdrChecker,
  3344  					checker.ICMPv6(
  3345  						checker.ICMPv6Type(header.ICMPv6EchoRequest),
  3346  						checker.ICMPv6Code(header.ICMPv6UnusedCode),
  3347  						checker.ICMPv6Payload(nil),
  3348  					),
  3349  				)
  3350  				reply.DecRef()
  3351  
  3352  				if n := incomingEndpoint.Drain(); n != 0 {
  3353  					t.Fatalf("e1.Drain() = %d, want = 0", n)
  3354  				}
  3355  			} else if reply != nil {
  3356  				t.Fatalf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply)
  3357  			}
  3358  
  3359  			if got, want := s.Stats().IP.Forwarding.InitializingSource.Value(), test.expectedInitializingSourceErrors; got != want {
  3360  				t.Errorf("s.Stats().IP.Forwarding.InitializingSource.Value() = %d, want = %d", got, want)
  3361  			}
  3362  
  3363  			if got, want := s.Stats().IP.Forwarding.LinkLocalSource.Value(), test.expectedLinkLocalSourceErrors; got != want {
  3364  				t.Errorf("s.Stats().IP.Forwarding.LinkLocalSource.Value() = %d, want = %d", got, want)
  3365  			}
  3366  
  3367  			if got, want := s.Stats().IP.Forwarding.LinkLocalDestination.Value(), test.expectedLinkLocalDestErrors; got != want {
  3368  				t.Errorf("s.Stats().IP.Forwarding.LinkLocalDestination.Value() = %d, want = %d", got, want)
  3369  			}
  3370  
  3371  			if got, want := s.Stats().IP.Forwarding.ExhaustedTTL.Value(), test.expectedExhaustedTTLErrors; got != want {
  3372  				t.Errorf("s.Stats().IP.Forwarding.ExhaustedTTL.Value() = %d, want = %d", got, want)
  3373  			}
  3374  
  3375  			if got, want := s.Stats().IP.Forwarding.Unrouteable.Value(), test.expectedPacketUnrouteableErrors; got != want {
  3376  				t.Errorf("s.Stats().IP.Forwarding.Unrouteable.Value() = %d, want = %d", got, want)
  3377  			}
  3378  
  3379  			if got, want := s.Stats().IP.Forwarding.ExtensionHeaderProblem.Value(), test.expectedExtensionHeaderErrors; got != want {
  3380  				t.Errorf("s.Stats().IP.Forwarding.ExtensionHeaderProblem.Value() = %d, want = %d", got, want)
  3381  			}
  3382  
  3383  			if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), test.expectedPacketTooBigErrors; got != want {
  3384  				t.Errorf("s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want)
  3385  			}
  3386  
  3387  			totalExpectedErrors := test.expectedPacketUnrouteableErrors + test.expectedPacketTooBigErrors + test.expectedExtensionHeaderErrors + test.expectedLinkLocalSourceErrors + test.expectedLinkLocalDestErrors + test.expectedExhaustedTTLErrors + test.expectedInitializingSourceErrors
  3388  			if got, want := s.Stats().IP.Forwarding.Errors.Value(), totalExpectedErrors; got != want {
  3389  				t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want)
  3390  			}
  3391  		})
  3392  	}
  3393  }
  3394  
  3395  func TestMulticastForwarding(t *testing.T) {
  3396  	const (
  3397  		multicastRouteMinTTL = 2
  3398  		packetTTL            = 2
  3399  	)
  3400  
  3401  	tests := []struct {
  3402  		name                          string
  3403  		extHdr                        func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker)
  3404  		payloadLength                 int
  3405  		expectedExtensionHeaderErrors uint64
  3406  		expectedPacketTooBigErrors    uint64
  3407  		expectPacketForwarded         bool
  3408  		expectedICMPError             *icmpError
  3409  	}{
  3410  		{
  3411  			name: "Hopbyhop with unknown option skippable action",
  3412  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3413  				return []byte{
  3414  					nextHdr, 1,
  3415  
  3416  					// Skippable unknown.
  3417  					63, 4, 1, 2, 3, 4,
  3418  
  3419  					// Skippable unknown.
  3420  					62, 6, 1, 2, 3, 4, 5, 6,
  3421  				}, hopByHopExtHdrID, checker.IPv6ExtHdr(checker.IPv6HopByHopExtensionHeader(checker.IPv6UnknownOption(), checker.IPv6UnknownOption()))
  3422  			},
  3423  			expectPacketForwarded: true,
  3424  		},
  3425  		{
  3426  			name: "Hopbyhop with unknown option discard action",
  3427  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3428  				return []byte{
  3429  					nextHdr, 1,
  3430  
  3431  					// Skippable unknown.
  3432  					63, 4, 1, 2, 3, 4,
  3433  
  3434  					// Discard unknown.
  3435  					127, 6, 1, 2, 3, 4, 5, 6,
  3436  				}, hopByHopExtHdrID, nil
  3437  			},
  3438  			expectedExtensionHeaderErrors: 1,
  3439  			expectPacketForwarded:         false,
  3440  		},
  3441  		{
  3442  			name: "Hopbyhop with unknown option discard and send icmp action",
  3443  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3444  				return []byte{
  3445  					nextHdr, 1,
  3446  
  3447  					// Skippable unknown.
  3448  					63, 4, 1, 2, 3, 4,
  3449  
  3450  					// Discard & send ICMP if option is unknown.
  3451  					191, 6, 1, 2, 3, 4, 5, 6,
  3452  				}, hopByHopExtHdrID, nil
  3453  			},
  3454  			expectedICMPError: &icmpError{
  3455  				icmpType: header.ICMPv6ParamProblem,
  3456  				icmpCode: header.ICMPv6UnknownOption,
  3457  			},
  3458  			expectedExtensionHeaderErrors: 1,
  3459  			expectPacketForwarded:         false,
  3460  		},
  3461  		{
  3462  			name: "Hopbyhop with unknown option discard and don't send icmp action for multicast",
  3463  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3464  				return []byte{
  3465  					nextHdr, 1,
  3466  
  3467  					// Skippable unknown.
  3468  					63, 4, 1, 2, 3, 4,
  3469  
  3470  					// Discard & send ICMP unless packet is for multicast destination if
  3471  					// option is unknown.
  3472  					255, 6, 1, 2, 3, 4, 5, 6,
  3473  				}, hopByHopExtHdrID, nil
  3474  			},
  3475  			expectedExtensionHeaderErrors: 1,
  3476  			expectPacketForwarded:         false,
  3477  		},
  3478  		{
  3479  			name: "Hopbyhop with router alert option",
  3480  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3481  				return []byte{
  3482  					nextHdr, 0,
  3483  
  3484  					// Router Alert option.
  3485  					5, 2, 0, 0, 0, 0,
  3486  				}, hopByHopExtHdrID, checker.IPv6ExtHdr(checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD)))
  3487  			},
  3488  			expectPacketForwarded: true,
  3489  		},
  3490  		{
  3491  			name: "Hopbyhop with two router alert options",
  3492  			extHdr: func(nextHdr uint8) ([]byte, uint8, checker.NetworkChecker) {
  3493  				return []byte{
  3494  					nextHdr, 1,
  3495  
  3496  					// Router Alert option.
  3497  					5, 2, 0, 0, 0, 0,
  3498  
  3499  					// Router Alert option.
  3500  					5, 2, 0, 0, 0, 0,
  3501  				}, hopByHopExtHdrID, nil
  3502  			},
  3503  			expectedExtensionHeaderErrors: 1,
  3504  			expectPacketForwarded:         false,
  3505  		},
  3506  		{
  3507  			name:          "Can't fragment",
  3508  			payloadLength: header.IPv6MinimumMTU + 1,
  3509  			expectedICMPError: &icmpError{
  3510  				icmpType: header.ICMPv6PacketTooBig,
  3511  				icmpCode: header.ICMPv6UnusedCode,
  3512  			},
  3513  			expectedPacketTooBigErrors: 1,
  3514  			expectPacketForwarded:      false,
  3515  		},
  3516  	}
  3517  
  3518  	for _, test := range tests {
  3519  		t.Run(test.name, func(t *testing.T) {
  3520  			c := newTestContext()
  3521  			defer c.cleanup()
  3522  			s := c.s
  3523  
  3524  			if _, err := s.EnableMulticastForwardingForProtocol(ProtocolNumber, &fakeMulticastEventDispatcher{}); err != nil {
  3525  				t.Fatalf("s.EnableMulticastForwardingForProtocol(%d, _): (_, %s)", ProtocolNumber, err)
  3526  			}
  3527  
  3528  			endpoints := make(map[tcpip.NICID]*channel.Endpoint)
  3529  			for nicID, addr := range defaultEndpointConfigs {
  3530  				ep := channel.New(1, header.IPv6MinimumMTU, "")
  3531  				defer ep.Close()
  3532  
  3533  				if err := s.CreateNIC(nicID, ep); err != nil {
  3534  					t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  3535  				}
  3536  				addr := tcpip.ProtocolAddress{Protocol: ProtocolNumber, AddressWithPrefix: addr}
  3537  				if err := s.AddProtocolAddress(nicID, addr, stack.AddressProperties{}); err != nil {
  3538  					t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, addr, err)
  3539  				}
  3540  				s.SetNICMulticastForwarding(nicID, ProtocolNumber, true /* enabled */)
  3541  				endpoints[nicID] = ep
  3542  			}
  3543  
  3544  			s.SetRouteTable([]tcpip.Route{
  3545  				{
  3546  					Destination: header.IPv6EmptySubnet,
  3547  					NIC:         incomingNICID,
  3548  				},
  3549  			})
  3550  
  3551  			srcAddr := remoteIPv6Addr1
  3552  			dstAddr := multicastIPv6Addr.Address
  3553  
  3554  			outgoingInterfaces := []stack.MulticastRouteOutgoingInterface{
  3555  				{ID: outgoingNICID, MinTTL: multicastRouteMinTTL},
  3556  			}
  3557  			addresses := stack.UnicastSourceAndMulticastDestination{
  3558  				Source:      srcAddr,
  3559  				Destination: multicastIPv6Addr.Address,
  3560  			}
  3561  
  3562  			route := stack.MulticastRoute{
  3563  				ExpectedInputInterface: incomingNICID,
  3564  				OutgoingInterfaces:     outgoingInterfaces,
  3565  			}
  3566  
  3567  			if err := s.AddMulticastRoute(ProtocolNumber, addresses, route); err != nil {
  3568  				t.Fatalf("s.AddMulticastRoute(%d, %#v, %#v): = %s", ProtocolNumber, addresses, route, err)
  3569  			}
  3570  
  3571  			transportProtocol := header.ICMPv6ProtocolNumber
  3572  			var extHdrBytes []byte
  3573  			extHdrChecker := checker.IPv6ExtHdr()
  3574  			if test.extHdr != nil {
  3575  				nextHdrID := hopByHopExtHdrID
  3576  				extHdrBytes, nextHdrID, extHdrChecker = test.extHdr(uint8(header.ICMPv6ProtocolNumber))
  3577  				transportProtocol = tcpip.TransportProtocolNumber(nextHdrID)
  3578  			}
  3579  			extHdrLen := len(extHdrBytes)
  3580  
  3581  			ipHeaderLength := header.IPv6MinimumSize
  3582  			icmpHeaderLength := header.ICMPv6MinimumSize
  3583  			payloadLength := icmpHeaderLength + test.payloadLength + extHdrLen
  3584  			totalLength := ipHeaderLength + payloadLength
  3585  			hdr := prependable.New(totalLength)
  3586  			hdr.Prepend(test.payloadLength)
  3587  			icmpH := header.ICMPv6(hdr.Prepend(icmpHeaderLength))
  3588  
  3589  			icmpH.SetIdent(randomIdent)
  3590  			icmpH.SetSequence(randomSequence)
  3591  			icmpH.SetType(header.ICMPv6EchoRequest)
  3592  			icmpH.SetCode(header.ICMPv6UnusedCode)
  3593  			icmpH.SetChecksum(0)
  3594  			icmpH.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  3595  				Header: icmpH,
  3596  				Src:    srcAddr,
  3597  				Dst:    dstAddr,
  3598  			}))
  3599  			copy(hdr.Prepend(extHdrLen), extHdrBytes)
  3600  			ip := header.IPv6(hdr.Prepend(ipHeaderLength))
  3601  			ip.Encode(&header.IPv6Fields{
  3602  				PayloadLength:     uint16(payloadLength),
  3603  				TransportProtocol: transportProtocol,
  3604  				HopLimit:          packetTTL,
  3605  				SrcAddr:           srcAddr,
  3606  				DstAddr:           dstAddr,
  3607  			})
  3608  			request := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3609  				Payload: buffer.MakeWithData(hdr.View()),
  3610  			})
  3611  
  3612  			incomingEndpoint, ok := endpoints[incomingNICID]
  3613  			if !ok {
  3614  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", incomingNICID)
  3615  			}
  3616  
  3617  			incomingEndpoint.InjectInbound(ProtocolNumber, request)
  3618  			request.DecRef()
  3619  
  3620  			reply := incomingEndpoint.Read()
  3621  
  3622  			outgoingEndpoint, ok := endpoints[outgoingNICID]
  3623  			if !ok {
  3624  				t.Fatalf("endpoints[%d] = (_, false), want (_, true)", outgoingNICID)
  3625  			}
  3626  
  3627  			if test.expectedICMPError != nil {
  3628  				if reply == nil {
  3629  					t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.expectedICMPError.icmpType)
  3630  				}
  3631  
  3632  				// As per RFC 4443, page 9:
  3633  				//
  3634  				//   The returned ICMP packet will contain as much of invoking packet
  3635  				//   as possible without the ICMPv6 packet exceeding the minimum IPv6
  3636  				//   MTU.
  3637  				expectedICMPPayloadLength := func() int {
  3638  					maxICMPPayloadLength := header.IPv6MinimumMTU - ipHeaderLength - icmpHeaderLength
  3639  					if len(hdr.View()) > maxICMPPayloadLength {
  3640  						return maxICMPPayloadLength
  3641  					}
  3642  					return len(hdr.View())
  3643  				}
  3644  
  3645  				payload := stack.PayloadSince(reply.NetworkHeader())
  3646  				defer payload.Release()
  3647  				checker.IPv6(t, payload,
  3648  					checker.SrcAddr(incomingIPv6Addr.Address),
  3649  					checker.DstAddr(srcAddr),
  3650  					checker.TTL(DefaultTTL),
  3651  					checker.ICMPv6(
  3652  						checker.ICMPv6Type(test.expectedICMPError.icmpType),
  3653  						checker.ICMPv6Code(test.expectedICMPError.icmpCode),
  3654  						checker.ICMPv6Payload(hdr.View()[:expectedICMPPayloadLength()]),
  3655  					),
  3656  				)
  3657  				reply.DecRef()
  3658  
  3659  				if n := outgoingEndpoint.Drain(); n != 0 {
  3660  					t.Fatalf("e2.Drain() = %d, want = 0", n)
  3661  				}
  3662  			} else if reply != nil {
  3663  				t.Fatalf("Expected no ICMP packet through incoming NIC, instead found: %#v", reply)
  3664  			}
  3665  
  3666  			reply = outgoingEndpoint.Read()
  3667  			if test.expectPacketForwarded {
  3668  				if reply == nil {
  3669  					t.Fatal("Expected ICMP Echo Request packet through outgoing NIC")
  3670  				}
  3671  
  3672  				payload := stack.PayloadSince(reply.NetworkHeader())
  3673  				defer payload.Release()
  3674  				checker.IPv6WithExtHdr(t, payload,
  3675  					checker.SrcAddr(srcAddr),
  3676  					checker.DstAddr(dstAddr),
  3677  					checker.TTL(packetTTL-1),
  3678  					extHdrChecker,
  3679  					checker.ICMPv6(
  3680  						checker.ICMPv6Type(header.ICMPv6EchoRequest),
  3681  						checker.ICMPv6Code(header.ICMPv6UnusedCode),
  3682  						checker.ICMPv6Payload(nil),
  3683  					),
  3684  				)
  3685  				reply.DecRef()
  3686  
  3687  				if n := incomingEndpoint.Drain(); n != 0 {
  3688  					t.Fatalf("e1.Drain() = %d, want = 0", n)
  3689  				}
  3690  			} else if reply != nil {
  3691  				t.Fatalf("Expected no ICMP Echo packet through outgoing NIC, instead found: %#v", reply)
  3692  			}
  3693  
  3694  			if got, want := s.Stats().IP.Forwarding.ExtensionHeaderProblem.Value(), test.expectedExtensionHeaderErrors; got != want {
  3695  				t.Errorf("s.Stats().IP.Forwarding.ExtensionHeaderProblem.Value() = %d, want = %d", got, want)
  3696  			}
  3697  
  3698  			if got, want := s.Stats().IP.Forwarding.PacketTooBig.Value(), test.expectedPacketTooBigErrors; got != want {
  3699  				t.Errorf("s.Stats().IP.Forwarding.PacketTooBig.Value() = %d, want = %d", got, want)
  3700  			}
  3701  
  3702  			totalExpectedErrors := test.expectedPacketTooBigErrors + test.expectedExtensionHeaderErrors
  3703  			if got, want := s.Stats().IP.Forwarding.Errors.Value(), totalExpectedErrors; got != want {
  3704  				t.Errorf("s.Stats().IP.Forwarding.Errors.Value() = %d, want = %d", got, want)
  3705  			}
  3706  		})
  3707  	}
  3708  }
  3709  
  3710  func TestMultiCounterStatsInitialization(t *testing.T) {
  3711  	c := newTestContext()
  3712  	defer c.cleanup()
  3713  	s := c.s
  3714  
  3715  	proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol)
  3716  	var nic testInterface
  3717  	ep := proto.NewEndpoint(&nic, nil).(*endpoint)
  3718  	// At this point, the Stack's stats and the NetworkEndpoint's stats are
  3719  	// supposed to be bound.
  3720  	refStack := s.Stats()
  3721  	refEP := ep.stats.localStats
  3722  	if err := testutil.ValidateMultiCounterStats(reflect.ValueOf(&ep.stats.ip).Elem(), []reflect.Value{reflect.ValueOf(&refStack.IP).Elem(), reflect.ValueOf(&refEP.IP).Elem()}, testutil.ValidateMultiCounterStatsOptions{
  3723  		ExpectMultiCounterStat:            true,
  3724  		ExpectMultiIntegralStatCounterMap: false,
  3725  	}); err != nil {
  3726  		t.Error(err)
  3727  	}
  3728  	if err := testutil.ValidateMultiCounterStats(reflect.ValueOf(&ep.stats.icmp).Elem(), []reflect.Value{reflect.ValueOf(&refStack.ICMP.V6).Elem(), reflect.ValueOf(&refEP.ICMP).Elem()}, testutil.ValidateMultiCounterStatsOptions{
  3729  		ExpectMultiCounterStat:            true,
  3730  		ExpectMultiIntegralStatCounterMap: false,
  3731  	}); err != nil {
  3732  		t.Error(err)
  3733  	}
  3734  }
  3735  
  3736  func TestIcmpRateLimit(t *testing.T) {
  3737  	var (
  3738  		host1IPv6Addr = tcpip.ProtocolAddress{
  3739  			Protocol: ProtocolNumber,
  3740  			AddressWithPrefix: tcpip.AddressWithPrefix{
  3741  				Address:   tcpip.AddrFromSlice(net.ParseIP("10::1").To16()),
  3742  				PrefixLen: 64,
  3743  			},
  3744  		}
  3745  		host2IPv6Addr = tcpip.ProtocolAddress{
  3746  			Protocol: ProtocolNumber,
  3747  			AddressWithPrefix: tcpip.AddressWithPrefix{
  3748  				Address:   tcpip.AddrFromSlice(net.ParseIP("10::2").To16()),
  3749  				PrefixLen: 64,
  3750  			},
  3751  		}
  3752  	)
  3753  	const icmpBurst = 5
  3754  
  3755  	c := newTestContext()
  3756  	defer c.cleanup()
  3757  	s := c.s
  3758  
  3759  	s.SetICMPBurst(icmpBurst)
  3760  
  3761  	e := channel.New(1, defaultMTU, tcpip.LinkAddress(""))
  3762  	defer e.Close()
  3763  	if err := s.CreateNIC(nicID, e); err != nil {
  3764  		t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
  3765  	}
  3766  	if err := s.AddProtocolAddress(nicID, host1IPv6Addr, stack.AddressProperties{}); err != nil {
  3767  		t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, host1IPv6Addr, err)
  3768  	}
  3769  	s.SetRouteTable([]tcpip.Route{
  3770  		{
  3771  			Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
  3772  			NIC:         nicID,
  3773  		},
  3774  	})
  3775  	tests := []struct {
  3776  		name         string
  3777  		createPacket func() []byte
  3778  		check        func(*testing.T, *channel.Endpoint, int)
  3779  	}{
  3780  		{
  3781  			name: "echo",
  3782  			createPacket: func() []byte {
  3783  				totalLength := header.IPv6MinimumSize + header.ICMPv6MinimumSize
  3784  				hdr := prependable.New(totalLength)
  3785  				icmpH := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize))
  3786  				icmpH.SetIdent(1)
  3787  				icmpH.SetSequence(1)
  3788  				icmpH.SetType(header.ICMPv6EchoRequest)
  3789  				icmpH.SetCode(header.ICMPv6UnusedCode)
  3790  				icmpH.SetChecksum(0)
  3791  				icmpH.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
  3792  					Header: icmpH,
  3793  					Src:    host2IPv6Addr.AddressWithPrefix.Address,
  3794  					Dst:    host1IPv6Addr.AddressWithPrefix.Address,
  3795  				}))
  3796  				payloadLength := hdr.UsedLength()
  3797  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  3798  				ip.Encode(&header.IPv6Fields{
  3799  					PayloadLength:     uint16(payloadLength),
  3800  					TransportProtocol: header.ICMPv6ProtocolNumber,
  3801  					HopLimit:          1,
  3802  					SrcAddr:           host2IPv6Addr.AddressWithPrefix.Address,
  3803  					DstAddr:           host1IPv6Addr.AddressWithPrefix.Address,
  3804  				})
  3805  				return hdr.View()
  3806  			},
  3807  			check: func(t *testing.T, e *channel.Endpoint, round int) {
  3808  				p := e.Read()
  3809  				if p == nil {
  3810  					t.Fatalf("expected echo response, no packet read in endpoint in round %d", round)
  3811  				}
  3812  				defer p.DecRef()
  3813  				if got, want := p.NetworkProtocolNumber, header.IPv6ProtocolNumber; got != want {
  3814  					t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", got, want)
  3815  				}
  3816  				payload := stack.PayloadSince(p.NetworkHeader())
  3817  				defer payload.Release()
  3818  				checker.IPv6(t, payload,
  3819  					checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
  3820  					checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address),
  3821  					checker.ICMPv6(
  3822  						checker.ICMPv6Type(header.ICMPv6EchoReply),
  3823  					))
  3824  			},
  3825  		},
  3826  		{
  3827  			name: "dst unreachable",
  3828  			createPacket: func() []byte {
  3829  				totalLength := header.IPv6MinimumSize + header.UDPMinimumSize
  3830  				hdr := prependable.New(totalLength)
  3831  				udpH := header.UDP(hdr.Prepend(header.UDPMinimumSize))
  3832  				udpH.Encode(&header.UDPFields{
  3833  					SrcPort: 100,
  3834  					DstPort: 101,
  3835  					Length:  header.UDPMinimumSize,
  3836  				})
  3837  
  3838  				// Calculate the UDP checksum and set it.
  3839  				sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, header.UDPMinimumSize)
  3840  				sum = checksum.Checksum(nil, sum)
  3841  				udpH.SetChecksum(^udpH.CalculateChecksum(sum))
  3842  
  3843  				payloadLength := hdr.UsedLength()
  3844  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  3845  				ip.Encode(&header.IPv6Fields{
  3846  					PayloadLength:     uint16(payloadLength),
  3847  					TransportProtocol: header.UDPProtocolNumber,
  3848  					HopLimit:          1,
  3849  					SrcAddr:           host2IPv6Addr.AddressWithPrefix.Address,
  3850  					DstAddr:           host1IPv6Addr.AddressWithPrefix.Address,
  3851  				})
  3852  				return hdr.View()
  3853  			},
  3854  			check: func(t *testing.T, e *channel.Endpoint, round int) {
  3855  				p := e.Read()
  3856  				if round >= icmpBurst {
  3857  					if p != nil {
  3858  						t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().AsRange().ToSlice(), round)
  3859  						p.DecRef()
  3860  					}
  3861  					return
  3862  				}
  3863  				if p == nil {
  3864  					t.Fatalf("expected unreachable in round %d, no packet read in endpoint", round)
  3865  				}
  3866  				payload := stack.PayloadSince(p.NetworkHeader())
  3867  				defer payload.Release()
  3868  				checker.IPv6(t, payload,
  3869  					checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
  3870  					checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address),
  3871  					checker.ICMPv6(
  3872  						checker.ICMPv6Type(header.ICMPv6DstUnreachable),
  3873  					))
  3874  				p.DecRef()
  3875  			},
  3876  		},
  3877  	}
  3878  	for _, testCase := range tests {
  3879  		t.Run(testCase.name, func(t *testing.T) {
  3880  			for round := 0; round < icmpBurst+1; round++ {
  3881  				pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3882  					Payload: buffer.MakeWithData(testCase.createPacket()),
  3883  				})
  3884  				e.InjectInbound(header.IPv6ProtocolNumber, pkt)
  3885  				pkt.DecRef()
  3886  				testCase.check(t, e, round)
  3887  			}
  3888  		})
  3889  	}
  3890  }
  3891  
  3892  // TestRejectMartianMappedPackets tests that IPv6 endpoints reject packets
  3893  // containing IPv4-mapped IPv6 addresses.
  3894  func TestRejectMartianMappedPackets(t *testing.T) {
  3895  	tcs := []struct {
  3896  		name            string
  3897  		wantSrcReceived uint64
  3898  		wantDstReceived uint64
  3899  		wantDelivered   uint64
  3900  		srcAddr         tcpip.Address
  3901  		dstAddr         tcpip.Address
  3902  	}{
  3903  		{
  3904  			name:            "bad source",
  3905  			wantSrcReceived: 1,
  3906  			srcAddr:         testutil.MustParse6("::ffff:1.2.3.4"),
  3907  			dstAddr:         testutil.MustParse6("fe80::2"),
  3908  		},
  3909  		{
  3910  			name:            "bad destination",
  3911  			wantDstReceived: 1,
  3912  			srcAddr:         testutil.MustParse6("fe80::2"),
  3913  			dstAddr:         testutil.MustParse6("::ffff:1.2.3.4"),
  3914  		},
  3915  		{
  3916  			name:            "bad source and destination",
  3917  			wantSrcReceived: 1,
  3918  			wantDstReceived: 1,
  3919  			srcAddr:         testutil.MustParse6("::ffff:1.2.3.4"),
  3920  			dstAddr:         testutil.MustParse6("::ffff:5.6.7.8"),
  3921  		},
  3922  		{
  3923  			name:          "valid source and destination",
  3924  			wantDelivered: 1,
  3925  			srcAddr:       testutil.MustParse6("fe80::2"),
  3926  			dstAddr:       header.IPv6AllNodesMulticastAddress,
  3927  		},
  3928  	}
  3929  
  3930  	for _, tc := range tcs {
  3931  		t.Run(tc.name, func(t *testing.T) {
  3932  			// Initialize the stack and add an address.
  3933  			ctx := newTestContext()
  3934  			defer ctx.cleanup()
  3935  			stk := ctx.s
  3936  
  3937  			channelEP := channel.New(1, header.IPv6MinimumMTU, linkAddr1)
  3938  			defer channelEP.Close()
  3939  			if err := stk.CreateNIC(nicID, channelEP); err != nil {
  3940  				t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
  3941  			}
  3942  
  3943  			stk.SetRouteTable([]tcpip.Route{
  3944  				{
  3945  					Destination: header.IPv6EmptySubnet,
  3946  					NIC:         nicID,
  3947  				},
  3948  			})
  3949  
  3950  			protocolAddr := tcpip.ProtocolAddress{
  3951  				Protocol:          ProtocolNumber,
  3952  				AddressWithPrefix: addr2.WithPrefix(),
  3953  			}
  3954  			if err := stk.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
  3955  				t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
  3956  			}
  3957  
  3958  			// We don't have to setup the UDP header properly, as
  3959  			// it should be rejected at the IP layer.
  3960  			hdr := prependable.New(header.IPv6MinimumSize + header.UDPMinimumSize)
  3961  			_ = header.UDP(hdr.Prepend(header.UDPMinimumSize))
  3962  
  3963  			payloadLength := hdr.UsedLength()
  3964  			ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
  3965  			ip.Encode(&header.IPv6Fields{
  3966  				PayloadLength:     uint16(payloadLength),
  3967  				TransportProtocol: udp.ProtocolNumber,
  3968  				HopLimit:          255,
  3969  				SrcAddr:           tc.srcAddr,
  3970  				DstAddr:           tc.dstAddr,
  3971  			})
  3972  
  3973  			// Send the packet out.
  3974  			pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  3975  				Payload: buffer.MakeWithData(hdr.View()),
  3976  			})
  3977  			channelEP.InjectInbound(ProtocolNumber, pkt)
  3978  			pkt.DecRef()
  3979  
  3980  			// Verify that stat counters are appropriately updated.
  3981  			srcStat := stk.Stats().IP.InvalidSourceAddressesReceived
  3982  			if got := srcStat.Value(); got != tc.wantSrcReceived {
  3983  				t.Errorf("got InvalidSourceAddressesReceived = %d, want = %d", got, tc.wantSrcReceived)
  3984  			}
  3985  			dstStat := stk.Stats().IP.InvalidDestinationAddressesReceived
  3986  			if got := dstStat.Value(); got != tc.wantDstReceived {
  3987  				t.Errorf("got InvalidDestinationAddressesReceived = %d, want = %d", got, tc.wantDstReceived)
  3988  			}
  3989  			deliveredStat := stk.Stats().IP.PacketsDelivered
  3990  			if got := deliveredStat.Value(); got != tc.wantDelivered {
  3991  				t.Errorf("got PacketsDelivered = %d, want = %d", got, tc.wantDelivered)
  3992  			}
  3993  		})
  3994  	}
  3995  }