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