code: func (e *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
  	e.mu.Lock()
  	defer e.mu.Unlock()
  	e.shutdownFlags |= flags
  
  	switch e.state {
  	case stateConnected:
  		// Close for read.
  		if (e.shutdownFlags & tcpip.ShutdownRead) != 0 {
  			// Mark read side as closed.
  			e.rcvListMu.Lock()
  			e.rcvClosed = true
  			rcvBufUsed := e.rcvBufUsed
  			e.rcvListMu.Unlock()
  
  			// If we're fully closed and we have unread data we need to abort
  			// the connection with a RST.
  			if (e.shutdownFlags&tcpip.ShutdownWrite) != 0 && rcvBufUsed > 0 {
  				e.notifyProtocolGoroutine(notifyReset)
  				return nil
  			}
  		}
  
  		// Close for write.
  		if (e.shutdownFlags & tcpip.ShutdownWrite) != 0 {
  			e.sndBufMu.Lock()
  
  			if e.sndClosed {
  				// Already closed.
  				e.sndBufMu.Unlock()
  				break
  			}
  
  			// Queue fin segment.
  			s := newSegmentFromView(&e.route, e.id, nil)
  			e.sndQueue.PushBack(s)
  			e.sndBufInQueue++
  
  			// Mark endpoint as closed.
  			e.sndClosed = true
  
  			e.sndBufMu.Unlock()
  
  			// Tell protocol goroutine to close.
  			e.sndCloseWaker.Assert()
  		}
  
  	case stateListen:
  		// Tell protocolListenLoop to stop.
  		if flags&tcpip.ShutdownRead != 0 {
  			e.notifyProtocolGoroutine(notifyClose)
  		}
  
  	default:
  		return tcpip.ErrNotConnected
  	}
  
  	return nil
  }
docs: // Shutdown closes the read and/or write end of the endpoint connection to its
  // peer.