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