1 /* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Andrew Galante, haiku.galante@gmail.com 8 * Hugo Santos, hugosantos@gmail.com 9 */ 10 11 12 #include "EndpointManager.h" 13 #include "TCPEndpoint.h" 14 15 #include <net_protocol.h> 16 #include <net_stat.h> 17 18 #include <KernelExport.h> 19 #include <util/list.h> 20 21 #include <netinet/in.h> 22 #include <netinet/ip.h> 23 #include <new> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include <lock.h> 28 #include <util/AutoLock.h> 29 30 #include <NetBufferUtilities.h> 31 #include <NetUtilities.h> 32 33 34 //#define TRACE_TCP 35 #ifdef TRACE_TCP 36 # define TRACE(x) dprintf x 37 # define TRACE_BLOCK(x) dump_block x 38 #else 39 # define TRACE(x) 40 # define TRACE_BLOCK(x) 41 #endif 42 43 44 typedef NetBufferField<uint16, offsetof(tcp_header, checksum)> TCPChecksumField; 45 46 47 net_buffer_module_info *gBufferModule; 48 net_datalink_module_info *gDatalinkModule; 49 net_socket_module_info *gSocketModule; 50 net_stack_module_info *gStackModule; 51 52 53 static EndpointManager* sEndpointManagers[AF_MAX]; 54 static rw_lock sEndpointManagersLock; 55 56 57 // The TCP header length is at most 64 bytes. 58 static const int kMaxOptionSize = 64 - sizeof(tcp_header); 59 60 61 /*! Returns an endpoint manager for the specified domain, if any. 62 You need to hold the sEndpointManagersLock when calling this function. 63 */ 64 static inline EndpointManager* 65 endpoint_manager_for_locked(int family) 66 { 67 if (family >= AF_MAX || family < 0) 68 return NULL; 69 70 return sEndpointManagers[family]; 71 } 72 73 74 /*! Returns an endpoint manager for the specified domain, if any */ 75 static inline EndpointManager* 76 endpoint_manager_for(net_domain* domain) 77 { 78 ReadLocker _(sEndpointManagersLock); 79 80 return endpoint_manager_for_locked(domain->family); 81 } 82 83 84 static inline void 85 bump_option(tcp_option *&option, size_t &length) 86 { 87 if (option->kind <= TCP_OPTION_NOP) { 88 length++; 89 option = (tcp_option *)((uint8 *)option + 1); 90 } else { 91 length += option->length; 92 option = (tcp_option *)((uint8 *)option + option->length); 93 } 94 } 95 96 97 static inline size_t 98 add_options(tcp_segment_header &segment, uint8 *buffer, size_t bufferSize) 99 { 100 tcp_option *option = (tcp_option *)buffer; 101 size_t length = 0; 102 103 if (segment.max_segment_size > 0 && length + 8 <= bufferSize) { 104 option->kind = TCP_OPTION_MAX_SEGMENT_SIZE; 105 option->length = 4; 106 option->max_segment_size = htons(segment.max_segment_size); 107 bump_option(option, length); 108 } 109 110 if ((segment.options & TCP_HAS_TIMESTAMPS) != 0 111 && length + 12 <= bufferSize) { 112 // two NOPs so the timestamps get aligned to a 4 byte boundary 113 option->kind = TCP_OPTION_NOP; 114 bump_option(option, length); 115 option->kind = TCP_OPTION_NOP; 116 bump_option(option, length); 117 option->kind = TCP_OPTION_TIMESTAMP; 118 option->length = 10; 119 option->timestamp.value = htonl(segment.timestamp_value); 120 // TSecr is opaque to us, we send it as we received it. 121 option->timestamp.reply = segment.timestamp_reply; 122 bump_option(option, length); 123 } 124 125 if ((segment.options & TCP_HAS_WINDOW_SCALE) != 0 126 && length + 4 <= bufferSize) { 127 // insert one NOP so that the subsequent data is aligned on a 4 byte boundary 128 option->kind = TCP_OPTION_NOP; 129 bump_option(option, length); 130 131 option->kind = TCP_OPTION_WINDOW_SHIFT; 132 option->length = 3; 133 option->window_shift = segment.window_shift; 134 bump_option(option, length); 135 } 136 137 if ((segment.options & TCP_SACK_PERMITTED) != 0 138 && length + 2 <= bufferSize) { 139 option->kind = TCP_OPTION_SACK_PERMITTED; 140 option->length = 2; 141 bump_option(option, length); 142 } 143 144 if (segment.sack_count > 0) { 145 int sackCount = ((int)(bufferSize - length) - 4) / sizeof(tcp_sack); 146 if (sackCount > segment.sack_count) 147 sackCount = segment.sack_count; 148 149 if (sackCount > 0) { 150 option->kind = TCP_OPTION_NOP; 151 bump_option(option, length); 152 option->kind = TCP_OPTION_NOP; 153 bump_option(option, length); 154 option->kind = TCP_OPTION_SACK; 155 option->length = 2 + sackCount * sizeof(tcp_sack); 156 memcpy(option->sack, segment.sacks, sackCount * sizeof(tcp_sack)); 157 bump_option(option, length); 158 } 159 } 160 161 if ((length & 3) == 0) { 162 // options completely fill out the option space 163 return length; 164 } 165 166 option->kind = TCP_OPTION_END; 167 return (length + 3) & ~3; 168 // bump to a multiple of 4 length 169 } 170 171 172 static void 173 process_options(tcp_segment_header &segment, net_buffer *buffer, size_t size) 174 { 175 if (size == 0) 176 return; 177 178 tcp_option *option; 179 180 uint8 optionsBuffer[kMaxOptionSize]; 181 if (gBufferModule->direct_access(buffer, sizeof(tcp_header), size, 182 (void **)&option) != B_OK) { 183 if ((size_t)size > sizeof(optionsBuffer)) { 184 dprintf("Ignoring TCP options larger than expected.\n"); 185 return; 186 } 187 188 gBufferModule->read(buffer, sizeof(tcp_header), optionsBuffer, size); 189 option = (tcp_option *)optionsBuffer; 190 } 191 192 while (size > 0) { 193 int32 length = -1; 194 195 switch (option->kind) { 196 case TCP_OPTION_END: 197 case TCP_OPTION_NOP: 198 length = 1; 199 break; 200 case TCP_OPTION_MAX_SEGMENT_SIZE: 201 if (option->length == 4 && size >= 4) 202 segment.max_segment_size = ntohs(option->max_segment_size); 203 break; 204 case TCP_OPTION_WINDOW_SHIFT: 205 if (option->length == 3 && size >= 3) { 206 segment.options |= TCP_HAS_WINDOW_SCALE; 207 segment.window_shift = option->window_shift; 208 } 209 break; 210 case TCP_OPTION_TIMESTAMP: 211 if (option->length == 10 && size >= 10) { 212 segment.options |= TCP_HAS_TIMESTAMPS; 213 segment.timestamp_value = option->timestamp.value; 214 segment.timestamp_reply = 215 ntohl(option->timestamp.reply); 216 } 217 break; 218 case TCP_OPTION_SACK_PERMITTED: 219 if (option->length == 2 && size >= 2) 220 segment.options |= TCP_SACK_PERMITTED; 221 break; 222 } 223 224 if (length < 0) { 225 length = option->length; 226 if (length == 0 || length > (ssize_t)size) 227 break; 228 } 229 230 option = (tcp_option *)((uint8 *)option + length); 231 size -= length; 232 } 233 } 234 235 236 #if 0 237 static void 238 dump_tcp_header(tcp_header &header) 239 { 240 dprintf(" source port: %u\n", ntohs(header.source_port)); 241 dprintf(" dest port: %u\n", ntohs(header.destination_port)); 242 dprintf(" sequence: %lu\n", header.Sequence()); 243 dprintf(" ack: %lu\n", header.Acknowledge()); 244 dprintf(" flags: %s%s%s%s%s%s\n", (header.flags & TCP_FLAG_FINISH) ? "FIN " : "", 245 (header.flags & TCP_FLAG_SYNCHRONIZE) ? "SYN " : "", 246 (header.flags & TCP_FLAG_RESET) ? "RST " : "", 247 (header.flags & TCP_FLAG_PUSH) ? "PUSH " : "", 248 (header.flags & TCP_FLAG_ACKNOWLEDGE) ? "ACK " : "", 249 (header.flags & TCP_FLAG_URGENT) ? "URG " : ""); 250 dprintf(" window: %u\n", header.AdvertisedWindow()); 251 dprintf(" urgent offset: %u\n", header.UrgentOffset()); 252 } 253 #endif 254 255 256 static int 257 dump_endpoints(int argc, char** argv) 258 { 259 for (int i = 0; i < AF_MAX; i++) { 260 EndpointManager* manager = sEndpointManagers[i]; 261 if (manager != NULL) 262 manager->Dump(); 263 } 264 265 return 0; 266 } 267 268 269 static int 270 dump_endpoint(int argc, char** argv) 271 { 272 if (argc < 2) { 273 kprintf("usage: tcp_endpoint [address]\n"); 274 return 0; 275 } 276 277 TCPEndpoint* endpoint = (TCPEndpoint*)parse_expression(argv[1]); 278 endpoint->Dump(); 279 280 return 0; 281 } 282 283 284 // #pragma mark - internal API 285 286 287 /*! Creates a new endpoint manager for the specified domain, or returns 288 an existing one for this domain. 289 */ 290 EndpointManager* 291 get_endpoint_manager(net_domain* domain) 292 { 293 // See if there is one already 294 EndpointManager* endpointManager = endpoint_manager_for(domain); 295 if (endpointManager != NULL) 296 return endpointManager; 297 298 WriteLocker _(sEndpointManagersLock); 299 300 endpointManager = endpoint_manager_for_locked(domain->family); 301 if (endpointManager != NULL) 302 return endpointManager; 303 304 // There is no endpoint manager for this domain yet, so we need 305 // to create one. 306 307 endpointManager = new(std::nothrow) EndpointManager(domain); 308 if (endpointManager == NULL) 309 return NULL; 310 311 if (endpointManager->Init() != B_OK) { 312 delete endpointManager; 313 return NULL; 314 } 315 316 sEndpointManagers[domain->family] = endpointManager; 317 return endpointManager; 318 } 319 320 321 void 322 put_endpoint_manager(EndpointManager* endpointManager) 323 { 324 // TODO: we may want to use reference counting instead of only discarding 325 // them on unload. But since there is likely only IPv4/v6 there is not much 326 // point to it. 327 } 328 329 330 const char* 331 name_for_state(tcp_state state) 332 { 333 switch (state) { 334 case CLOSED: 335 return "closed"; 336 case LISTEN: 337 return "listen"; 338 case SYNCHRONIZE_SENT: 339 return "syn-sent"; 340 case SYNCHRONIZE_RECEIVED: 341 return "syn-received"; 342 case ESTABLISHED: 343 return "established"; 344 345 // peer closes the connection 346 case FINISH_RECEIVED: 347 return "close-wait"; 348 case WAIT_FOR_FINISH_ACKNOWLEDGE: 349 return "last-ack"; 350 351 // we close the connection 352 case FINISH_SENT: 353 return "fin-wait1"; 354 case FINISH_ACKNOWLEDGED: 355 return "fin-wait2"; 356 case CLOSING: 357 return "closing"; 358 359 case TIME_WAIT: 360 return "time-wait"; 361 } 362 363 return "-"; 364 } 365 366 367 /*! Constructs a TCP header on \a buffer with the specified values 368 for \a flags, \a seq \a ack and \a advertisedWindow. 369 */ 370 status_t 371 add_tcp_header(net_address_module_info* addressModule, 372 tcp_segment_header& segment, net_buffer* buffer) 373 { 374 buffer->protocol = IPPROTO_TCP; 375 376 uint8 optionsBuffer[kMaxOptionSize]; 377 uint32 optionsLength = add_options(segment, optionsBuffer, 378 sizeof(optionsBuffer)); 379 380 NetBufferPrepend<tcp_header> bufferHeader(buffer, 381 sizeof(tcp_header) + optionsLength); 382 if (bufferHeader.Status() != B_OK) 383 return bufferHeader.Status(); 384 385 tcp_header& header = bufferHeader.Data(); 386 387 header.source_port = addressModule->get_port(buffer->source); 388 header.destination_port = addressModule->get_port(buffer->destination); 389 header.sequence = htonl(segment.sequence); 390 header.acknowledge = (segment.flags & TCP_FLAG_ACKNOWLEDGE) 391 ? htonl(segment.acknowledge) : 0; 392 header.reserved = 0; 393 header.header_length = (sizeof(tcp_header) + optionsLength) >> 2; 394 header.flags = segment.flags; 395 header.advertised_window = htons(segment.advertised_window); 396 header.checksum = 0; 397 header.urgent_offset = htons(segment.urgent_offset); 398 399 // we must detach before calculating the checksum as we may 400 // not have a contiguous buffer. 401 bufferHeader.Sync(); 402 403 if (optionsLength > 0) { 404 gBufferModule->write(buffer, sizeof(tcp_header), optionsBuffer, 405 optionsLength); 406 } 407 408 TRACE(("add_tcp_header(): buffer %p, flags 0x%x, seq %lu, ack %lu, up %u, " 409 "win %u\n", buffer, segment.flags, segment.sequence, 410 segment.acknowledge, segment.urgent_offset, segment.advertised_window)); 411 412 *TCPChecksumField(buffer) = Checksum::PseudoHeader(addressModule, 413 gBufferModule, buffer, IPPROTO_TCP); 414 415 return B_OK; 416 } 417 418 419 size_t 420 tcp_options_length(tcp_segment_header& segment) 421 { 422 size_t length = 0; 423 424 if (segment.max_segment_size > 0) 425 length += 4; 426 427 if (segment.options & TCP_HAS_TIMESTAMPS) 428 length += 12; 429 430 if (segment.options & TCP_HAS_WINDOW_SCALE) 431 length += 4; 432 433 if (segment.options & TCP_SACK_PERMITTED) 434 length += 2; 435 436 if (segment.sack_count > 0) { 437 int sackCount = min_c((int)((kMaxOptionSize - length - 4) 438 / sizeof(tcp_sack)), segment.sack_count); 439 if (sackCount > 0) 440 length += 4 + sackCount * sizeof(tcp_sack); 441 } 442 443 if ((length & 3) == 0) 444 return length; 445 446 return (length + 3) & ~3; 447 } 448 449 450 // #pragma mark - protocol API 451 452 453 net_protocol* 454 tcp_init_protocol(net_socket* socket) 455 { 456 socket->send.buffer_size = 32768; 457 // override net_socket default 458 459 TCPEndpoint* protocol = new (std::nothrow) TCPEndpoint(socket); 460 if (protocol == NULL) 461 return NULL; 462 463 if (protocol->InitCheck() != B_OK) { 464 delete protocol; 465 return NULL; 466 } 467 468 TRACE(("Creating new TCPEndpoint: %p\n", protocol)); 469 socket->protocol = IPPROTO_TCP; 470 return protocol; 471 } 472 473 474 status_t 475 tcp_uninit_protocol(net_protocol* protocol) 476 { 477 TRACE(("Deleting TCPEndpoint: %p\n", protocol)); 478 delete (TCPEndpoint*)protocol; 479 return B_OK; 480 } 481 482 483 status_t 484 tcp_open(net_protocol* protocol) 485 { 486 return ((TCPEndpoint*)protocol)->Open(); 487 } 488 489 490 status_t 491 tcp_close(net_protocol* protocol) 492 { 493 return ((TCPEndpoint*)protocol)->Close(); 494 } 495 496 497 status_t 498 tcp_free(net_protocol* protocol) 499 { 500 ((TCPEndpoint*)protocol)->Free(); 501 return B_OK; 502 } 503 504 505 status_t 506 tcp_connect(net_protocol* protocol, const struct sockaddr* address) 507 { 508 return ((TCPEndpoint*)protocol)->Connect(address); 509 } 510 511 512 status_t 513 tcp_accept(net_protocol* protocol, struct net_socket** _acceptedSocket) 514 { 515 return ((TCPEndpoint*)protocol)->Accept(_acceptedSocket); 516 } 517 518 519 status_t 520 tcp_control(net_protocol* _protocol, int level, int option, void* value, 521 size_t* _length) 522 { 523 TCPEndpoint* protocol = (TCPEndpoint*)_protocol; 524 525 if ((level & LEVEL_MASK) == IPPROTO_TCP) { 526 if (option == NET_STAT_SOCKET) 527 return protocol->FillStat((net_stat*)value); 528 } 529 530 return protocol->next->module->control(protocol->next, level, option, 531 value, _length); 532 } 533 534 535 status_t 536 tcp_getsockopt(net_protocol* _protocol, int level, int option, void* value, 537 int* _length) 538 { 539 TCPEndpoint* protocol = (TCPEndpoint*)_protocol; 540 541 if (level == IPPROTO_TCP) 542 return protocol->GetOption(option, value, _length); 543 544 return protocol->next->module->getsockopt(protocol->next, level, option, 545 value, _length); 546 } 547 548 549 status_t 550 tcp_setsockopt(net_protocol* _protocol, int level, int option, 551 const void* _value, int length) 552 { 553 TCPEndpoint* protocol = (TCPEndpoint*)_protocol; 554 555 if (level == SOL_SOCKET) { 556 if (option == SO_SNDBUF || option == SO_RCVBUF) { 557 if (length != sizeof(int)) 558 return B_BAD_VALUE; 559 560 status_t status; 561 const int* value = (const int*)_value; 562 563 if (option == SO_SNDBUF) 564 status = protocol->SetSendBufferSize(*value); 565 else 566 status = protocol->SetReceiveBufferSize(*value); 567 568 if (status < B_OK) 569 return status; 570 } 571 } else if (level == IPPROTO_TCP) 572 return protocol->SetOption(option, _value, length); 573 574 return protocol->next->module->setsockopt(protocol->next, level, option, 575 _value, length); 576 } 577 578 579 status_t 580 tcp_bind(net_protocol* protocol, const struct sockaddr* address) 581 { 582 return ((TCPEndpoint*)protocol)->Bind(address); 583 } 584 585 586 status_t 587 tcp_unbind(net_protocol* protocol, struct sockaddr* address) 588 { 589 return ((TCPEndpoint*)protocol)->Unbind(address); 590 } 591 592 593 status_t 594 tcp_listen(net_protocol* protocol, int count) 595 { 596 return ((TCPEndpoint*)protocol)->Listen(count); 597 } 598 599 600 status_t 601 tcp_shutdown(net_protocol* protocol, int direction) 602 { 603 return ((TCPEndpoint*)protocol)->Shutdown(direction); 604 } 605 606 607 status_t 608 tcp_send_data(net_protocol* protocol, net_buffer* buffer) 609 { 610 return ((TCPEndpoint*)protocol)->SendData(buffer); 611 } 612 613 614 status_t 615 tcp_send_routed_data(net_protocol* protocol, struct net_route* route, 616 net_buffer* buffer) 617 { 618 // TCP never sends routed data 619 return B_ERROR; 620 } 621 622 623 ssize_t 624 tcp_send_avail(net_protocol* protocol) 625 { 626 return ((TCPEndpoint*)protocol)->SendAvailable(); 627 } 628 629 630 status_t 631 tcp_read_data(net_protocol* protocol, size_t numBytes, uint32 flags, 632 net_buffer** _buffer) 633 { 634 return ((TCPEndpoint*)protocol)->ReadData(numBytes, flags, _buffer); 635 } 636 637 638 ssize_t 639 tcp_read_avail(net_protocol* protocol) 640 { 641 return ((TCPEndpoint*)protocol)->ReadAvailable(); 642 } 643 644 645 struct net_domain* 646 tcp_get_domain(net_protocol* protocol) 647 { 648 return protocol->next->module->get_domain(protocol->next); 649 } 650 651 652 size_t 653 tcp_get_mtu(net_protocol* protocol, const struct sockaddr* address) 654 { 655 return protocol->next->module->get_mtu(protocol->next, address); 656 } 657 658 659 status_t 660 tcp_receive_data(net_buffer* buffer) 661 { 662 TRACE(("TCP: Received buffer %p\n", buffer)); 663 664 if (buffer->interface_address == NULL 665 || buffer->interface_address->domain == NULL) 666 return B_ERROR; 667 668 net_domain* domain = buffer->interface_address->domain; 669 net_address_module_info* addressModule = domain->address_module; 670 671 NetBufferHeaderReader<tcp_header> bufferHeader(buffer); 672 if (bufferHeader.Status() < B_OK) 673 return bufferHeader.Status(); 674 675 tcp_header& header = bufferHeader.Data(); 676 677 uint16 headerLength = header.HeaderLength(); 678 if (headerLength < sizeof(tcp_header)) 679 return B_BAD_DATA; 680 681 if (Checksum::PseudoHeader(addressModule, gBufferModule, buffer, 682 IPPROTO_TCP) != 0) 683 return B_BAD_DATA; 684 685 addressModule->set_port(buffer->source, header.source_port); 686 addressModule->set_port(buffer->destination, header.destination_port); 687 688 TRACE((" Looking for: peer %s, local %s\n", 689 AddressString(domain, buffer->source, true).Data(), 690 AddressString(domain, buffer->destination, true).Data())); 691 //dump_tcp_header(header); 692 //gBufferModule->dump(buffer); 693 694 tcp_segment_header segment(header.flags); 695 segment.sequence = header.Sequence(); 696 segment.acknowledge = header.Acknowledge(); 697 segment.advertised_window = header.AdvertisedWindow(); 698 segment.urgent_offset = header.UrgentOffset(); 699 process_options(segment, buffer, headerLength - sizeof(tcp_header)); 700 701 bufferHeader.Remove(headerLength); 702 // we no longer need to keep the header around 703 704 EndpointManager* endpointManager = endpoint_manager_for(domain); 705 if (endpointManager == NULL) { 706 TRACE((" No endpoint manager!\n")); 707 return B_ERROR; 708 } 709 710 int32 segmentAction = DROP; 711 712 TCPEndpoint* endpoint = endpointManager->FindConnection( 713 buffer->destination, buffer->source); 714 if (endpoint != NULL) { 715 segmentAction = endpoint->SegmentReceived(segment, buffer); 716 gSocketModule->release_socket(endpoint->socket); 717 } else if ((segment.flags & TCP_FLAG_RESET) == 0) 718 segmentAction = DROP | RESET; 719 720 if ((segmentAction & RESET) != 0) { 721 // send reset 722 endpointManager->ReplyWithReset(segment, buffer); 723 } 724 if ((segmentAction & DROP) != 0) 725 gBufferModule->free(buffer); 726 727 return B_OK; 728 } 729 730 731 status_t 732 tcp_error_received(net_error error, net_buffer* data) 733 { 734 return B_ERROR; 735 } 736 737 738 status_t 739 tcp_error_reply(net_protocol* protocol, net_buffer* cause, net_error error, 740 net_error_data* errorData) 741 { 742 return B_ERROR; 743 } 744 745 746 // #pragma mark - 747 748 749 static status_t 750 tcp_init() 751 { 752 rw_lock_init(&sEndpointManagersLock, "endpoint managers"); 753 754 status_t status = gStackModule->register_domain_protocols(AF_INET, 755 SOCK_STREAM, 0, 756 "network/protocols/tcp/v1", 757 "network/protocols/ipv4/v1", 758 NULL); 759 if (status < B_OK) 760 return status; 761 status = gStackModule->register_domain_protocols(AF_INET6, 762 SOCK_STREAM, 0, 763 "network/protocols/tcp/v1", 764 "network/protocols/ipv6/v1", 765 NULL); 766 if (status < B_OK) 767 return status; 768 769 status = gStackModule->register_domain_protocols(AF_INET, SOCK_STREAM, 770 IPPROTO_TCP, 771 "network/protocols/tcp/v1", 772 "network/protocols/ipv4/v1", 773 NULL); 774 if (status < B_OK) 775 return status; 776 status = gStackModule->register_domain_protocols(AF_INET6, SOCK_STREAM, 777 IPPROTO_TCP, 778 "network/protocols/tcp/v1", 779 "network/protocols/ipv6/v1", 780 NULL); 781 if (status < B_OK) 782 return status; 783 784 status = gStackModule->register_domain_receiving_protocol(AF_INET, 785 IPPROTO_TCP, "network/protocols/tcp/v1"); 786 if (status < B_OK) 787 return status; 788 status = gStackModule->register_domain_receiving_protocol(AF_INET6, 789 IPPROTO_TCP, "network/protocols/tcp/v1"); 790 if (status < B_OK) 791 return status; 792 793 add_debugger_command("tcp_endpoints", dump_endpoints, 794 "lists all open TCP endpoints"); 795 add_debugger_command("tcp_endpoint", dump_endpoint, 796 "dumps a TCP endpoint internal state"); 797 798 return B_OK; 799 } 800 801 802 static status_t 803 tcp_uninit() 804 { 805 remove_debugger_command("tcp_endpoint", dump_endpoint); 806 remove_debugger_command("tcp_endpoints", dump_endpoints); 807 808 rw_lock_destroy(&sEndpointManagersLock); 809 810 for (int i = 0; i < AF_MAX; i++) { 811 delete sEndpointManagers[i]; 812 } 813 814 return B_OK; 815 } 816 817 818 static status_t 819 tcp_std_ops(int32 op, ...) 820 { 821 switch (op) { 822 case B_MODULE_INIT: 823 return tcp_init(); 824 825 case B_MODULE_UNINIT: 826 return tcp_uninit(); 827 828 default: 829 return B_ERROR; 830 } 831 } 832 833 834 net_protocol_module_info sTCPModule = { 835 { 836 "network/protocols/tcp/v1", 837 0, 838 tcp_std_ops 839 }, 840 0, 841 842 tcp_init_protocol, 843 tcp_uninit_protocol, 844 tcp_open, 845 tcp_close, 846 tcp_free, 847 tcp_connect, 848 tcp_accept, 849 tcp_control, 850 tcp_getsockopt, 851 tcp_setsockopt, 852 tcp_bind, 853 tcp_unbind, 854 tcp_listen, 855 tcp_shutdown, 856 tcp_send_data, 857 tcp_send_routed_data, 858 tcp_send_avail, 859 tcp_read_data, 860 tcp_read_avail, 861 tcp_get_domain, 862 tcp_get_mtu, 863 tcp_receive_data, 864 NULL, // deliver_data() 865 tcp_error_received, 866 tcp_error_reply, 867 NULL, // add_ancillary_data() 868 NULL, // process_ancillary_data() 869 NULL, // process_ancillary_data_no_container() 870 NULL, // send_data_no_buffer() 871 NULL // read_data_no_buffer() 872 }; 873 874 module_dependency module_dependencies[] = { 875 {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 876 {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 877 {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 878 {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule}, 879 {} 880 }; 881 882 module_info *modules[] = { 883 (module_info *)&sTCPModule, 884 NULL 885 }; 886