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