xref: /haiku/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp (revision 90c3b9bf9fe633e4c6a59d42c11c3f523183c553)
1 /*
2  * Copyright 2006-2011, 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  *		Atis Elsts, the.kfx@gmail.com
8  */
9 
10 
11 #include "ipv6_address.h"
12 #include "ipv6_utils.h"
13 #include "multicast.h"
14 
15 #include <net_datalink.h>
16 #include <net_datalink_protocol.h>
17 #include <net_device.h>
18 #include <net_protocol.h>
19 #include <net_stack.h>
20 #include <NetBufferUtilities.h>
21 #include <ProtocolUtilities.h>
22 
23 #include <ByteOrder.h>
24 #include <KernelExport.h>
25 #include <util/AutoLock.h>
26 #include <util/list.h>
27 #include <util/DoublyLinkedList.h>
28 #include <util/MultiHashTable.h>
29 
30 #include <netinet6/in6.h>
31 #include <netinet/ip6.h>
32 #include <netinet/icmp6.h>
33 #include <new>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <utility>
38 
39 
40 //#define TRACE_IPV6
41 #ifdef TRACE_IPV6
42 	#define TRACE(format, args...) \
43 		dprintf("IPv6 [%llu] " format "\n", system_time(), ##args)
44 	#define TRACE_SK(protocol, format, args...) \
45 		dprintf("IPv6 [%llu] %p " format "\n", system_time(), protocol, ##args)
46 #else
47 	#define TRACE(args...)
48 	#define TRACE_SK(args...)
49 #endif
50 
51 
52 #define MAX_HASH_FRAGMENTS 		64
53 	// slots in the fragment packet's hash
54 #define FRAGMENT_TIMEOUT		60000000LL
55 	// discard fragment after 60 seconds [RFC 2460]
56 
57 
58 struct IPv6Header {
59 	struct ip6_hdr header;
60 
61 	uint8 ProtocolVersion() const { return header.ip6_vfc & IPV6_VERSION_MASK; }
62 	uint8 ServiceType() const { return ntohl(header.ip6_flow) >> 20;}
63 	uint16 PayloadLength() const { return ntohs(header.ip6_plen); }
64 	const in6_addr& Dst() const { return header.ip6_dst; }
65 	const in6_addr& Src() const { return header.ip6_src; }
66 	uint8 NextHeader() const { return header.ip6_nxt; }
67 	uint16 GetHeaderOffset(net_buffer* buffer, uint32 headerCode = ~0u) const;
68 };
69 
70 
71 typedef DoublyLinkedList<struct net_buffer,
72 	DoublyLinkedListCLink<struct net_buffer> > FragmentList;
73 
74 
75 // TODO: make common fragmentation interface for both address families
76 struct ipv6_packet_key {
77 	in6_addr	source;
78 	in6_addr	destination;
79 	// We use uint32 here due to the hash function
80 	uint32		id;
81 	uint32		protocol;
82 };
83 
84 
85 class FragmentPacket {
86 public:
87 								FragmentPacket(const ipv6_packet_key& key);
88 								~FragmentPacket();
89 
90 			status_t			AddFragment(uint16 start, uint16 end,
91 									net_buffer* buffer, bool lastFragment);
92 			status_t			Reassemble(net_buffer* to);
93 
94 			bool				IsComplete() const
95 									{ return fReceivedLastFragment
96 										&& fBytesLeft == 0; }
97 
98 			const ipv6_packet_key& Key() const { return fKey; }
99 			FragmentPacket*&	HashTableLink() { return fNext; }
100 
101 	static	void				StaleTimer(struct net_timer* timer, void* data);
102 
103 private:
104 			FragmentPacket*		fNext;
105 			struct ipv6_packet_key fKey;
106 			uint32				fIndex;
107 			int32				fBytesLeft;
108 			FragmentList		fFragments;
109 			net_timer			fTimer;
110 			bool				fReceivedLastFragment;
111 };
112 
113 
114 struct FragmentHashDefinition {
115 	typedef ipv6_packet_key KeyType;
116 	typedef FragmentPacket ValueType;
117 
118 	size_t HashKey(const KeyType& key) const
119 	{
120 		return jenkins_hashword((const uint32*)&key,
121 			sizeof(ipv6_packet_key) / sizeof(uint32), 0);
122 	}
123 
124 	size_t Hash(ValueType* value) const
125 	{
126 		return HashKey(value->Key());
127 	}
128 
129 	bool Compare(const KeyType& key, ValueType* value) const
130 	{
131 		const ipv6_packet_key& packetKey = value->Key();
132 
133 		return packetKey.id == key.id
134 			&& packetKey.source == key.source
135 			&& packetKey.destination == key.destination
136 			&& packetKey.protocol == key.protocol;
137 	}
138 
139 	ValueType*& GetLink(ValueType* value) const
140 	{
141 		return value->HashTableLink();
142 	}
143 };
144 
145 
146 typedef BOpenHashTable<FragmentHashDefinition, false, true> FragmentTable;
147 
148 
149 class RawSocket
150 	: public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
151 public:
152 							RawSocket(net_socket* socket);
153 };
154 
155 
156 typedef DoublyLinkedList<RawSocket> RawSocketList;
157 
158 typedef MulticastGroupInterface<IPv6Multicast> IPv6GroupInterface;
159 typedef MulticastFilter<IPv6Multicast> IPv6MulticastFilter;
160 
161 struct MulticastStateHash {
162 	typedef std::pair<const in6_addr*, uint32> KeyType;
163 	typedef IPv6GroupInterface ValueType;
164 
165 	size_t HashKey(const KeyType &key) const;
166 	size_t Hash(ValueType* value) const
167 		{ return HashKey(std::make_pair(&value->Address(),
168 			value->Interface()->index)); }
169 	bool Compare(const KeyType &key, ValueType* value) const
170 		{ return value->Interface()->index == key.second
171 			&& value->Address() == *key.first; }
172 	bool CompareValues(ValueType* value1, ValueType* value2) const
173 		{ return value1->Interface()->index == value2->Interface()->index
174 			&& value1->Address() == value2->Address(); }
175 	ValueType*& GetLink(ValueType* value) const { return value->HashLink(); }
176 };
177 
178 
179 struct ipv6_protocol : net_protocol {
180 	ipv6_protocol()
181 		:
182 		raw(NULL),
183 		multicast_filter(this)
184 	{
185 	}
186 
187 	~ipv6_protocol()
188 	{
189 		delete raw;
190 	}
191 
192 	RawSocket	*raw;
193 	uint8		service_type;
194 	uint8		time_to_live;
195 	uint8		multicast_time_to_live;
196 	uint8		receive_hoplimit;
197 	uint8		receive_pktinfo;
198 	struct sockaddr* multicast_address; // for IPV6_MULTICAST_IF
199 
200 	IPv6MulticastFilter multicast_filter;
201 };
202 
203 
204 static const int kDefaultTTL = IPV6_DEFHLIM;
205 static const int kDefaultMulticastTTL = 1;
206 
207 
208 extern net_protocol_module_info gIPv6Module;
209 	// we need this in ipv6_std_ops() for registering the AF_INET6 domain
210 
211 net_stack_module_info* gStackModule;
212 net_buffer_module_info* gBufferModule;
213 
214 static struct net_domain* sDomain;
215 static net_datalink_module_info* sDatalinkModule;
216 static net_socket_module_info* sSocketModule;
217 static RawSocketList sRawSockets;
218 static mutex sRawSocketsLock;
219 static mutex sFragmentLock;
220 static FragmentTable sFragmentHash;
221 static int32 sFragmentID;
222 static mutex sMulticastGroupsLock;
223 
224 typedef MultiHashTable<MulticastStateHash> MulticastState;
225 static MulticastState* sMulticastState;
226 
227 static net_protocol_module_info* sReceivingProtocol[256];
228 static mutex sReceivingProtocolLock;
229 
230 
231 uint16
232 IPv6Header::GetHeaderOffset(net_buffer* buffer, uint32 headerCode) const
233 {
234 	uint16 offset = sizeof(struct ip6_hdr);
235 	uint8 next = header.ip6_nxt;
236 
237 	// these are the extension headers that might be supported one day
238 	while (next != headerCode
239 		&& (next == IPPROTO_HOPOPTS
240 			|| next == IPPROTO_ROUTING
241 			|| next == IPPROTO_FRAGMENT
242 			|| next == IPPROTO_ESP
243 			|| next == IPPROTO_AH
244 			|| next == IPPROTO_DSTOPTS)) {
245 		struct ip6_ext extensionHeader;
246 		status_t status = gBufferModule->read(buffer, offset,
247 			&extensionHeader, sizeof(ip6_ext));
248 		if (status != B_OK)
249 			break;
250 
251 		next = extensionHeader.ip6e_nxt;
252 		offset += extensionHeader.ip6e_len;
253 	}
254 
255 	// were we looking for a specific header?
256 	if (headerCode != ~0u) {
257 		if (next == headerCode) {
258 			// found the specific header
259 			return offset;
260 		}
261 		// return 0 if fragement header is not present
262 		return 0;
263 	}
264 
265 	// the general transport layer header case
266 	buffer->protocol = next;
267 	return offset;
268 }
269 
270 
271 RawSocket::RawSocket(net_socket* socket)
272 	:
273 	DatagramSocket<>("ipv6 raw socket", socket)
274 {
275 }
276 
277 
278 //	#pragma mark -
279 
280 
281 FragmentPacket::FragmentPacket(const ipv6_packet_key &key)
282 	:
283 	fKey(key),
284 	fBytesLeft(IPV6_MAXPACKET),
285 	fReceivedLastFragment(false)
286 {
287 	gStackModule->init_timer(&fTimer, FragmentPacket::StaleTimer, this);
288 }
289 
290 
291 FragmentPacket::~FragmentPacket()
292 {
293 	// cancel the kill timer
294 	gStackModule->set_timer(&fTimer, -1);
295 
296 	// delete all fragments
297 	net_buffer* buffer;
298 	while ((buffer = fFragments.RemoveHead()) != NULL) {
299 		gBufferModule->free(buffer);
300 	}
301 }
302 
303 
304 status_t
305 FragmentPacket::AddFragment(uint16 start, uint16 end, net_buffer* buffer,
306 	bool lastFragment)
307 {
308 	// restart the timer
309 	gStackModule->set_timer(&fTimer, FRAGMENT_TIMEOUT);
310 
311 	if (start >= end) {
312 		// invalid fragment
313 		return B_BAD_DATA;
314 	}
315 
316 	// Search for a position in the list to insert the fragment
317 
318 	FragmentList::ReverseIterator iterator = fFragments.GetReverseIterator();
319 	net_buffer* previous = NULL;
320 	net_buffer* next = NULL;
321 	while ((previous = iterator.Next()) != NULL) {
322 		if (previous->fragment.start <= start) {
323 			// The new fragment can be inserted after this one
324 			break;
325 		}
326 
327 		next = previous;
328 	}
329 
330 	// See if we already have the fragment's data
331 
332 	if (previous != NULL && previous->fragment.start <= start
333 		&& previous->fragment.end >= end) {
334 		// we do, so we can just drop this fragment
335 		gBufferModule->free(buffer);
336 		return B_OK;
337 	}
338 
339 	fIndex = buffer->index;
340 		// adopt the buffer's device index
341 
342 	TRACE("    previous: %p, next: %p", previous, next);
343 
344 	// If we have parts of the data already, truncate as needed
345 
346 	if (previous != NULL && previous->fragment.end > start) {
347 		TRACE("    remove header %d bytes", previous->fragment.end - start);
348 		gBufferModule->remove_header(buffer, previous->fragment.end - start);
349 		start = previous->fragment.end;
350 	}
351 	if (next != NULL && next->fragment.start < end) {
352 		TRACE("    remove trailer %d bytes", next->fragment.start - end);
353 		gBufferModule->remove_trailer(buffer, next->fragment.start - end);
354 		end = next->fragment.start;
355 	}
356 
357 	// Now try if we can already merge the fragments together
358 
359 	// We will always keep the last buffer received, so that we can still
360 	// report an error (in which case we're not responsible for freeing it)
361 
362 	if (previous != NULL && previous->fragment.end == start) {
363 		fFragments.Remove(previous);
364 
365 		buffer->fragment.start = previous->fragment.start;
366 		buffer->fragment.end = end;
367 
368 		status_t status = gBufferModule->merge(buffer, previous, false);
369 		TRACE("    merge previous: %s", strerror(status));
370 		if (status != B_OK) {
371 			fFragments.Insert(next, previous);
372 			return status;
373 		}
374 
375 		fFragments.Insert(next, buffer);
376 
377 		// cut down existing hole
378 		fBytesLeft -= end - start;
379 
380 		if (lastFragment && !fReceivedLastFragment) {
381 			fReceivedLastFragment = true;
382 			fBytesLeft -= IPV6_MAXPACKET - end;
383 		}
384 
385 		TRACE("    hole length: %d", (int)fBytesLeft);
386 
387 		return B_OK;
388 	} else if (next != NULL && next->fragment.start == end) {
389 		net_buffer* afterNext = (net_buffer*)next->link.next;
390 		fFragments.Remove(next);
391 
392 		buffer->fragment.start = start;
393 		buffer->fragment.end = next->fragment.end;
394 
395 		status_t status = gBufferModule->merge(buffer, next, true);
396 		TRACE("    merge next: %s", strerror(status));
397 		if (status != B_OK) {
398 			// Insert "next" at its previous position
399 			fFragments.Insert(afterNext, next);
400 			return status;
401 		}
402 
403 		fFragments.Insert(afterNext, buffer);
404 
405 		// cut down existing hole
406 		fBytesLeft -= end - start;
407 
408 		if (lastFragment && !fReceivedLastFragment) {
409 			fReceivedLastFragment = true;
410 			fBytesLeft -= IPV6_MAXPACKET - end;
411 		}
412 
413 		TRACE("    hole length: %d", (int)fBytesLeft);
414 
415 		return B_OK;
416 	}
417 
418 	// We couldn't merge the fragments, so we need to add it as is
419 
420 	TRACE("    new fragment: %p, bytes %d-%d", buffer, start, end);
421 
422 	buffer->fragment.start = start;
423 	buffer->fragment.end = end;
424 	fFragments.Insert(next, buffer);
425 
426 	// update length of the hole, if any
427 	fBytesLeft -= end - start;
428 
429 	if (lastFragment && !fReceivedLastFragment) {
430 		fReceivedLastFragment = true;
431 		fBytesLeft -= IPV6_MAXPACKET - end;
432 	}
433 
434 	TRACE("    hole length: %d", (int)fBytesLeft);
435 
436 	return B_OK;
437 }
438 
439 
440 /*!	Reassembles the fragments to the specified buffer \a to.
441 	This buffer must have been added via AddFragment() before.
442 */
443 status_t
444 FragmentPacket::Reassemble(net_buffer* to)
445 {
446 	if (!IsComplete())
447 		return B_ERROR;
448 
449 	net_buffer* buffer = NULL;
450 
451 	net_buffer* fragment;
452 	while ((fragment = fFragments.RemoveHead()) != NULL) {
453 		if (buffer != NULL) {
454 			status_t status;
455 			if (to == fragment) {
456 				status = gBufferModule->merge(fragment, buffer, false);
457 				buffer = fragment;
458 			} else
459 				status = gBufferModule->merge(buffer, fragment, true);
460 			if (status != B_OK)
461 				return status;
462 		} else
463 			buffer = fragment;
464 	}
465 
466 	if (buffer != to)
467 		panic("ipv6 packet reassembly did not work correctly.");
468 
469 	to->index = fIndex;
470 		// reset the buffer's device index
471 
472 	return B_OK;
473 }
474 
475 
476 /*static*/ void
477 FragmentPacket::StaleTimer(struct net_timer* timer, void* data)
478 {
479 	FragmentPacket* packet = (FragmentPacket*)data;
480 	TRACE("Assembling FragmentPacket %p timed out!", packet);
481 
482 	MutexLocker locker(&sFragmentLock);
483 	sFragmentHash.Remove(packet);
484 	locker.Unlock();
485 
486 	if (!packet->fFragments.IsEmpty()) {
487 		// Send error: fragment reassembly time exceeded
488 		sDomain->module->error_reply(NULL, packet->fFragments.First(),
489 			B_NET_ERROR_REASSEMBLY_TIME_EXCEEDED, NULL);
490 	}
491 
492 	delete packet;
493 }
494 
495 
496 //	#pragma mark -
497 
498 
499 size_t
500 MulticastStateHash::HashKey(const KeyType &key) const
501 {
502 	size_t result = 0;
503 	result = jenkins_hashword((const uint32*)key.first,
504 		sizeof(in6_addr) / sizeof(uint32), result);
505 	result = jenkins_hashword(&key.second, 1, result);
506 	return result;
507 }
508 
509 
510 //	#pragma mark -
511 
512 
513 static inline void
514 dump_ipv6_header(IPv6Header &header)
515 {
516 #ifdef TRACE_IPV6
517 	char addrbuf[INET6_ADDRSTRLEN];
518 	dprintf("  version: %d\n", header.ProtocolVersion() >> 4);
519 	dprintf("  service_type: %d\n", header.ServiceType());
520 	dprintf("  payload_length: %d\n", header.PayloadLength());
521 	dprintf("  next_header: %d\n", header.NextHeader());
522 	dprintf("  hop_limit: %d\n", header.header.ip6_hops);
523 	dprintf("  source: %s\n", ip6_sprintf(&header.header.ip6_src, addrbuf));
524 	dprintf("  destination: %s\n",
525 		ip6_sprintf(&header.header.ip6_dst, addrbuf));
526 #endif
527 }
528 
529 
530 /*!	Attempts to re-assemble fragmented packets.
531 	\return B_OK if everything went well; if it could reassemble the packet,
532 		\a _buffer will point to its buffer, otherwise, it will be \c NULL.
533 	\return various error codes if something went wrong (mostly B_NO_MEMORY)
534 */
535 static status_t
536 reassemble_fragments(const IPv6Header &header, net_buffer** _buffer,
537 	uint16 offset)
538 {
539 	net_buffer* buffer = *_buffer;
540 	status_t status;
541 
542 	ip6_frag fragmentHeader;
543 	status = gBufferModule->read(buffer, offset, &fragmentHeader,
544 		sizeof(ip6_frag));
545 
546 	if (status != B_OK)
547 		return status;
548 
549 	struct ipv6_packet_key key;
550 	memcpy(&key.source, &header.Src(), sizeof(in6_addr));
551 	memcpy(&key.destination, &header.Dst(), sizeof(in6_addr));
552 	key.id = fragmentHeader.ip6f_ident;
553 	key.protocol = fragmentHeader.ip6f_nxt;
554 
555 	// TODO: Make locking finer grained.
556 	MutexLocker locker(&sFragmentLock);
557 
558 	FragmentPacket* packet = sFragmentHash.Lookup(key);
559 	if (packet == NULL) {
560 		// New fragment packet
561 		packet = new (std::nothrow) FragmentPacket(key);
562 		if (packet == NULL)
563 			return B_NO_MEMORY;
564 
565 		// add packet to hash
566 		status = sFragmentHash.Insert(packet);
567 		if (status != B_OK) {
568 			delete packet;
569 			return status;
570 		}
571 	}
572 
573 	uint16 start = ntohs(fragmentHeader.ip6f_offlg & IP6F_OFF_MASK);
574 	uint16 end = start + header.PayloadLength();
575 	bool lastFragment = (fragmentHeader.ip6f_offlg & IP6F_MORE_FRAG) == 0;
576 
577 	TRACE("   Received IPv6 %sfragment of size %d, offset %d.",
578 		lastFragment ? "last ": "", end - start, start);
579 
580 	// Remove header unless this is the first fragment
581 	if (start != 0)
582 		gBufferModule->remove_header(buffer, offset);
583 
584 	status = packet->AddFragment(start, end, buffer, lastFragment);
585 	if (status != B_OK)
586 		return status;
587 
588 	if (packet->IsComplete()) {
589 		sFragmentHash.Remove(packet);
590 			// no matter if reassembling succeeds, we won't need this packet
591 			// anymore
592 
593 		status = packet->Reassemble(buffer);
594 		delete packet;
595 
596 		// _buffer does not change
597 		return status;
598 	}
599 
600 	// This indicates that the packet is not yet complete
601 	*_buffer = NULL;
602 	return B_OK;
603 }
604 
605 
606 /*!	Fragments the incoming buffer and send all fragments via the specified
607 	\a route.
608 */
609 static status_t
610 send_fragments(ipv6_protocol* protocol, struct net_route* route,
611 	net_buffer* buffer, uint32 mtu)
612 {
613 	TRACE_SK(protocol, "SendFragments(%lu bytes, mtu %lu)", buffer->size, mtu);
614 
615 	NetBufferHeaderReader<IPv6Header> originalHeader(buffer);
616 	if (originalHeader.Status() != B_OK)
617 		return originalHeader.Status();
618 
619 	// TODO: currently FragHeader goes always as the last one, but in theory
620 	// ext. headers like AuthHeader and DestOptions should go after it.
621 	uint16 headersLength = originalHeader->GetHeaderOffset(buffer);
622 	uint16 extensionHeadersLength = headersLength
623 		- sizeof(ip6_hdr) + sizeof(ip6_frag);
624 	uint32 bytesLeft = buffer->size - headersLength;
625 	uint32 fragmentOffset = 0;
626 	status_t status = B_OK;
627 
628 	// TODO: this is rather inefficient
629 	net_buffer* headerBuffer = gBufferModule->clone(buffer, false);
630 	if (headerBuffer == NULL)
631 		return B_NO_MEMORY;
632 
633 	status = gBufferModule->remove_trailer(headerBuffer, bytesLeft);
634 	if (status != B_OK)
635 		return status;
636 
637 	uint8 data[bytesLeft];
638 	status = gBufferModule->read(buffer, headersLength, data, bytesLeft);
639 	if (status != B_OK)
640 		return status;
641 
642 	// TODO (from ipv4): we need to make sure all header space is contiguous or
643 	// use another construct.
644 	NetBufferHeaderReader<IPv6Header> bufferHeader(headerBuffer);
645 
646 	// Adapt MTU to be a multiple of 8 (fragment offsets can only be specified
647 	// this way)
648 	mtu -= headersLength + sizeof(ip6_frag);
649 	mtu &= ~7;
650 	TRACE("  adjusted MTU to %ld, bytesLeft %ld", mtu, bytesLeft);
651 
652 	while (bytesLeft > 0) {
653 		uint32 fragmentLength = min_c(bytesLeft, mtu);
654 		bytesLeft -= fragmentLength;
655 		bool lastFragment = bytesLeft == 0;
656 
657 		bufferHeader->header.ip6_nxt = IPPROTO_FRAGMENT;
658 		bufferHeader->header.ip6_plen
659 			= htons(fragmentLength + extensionHeadersLength);
660 		bufferHeader.Sync();
661 
662 		ip6_frag fragmentHeader;
663 		fragmentHeader.ip6f_nxt = originalHeader->NextHeader();
664 		fragmentHeader.ip6f_reserved = 0;
665 		fragmentHeader.ip6f_offlg = htons(fragmentOffset) & IP6F_OFF_MASK;
666 		if (!lastFragment)
667 			fragmentHeader.ip6f_offlg |= IP6F_MORE_FRAG;
668 		fragmentHeader.ip6f_ident = htonl(atomic_add(&sFragmentID, 1));
669 
670 		TRACE("  send fragment of %ld bytes (%ld bytes left)", fragmentLength,
671 			bytesLeft);
672 
673 		net_buffer* fragmentBuffer;
674 		if (!lastFragment)
675 			fragmentBuffer = gBufferModule->clone(headerBuffer, false);
676 		else
677 			fragmentBuffer = buffer;
678 
679 		if (fragmentBuffer == NULL) {
680 			status = B_NO_MEMORY;
681 			break;
682 		}
683 
684 		// copy data to fragment
685 		do {
686 			status = gBufferModule->append(
687 				fragmentBuffer, &fragmentHeader, sizeof(ip6_frag));
688 			if (status != B_OK)
689 				break;
690 
691 			status = gBufferModule->append(
692 				fragmentBuffer, &data[fragmentOffset], fragmentLength);
693 			if (status != B_OK)
694 				break;
695 
696 			// send fragment
697 			status = sDatalinkModule->send_routed_data(route, fragmentBuffer);
698 		} while (false);
699 
700 		if (lastFragment) {
701 			// we don't own the last buffer, so we don't have to free it
702 			break;
703 		}
704 
705 		if (status != B_OK) {
706 			gBufferModule->free(fragmentBuffer);
707 			break;
708 		}
709 
710 		fragmentOffset += fragmentLength;
711 	}
712 
713 	gBufferModule->free(headerBuffer);
714 	return status;
715 }
716 
717 
718 static status_t
719 deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
720 	bool deliverToRaw, net_interface *interface)
721 {
722 	sockaddr_in6* multicastAddr = (sockaddr_in6*)buffer->destination;
723 
724 	MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
725 		&multicastAddr->sin6_addr, interface->index));
726 
727 	while (it.HasNext()) {
728 		IPv6GroupInterface* state = it.Next();
729 		ipv6_protocol* ipproto = state->Parent()->Socket();
730 
731 		if (deliverToRaw && ipproto->raw == NULL)
732 			continue;
733 
734 		if (state->FilterAccepts(buffer)) {
735 			// TODO: do as in IPv4 code
736 			module->deliver_data(ipproto, buffer);
737 		}
738 	}
739 
740 	return B_OK;
741 }
742 
743 
744 static status_t
745 deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
746 	bool deliverToRaw)
747 {
748 	if (module->deliver_data == NULL)
749 		return B_OK;
750 
751 	MutexLocker _(sMulticastGroupsLock);
752 
753 	status_t status = B_OK;
754 	if (buffer->interface_address != NULL) {
755 		status = deliver_multicast(module, buffer, deliverToRaw,
756 			buffer->interface_address->interface);
757 	} else {
758 #if 0 //  FIXME: multicast
759 		net_domain_private* domain = (net_domain_private*)sDomain;
760 		RecursiveLocker locker(domain->lock);
761 
762 		net_interface* interface = NULL;
763 		while (true) {
764 			interface = (net_interface*)list_get_next_item(
765 				&domain->interfaces, interface);
766 			if (interface == NULL)
767 				break;
768 
769 			status = deliver_multicast(module, buffer, deliverToRaw, interface);
770 			if (status < B_OK)
771 				break;
772 		}
773 #endif
774 	}
775 	return status;
776 }
777 
778 
779 static void
780 raw_receive_data(net_buffer* buffer)
781 {
782 	MutexLocker locker(sRawSocketsLock);
783 
784 	if (sRawSockets.IsEmpty())
785 		return;
786 
787 	TRACE("RawReceiveData(%i)", buffer->protocol);
788 
789 	if ((buffer->flags & MSG_MCAST) != 0) {
790 		deliver_multicast(&gIPv6Module, buffer, true);
791 	} else {
792 		RawSocketList::Iterator iterator = sRawSockets.GetIterator();
793 
794 		while (iterator.HasNext()) {
795 			RawSocket* raw = iterator.Next();
796 
797 			if (raw->Socket()->protocol == buffer->protocol)
798 				raw->EnqueueClone(buffer);
799 		}
800 	}
801 }
802 
803 
804 static inline sockaddr*
805 fill_sockaddr_in6(sockaddr_in6* target, const in6_addr &address)
806 {
807 	target->sin6_family = AF_INET6;
808 	target->sin6_len = sizeof(sockaddr_in6);
809 	target->sin6_port = 0;
810 	target->sin6_flowinfo = 0;
811 	memcpy(target->sin6_addr.s6_addr, address.s6_addr, sizeof(in6_addr));
812 	target->sin6_scope_id = 0;
813 	return (sockaddr*)target;
814 }
815 
816 
817 status_t
818 IPv6Multicast::JoinGroup(IPv6GroupInterface* state)
819 {
820 	MutexLocker _(sMulticastGroupsLock);
821 
822 	sockaddr_in6 groupAddr;
823 	status_t status = sDatalinkModule->join_multicast(state->Interface(),
824 		sDomain, fill_sockaddr_in6(&groupAddr, state->Address()));
825 	if (status != B_OK)
826 		return status;
827 
828 	sMulticastState->Insert(state);
829 	return B_OK;
830 }
831 
832 
833 status_t
834 IPv6Multicast::LeaveGroup(IPv6GroupInterface* state)
835 {
836 	MutexLocker _(sMulticastGroupsLock);
837 
838 	sMulticastState->Remove(state);
839 
840 	sockaddr_in6 groupAddr;
841 	return sDatalinkModule->leave_multicast(state->Interface(), sDomain,
842 		fill_sockaddr_in6(&groupAddr, state->Address()));
843 }
844 
845 
846 static net_protocol_module_info*
847 receiving_protocol(uint8 protocol)
848 {
849 	net_protocol_module_info* module = sReceivingProtocol[protocol];
850 	if (module != NULL)
851 		return module;
852 
853 	MutexLocker locker(sReceivingProtocolLock);
854 
855 	module = sReceivingProtocol[protocol];
856 	if (module != NULL)
857 		return module;
858 
859 	if (gStackModule->get_domain_receiving_protocol(sDomain, protocol,
860 			&module) == B_OK)
861 		sReceivingProtocol[protocol] = module;
862 
863 	return module;
864 }
865 
866 
867 static status_t
868 ipv6_delta_group(IPv6GroupInterface* group, int option,
869 	net_interface* interface, const in6_addr* sourceAddr)
870 {
871 	switch (option) {
872 		case IPV6_JOIN_GROUP:
873 			return group->Add();
874 		case IPV6_LEAVE_GROUP:
875 			return group->Drop();
876 	}
877 
878 	return B_ERROR;
879 }
880 
881 
882 static status_t
883 ipv6_delta_membership(ipv6_protocol* protocol, int option,
884 	net_interface* interface, const in6_addr* groupAddr,
885 	const in6_addr* sourceAddr)
886 {
887 	IPv6MulticastFilter &filter = protocol->multicast_filter;
888 	IPv6GroupInterface* state = NULL;
889 	status_t status = B_OK;
890 
891 	switch (option) {
892 		// TODO: support more options
893 		case IPV6_JOIN_GROUP:
894 			status = filter.GetState(*groupAddr, interface, state, true);
895 			break;
896 
897 		case IPV6_LEAVE_GROUP:
898 			filter.GetState(*groupAddr, interface, state, false);
899 			if (state == NULL)
900 				return EADDRNOTAVAIL;
901 			break;
902 	}
903 
904 	if (status != B_OK)
905 		return status;
906 
907 	status = ipv6_delta_group(state, option, interface, sourceAddr);
908 	filter.ReturnState(state);
909 	return status;
910 }
911 
912 
913 static status_t
914 ipv6_delta_membership(ipv6_protocol* protocol, int option,
915 	uint32 interfaceIndex, in6_addr* groupAddr, in6_addr* sourceAddr)
916 {
917 	net_interface* interface;
918 
919 	// TODO: can the interface be unspecified?
920 	interface = sDatalinkModule->get_interface(sDomain, interfaceIndex);
921 
922 	if (interface == NULL)
923 		return B_DEVICE_NOT_FOUND;
924 
925 	return ipv6_delta_membership(protocol, option, interface,
926 		groupAddr, sourceAddr);
927 }
928 
929 
930 static status_t
931 get_int_option(void* target, size_t length, int value)
932 {
933 	if (length != sizeof(int))
934 		return B_BAD_VALUE;
935 
936 	return user_memcpy(target, &value, sizeof(int));
937 }
938 
939 
940 template<typename Type> static status_t
941 set_int_option(Type &target, const void* _value, size_t length)
942 {
943 	int value;
944 
945 	if (length != sizeof(int))
946 		return B_BAD_VALUE;
947 
948 	if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
949 		return B_BAD_ADDRESS;
950 
951 	target = value;
952 	return B_OK;
953 }
954 
955 
956 //	#pragma mark -
957 
958 
959 net_protocol*
960 ipv6_init_protocol(net_socket* socket)
961 {
962 	ipv6_protocol* protocol = new (std::nothrow) ipv6_protocol();
963 	if (protocol == NULL)
964 		return NULL;
965 
966 	protocol->raw = NULL;
967 	protocol->service_type = 0;
968 	protocol->time_to_live = kDefaultTTL;
969 	protocol->multicast_time_to_live = kDefaultMulticastTTL;
970 	protocol->receive_hoplimit = 0;
971 	protocol->receive_pktinfo = 0;
972 	protocol->multicast_address = NULL;
973 	return protocol;
974 }
975 
976 
977 status_t
978 ipv6_uninit_protocol(net_protocol* _protocol)
979 {
980 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
981 
982 	delete protocol;
983 	return B_OK;
984 }
985 
986 
987 /*!	Since open() is only called on the top level protocol, when we get here
988 	it means we are on a SOCK_RAW socket.
989 */
990 status_t
991 ipv6_open(net_protocol* _protocol)
992 {
993 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
994 
995 	RawSocket* raw = new (std::nothrow) RawSocket(protocol->socket);
996 	if (raw == NULL)
997 		return B_NO_MEMORY;
998 
999 	status_t status = raw->InitCheck();
1000 	if (status != B_OK) {
1001 		delete raw;
1002 		return status;
1003 	}
1004 
1005 	TRACE_SK(protocol, "Open()");
1006 
1007 	protocol->raw = raw;
1008 
1009 	MutexLocker locker(sRawSocketsLock);
1010 	sRawSockets.Add(raw);
1011 	return B_OK;
1012 }
1013 
1014 
1015 status_t
1016 ipv6_close(net_protocol* _protocol)
1017 {
1018 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1019 	RawSocket* raw = protocol->raw;
1020 	if (raw == NULL)
1021 		return B_ERROR;
1022 
1023 	TRACE_SK(protocol, "Close()");
1024 
1025 	MutexLocker locker(sRawSocketsLock);
1026 	sRawSockets.Remove(raw);
1027 	delete raw;
1028 	protocol->raw = NULL;
1029 
1030 	return B_OK;
1031 }
1032 
1033 
1034 status_t
1035 ipv6_free(net_protocol* protocol)
1036 {
1037 	return B_OK;
1038 }
1039 
1040 
1041 status_t
1042 ipv6_connect(net_protocol* protocol, const struct sockaddr* address)
1043 {
1044 	return B_ERROR;
1045 }
1046 
1047 
1048 status_t
1049 ipv6_accept(net_protocol* protocol, struct net_socket** _acceptedSocket)
1050 {
1051 	return EOPNOTSUPP;
1052 }
1053 
1054 
1055 status_t
1056 ipv6_control(net_protocol* _protocol, int level, int option, void* value,
1057 	size_t* _length)
1058 {
1059 	if ((level & LEVEL_MASK) != IPPROTO_IPV6)
1060 		return sDatalinkModule->control(sDomain, option, value, _length);
1061 
1062 	return B_BAD_VALUE;
1063 }
1064 
1065 
1066 status_t
1067 ipv6_getsockopt(net_protocol* _protocol, int level, int option, void* value,
1068 	int* _length)
1069 {
1070 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1071 
1072 	if (level == IPPROTO_IPV6) {
1073 		// TODO: support more of these options
1074 
1075 		if (option == IPV6_MULTICAST_HOPS) {
1076 			return get_int_option(value, *_length,
1077 				protocol->multicast_time_to_live);
1078 		}
1079 		if (option == IPV6_MULTICAST_LOOP)
1080 			return EOPNOTSUPP;
1081 		if (option == IPV6_UNICAST_HOPS)
1082 			return get_int_option(value, *_length, protocol->time_to_live);
1083 		if (option == IPV6_V6ONLY)
1084 			return EOPNOTSUPP;
1085 		if (option == IPV6_RECVPKTINFO)
1086 			return get_int_option(value, *_length, protocol->receive_pktinfo);
1087 		if (option == IPV6_RECVHOPLIMIT)
1088 			return get_int_option(value, *_length, protocol->receive_hoplimit);
1089 		if (option == IPV6_JOIN_GROUP
1090 			|| option == IPV6_LEAVE_GROUP)
1091 			return EOPNOTSUPP;
1092 
1093 		dprintf("IPv6::getsockopt(): get unknown option: %d\n", option);
1094 		return ENOPROTOOPT;
1095 	}
1096 
1097 	return sSocketModule->get_option(protocol->socket, level, option, value,
1098 		_length);
1099 }
1100 
1101 
1102 status_t
1103 ipv6_setsockopt(net_protocol* _protocol, int level, int option,
1104 	const void* value, int length)
1105 {
1106 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1107 
1108 	if (level == IPPROTO_IPV6) {
1109 		// TODO: support more of these options
1110 
1111 		if (option == IPV6_MULTICAST_IF) {
1112 			if (length != sizeof(struct in6_addr))
1113 				return B_BAD_VALUE;
1114 
1115 			struct sockaddr_in6* address = new (std::nothrow) sockaddr_in6;
1116 			if (address == NULL)
1117 				return B_NO_MEMORY;
1118 
1119 			if (user_memcpy(&address->sin6_addr, value, sizeof(in6_addr))
1120 					!= B_OK) {
1121 				delete address;
1122 				return B_BAD_ADDRESS;
1123 			}
1124 
1125 			// Using the unspecifed address to remove the previous setting.
1126 			if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)) {
1127 				delete address;
1128 				delete protocol->multicast_address;
1129 				protocol->multicast_address = NULL;
1130 				return B_OK;
1131 			}
1132 
1133 			struct net_interface* interface
1134 				= sDatalinkModule->get_interface_with_address(
1135 					(sockaddr*)address);
1136 			if (interface == NULL) {
1137 				delete address;
1138 				return EADDRNOTAVAIL;
1139 			}
1140 
1141 			delete protocol->multicast_address;
1142 			protocol->multicast_address = (struct sockaddr*)address;
1143 
1144 			sDatalinkModule->put_interface(interface);
1145 			return B_OK;
1146 		}
1147 		if (option == IPV6_MULTICAST_HOPS) {
1148 			return set_int_option(protocol->multicast_time_to_live,
1149 				value, length);
1150 		}
1151 		if (option == IPV6_MULTICAST_LOOP)
1152 			return EOPNOTSUPP;
1153 		if (option == IPV6_UNICAST_HOPS)
1154 			return set_int_option(protocol->time_to_live, value, length);
1155 		if (option == IPV6_V6ONLY)
1156 			return EOPNOTSUPP;
1157 		if (option == IPV6_RECVPKTINFO)
1158 			return set_int_option(protocol->receive_pktinfo, value, length);
1159 		if (option == IPV6_RECVHOPLIMIT)
1160 			return set_int_option(protocol->receive_hoplimit, value, length);
1161 		if (option == IPV6_JOIN_GROUP || option == IPV6_LEAVE_GROUP) {
1162 			ipv6_mreq mreq;
1163 			if (length != sizeof(ipv6_mreq))
1164 				return B_BAD_VALUE;
1165 			if (user_memcpy(&mreq, value, sizeof(ipv6_mreq)) != B_OK)
1166 				return B_BAD_ADDRESS;
1167 
1168 			return ipv6_delta_membership(protocol, option,
1169 				mreq.ipv6mr_interface, &mreq.ipv6mr_multiaddr, NULL);
1170 		}
1171 
1172 		dprintf("IPv6::setsockopt(): set unknown option: %d\n", option);
1173 		return ENOPROTOOPT;
1174 	}
1175 
1176 	return sSocketModule->set_option(protocol->socket, level, option,
1177 		value, length);
1178 }
1179 
1180 
1181 status_t
1182 ipv6_bind(net_protocol* protocol, const sockaddr* _address)
1183 {
1184 	if (_address->sa_family != AF_INET6)
1185 		return EAFNOSUPPORT;
1186 
1187 	const sockaddr_in6* address = (const sockaddr_in6*)_address;
1188 
1189 	// only INADDR_ANY and addresses of local interfaces are accepted:
1190 	if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)
1191 		|| IN6_IS_ADDR_MULTICAST(&address->sin6_addr)
1192 		|| sDatalinkModule->is_local_address(sDomain, _address, NULL, NULL)) {
1193 		memcpy(&protocol->socket->address, address, sizeof(sockaddr_in6));
1194 		protocol->socket->address.ss_len = sizeof(sockaddr_in6);
1195 			// explicitly set length, as our callers can't be trusted to
1196 			// always provide the correct length!
1197 		return B_OK;
1198 	}
1199 
1200 	return B_ERROR;
1201 		// address is unknown on this host
1202 }
1203 
1204 
1205 status_t
1206 ipv6_unbind(net_protocol* protocol, struct sockaddr* address)
1207 {
1208 	// nothing to do here
1209 	return B_OK;
1210 }
1211 
1212 
1213 status_t
1214 ipv6_listen(net_protocol* protocol, int count)
1215 {
1216 	return EOPNOTSUPP;
1217 }
1218 
1219 
1220 status_t
1221 ipv6_shutdown(net_protocol* protocol, int direction)
1222 {
1223 	return EOPNOTSUPP;
1224 }
1225 
1226 
1227 static uint8
1228 ip6_select_hoplimit(net_protocol* _protocol, net_buffer* buffer)
1229 {
1230 	// TODO: the precedence should be as follows:
1231 	// 1. Hoplimit value specified via ioctl.
1232 	// 2. (If the outgoing interface is detected) the current
1233 	//     hop limit of the interface specified by router advertisement.
1234 	// 3. The system default hoplimit.
1235 
1236 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1237 	const bool isMulticast = buffer->flags & MSG_MCAST;
1238 
1239 	if (protocol) {
1240 		return isMulticast ? protocol->multicast_time_to_live
1241 			: protocol->time_to_live;
1242 	}
1243 	return isMulticast ? kDefaultMulticastTTL : kDefaultTTL;
1244 }
1245 
1246 
1247 status_t
1248 ipv6_send_routed_data(net_protocol* _protocol, struct net_route* route,
1249 	net_buffer* buffer)
1250 {
1251 	if (route == NULL)
1252 		return B_BAD_VALUE;
1253 
1254 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1255 	net_interface* interface = route->interface_address->interface;
1256 	uint8 protocolNumber;
1257 	if (protocol != NULL && protocol->socket != NULL)
1258 		protocolNumber = protocol->socket->protocol;
1259 	else
1260 		protocolNumber = buffer->protocol;
1261 
1262 	TRACE_SK(protocol, "SendRoutedData(%p, %p [%ld bytes])", route, buffer,
1263 		buffer->size);
1264 
1265 	sockaddr_in6& source = *(sockaddr_in6*)buffer->source;
1266 	sockaddr_in6& destination = *(sockaddr_in6*)buffer->destination;
1267 
1268 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1269 
1270 	if (IN6_IS_ADDR_UNSPECIFIED(&destination.sin6_addr))
1271 		return EDESTADDRREQ;
1272 
1273 	if (IN6_IS_ADDR_MULTICAST(&destination.sin6_addr))
1274 		buffer->flags |= MSG_MCAST;
1275 
1276 	uint16 dataLength = buffer->size;
1277 
1278 	// Add IPv6 header
1279 
1280 	NetBufferPrepend<ip6_hdr> header(buffer);
1281 	if (header.Status() != B_OK)
1282 		return header.Status();
1283 
1284 	if (buffer->size > 0xffff)
1285 		return EMSGSIZE;
1286 
1287 	uint32 flowinfo = 0;
1288 		// TODO: fill in the flow id from somewhere
1289 	if (protocol) {
1290 		// fill in traffic class
1291 		flowinfo |= htonl(protocol->service_type << 20);
1292 	}
1293 	// set lower 28 bits
1294 	header->ip6_flow = htonl(flowinfo) & IPV6_FLOWINFO_MASK;
1295 	// set upper 4 bits
1296 	header->ip6_vfc |= IPV6_VERSION;
1297 	header->ip6_plen = htons(dataLength);
1298 	header->ip6_nxt = protocolNumber;
1299 	header->ip6_hlim = ip6_select_hoplimit(protocol, buffer);
1300 	memcpy(&header->ip6_src, &source.sin6_addr, sizeof(in6_addr));
1301 	memcpy(&header->ip6_dst, &destination.sin6_addr, sizeof(in6_addr));
1302 
1303 	header.Sync();
1304 
1305 	// write the checksum for ICMPv6 sockets
1306 	if (protocolNumber == IPPROTO_ICMPV6
1307 		&& dataLength >= sizeof(struct icmp6_hdr)) {
1308 		NetBufferField<uint16, sizeof(ip6_hdr)
1309 			+ offsetof(icmp6_hdr, icmp6_cksum)>
1310 			icmpChecksum(buffer);
1311 		// first make sure the existing checksum is zero
1312 		*icmpChecksum = 0;
1313 		icmpChecksum.Sync();
1314 
1315 		uint16 checksum = gBufferModule->checksum(buffer, sizeof(ip6_hdr),
1316 			buffer->size - sizeof(ip6_hdr), false);
1317 		checksum = ipv6_checksum(&header->ip6_src,
1318 			&header->ip6_dst, dataLength, protocolNumber,
1319 			checksum);
1320 		*icmpChecksum = checksum;
1321 	}
1322 
1323 	char addrbuf[INET6_ADDRSTRLEN];
1324 	ip6_sprintf(&destination.sin6_addr, addrbuf);
1325 	TRACE_SK(protocol, "  SendRoutedData(): destination: %s", addrbuf);
1326 
1327 	uint32 mtu = route->mtu ? route->mtu : interface->mtu;
1328 	if (buffer->size > mtu) {
1329 		// we need to fragment the packet
1330 		return send_fragments(protocol, route, buffer, mtu);
1331 	}
1332 
1333 	return sDatalinkModule->send_routed_data(route, buffer);
1334 }
1335 
1336 
1337 status_t
1338 ipv6_send_data(net_protocol* _protocol, net_buffer* buffer)
1339 {
1340 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1341 
1342 	TRACE_SK(protocol, "SendData(%p [%ld bytes])", buffer, buffer->size);
1343 
1344 	sockaddr_in6* destination = (sockaddr_in6*)buffer->destination;
1345 
1346 	// handle IPV6_MULTICAST_IF
1347 	if (IN6_IS_ADDR_MULTICAST(&destination->sin6_addr)
1348 		&& protocol->multicast_address != NULL) {
1349 		net_interface_address* address = sDatalinkModule->get_interface_address(
1350 			protocol->multicast_address);
1351 		if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
1352 			sDatalinkModule->put_interface_address(address);
1353 			return EADDRNOTAVAIL;
1354 		}
1355 
1356 		sDatalinkModule->put_interface_address(buffer->interface_address);
1357 		buffer->interface_address = address;
1358 			// the buffer takes over ownership of the address
1359 
1360 		net_route* route = sDatalinkModule->get_route(sDomain, address->local);
1361 		if (route == NULL)
1362 			return ENETUNREACH;
1363 
1364 		return sDatalinkModule->send_routed_data(route, buffer);
1365 	}
1366 
1367 	return sDatalinkModule->send_data(protocol, sDomain, buffer);
1368 }
1369 
1370 
1371 ssize_t
1372 ipv6_send_avail(net_protocol* protocol)
1373 {
1374 	return B_ERROR;
1375 }
1376 
1377 
1378 status_t
1379 ipv6_read_data(net_protocol* _protocol, size_t numBytes, uint32 flags,
1380 	net_buffer** _buffer)
1381 {
1382 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1383 	RawSocket* raw = protocol->raw;
1384 	if (raw == NULL)
1385 		return B_ERROR;
1386 
1387 	TRACE_SK(protocol, "ReadData(%lu, 0x%lx)", numBytes, flags);
1388 
1389 	return raw->Dequeue(flags, _buffer);
1390 }
1391 
1392 
1393 ssize_t
1394 ipv6_read_avail(net_protocol* _protocol)
1395 {
1396 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1397 	RawSocket* raw = protocol->raw;
1398 	if (raw == NULL)
1399 		return B_ERROR;
1400 
1401 	return raw->AvailableData();
1402 }
1403 
1404 
1405 struct net_domain*
1406 ipv6_get_domain(net_protocol* protocol)
1407 {
1408 	return sDomain;
1409 }
1410 
1411 
1412 size_t
1413 ipv6_get_mtu(net_protocol* protocol, const struct sockaddr* address)
1414 {
1415 	net_route* route = sDatalinkModule->get_route(sDomain, address);
1416 	if (route == NULL)
1417 		return 0;
1418 
1419 	size_t mtu;
1420 	if (route->mtu != 0)
1421 		mtu = route->mtu;
1422 	else
1423 		mtu = route->interface_address->interface->mtu;
1424 
1425 	sDatalinkModule->put_route(sDomain, route);
1426 	// TODO: what about extension headers?
1427 	// this function probably shoud be changed in calling places, not here
1428 	return mtu - sizeof(ip6_hdr);
1429 }
1430 
1431 
1432 status_t
1433 ipv6_receive_data(net_buffer* buffer)
1434 {
1435 	TRACE("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
1436 
1437 	NetBufferHeaderReader<IPv6Header> bufferHeader(buffer);
1438 	if (bufferHeader.Status() != B_OK)
1439 		return bufferHeader.Status();
1440 
1441 	IPv6Header &header = bufferHeader.Data();
1442 	// dump_ipv6_header(header);
1443 
1444 	if (header.ProtocolVersion() != IPV6_VERSION)
1445 		return B_BAD_TYPE;
1446 
1447 	uint16 packetLength = header.PayloadLength() + sizeof(ip6_hdr);
1448 	if (packetLength > buffer->size)
1449 		return B_BAD_DATA;
1450 
1451 	// lower layers notion of Broadcast or Multicast have no relevance to us
1452 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1453 
1454 	sockaddr_in6 destination;
1455 	fill_sockaddr_in6(&destination, header.Dst());
1456 
1457 	if (IN6_IS_ADDR_MULTICAST(&destination.sin6_addr)) {
1458 		buffer->flags |= MSG_MCAST;
1459 	} else {
1460 		uint32 matchedAddressType = 0;
1461 
1462 		// test if the packet is really for us
1463 		if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
1464 				&buffer->interface_address, &matchedAddressType)
1465 			&& !sDatalinkModule->is_local_link_address(sDomain, true,
1466 				buffer->destination, &buffer->interface_address)) {
1467 
1468 			char srcbuf[INET6_ADDRSTRLEN];
1469 			char dstbuf[INET6_ADDRSTRLEN];
1470 			ip6_sprintf(&header.Src(), srcbuf);
1471 			ip6_sprintf(&header.Dst(), dstbuf);
1472 			TRACE("  ipv6_receive_data(): packet was not for us %s -> %s",
1473 				srcbuf, dstbuf);
1474 
1475 			// TODO: Send ICMPv6 error: Host unreachable
1476 			return B_ERROR;
1477 		}
1478 
1479 		// copy over special address types (MSG_BCAST or MSG_MCAST):
1480 		buffer->flags |= matchedAddressType;
1481 	}
1482 
1483 	// set net_buffer's source/destination address
1484 	fill_sockaddr_in6((struct sockaddr_in6*)buffer->source, header.Src());
1485 	memcpy(buffer->destination, &destination, sizeof(sockaddr_in6));
1486 
1487 	// get the transport protocol and transport header offset
1488 	uint16 transportHeaderOffset = header.GetHeaderOffset(buffer);
1489 	uint8 protocol = buffer->protocol;
1490 
1491 	// remove any trailing/padding data
1492 	status_t status = gBufferModule->trim(buffer, packetLength);
1493 	if (status != B_OK)
1494 		return status;
1495 
1496 	// check for fragmentation
1497 	uint16 fragmentHeaderOffset
1498 		= header.GetHeaderOffset(buffer, IPPROTO_FRAGMENT);
1499 
1500 	if (fragmentHeaderOffset != 0) {
1501 		// this is a fragment
1502 		TRACE("  ipv6_receive_data(): Found a Fragment!");
1503 		status = reassemble_fragments(header, &buffer, fragmentHeaderOffset);
1504 		TRACE("  ipv6_receive_data():  -> %s", strerror(status));
1505 		if (status != B_OK)
1506 			return status;
1507 
1508 		if (buffer == NULL) {
1509 			// buffer was put into fragment packet
1510 			TRACE("  ipv6_receive_data(): Not yet assembled.");
1511 			return B_OK;
1512 		}
1513 	}
1514 
1515 	// tell the buffer to preserve removed ipv6 header - may need it later
1516 	gBufferModule->store_header(buffer);
1517 
1518 	// remove ipv6 headers for now
1519 	gBufferModule->remove_header(buffer, transportHeaderOffset);
1520 
1521 	// deliver the data to raw sockets
1522 	raw_receive_data(buffer);
1523 
1524 	net_protocol_module_info* module = receiving_protocol(protocol);
1525 	if (module == NULL) {
1526 		// no handler for this packet
1527 		return EAFNOSUPPORT;
1528 	}
1529 
1530 	if ((buffer->flags & MSG_MCAST) != 0) {
1531 		// Unfortunately historical reasons dictate that the IP multicast
1532 		// model be a little different from the unicast one. We deliver
1533 		// this frame directly to all sockets registered with interest
1534 		// for this multicast group.
1535 		return deliver_multicast(module, buffer, false);
1536 	}
1537 
1538 	return module->receive_data(buffer);
1539 }
1540 
1541 
1542 status_t
1543 ipv6_deliver_data(net_protocol* _protocol, net_buffer* buffer)
1544 {
1545 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1546 
1547 	if (protocol->raw == NULL)
1548 		return B_ERROR;
1549 
1550 	return protocol->raw->EnqueueClone(buffer);
1551 }
1552 
1553 
1554 status_t
1555 ipv6_error_received(net_error error, net_buffer* data)
1556 {
1557 	return B_ERROR;
1558 }
1559 
1560 
1561 status_t
1562 ipv6_error_reply(net_protocol* protocol, net_buffer* cause, net_error error,
1563 	net_error_data* errorData)
1564 {
1565 	return B_ERROR;
1566 }
1567 
1568 
1569 ssize_t
1570 ipv6_process_ancillary_data_no_container(net_protocol* _protocol,
1571 	net_buffer* buffer, void* msgControl, size_t msgControlLen)
1572 {
1573 	ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
1574 	ssize_t bytesWritten = 0;
1575 
1576 	if (protocol->receive_hoplimit != 0) {
1577 		TRACE("receive_hoplimit");
1578 
1579 		if (msgControlLen < CMSG_SPACE(sizeof(int)))
1580 			return B_NO_MEMORY;
1581 
1582 		// use some default value (64 at the moment) when the real one fails
1583 		int hopLimit = IPV6_DEFHLIM;
1584 
1585 		if (gBufferModule->stored_header_length(buffer)
1586 				>= (int)sizeof(ip6_hdr)) {
1587 			IPv6Header header;
1588 			if (gBufferModule->restore_header(buffer, 0,
1589 					&header, sizeof(ip6_hdr)) == B_OK
1590 				&& header.ProtocolVersion() != IPV6_VERSION) {
1591 				// header is OK, take hoplimit from it
1592 				hopLimit = header.header.ip6_hlim;
1593 			}
1594 		}
1595 
1596 		cmsghdr* messageHeader = (cmsghdr*)((char*)msgControl + bytesWritten);
1597 		messageHeader->cmsg_len = CMSG_LEN(sizeof(int));
1598 		messageHeader->cmsg_level = IPPROTO_IPV6;
1599 		messageHeader->cmsg_type = IPV6_HOPLIMIT;
1600 
1601 		memcpy(CMSG_DATA(messageHeader), &hopLimit, sizeof(int));
1602 
1603 		bytesWritten += CMSG_SPACE(sizeof(int));
1604 		msgControlLen -= CMSG_SPACE(sizeof(int));
1605 	}
1606 
1607 	if (protocol->receive_pktinfo != 0) {
1608 		TRACE("receive_pktinfo");
1609 
1610 		if (msgControlLen < CMSG_SPACE(sizeof(struct in6_pktinfo)))
1611 			return B_NO_MEMORY;
1612 
1613 		cmsghdr* messageHeader = (cmsghdr*)((char*)msgControl + bytesWritten);
1614 		messageHeader->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1615 		messageHeader->cmsg_level = IPPROTO_IPV6;
1616 		messageHeader->cmsg_type = IPV6_PKTINFO;
1617 
1618 		struct in6_pktinfo pi;
1619 		memcpy(&pi.ipi6_addr,
1620 			&((struct sockaddr_in6*)buffer->destination)->sin6_addr,
1621 			sizeof(struct in6_addr));
1622 		if (buffer->interface_address != NULL
1623 			&& buffer->interface_address->interface != NULL)
1624 			pi.ipi6_ifindex = buffer->interface_address->interface->index;
1625 		else
1626 			pi.ipi6_ifindex = 0;
1627 		memcpy(CMSG_DATA(messageHeader), &pi, sizeof(struct in6_pktinfo));
1628 
1629 		bytesWritten += CMSG_SPACE(sizeof(struct in6_pktinfo));
1630 		msgControlLen -= CMSG_SPACE(sizeof(struct in6_pktinfo));
1631 	}
1632 
1633 	return bytesWritten;
1634 }
1635 
1636 
1637 //	#pragma mark -
1638 
1639 
1640 status_t
1641 init_ipv6()
1642 {
1643 	mutex_init(&sRawSocketsLock, "raw sockets");
1644 	mutex_init(&sFragmentLock, "IPv4 Fragments");
1645 	mutex_init(&sMulticastGroupsLock, "IPv6 multicast groups");
1646 	mutex_init(&sReceivingProtocolLock, "IPv6 receiving protocols");
1647 
1648 	status_t status;
1649 
1650 	sMulticastState = new MulticastState();
1651 	if (sMulticastState == NULL) {
1652 		status = B_NO_MEMORY;
1653 		goto err1;
1654 	}
1655 
1656 	status = sMulticastState->Init();
1657 	if (status != B_OK)
1658 		goto err2;
1659 
1660 	new (&sFragmentHash) FragmentTable();
1661 	status = sFragmentHash.Init(256);
1662 	if (status != B_OK)
1663 		goto err3;
1664 
1665 	new (&sRawSockets) RawSocketList;
1666 		// static initializers do not work in the kernel,
1667 		// so we have to do it here, manually
1668 		// TODO: for modules, this shouldn't be required
1669 
1670 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_RAW, 0,
1671 		NET_IPV6_MODULE_NAME, NULL);
1672 	if (status != B_OK)
1673 		goto err3;
1674 
1675 	status = gStackModule->register_domain(AF_INET6, "internet6", &gIPv6Module,
1676 		&gIPv6AddressModule, &sDomain);
1677 	if (status != B_OK)
1678 		goto err3;
1679 
1680 	TRACE("init_ipv6: OK");
1681 	return B_OK;
1682 
1683 err3:
1684 	sFragmentHash.~FragmentTable();
1685 err2:
1686 	delete sMulticastState;
1687 err1:
1688 	mutex_destroy(&sReceivingProtocolLock);
1689 	mutex_destroy(&sMulticastGroupsLock);
1690 	mutex_destroy(&sFragmentLock);
1691 	mutex_destroy(&sRawSocketsLock);
1692 	TRACE("init_ipv6: error %s", strerror(status));
1693 	return status;
1694 }
1695 
1696 
1697 status_t
1698 uninit_ipv6()
1699 {
1700 	mutex_lock(&sReceivingProtocolLock);
1701 
1702 	// put all the domain receiving protocols we gathered so far
1703 	for (uint32 i = 0; i < 256; i++) {
1704 		if (sReceivingProtocol[i] != NULL)
1705 			gStackModule->put_domain_receiving_protocol(sDomain, i);
1706 	}
1707 
1708 	sFragmentHash.~FragmentTable();
1709 	delete sMulticastState;
1710 
1711 	gStackModule->unregister_domain(sDomain);
1712 	mutex_unlock(&sReceivingProtocolLock);
1713 
1714 	mutex_destroy(&sMulticastGroupsLock);
1715 	mutex_destroy(&sFragmentLock);
1716 	mutex_destroy(&sRawSocketsLock);
1717 	mutex_destroy(&sReceivingProtocolLock);
1718 
1719 	return B_OK;
1720 }
1721 
1722 
1723 static status_t
1724 ipv6_std_ops(int32 op, ...)
1725 {
1726 	switch (op) {
1727 		case B_MODULE_INIT:
1728 			return init_ipv6();
1729 		case B_MODULE_UNINIT:
1730 			return uninit_ipv6();
1731 		default:
1732 			return B_ERROR;
1733 	}
1734 }
1735 
1736 
1737 net_protocol_module_info gIPv6Module = {
1738 	{
1739 		NET_IPV6_MODULE_NAME,
1740 		0,
1741 		ipv6_std_ops
1742 	},
1743 	NET_PROTOCOL_ATOMIC_MESSAGES,
1744 
1745 	ipv6_init_protocol,
1746 	ipv6_uninit_protocol,
1747 	ipv6_open,
1748 	ipv6_close,
1749 	ipv6_free,
1750 	ipv6_connect,
1751 	ipv6_accept,
1752 	ipv6_control,
1753 	ipv6_getsockopt,
1754 	ipv6_setsockopt,
1755 	ipv6_bind,
1756 	ipv6_unbind,
1757 	ipv6_listen,
1758 	ipv6_shutdown,
1759 	ipv6_send_data,
1760 	ipv6_send_routed_data,
1761 	ipv6_send_avail,
1762 	ipv6_read_data,
1763 	ipv6_read_avail,
1764 	ipv6_get_domain,
1765 	ipv6_get_mtu,
1766 	ipv6_receive_data,
1767 	ipv6_deliver_data,
1768 	ipv6_error_received,
1769 	ipv6_error_reply,
1770 	NULL,		// add_ancillary_data()
1771 	NULL,		// process_ancillary_data()
1772 	ipv6_process_ancillary_data_no_container,
1773 	NULL,		// send_data_no_buffer()
1774 	NULL		// read_data_no_buffer()
1775 };
1776 
1777 module_dependency module_dependencies[] = {
1778 	{NET_STACK_MODULE_NAME, (module_info**)&gStackModule},
1779 	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
1780 	{NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule},
1781 	{NET_SOCKET_MODULE_NAME, (module_info**)&sSocketModule},
1782 	{}
1783 };
1784 
1785 module_info* modules[] = {
1786 	(module_info*)&gIPv6Module,
1787 	NULL
1788 };
1789