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