xref: /haiku/src/add-ons/kernel/network/protocols/tcp/tcp.cpp (revision 5e96d7d537fbec23bad4ae9b4c8e7b02e769f0c6)
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