github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/transport/raw/endpoint.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 raw provides the implementation of raw sockets (see raw(7)). Raw 16 // sockets allow applications to: 17 // 18 // * manually write and inspect transport layer headers and payloads 19 // * receive all traffic of a given transport protocol (e.g. ICMP or UDP) 20 // * optionally write and inspect network layer headers of packets 21 // 22 // Raw sockets don't have any notion of ports, and incoming packets are 23 // demultiplexed solely by protocol number. Thus, a raw UDP endpoint will 24 // receive every UDP packet received by netstack. bind(2) and connect(2) can be 25 // used to filter incoming packets by source and destination. 26 package raw 27 28 import ( 29 "io" 30 "time" 31 32 "github.com/SagerNet/gvisor/pkg/sync" 33 "github.com/SagerNet/gvisor/pkg/tcpip" 34 "github.com/SagerNet/gvisor/pkg/tcpip/buffer" 35 "github.com/SagerNet/gvisor/pkg/tcpip/header" 36 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 37 "github.com/SagerNet/gvisor/pkg/waiter" 38 ) 39 40 // +stateify savable 41 type rawPacket struct { 42 rawPacketEntry 43 // data holds the actual packet data, including any headers and 44 // payload. 45 data buffer.VectorisedView `state:".(buffer.VectorisedView)"` 46 receivedAt time.Time `state:".(int64)"` 47 // senderAddr is the network address of the sender. 48 senderAddr tcpip.FullAddress 49 } 50 51 // endpoint is the raw socket implementation of tcpip.Endpoint. It is legal to 52 // have goroutines make concurrent calls into the endpoint. 53 // 54 // Lock order: 55 // endpoint.mu 56 // endpoint.rcvMu 57 // 58 // +stateify savable 59 type endpoint struct { 60 stack.TransportEndpointInfo 61 tcpip.DefaultSocketOptionsHandler 62 63 // The following fields are initialized at creation time and are 64 // immutable. 65 stack *stack.Stack `state:"manual"` 66 waiterQueue *waiter.Queue 67 associated bool 68 69 // The following fields are used to manage the receive queue and are 70 // protected by rcvMu. 71 rcvMu sync.Mutex `state:"nosave"` 72 rcvList rawPacketList 73 rcvBufSize int 74 rcvClosed bool 75 76 // The following fields are protected by mu. 77 mu sync.RWMutex `state:"nosave"` 78 closed bool 79 connected bool 80 bound bool 81 // route is the route to a remote network endpoint. It is set via 82 // Connect(), and is valid only when conneted is true. 83 route *stack.Route `state:"manual"` 84 stats tcpip.TransportEndpointStats `state:"nosave"` 85 // owner is used to get uid and gid of the packet. 86 owner tcpip.PacketOwner 87 88 // ops is used to get socket level options. 89 ops tcpip.SocketOptions 90 91 // frozen indicates if the packets should be delivered to the endpoint 92 // during restore. 93 frozen bool 94 } 95 96 // NewEndpoint returns a raw endpoint for the given protocols. 97 func NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) { 98 return newEndpoint(stack, netProto, transProto, waiterQueue, true /* associated */) 99 } 100 101 func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue, associated bool) (tcpip.Endpoint, tcpip.Error) { 102 if netProto != header.IPv4ProtocolNumber && netProto != header.IPv6ProtocolNumber { 103 return nil, &tcpip.ErrUnknownProtocol{} 104 } 105 106 e := &endpoint{ 107 stack: s, 108 TransportEndpointInfo: stack.TransportEndpointInfo{ 109 NetProto: netProto, 110 TransProto: transProto, 111 }, 112 waiterQueue: waiterQueue, 113 associated: associated, 114 } 115 e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) 116 e.ops.SetHeaderIncluded(!associated) 117 e.ops.SetSendBufferSize(32*1024, false /* notify */) 118 e.ops.SetReceiveBufferSize(32*1024, false /* notify */) 119 120 // Override with stack defaults. 121 var ss tcpip.SendBufferSizeOption 122 if err := s.Option(&ss); err == nil { 123 e.ops.SetSendBufferSize(int64(ss.Default), false /* notify */) 124 } 125 126 var rs tcpip.ReceiveBufferSizeOption 127 if err := s.Option(&rs); err == nil { 128 e.ops.SetReceiveBufferSize(int64(rs.Default), false /* notify */) 129 } 130 131 // Unassociated endpoints are write-only and users call Write() with IP 132 // headers included. Because they're write-only, We don't need to 133 // register with the stack. 134 if !associated { 135 e.ops.SetReceiveBufferSize(0, false) 136 e.waiterQueue = nil 137 return e, nil 138 } 139 140 if err := e.stack.RegisterRawTransportEndpoint(e.NetProto, e.TransProto, e); err != nil { 141 return nil, err 142 } 143 144 return e, nil 145 } 146 147 // Abort implements stack.TransportEndpoint.Abort. 148 func (e *endpoint) Abort() { 149 e.Close() 150 } 151 152 // Close implements tcpip.Endpoint.Close. 153 func (e *endpoint) Close() { 154 e.mu.Lock() 155 defer e.mu.Unlock() 156 157 if e.closed || !e.associated { 158 return 159 } 160 161 e.stack.UnregisterRawTransportEndpoint(e.NetProto, e.TransProto, e) 162 163 e.rcvMu.Lock() 164 defer e.rcvMu.Unlock() 165 166 // Clear the receive list. 167 e.rcvClosed = true 168 e.rcvBufSize = 0 169 for !e.rcvList.Empty() { 170 e.rcvList.Remove(e.rcvList.Front()) 171 } 172 173 e.connected = false 174 175 if e.route != nil { 176 e.route.Release() 177 e.route = nil 178 } 179 180 e.closed = true 181 182 e.waiterQueue.Notify(waiter.EventHUp | waiter.EventErr | waiter.ReadableEvents | waiter.WritableEvents) 183 } 184 185 // ModerateRecvBuf implements tcpip.Endpoint.ModerateRecvBuf. 186 func (*endpoint) ModerateRecvBuf(int) {} 187 188 func (e *endpoint) SetOwner(owner tcpip.PacketOwner) { 189 e.mu.Lock() 190 defer e.mu.Unlock() 191 e.owner = owner 192 } 193 194 // Read implements tcpip.Endpoint.Read. 195 func (e *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResult, tcpip.Error) { 196 e.rcvMu.Lock() 197 198 // If there's no data to read, return that read would block or that the 199 // endpoint is closed. 200 if e.rcvList.Empty() { 201 var err tcpip.Error = &tcpip.ErrWouldBlock{} 202 if e.rcvClosed { 203 e.stats.ReadErrors.ReadClosed.Increment() 204 err = &tcpip.ErrClosedForReceive{} 205 } 206 e.rcvMu.Unlock() 207 return tcpip.ReadResult{}, err 208 } 209 210 pkt := e.rcvList.Front() 211 if !opts.Peek { 212 e.rcvList.Remove(pkt) 213 e.rcvBufSize -= pkt.data.Size() 214 } 215 216 e.rcvMu.Unlock() 217 218 res := tcpip.ReadResult{ 219 Total: pkt.data.Size(), 220 ControlMessages: tcpip.ControlMessages{ 221 HasTimestamp: true, 222 Timestamp: pkt.receivedAt.UnixNano(), 223 }, 224 } 225 if opts.NeedRemoteAddr { 226 res.RemoteAddr = pkt.senderAddr 227 } 228 229 n, err := pkt.data.ReadTo(dst, opts.Peek) 230 if n == 0 && err != nil { 231 return res, &tcpip.ErrBadBuffer{} 232 } 233 res.Count = n 234 return res, nil 235 } 236 237 // Write implements tcpip.Endpoint.Write. 238 func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcpip.Error) { 239 // We can create, but not write to, unassociated IPv6 endpoints. 240 if !e.associated && e.TransportEndpointInfo.NetProto == header.IPv6ProtocolNumber { 241 return 0, &tcpip.ErrInvalidOptionValue{} 242 } 243 244 if opts.To != nil { 245 // Raw sockets do not support sending to a IPv4 address on a IPv6 endpoint. 246 if e.TransportEndpointInfo.NetProto == header.IPv6ProtocolNumber && len(opts.To.Addr) != header.IPv6AddressSize { 247 return 0, &tcpip.ErrInvalidOptionValue{} 248 } 249 } 250 251 n, err := e.write(p, opts) 252 switch err.(type) { 253 case nil: 254 e.stats.PacketsSent.Increment() 255 case *tcpip.ErrMessageTooLong, *tcpip.ErrInvalidOptionValue: 256 e.stats.WriteErrors.InvalidArgs.Increment() 257 case *tcpip.ErrClosedForSend: 258 e.stats.WriteErrors.WriteClosed.Increment() 259 case *tcpip.ErrInvalidEndpointState: 260 e.stats.WriteErrors.InvalidEndpointState.Increment() 261 case *tcpip.ErrNoRoute, *tcpip.ErrBroadcastDisabled, *tcpip.ErrNetworkUnreachable: 262 // Errors indicating any problem with IP routing of the packet. 263 e.stats.SendErrors.NoRoute.Increment() 264 default: 265 // For all other errors when writing to the network layer. 266 e.stats.SendErrors.SendToNetworkFailed.Increment() 267 } 268 return n, err 269 } 270 271 func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcpip.Error) { 272 // MSG_MORE is unimplemented. This also means that MSG_EOR is a no-op. 273 if opts.More { 274 return 0, &tcpip.ErrInvalidOptionValue{} 275 } 276 payloadBytes, route, owner, err := func() ([]byte, *stack.Route, tcpip.PacketOwner, tcpip.Error) { 277 e.mu.RLock() 278 defer e.mu.RUnlock() 279 280 if e.closed { 281 return nil, nil, nil, &tcpip.ErrInvalidEndpointState{} 282 } 283 284 payloadBytes := make([]byte, p.Len()) 285 if _, err := io.ReadFull(p, payloadBytes); err != nil { 286 return nil, nil, nil, &tcpip.ErrBadBuffer{} 287 } 288 289 // Did the user caller provide a destination? If not, use the connected 290 // destination. 291 if opts.To == nil { 292 // If the user doesn't specify a destination, they should have 293 // connected to another address. 294 if !e.connected { 295 return nil, nil, nil, &tcpip.ErrDestinationRequired{} 296 } 297 298 e.route.Acquire() 299 300 return payloadBytes, e.route, e.owner, nil 301 } 302 303 // The caller provided a destination. Reject destination address if it 304 // goes through a different NIC than the endpoint was bound to. 305 nic := opts.To.NIC 306 if e.bound && nic != 0 && nic != e.BindNICID { 307 return nil, nil, nil, &tcpip.ErrNoRoute{} 308 } 309 310 // Find the route to the destination. If BindAddress is 0, 311 // FindRoute will choose an appropriate source address. 312 route, err := e.stack.FindRoute(nic, e.BindAddr, opts.To.Addr, e.NetProto, false) 313 if err != nil { 314 return nil, nil, nil, err 315 } 316 317 return payloadBytes, route, e.owner, nil 318 }() 319 if err != nil { 320 return 0, err 321 } 322 defer route.Release() 323 324 if e.ops.GetHeaderIncluded() { 325 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 326 Data: buffer.View(payloadBytes).ToVectorisedView(), 327 }) 328 if err := route.WriteHeaderIncludedPacket(pkt); err != nil { 329 return 0, err 330 } 331 } else { 332 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 333 ReserveHeaderBytes: int(route.MaxHeaderLength()), 334 Data: buffer.View(payloadBytes).ToVectorisedView(), 335 }) 336 pkt.Owner = owner 337 if err := route.WritePacket(stack.NetworkHeaderParams{ 338 Protocol: e.TransProto, 339 TTL: route.DefaultTTL(), 340 TOS: stack.DefaultTOS, 341 }, pkt); err != nil { 342 return 0, err 343 } 344 } 345 346 return int64(len(payloadBytes)), nil 347 } 348 349 // Disconnect implements tcpip.Endpoint.Disconnect. 350 func (*endpoint) Disconnect() tcpip.Error { 351 return &tcpip.ErrNotSupported{} 352 } 353 354 // Connect implements tcpip.Endpoint.Connect. 355 func (e *endpoint) Connect(addr tcpip.FullAddress) tcpip.Error { 356 // Raw sockets do not support connecting to a IPv4 address on a IPv6 endpoint. 357 if e.TransportEndpointInfo.NetProto == header.IPv6ProtocolNumber && len(addr.Addr) != header.IPv6AddressSize { 358 return &tcpip.ErrAddressFamilyNotSupported{} 359 } 360 361 e.mu.Lock() 362 defer e.mu.Unlock() 363 364 if e.closed { 365 return &tcpip.ErrInvalidEndpointState{} 366 } 367 368 nic := addr.NIC 369 if e.bound { 370 if e.BindNICID == 0 { 371 // If we're bound, but not to a specific NIC, the NIC 372 // in addr will be used. Nothing to do here. 373 } else if addr.NIC == 0 { 374 // If we're bound to a specific NIC, but addr doesn't 375 // specify a NIC, use the bound NIC. 376 nic = e.BindNICID 377 } else if addr.NIC != e.BindNICID { 378 // We're bound and addr specifies a NIC. They must be 379 // the same. 380 return &tcpip.ErrInvalidEndpointState{} 381 } 382 } 383 384 // Find a route to the destination. 385 route, err := e.stack.FindRoute(nic, "", addr.Addr, e.NetProto, false) 386 if err != nil { 387 return err 388 } 389 390 if e.associated { 391 // Re-register the endpoint with the appropriate NIC. 392 if err := e.stack.RegisterRawTransportEndpoint(e.NetProto, e.TransProto, e); err != nil { 393 route.Release() 394 return err 395 } 396 e.stack.UnregisterRawTransportEndpoint(e.NetProto, e.TransProto, e) 397 e.RegisterNICID = nic 398 } 399 400 if e.route != nil { 401 // If the endpoint was previously connected then release any previous route. 402 e.route.Release() 403 } 404 e.route = route 405 e.connected = true 406 407 return nil 408 } 409 410 // Shutdown implements tcpip.Endpoint.Shutdown. It's a noop for raw sockets. 411 func (e *endpoint) Shutdown(tcpip.ShutdownFlags) tcpip.Error { 412 e.mu.Lock() 413 defer e.mu.Unlock() 414 415 if !e.connected { 416 return &tcpip.ErrNotConnected{} 417 } 418 return nil 419 } 420 421 // Listen implements tcpip.Endpoint.Listen. 422 func (*endpoint) Listen(int) tcpip.Error { 423 return &tcpip.ErrNotSupported{} 424 } 425 426 // Accept implements tcpip.Endpoint.Accept. 427 func (*endpoint) Accept(*tcpip.FullAddress) (tcpip.Endpoint, *waiter.Queue, tcpip.Error) { 428 return nil, nil, &tcpip.ErrNotSupported{} 429 } 430 431 // Bind implements tcpip.Endpoint.Bind. 432 func (e *endpoint) Bind(addr tcpip.FullAddress) tcpip.Error { 433 e.mu.Lock() 434 defer e.mu.Unlock() 435 436 // If a local address was specified, verify that it's valid. 437 if len(addr.Addr) != 0 && e.stack.CheckLocalAddress(e.RegisterNICID, e.NetProto, addr.Addr) == 0 { 438 return &tcpip.ErrBadLocalAddress{} 439 } 440 441 if e.associated { 442 // Re-register the endpoint with the appropriate NIC. 443 if err := e.stack.RegisterRawTransportEndpoint(e.NetProto, e.TransProto, e); err != nil { 444 return err 445 } 446 e.stack.UnregisterRawTransportEndpoint(e.NetProto, e.TransProto, e) 447 e.RegisterNICID = addr.NIC 448 e.BindNICID = addr.NIC 449 } 450 451 e.BindAddr = addr.Addr 452 e.bound = true 453 454 return nil 455 } 456 457 // GetLocalAddress implements tcpip.Endpoint.GetLocalAddress. 458 func (*endpoint) GetLocalAddress() (tcpip.FullAddress, tcpip.Error) { 459 return tcpip.FullAddress{}, &tcpip.ErrNotSupported{} 460 } 461 462 // GetRemoteAddress implements tcpip.Endpoint.GetRemoteAddress. 463 func (*endpoint) GetRemoteAddress() (tcpip.FullAddress, tcpip.Error) { 464 // Even a connected socket doesn't return a remote address. 465 return tcpip.FullAddress{}, &tcpip.ErrNotConnected{} 466 } 467 468 // Readiness implements tcpip.Endpoint.Readiness. 469 func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask { 470 // The endpoint is always writable. 471 result := waiter.WritableEvents & mask 472 473 // Determine whether the endpoint is readable. 474 if (mask & waiter.ReadableEvents) != 0 { 475 e.rcvMu.Lock() 476 if !e.rcvList.Empty() || e.rcvClosed { 477 result |= waiter.ReadableEvents 478 } 479 e.rcvMu.Unlock() 480 } 481 482 return result 483 } 484 485 // SetSockOpt implements tcpip.Endpoint.SetSockOpt. 486 func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) tcpip.Error { 487 switch opt.(type) { 488 case *tcpip.SocketDetachFilterOption: 489 return nil 490 491 default: 492 return &tcpip.ErrUnknownProtocolOption{} 493 } 494 } 495 496 func (*endpoint) SetSockOptInt(tcpip.SockOptInt, int) tcpip.Error { 497 return &tcpip.ErrUnknownProtocolOption{} 498 } 499 500 // GetSockOpt implements tcpip.Endpoint.GetSockOpt. 501 func (*endpoint) GetSockOpt(tcpip.GettableSocketOption) tcpip.Error { 502 return &tcpip.ErrUnknownProtocolOption{} 503 } 504 505 // GetSockOptInt implements tcpip.Endpoint.GetSockOptInt. 506 func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) { 507 switch opt { 508 case tcpip.ReceiveQueueSizeOption: 509 v := 0 510 e.rcvMu.Lock() 511 if !e.rcvList.Empty() { 512 p := e.rcvList.Front() 513 v = p.data.Size() 514 } 515 e.rcvMu.Unlock() 516 return v, nil 517 518 default: 519 return -1, &tcpip.ErrUnknownProtocolOption{} 520 } 521 } 522 523 // HandlePacket implements stack.RawTransportEndpoint.HandlePacket. 524 func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { 525 e.mu.RLock() 526 e.rcvMu.Lock() 527 528 // Drop the packet if our buffer is currently full or if this is an unassociated 529 // endpoint (i.e endpoint created w/ IPPROTO_RAW). Such endpoints are send only 530 // See: https://man7.org/linux/man-pages/man7/raw.7.html 531 // 532 // An IPPROTO_RAW socket is send only. If you really want to receive 533 // all IP packets, use a packet(7) socket with the ETH_P_IP protocol. 534 // Note that packet sockets don't reassemble IP fragments, unlike raw 535 // sockets. 536 if e.rcvClosed || !e.associated { 537 e.rcvMu.Unlock() 538 e.mu.RUnlock() 539 e.stack.Stats().DroppedPackets.Increment() 540 e.stats.ReceiveErrors.ClosedReceiver.Increment() 541 return 542 } 543 544 rcvBufSize := e.ops.GetReceiveBufferSize() 545 if e.frozen || e.rcvBufSize >= int(rcvBufSize) { 546 e.rcvMu.Unlock() 547 e.mu.RUnlock() 548 e.stack.Stats().DroppedPackets.Increment() 549 e.stats.ReceiveErrors.ReceiveBufferOverflow.Increment() 550 return 551 } 552 553 remoteAddr := pkt.Network().SourceAddress() 554 555 if e.bound { 556 // If bound to a NIC, only accept data for that NIC. 557 if e.BindNICID != 0 && e.BindNICID != pkt.NICID { 558 e.rcvMu.Unlock() 559 e.mu.RUnlock() 560 return 561 } 562 // If bound to an address, only accept data for that address. 563 if e.BindAddr != "" && e.BindAddr != remoteAddr { 564 e.rcvMu.Unlock() 565 e.mu.RUnlock() 566 return 567 } 568 } 569 570 // If connected, only accept packets from the remote address we 571 // connected to. 572 if e.connected && e.route.RemoteAddress() != remoteAddr { 573 e.rcvMu.Unlock() 574 e.mu.RUnlock() 575 return 576 } 577 578 wasEmpty := e.rcvBufSize == 0 579 580 // Push new packet into receive list and increment the buffer size. 581 packet := &rawPacket{ 582 senderAddr: tcpip.FullAddress{ 583 NIC: pkt.NICID, 584 Addr: remoteAddr, 585 }, 586 } 587 588 // Raw IPv4 endpoints return the IP header, but IPv6 endpoints do not. 589 // We copy headers' underlying bytes because pkt.*Header may point to 590 // the middle of a slice, and another struct may point to the "outer" 591 // slice. Save/restore doesn't support overlapping slices and will fail. 592 var combinedVV buffer.VectorisedView 593 if e.TransportEndpointInfo.NetProto == header.IPv4ProtocolNumber { 594 network, transport := pkt.NetworkHeader().View(), pkt.TransportHeader().View() 595 headers := make(buffer.View, 0, len(network)+len(transport)) 596 headers = append(headers, network...) 597 headers = append(headers, transport...) 598 combinedVV = headers.ToVectorisedView() 599 } else { 600 combinedVV = append(buffer.View(nil), pkt.TransportHeader().View()...).ToVectorisedView() 601 } 602 combinedVV.Append(pkt.Data().ExtractVV()) 603 packet.data = combinedVV 604 packet.receivedAt = e.stack.Clock().Now() 605 606 e.rcvList.PushBack(packet) 607 e.rcvBufSize += packet.data.Size() 608 e.rcvMu.Unlock() 609 e.mu.RUnlock() 610 e.stats.PacketsReceived.Increment() 611 // Notify waiters that there's data to be read. 612 if wasEmpty { 613 e.waiterQueue.Notify(waiter.ReadableEvents) 614 } 615 } 616 617 // State implements socket.Socket.State. 618 func (e *endpoint) State() uint32 { 619 return 0 620 } 621 622 // Info returns a copy of the endpoint info. 623 func (e *endpoint) Info() tcpip.EndpointInfo { 624 e.mu.RLock() 625 // Make a copy of the endpoint info. 626 ret := e.TransportEndpointInfo 627 e.mu.RUnlock() 628 return &ret 629 } 630 631 // Stats returns a pointer to the endpoint stats. 632 func (e *endpoint) Stats() tcpip.EndpointStats { 633 return &e.stats 634 } 635 636 // Wait implements stack.TransportEndpoint.Wait. 637 func (*endpoint) Wait() {} 638 639 // LastError implements tcpip.Endpoint.LastError. 640 func (*endpoint) LastError() tcpip.Error { 641 return nil 642 } 643 644 // SocketOptions implements tcpip.Endpoint.SocketOptions. 645 func (e *endpoint) SocketOptions() *tcpip.SocketOptions { 646 return &e.ops 647 } 648 649 // freeze prevents any more packets from being delivered to the endpoint. 650 func (e *endpoint) freeze() { 651 e.mu.Lock() 652 e.frozen = true 653 e.mu.Unlock() 654 } 655 656 // thaw unfreezes a previously frozen endpoint using endpoint.freeze() allows 657 // new packets to be delivered again. 658 func (e *endpoint) thaw() { 659 e.mu.Lock() 660 e.frozen = false 661 e.mu.Unlock() 662 }