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