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