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