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