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