xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp (revision 7b3e89c0944ae1efa9a8fc66c7303874b7a344b2)
1 /*
2  * Copyright 2006-2010, 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  */
8 
9 
10 #include "ipv4.h"
11 #include "ipv4_address.h"
12 #include "multicast.h"
13 
14 #include <net_datalink.h>
15 #include <net_datalink_protocol.h>
16 #include <net_device.h>
17 #include <net_protocol.h>
18 #include <net_stack.h>
19 #include <NetBufferUtilities.h>
20 #include <ProtocolUtilities.h>
21 
22 #include <KernelExport.h>
23 #include <util/AutoLock.h>
24 #include <util/list.h>
25 #include <util/DoublyLinkedList.h>
26 #include <util/MultiHashTable.h>
27 
28 #include <netinet/in.h>
29 #include <netinet/ip.h>
30 #include <new>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <utility>
35 
36 
37 //#define TRACE_IPV4
38 #ifdef TRACE_IPV4
39 #	define TRACE(format, args...) \
40 		dprintf("IPv4 [%" B_PRIdBIGTIME "] " format "\n", system_time() , \
41 			##args)
42 #	define TRACE_SK(protocol, format, args...) \
43 		dprintf("IPv4 [%" B_PRIdBIGTIME "] %p " format "\n", system_time(), \
44 			protocol , ##args)
45 #	define TRACE_ONLY(x) x
46 #else
47 #	define TRACE(args...) ;
48 #	define TRACE_SK(args...) ;
49 #	define TRACE_ONLY(x)
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
57 
58 
59 typedef DoublyLinkedList<struct net_buffer,
60 	DoublyLinkedListCLink<struct net_buffer> > FragmentList;
61 
62 typedef NetBufferField<uint16, offsetof(ipv4_header, checksum)> IPChecksumField;
63 
64 struct ipv4_packet_key {
65 	in_addr_t	source;
66 	in_addr_t	destination;
67 	uint16		id;
68 	uint8		protocol;
69 };
70 
71 
72 class FragmentPacket {
73 public:
74 								FragmentPacket(const ipv4_packet_key& key);
75 								~FragmentPacket();
76 
77 			status_t			AddFragment(uint16 start, uint16 end,
78 									net_buffer* buffer, bool lastFragment);
79 			status_t			Reassemble(net_buffer* to);
80 
81 			bool				IsComplete() const
82 									{ return fReceivedLastFragment
83 										&& fBytesLeft == 0; }
84 
85 			const ipv4_packet_key& Key() const { return fKey; }
86 			FragmentPacket*&	HashTableLink() { return fNext; }
87 
88 	static	void				StaleTimer(struct net_timer* timer, void* data);
89 
90 private:
91 			FragmentPacket*		fNext;
92 			struct ipv4_packet_key fKey;
93 			uint32				fIndex;
94 			bool				fReceivedLastFragment;
95 			int32				fBytesLeft;
96 			FragmentList		fFragments;
97 			net_timer			fTimer;
98 };
99 
100 
101 struct FragmentHashDefinition {
102 	typedef ipv4_packet_key KeyType;
103 	typedef FragmentPacket ValueType;
104 
105 	size_t HashKey(const KeyType& key) const
106 	{
107 		return (key.source ^ key.destination ^ key.protocol ^ key.id);
108 	}
109 
110 	size_t Hash(ValueType* value) const
111 	{
112 		return HashKey(value->Key());
113 	}
114 
115 	bool Compare(const KeyType& key, ValueType* value) const
116 	{
117 		const ipv4_packet_key& packetKey = value->Key();
118 
119 		return packetKey.id == key.id
120 			&& packetKey.source == key.source
121 			&& packetKey.destination == key.destination
122 			&& packetKey.protocol == key.protocol;
123 	}
124 
125 	ValueType*& GetLink(ValueType* value) const
126 	{
127 		return value->HashTableLink();
128 	}
129 };
130 
131 typedef BOpenHashTable<FragmentHashDefinition, false, true> FragmentTable;
132 
133 
134 class RawSocket
135 	: public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
136 public:
137 								RawSocket(net_socket* socket);
138 };
139 
140 typedef DoublyLinkedList<RawSocket> RawSocketList;
141 
142 typedef MulticastGroupInterface<IPv4Multicast> IPv4GroupInterface;
143 typedef MulticastFilter<IPv4Multicast> IPv4MulticastFilter;
144 
145 struct MulticastStateHash {
146 	typedef std::pair<const in_addr* , uint32> KeyType;
147 	typedef IPv4GroupInterface ValueType;
148 
149 	size_t HashKey(const KeyType &key) const
150 		{ return key.first->s_addr ^ key.second; }
151 	size_t Hash(ValueType* value) const
152 		{ return HashKey(std::make_pair(&value->Address(),
153 			value->Interface()->index)); }
154 	bool Compare(const KeyType &key, ValueType* value) const
155 		{ return value->Interface()->index == key.second
156 			&& value->Address().s_addr == key.first->s_addr; }
157 	bool CompareValues(ValueType* value1, ValueType* value2) const
158 		{ return value1->Interface()->index == value2->Interface()->index
159 			&& value1->Address().s_addr == value2->Address().s_addr; }
160 	ValueType*& GetLink(ValueType* value) const { return value->MulticastGroupsHashLink(); }
161 };
162 
163 
164 struct ipv4_protocol : net_protocol {
165 	ipv4_protocol()
166 		:
167 		raw(NULL),
168 		multicast_filter(this)
169 	{
170 	}
171 
172 	~ipv4_protocol()
173 	{
174 		delete raw;
175 	}
176 
177 	RawSocket*			raw;
178 	uint8				service_type;
179 	uint8				time_to_live;
180 	uint8				multicast_time_to_live;
181 	bool				multicast_loopback;
182 	uint32				flags;
183 	struct sockaddr*	multicast_address; // for IP_MULTICAST_IF
184 
185 	IPv4MulticastFilter	multicast_filter;
186 };
187 
188 // protocol flags
189 #define IP_FLAG_HEADER_INCLUDED		0x01
190 #define IP_FLAG_RECEIVE_DEST_ADDR	0x02
191 
192 
193 static const int kDefaultTTL = 254;
194 static const int kDefaultMulticastTTL = 1;
195 static const bool kDefaultMulticastLoopback = true;
196 
197 
198 extern net_protocol_module_info gIPv4Module;
199 	// we need this in ipv4_std_ops() for registering the AF_INET domain
200 
201 net_stack_module_info* gStackModule;
202 net_buffer_module_info* gBufferModule;
203 
204 static struct net_domain* sDomain;
205 static net_datalink_module_info* sDatalinkModule;
206 static net_socket_module_info* sSocketModule;
207 static int32 sPacketID;
208 static RawSocketList sRawSockets;
209 static mutex sRawSocketsLock;
210 static mutex sFragmentLock;
211 static FragmentTable sFragmentHash;
212 static mutex sMulticastGroupsLock;
213 
214 typedef MultiHashTable<MulticastStateHash> MulticastState;
215 static MulticastState* sMulticastState;
216 
217 static net_protocol_module_info* sReceivingProtocol[256];
218 static mutex sReceivingProtocolLock;
219 
220 
221 static const char*
222 print_address(const in_addr* address, char* buf, size_t bufLen)
223 {
224 	unsigned int addr = ntohl(address->s_addr);
225 
226 	snprintf(buf, bufLen, "%u.%u.%u.%u", (addr >> 24) & 0xff,
227 		(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
228 
229 	return buf;
230 }
231 
232 
233 RawSocket::RawSocket(net_socket* socket)
234 	:
235 	DatagramSocket<>("ipv4 raw socket", socket)
236 {
237 }
238 
239 
240 //	#pragma mark -
241 
242 
243 FragmentPacket::FragmentPacket(const ipv4_packet_key& key)
244 	:
245 	fKey(key),
246 	fIndex(0),
247 	fReceivedLastFragment(false),
248 	fBytesLeft(IP_MAXPACKET)
249 {
250 	gStackModule->init_timer(&fTimer, FragmentPacket::StaleTimer, this);
251 }
252 
253 
254 FragmentPacket::~FragmentPacket()
255 {
256 	// cancel the kill timer
257 	gStackModule->set_timer(&fTimer, -1);
258 
259 	// delete all fragments
260 	net_buffer* buffer;
261 	while ((buffer = fFragments.RemoveHead()) != NULL) {
262 		gBufferModule->free(buffer);
263 	}
264 }
265 
266 
267 status_t
268 FragmentPacket::AddFragment(uint16 start, uint16 end, net_buffer* buffer,
269 	bool lastFragment)
270 {
271 	// restart the timer
272 	gStackModule->set_timer(&fTimer, FRAGMENT_TIMEOUT);
273 
274 	if (start >= end) {
275 		// invalid fragment
276 		return B_BAD_DATA;
277 	}
278 
279 	// Search for a position in the list to insert the fragment
280 
281 	FragmentList::ReverseIterator iterator = fFragments.GetReverseIterator();
282 	net_buffer* previous = NULL;
283 	net_buffer* next = NULL;
284 	while ((previous = iterator.Next()) != NULL) {
285 		if (previous->fragment.start <= start) {
286 			// The new fragment can be inserted after this one
287 			break;
288 		}
289 
290 		next = previous;
291 	}
292 
293 	// See if we already have the fragment's data
294 
295 	if (previous != NULL && previous->fragment.start <= start
296 		&& previous->fragment.end >= end) {
297 		// we do, so we can just drop this fragment
298 		gBufferModule->free(buffer);
299 		return B_OK;
300 	}
301 
302 	fIndex = buffer->index;
303 		// adopt the buffer's device index
304 
305 	TRACE("    previous: %p, next: %p", previous, next);
306 
307 	// If we have parts of the data already, truncate as needed
308 
309 	if (previous != NULL && previous->fragment.end > start) {
310 		TRACE("    remove header %d bytes", previous->fragment.end - start);
311 		gBufferModule->remove_header(buffer, previous->fragment.end - start);
312 		start = previous->fragment.end;
313 	}
314 	if (next != NULL && end > next->fragment.start) {
315 		TRACE("    remove trailer %d bytes", end - next->fragment.start);
316 		gBufferModule->remove_trailer(buffer, end - next->fragment.start);
317 		end = next->fragment.start;
318 	}
319 
320 	// Now try if we can already merge the fragments together
321 
322 	// We will always keep the last buffer received, so that we can still
323 	// report an error (in which case we're not responsible for freeing it)
324 
325 	if (previous != NULL && previous->fragment.end == start) {
326 		fFragments.Remove(previous);
327 
328 		buffer->fragment.start = previous->fragment.start;
329 		buffer->fragment.end = end;
330 
331 		status_t status = gBufferModule->merge(buffer, previous, false);
332 		TRACE("    merge previous: %s", strerror(status));
333 		if (status != B_OK) {
334 			fFragments.Insert(next, previous);
335 			return status;
336 		}
337 
338 		fFragments.Insert(next, buffer);
339 
340 		// cut down existing hole
341 		fBytesLeft -= end - start;
342 
343 		if (lastFragment && !fReceivedLastFragment) {
344 			fReceivedLastFragment = true;
345 			fBytesLeft -= IP_MAXPACKET - end;
346 		}
347 
348 		TRACE("    hole length: %d", (int)fBytesLeft);
349 
350 		return B_OK;
351 	} else if (next != NULL && next->fragment.start == end) {
352 		net_buffer* afterNext = (net_buffer*)next->link.next;
353 		fFragments.Remove(next);
354 
355 		buffer->fragment.start = start;
356 		buffer->fragment.end = next->fragment.end;
357 
358 		status_t status = gBufferModule->merge(buffer, next, true);
359 		TRACE("    merge next: %s", strerror(status));
360 		if (status != B_OK) {
361 			// Insert "next" at its previous position
362 			fFragments.Insert(afterNext, next);
363 			return status;
364 		}
365 
366 		fFragments.Insert(afterNext, buffer);
367 
368 		// cut down existing hole
369 		fBytesLeft -= end - start;
370 
371 		if (lastFragment && !fReceivedLastFragment) {
372 			fReceivedLastFragment = true;
373 			fBytesLeft -= IP_MAXPACKET - end;
374 		}
375 
376 		TRACE("    hole length: %d", (int)fBytesLeft);
377 
378 		return B_OK;
379 	}
380 
381 	// We couldn't merge the fragments, so we need to add it as is
382 
383 	TRACE("    new fragment: %p, bytes %d-%d", buffer, start, end);
384 
385 	buffer->fragment.start = start;
386 	buffer->fragment.end = end;
387 	fFragments.Insert(next, buffer);
388 
389 	// update length of the hole, if any
390 	fBytesLeft -= end - start;
391 
392 	if (lastFragment && !fReceivedLastFragment) {
393 		fReceivedLastFragment = true;
394 		fBytesLeft -= IP_MAXPACKET - end;
395 	}
396 
397 	TRACE("    hole length: %d", (int)fBytesLeft);
398 
399 	return B_OK;
400 }
401 
402 
403 /*!	Reassembles the fragments to the specified buffer \a to.
404 	This buffer must have been added via AddFragment() before.
405 */
406 status_t
407 FragmentPacket::Reassemble(net_buffer* to)
408 {
409 	if (!IsComplete())
410 		return B_ERROR;
411 
412 	net_buffer* buffer = NULL;
413 
414 	net_buffer* fragment;
415 	while ((fragment = fFragments.RemoveHead()) != NULL) {
416 		if (buffer != NULL) {
417 			status_t status;
418 			if (to == fragment) {
419 				status = gBufferModule->merge(fragment, buffer, false);
420 				buffer = fragment;
421 			} else
422 				status = gBufferModule->merge(buffer, fragment, true);
423 			if (status != B_OK)
424 				return status;
425 		} else
426 			buffer = fragment;
427 	}
428 
429 	if (buffer != to)
430 		panic("ipv4 packet reassembly did not work correctly.");
431 
432 	to->index = fIndex;
433 		// reset the buffer's device index
434 
435 	return B_OK;
436 }
437 
438 
439 /*static*/ void
440 FragmentPacket::StaleTimer(struct net_timer* timer, void* data)
441 {
442 	FragmentPacket* packet = (FragmentPacket*)data;
443 	TRACE("Assembling FragmentPacket %p timed out!", packet);
444 
445 	MutexLocker locker(&sFragmentLock);
446 	sFragmentHash.Remove(packet);
447 	locker.Unlock();
448 
449 	if (!packet->fFragments.IsEmpty()) {
450 		// Send error: fragment reassembly time exceeded
451 		sDomain->module->error_reply(NULL, packet->fFragments.First(),
452 			B_NET_ERROR_REASSEMBLY_TIME_EXCEEDED, NULL);
453 	}
454 
455 	delete packet;
456 }
457 
458 
459 //	#pragma mark -
460 
461 
462 #ifdef TRACE_IPV4
463 static void
464 dump_ipv4_header(ipv4_header &header)
465 {
466 	struct pretty_ipv4 {
467 	#if B_HOST_IS_LENDIAN == 1
468 		uint8 a;
469 		uint8 b;
470 		uint8 c;
471 		uint8 d;
472 	#else
473 		uint8 d;
474 		uint8 c;
475 		uint8 b;
476 		uint8 a;
477 	#endif
478 	};
479 	struct pretty_ipv4* src = (struct pretty_ipv4*)&header.source;
480 	struct pretty_ipv4* dst = (struct pretty_ipv4*)&header.destination;
481 	dprintf("  version: %d\n", header.version);
482 	dprintf("  header_length: 4 * %d\n", header.header_length);
483 	dprintf("  service_type: %d\n", header.service_type);
484 	dprintf("  total_length: %d\n", header.TotalLength());
485 	dprintf("  id: %d\n", ntohs(header.id));
486 	dprintf("  fragment_offset: %d (flags: %c%c%c)\n",
487 		header.FragmentOffset() & IP_FRAGMENT_OFFSET_MASK,
488 		(header.FragmentOffset() & IP_RESERVED_FLAG) ? 'r' : '-',
489 		(header.FragmentOffset() & IP_DONT_FRAGMENT) ? 'd' : '-',
490 		(header.FragmentOffset() & IP_MORE_FRAGMENTS) ? 'm' : '-');
491 	dprintf("  time_to_live: %d\n", header.time_to_live);
492 	dprintf("  protocol: %d\n", header.protocol);
493 	dprintf("  checksum: %d\n", ntohs(header.checksum));
494 	dprintf("  source: %d.%d.%d.%d\n", src->a, src->b, src->c, src->d);
495 	dprintf("  destination: %d.%d.%d.%d\n", dst->a, dst->b, dst->c, dst->d);
496 }
497 #endif	// TRACE_IPV4
498 
499 
500 static int
501 dump_ipv4_multicast(int argc, char** argv)
502 {
503 	MulticastState::Iterator groupIterator = sMulticastState->GetIterator();
504 
505 	while (groupIterator.HasNext()) {
506 		IPv4GroupInterface* state = groupIterator.Next();
507 
508 		char addressBuffer[64];
509 
510 		kprintf("%p: group <%s, %s, %s {", state, state->Interface()->name,
511 			print_address(&state->Address(), addressBuffer,
512 			sizeof(addressBuffer)),
513 			state->Mode() == IPv4GroupInterface::kExclude
514 				? "Exclude" : "Include");
515 
516 		int count = 0;
517 		IPv4GroupInterface::AddressSet::Iterator addressIterator
518 			= state->Sources().GetIterator();
519 		while (addressIterator.HasNext()) {
520 			kprintf("%s%s", count > 0 ? ", " : "",
521 				print_address(&addressIterator.Next(),
522 				addressBuffer, sizeof(addressBuffer)));
523 			count++;
524 		}
525 
526 		kprintf("}> sock %p\n", state->Parent()->Socket());
527 	}
528 
529 	return 0;
530 }
531 
532 
533 /*!	Attempts to re-assemble fragmented packets.
534 	\return B_OK if everything went well; if it could reassemble the packet, \a _buffer
535 		will point to its buffer, otherwise, it will be \c NULL.
536 	\return various error codes if something went wrong (mostly B_NO_MEMORY)
537 */
538 static status_t
539 reassemble_fragments(const ipv4_header &header, net_buffer** _buffer)
540 {
541 	net_buffer* buffer = *_buffer;
542 	status_t status;
543 
544 	struct ipv4_packet_key key;
545 	key.source = (in_addr_t)header.source;
546 	key.destination = (in_addr_t)header.destination;
547 	key.id = header.id;
548 	key.protocol = header.protocol;
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 fragmentOffset = header.FragmentOffset();
569 	uint16 start = (fragmentOffset & IP_FRAGMENT_OFFSET_MASK) << 3;
570 	uint16 end = start + header.TotalLength() - header.HeaderLength();
571 	bool lastFragment = (fragmentOffset & IP_MORE_FRAGMENTS) == 0;
572 
573 	TRACE("   Received IPv4 %sfragment of size %d, offset %d.",
574 		lastFragment ? "last ": "", end - start, start);
575 
576 	// Remove header unless this is the first fragment
577 	if (start != 0)
578 		gBufferModule->remove_header(buffer, header.HeaderLength());
579 
580 	status = packet->AddFragment(start, end, buffer, lastFragment);
581 	if (status != B_OK)
582 		return status;
583 
584 	if (packet->IsComplete()) {
585 		sFragmentHash.Remove(packet);
586 			// no matter if reassembling succeeds, we won't need this packet
587 			// anymore
588 
589 		status = packet->Reassemble(buffer);
590 		delete packet;
591 
592 		// _buffer does not change
593 		return status;
594 	}
595 
596 	// This indicates that the packet is not yet complete
597 	*_buffer = NULL;
598 	return B_OK;
599 }
600 
601 
602 /*!	Fragments the incoming buffer and send all fragments via the specified
603 	\a route.
604 */
605 static status_t
606 send_fragments(ipv4_protocol* protocol, struct net_route* route,
607 	net_buffer* buffer, uint32 mtu)
608 {
609 	TRACE_SK(protocol, "SendFragments(%" B_PRIu32 " bytes, mtu %" B_PRIu32 ")",
610 		buffer->size, mtu);
611 
612 	NetBufferHeaderReader<ipv4_header> originalHeader(buffer);
613 	if (originalHeader.Status() != B_OK)
614 		return originalHeader.Status();
615 
616 	uint16 headerLength = originalHeader->HeaderLength();
617 	uint32 bytesLeft = buffer->size - headerLength;
618 	uint32 fragmentOffset = 0;
619 	status_t status = B_OK;
620 
621 	net_buffer* headerBuffer = gBufferModule->split(buffer, headerLength);
622 	if (headerBuffer == NULL)
623 		return B_NO_MEMORY;
624 
625 	// TODO: we need to make sure ipv4_header is contiguous or
626 	// use another construct.
627 	NetBufferHeaderReader<ipv4_header> bufferHeader(headerBuffer);
628 	ipv4_header* header = &bufferHeader.Data();
629 
630 	// Adapt MTU to be a multiple of 8 (fragment offsets can only be specified
631 	// this way)
632 	mtu -= headerLength;
633 	mtu &= ~7;
634 	TRACE("  adjusted MTU to %" B_PRIu32 ", bytesLeft %" B_PRIu32, mtu,
635 		bytesLeft);
636 
637 	while (bytesLeft > 0) {
638 		uint32 fragmentLength = min_c(bytesLeft, mtu);
639 		bytesLeft -= fragmentLength;
640 		bool lastFragment = bytesLeft == 0;
641 
642 		header->total_length = htons(fragmentLength + headerLength);
643 		header->fragment_offset = htons((lastFragment ? 0 : IP_MORE_FRAGMENTS)
644 			| (fragmentOffset >> 3));
645 		header->checksum = 0;
646 		header->checksum = gStackModule->checksum((uint8*)header,
647 			headerLength);
648 			// TODO: compute the checksum only for those parts that changed?
649 
650 		TRACE("  send fragment of %" B_PRIu32 " bytes (%" B_PRIu32 " bytes "
651 			"left)", fragmentLength, bytesLeft);
652 
653 		net_buffer* fragmentBuffer;
654 		if (!lastFragment) {
655 			fragmentBuffer = gBufferModule->split(buffer, fragmentLength);
656 			fragmentOffset += fragmentLength;
657 		} else
658 			fragmentBuffer = buffer;
659 
660 		if (fragmentBuffer == NULL) {
661 			status = B_NO_MEMORY;
662 			break;
663 		}
664 
665 		// copy header to fragment
666 		status = gBufferModule->prepend(fragmentBuffer, header, headerLength);
667 
668 		// send fragment
669 		if (status == B_OK)
670 			status = sDatalinkModule->send_routed_data(route, fragmentBuffer);
671 
672 		if (lastFragment) {
673 			// we don't own the last buffer, so we don't have to free it
674 			break;
675 		}
676 
677 		if (status != B_OK) {
678 			gBufferModule->free(fragmentBuffer);
679 			break;
680 		}
681 	}
682 
683 	gBufferModule->free(headerBuffer);
684 	return status;
685 }
686 
687 
688 status_t ipv4_receive_data(net_buffer* buffer);
689 
690 
691 /*!	Delivers the provided \a buffer to all listeners of this multicast group.
692 	Does not take over ownership of the buffer.
693 */
694 static bool
695 deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
696 	bool deliverToRaw)
697 {
698 	TRACE("deliver_multicast(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
699 	if (module->deliver_data == NULL)
700 		return false;
701 
702 	MutexLocker _(sMulticastGroupsLock);
703 
704 	sockaddr_in* multicastAddr = (sockaddr_in*)buffer->destination;
705 
706 	uint32 index = buffer->index;
707 	if (buffer->interface_address != NULL)
708 		index = buffer->interface_address->interface->index;
709 
710 	MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
711 		&multicastAddr->sin_addr, index));
712 
713 	size_t count = 0;
714 
715 	while (it.HasNext()) {
716 		IPv4GroupInterface* state = it.Next();
717 
718 		ipv4_protocol* ipProtocol = state->Parent()->Socket();
719 		if (deliverToRaw && (ipProtocol->raw == NULL
720 				|| ipProtocol->socket->protocol != buffer->protocol))
721 			continue;
722 
723 		if (state->FilterAccepts(buffer)) {
724 			net_protocol* protocol = ipProtocol;
725 			if (protocol->module != module) {
726 				// as multicast filters are installed with an IPv4 protocol
727 				// reference, we need to go and find the appropriate instance
728 				// related to the 'receiving protocol' with module 'module'.
729 				protocol = ipProtocol->socket->first_protocol;
730 
731 				while (protocol != NULL && protocol->module != module)
732 					protocol = protocol->next;
733 			}
734 
735 			if (protocol != NULL) {
736 				module->deliver_data(protocol, buffer);
737 				count++;
738 			}
739 		}
740 	}
741 
742 	return count > 0;
743 }
744 
745 
746 /*!	Delivers the buffer to all listening raw sockets without taking ownership of
747 	the provided \a buffer.
748 	Returns \c true if there was any receiver, \c false if not.
749 */
750 static bool
751 raw_receive_data(net_buffer* buffer)
752 {
753 	MutexLocker locker(sRawSocketsLock);
754 
755 	if (sRawSockets.IsEmpty())
756 		return false;
757 
758 	TRACE("RawReceiveData(%i)", buffer->protocol);
759 
760 	if ((buffer->flags & MSG_MCAST) != 0) {
761 		// we need to call deliver_multicast here separately as
762 		// buffer still has the IP header, and it won't in the
763 		// next call. This isn't very optimized but works for now.
764 		// A better solution would be to hold separate hash tables
765 		// and lists for RAW and non-RAW sockets.
766 		return deliver_multicast(&gIPv4Module, buffer, true);
767 	}
768 
769 	RawSocketList::Iterator iterator = sRawSockets.GetIterator();
770 	size_t count = 0;
771 
772 	while (iterator.HasNext()) {
773 		RawSocket* raw = iterator.Next();
774 
775 		if (raw->Socket()->protocol == buffer->protocol) {
776 			raw->EnqueueClone(buffer);
777 			count++;
778 		}
779 	}
780 
781 	return count > 0;
782 }
783 
784 
785 static inline sockaddr*
786 fill_sockaddr_in(sockaddr_in* target, in_addr_t address)
787 {
788 	target->sin_family = AF_INET;
789 	target->sin_len = sizeof(sockaddr_in);
790 	target->sin_port = 0;
791 	target->sin_addr.s_addr = address;
792 	return (sockaddr*)target;
793 }
794 
795 
796 static status_t
797 get_int_option(void* target, size_t length, int value)
798 {
799 	if (length != sizeof(int))
800 		return B_BAD_VALUE;
801 
802 	return user_memcpy(target, &value, sizeof(int));
803 }
804 
805 
806 static status_t
807 get_char_int_option(void* target, size_t length, int value)
808 {
809 	if (length == sizeof(int))
810 		return user_memcpy(target, &value, sizeof(int));
811 	if (length == sizeof(unsigned char)) {
812 		unsigned char uvalue = value;
813 		return user_memcpy(target, &uvalue, sizeof(uvalue));
814 	}
815 	return B_BAD_VALUE;
816 }
817 
818 
819 template<typename Type> static status_t
820 set_int_option(Type &target, const void* _value, size_t length)
821 {
822 	int value;
823 
824 	if (length != sizeof(int))
825 		return B_BAD_VALUE;
826 
827 	if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
828 		return B_BAD_ADDRESS;
829 
830 	target = value;
831 	return B_OK;
832 }
833 
834 
835 template<typename Type> static status_t
836 set_char_int_option(Type &target, const void* _value, size_t length)
837 {
838 	if (length == sizeof(int)) {
839 		int value;
840 		if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
841 			return B_BAD_ADDRESS;
842 		if (value > 255)
843 			return B_BAD_VALUE;
844 		target = value;
845 		return B_OK;
846 	}
847 	if (length == sizeof(unsigned char)) {
848 		unsigned char value;
849 		if (user_memcpy(&value, _value, sizeof(value)) != B_OK)
850 			return B_BAD_ADDRESS;
851 
852 		target = value;
853 		return B_OK;
854 	}
855 	return B_BAD_VALUE;
856 }
857 
858 
859 static net_protocol_module_info*
860 receiving_protocol(uint8 protocol)
861 {
862 	net_protocol_module_info* module = sReceivingProtocol[protocol];
863 	if (module != NULL)
864 		return module;
865 
866 	MutexLocker locker(sReceivingProtocolLock);
867 
868 	module = sReceivingProtocol[protocol];
869 	if (module != NULL)
870 		return module;
871 
872 	if (gStackModule->get_domain_receiving_protocol(sDomain, protocol,
873 			&module) == B_OK)
874 		sReceivingProtocol[protocol] = module;
875 
876 	return module;
877 }
878 
879 
880 // #pragma mark - multicast
881 
882 
883 status_t
884 IPv4Multicast::JoinGroup(IPv4GroupInterface* state)
885 {
886 	MutexLocker _(sMulticastGroupsLock);
887 
888 	sockaddr_in groupAddr;
889 	status_t status = sDatalinkModule->join_multicast(state->Interface(),
890 		sDomain, fill_sockaddr_in(&groupAddr, state->Address().s_addr));
891 	if (status != B_OK)
892 		return status;
893 
894 	sMulticastState->Insert(state);
895 	return B_OK;
896 }
897 
898 
899 status_t
900 IPv4Multicast::LeaveGroup(IPv4GroupInterface* state)
901 {
902 	MutexLocker _(sMulticastGroupsLock);
903 
904 	sMulticastState->Remove(state);
905 
906 	sockaddr_in groupAddr;
907 	return sDatalinkModule->leave_multicast(state->Interface(), sDomain,
908 		fill_sockaddr_in(&groupAddr, state->Address().s_addr));
909 }
910 
911 
912 static status_t
913 ipv4_delta_group(IPv4GroupInterface* group, int option,
914 	net_interface* interface, const in_addr* sourceAddr)
915 {
916 	switch (option) {
917 		case IP_ADD_MEMBERSHIP:
918 			return group->Add();
919 		case IP_DROP_MEMBERSHIP:
920 			return group->Drop();
921 		case IP_BLOCK_SOURCE:
922 			return group->BlockSource(*sourceAddr);
923 		case IP_UNBLOCK_SOURCE:
924 			return group->UnblockSource(*sourceAddr);
925 		case IP_ADD_SOURCE_MEMBERSHIP:
926 			return group->AddSSM(*sourceAddr);
927 		case IP_DROP_SOURCE_MEMBERSHIP:
928 			return group->DropSSM(*sourceAddr);
929 	}
930 
931 	return B_ERROR;
932 }
933 
934 
935 static status_t
936 ipv4_delta_membership(ipv4_protocol* protocol, int option,
937 	net_interface* interface, const in_addr* groupAddr,
938 	const in_addr* sourceAddr)
939 {
940 	IPv4MulticastFilter& filter = protocol->multicast_filter;
941 	IPv4GroupInterface* state = NULL;
942 	status_t status = B_OK;
943 
944 	switch (option) {
945 		case IP_ADD_MEMBERSHIP:
946 		case IP_ADD_SOURCE_MEMBERSHIP:
947 			status = filter.GetState(*groupAddr, interface, state, true);
948 			break;
949 
950 		case IP_DROP_MEMBERSHIP:
951 		case IP_BLOCK_SOURCE:
952 		case IP_UNBLOCK_SOURCE:
953 		case IP_DROP_SOURCE_MEMBERSHIP:
954 			filter.GetState(*groupAddr, interface, state, false);
955 			if (state == NULL) {
956 				if (option == IP_DROP_MEMBERSHIP
957 					|| option == IP_DROP_SOURCE_MEMBERSHIP)
958 					return EADDRNOTAVAIL;
959 
960 				return B_BAD_VALUE;
961 			}
962 			break;
963 	}
964 
965 	if (status != B_OK)
966 		return status;
967 
968 	status = ipv4_delta_group(state, option, interface, sourceAddr);
969 	filter.ReturnState(state);
970 	return status;
971 }
972 
973 
974 static int
975 generic_to_ipv4(int option)
976 {
977 	switch (option) {
978 		case MCAST_JOIN_GROUP:
979 			return IP_ADD_MEMBERSHIP;
980 		case MCAST_JOIN_SOURCE_GROUP:
981 			return IP_ADD_SOURCE_MEMBERSHIP;
982 		case MCAST_LEAVE_GROUP:
983 			return IP_DROP_MEMBERSHIP;
984 		case MCAST_BLOCK_SOURCE:
985 			return IP_BLOCK_SOURCE;
986 		case MCAST_UNBLOCK_SOURCE:
987 			return IP_UNBLOCK_SOURCE;
988 		case MCAST_LEAVE_SOURCE_GROUP:
989 			return IP_DROP_SOURCE_MEMBERSHIP;
990 	}
991 
992 	return -1;
993 }
994 
995 
996 static net_interface*
997 get_multicast_interface(ipv4_protocol* protocol, const in_addr* address)
998 {
999 	// TODO: this is broken and leaks references
1000 	sockaddr_in groupAddr;
1001 	net_route* route = sDatalinkModule->get_route(sDomain,
1002 		fill_sockaddr_in(&groupAddr, address ? address->s_addr : INADDR_ANY));
1003 	if (route == NULL)
1004 		return NULL;
1005 
1006 	return route->interface_address->interface;
1007 }
1008 
1009 
1010 static status_t
1011 ipv4_delta_membership(ipv4_protocol* protocol, int option,
1012 	in_addr* interfaceAddr, in_addr* groupAddr, in_addr* sourceAddr)
1013 {
1014 	net_interface* interface = NULL;
1015 
1016 	if (interfaceAddr->s_addr == INADDR_ANY) {
1017 		interface = get_multicast_interface(protocol, groupAddr);
1018 	} else {
1019 		sockaddr_in address;
1020 		interface = sDatalinkModule->get_interface_with_address(
1021 			fill_sockaddr_in(&address, interfaceAddr->s_addr));
1022 	}
1023 
1024 	if (interface == NULL)
1025 		return B_DEVICE_NOT_FOUND;
1026 
1027 	return ipv4_delta_membership(protocol, option, interface,
1028 		groupAddr, sourceAddr);
1029 }
1030 
1031 
1032 static status_t
1033 ipv4_generic_delta_membership(ipv4_protocol* protocol, int option,
1034 	uint32 index, const sockaddr_storage* _groupAddr,
1035 	const sockaddr_storage* _sourceAddr)
1036 {
1037 	if (_groupAddr->ss_family != AF_INET
1038 		|| (_sourceAddr != NULL && _sourceAddr->ss_family != AF_INET))
1039 		return B_BAD_VALUE;
1040 
1041 	const in_addr* groupAddr = &((const sockaddr_in*)_groupAddr)->sin_addr;
1042 
1043 	// TODO: this is broken and leaks references
1044 	net_interface* interface;
1045 	if (index == 0)
1046 		interface = get_multicast_interface(protocol, groupAddr);
1047 	else
1048 		interface = sDatalinkModule->get_interface(sDomain, index);
1049 
1050 	if (interface == NULL)
1051 		return B_DEVICE_NOT_FOUND;
1052 
1053 	const in_addr* sourceAddr = NULL;
1054 	if (_sourceAddr != NULL)
1055 		sourceAddr = &((const sockaddr_in*)_sourceAddr)->sin_addr;
1056 
1057 	return ipv4_delta_membership(protocol, generic_to_ipv4(option), interface,
1058 		groupAddr, sourceAddr);
1059 }
1060 
1061 
1062 //	#pragma mark - module interface
1063 
1064 
1065 net_protocol*
1066 ipv4_init_protocol(net_socket* socket)
1067 {
1068 	ipv4_protocol* protocol = new (std::nothrow) ipv4_protocol();
1069 	if (protocol == NULL)
1070 		return NULL;
1071 
1072 	protocol->raw = NULL;
1073 	protocol->service_type = 0;
1074 	protocol->time_to_live = kDefaultTTL;
1075 	protocol->multicast_time_to_live = kDefaultMulticastTTL;
1076 	protocol->multicast_loopback = kDefaultMulticastLoopback;
1077 	protocol->flags = 0;
1078 	protocol->multicast_address = NULL;
1079 	return protocol;
1080 }
1081 
1082 
1083 status_t
1084 ipv4_uninit_protocol(net_protocol* _protocol)
1085 {
1086 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1087 
1088 	delete protocol;
1089 
1090 	return B_OK;
1091 }
1092 
1093 
1094 /*!	Since open() is only called on the top level protocol, when we get here
1095 	it means we are on a SOCK_RAW socket.
1096 */
1097 status_t
1098 ipv4_open(net_protocol* _protocol)
1099 {
1100 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1101 
1102 	// Only root may open raw sockets
1103 	if (geteuid() != 0)
1104 		return B_NOT_ALLOWED;
1105 
1106 	RawSocket* raw = new (std::nothrow) RawSocket(protocol->socket);
1107 	if (raw == NULL)
1108 		return B_NO_MEMORY;
1109 
1110 	status_t status = raw->InitCheck();
1111 	if (status != B_OK) {
1112 		delete raw;
1113 		return status;
1114 	}
1115 
1116 	TRACE_SK(protocol, "Open()");
1117 
1118 	protocol->raw = raw;
1119 
1120 	MutexLocker locker(sRawSocketsLock);
1121 	sRawSockets.Add(raw);
1122 	return B_OK;
1123 }
1124 
1125 
1126 status_t
1127 ipv4_close(net_protocol* _protocol)
1128 {
1129 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1130 	RawSocket* raw = protocol->raw;
1131 	if (raw == NULL)
1132 		return B_ERROR;
1133 
1134 	TRACE_SK(protocol, "Close()");
1135 
1136 	MutexLocker locker(sRawSocketsLock);
1137 	sRawSockets.Remove(raw);
1138 	delete raw;
1139 	protocol->raw = NULL;
1140 
1141 	return B_OK;
1142 }
1143 
1144 
1145 status_t
1146 ipv4_free(net_protocol* protocol)
1147 {
1148 	return B_OK;
1149 }
1150 
1151 
1152 status_t
1153 ipv4_connect(net_protocol* protocol, const struct sockaddr* address)
1154 {
1155 	return B_ERROR;
1156 }
1157 
1158 
1159 status_t
1160 ipv4_accept(net_protocol* protocol, struct net_socket** _acceptedSocket)
1161 {
1162 	return B_NOT_SUPPORTED;
1163 }
1164 
1165 
1166 status_t
1167 ipv4_control(net_protocol* _protocol, int level, int option, void* value,
1168 	size_t* _length)
1169 {
1170 	if ((level & LEVEL_MASK) != IPPROTO_IP)
1171 		return sDatalinkModule->control(sDomain, option, value, _length);
1172 
1173 	return B_BAD_VALUE;
1174 }
1175 
1176 
1177 status_t
1178 ipv4_getsockopt(net_protocol* _protocol, int level, int option, void* value,
1179 	int* _length)
1180 {
1181 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1182 
1183 	if (level == IPPROTO_IP) {
1184 		bool isDgramOrRaw = protocol->socket->type == SOCK_DGRAM
1185 			|| protocol->socket->type == SOCK_RAW;
1186 		if (option == IP_HDRINCL) {
1187 			return get_int_option(value, *_length,
1188 				(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
1189 		}
1190 		if (option == IP_RECVDSTADDR) {
1191 			return get_int_option(value, *_length,
1192 				(protocol->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0);
1193 		}
1194 		if (option == IP_TTL)
1195 			return get_int_option(value, *_length, protocol->time_to_live);
1196 		if (option == IP_TOS)
1197 			return get_int_option(value, *_length, protocol->service_type);
1198 		if (option == IP_MULTICAST_IF) {
1199 			if (*_length != sizeof(struct in_addr))
1200 				return B_BAD_VALUE;
1201 			if (!isDgramOrRaw)
1202 				return B_NOT_SUPPORTED;
1203 			struct sockaddr_in defaultAddress;
1204 			defaultAddress.sin_addr.s_addr = htonl(INADDR_ANY);
1205 			struct sockaddr_in* address =
1206 				(struct sockaddr_in*)protocol->multicast_address;
1207 			if (address == NULL)
1208 				address = &defaultAddress;
1209 			if (user_memcpy(value, &address->sin_addr, sizeof(struct in_addr))
1210 					!= B_OK) {
1211 				return B_BAD_ADDRESS;
1212 			}
1213 			return B_OK;
1214 		}
1215 		if (option == IP_MULTICAST_TTL) {
1216 			if (!isDgramOrRaw)
1217 				return B_NOT_SUPPORTED;
1218 			return get_char_int_option(value, *_length,
1219 				protocol->multicast_time_to_live);
1220 		}
1221 		if (option == IP_MULTICAST_LOOP) {
1222 			if (!isDgramOrRaw)
1223 				return B_NOT_SUPPORTED;
1224 			return get_char_int_option(value, *_length,
1225 				protocol->multicast_loopback ? 1 : 0);
1226 		}
1227 		if (option == IP_ADD_MEMBERSHIP
1228 			|| option == IP_DROP_MEMBERSHIP
1229 			|| option == IP_BLOCK_SOURCE
1230 			|| option == IP_UNBLOCK_SOURCE
1231 			|| option == IP_ADD_SOURCE_MEMBERSHIP
1232 			|| option == IP_DROP_SOURCE_MEMBERSHIP
1233 			|| option == MCAST_JOIN_GROUP
1234 			|| option == MCAST_LEAVE_GROUP
1235 			|| option == MCAST_BLOCK_SOURCE
1236 			|| option == MCAST_UNBLOCK_SOURCE
1237 			|| option == MCAST_JOIN_SOURCE_GROUP
1238 			|| option == MCAST_LEAVE_SOURCE_GROUP) {
1239 			// RFC 3678, Section 4.1:
1240 			// ``An error of EOPNOTSUPP is returned if these options are
1241 			// used with getsockopt().''
1242 			return B_NOT_SUPPORTED;
1243 		}
1244 
1245 		dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
1246 		return ENOPROTOOPT;
1247 	}
1248 
1249 	return sSocketModule->get_option(protocol->socket, level, option, value,
1250 		_length);
1251 }
1252 
1253 
1254 status_t
1255 ipv4_setsockopt(net_protocol* _protocol, int level, int option,
1256 	const void* value, int length)
1257 {
1258 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1259 
1260 	if (level == IPPROTO_IP) {
1261 		bool isDgramOrRaw = protocol->socket->type == SOCK_DGRAM
1262 			|| protocol->socket->type == SOCK_RAW;
1263 		if (option == IP_HDRINCL) {
1264 			int headerIncluded;
1265 			if (length != sizeof(int))
1266 				return B_BAD_VALUE;
1267 			if (user_memcpy(&headerIncluded, value, sizeof(headerIncluded))
1268 					!= B_OK)
1269 				return B_BAD_ADDRESS;
1270 
1271 			if (headerIncluded)
1272 				protocol->flags |= IP_FLAG_HEADER_INCLUDED;
1273 			else
1274 				protocol->flags &= ~IP_FLAG_HEADER_INCLUDED;
1275 
1276 			return B_OK;
1277 		}
1278 		if (option == IP_RECVDSTADDR) {
1279 			int getAddress;
1280 			if (length != sizeof(int))
1281 				return B_BAD_VALUE;
1282 			if (user_memcpy(&getAddress, value, sizeof(int)) != B_OK)
1283 				return B_BAD_ADDRESS;
1284 
1285 			if (getAddress && (protocol->socket->type == SOCK_DGRAM
1286 					|| protocol->socket->type == SOCK_RAW))
1287 				protocol->flags |= IP_FLAG_RECEIVE_DEST_ADDR;
1288 			else
1289 				protocol->flags &= ~IP_FLAG_RECEIVE_DEST_ADDR;
1290 
1291 			return B_OK;
1292 		}
1293 		if (option == IP_TTL)
1294 			return set_int_option(protocol->time_to_live, value, length);
1295 		if (option == IP_TOS)
1296 			return set_int_option(protocol->service_type, value, length);
1297 		if (option == IP_MULTICAST_IF) {
1298 			if (length != sizeof(struct in_addr))
1299 				return B_BAD_VALUE;
1300 			if (!isDgramOrRaw)
1301 				return B_NOT_SUPPORTED;
1302 
1303 			struct sockaddr_in* address = new (std::nothrow) sockaddr_in;
1304 			if (address == NULL)
1305 				return B_NO_MEMORY;
1306 
1307 			struct in_addr sin_addr;
1308 			if (user_memcpy(&sin_addr, value, sizeof(struct in_addr))
1309 					!= B_OK) {
1310 				delete address;
1311 				return B_BAD_ADDRESS;
1312 			}
1313 			fill_sockaddr_in(address, sin_addr.s_addr);
1314 
1315 			// Using INADDR_ANY to remove the previous setting.
1316 			if (address->sin_addr.s_addr == htonl(INADDR_ANY)) {
1317 				delete address;
1318 				delete protocol->multicast_address;
1319 				protocol->multicast_address = NULL;
1320 				return B_OK;
1321 			}
1322 
1323 			struct net_interface* interface
1324 				= sDatalinkModule->get_interface_with_address(
1325 					(sockaddr*)address);
1326 			if (interface == NULL) {
1327 				delete address;
1328 				return EADDRNOTAVAIL;
1329 			}
1330 
1331 			delete protocol->multicast_address;
1332 			protocol->multicast_address = (struct sockaddr*)address;
1333 
1334 			sDatalinkModule->put_interface(interface);
1335 			return B_OK;
1336 		}
1337 		if (option == IP_MULTICAST_TTL) {
1338 			if (!isDgramOrRaw)
1339 				return B_NOT_SUPPORTED;
1340 			return set_char_int_option(protocol->multicast_time_to_live, value,
1341 				length);
1342 		}
1343 		if (option == IP_MULTICAST_LOOP) {
1344 			if (!isDgramOrRaw)
1345 				return B_NOT_SUPPORTED;
1346 			uint8 multicast_loopback;
1347 			status_t status = set_char_int_option(multicast_loopback, value,
1348 				length);
1349 			if (status == B_OK)
1350 				protocol->multicast_loopback = multicast_loopback != 0;
1351 			return status;
1352 		}
1353 		if (option == IP_ADD_MEMBERSHIP || option == IP_DROP_MEMBERSHIP) {
1354 			if (!isDgramOrRaw)
1355 				return B_NOT_SUPPORTED;
1356 			ip_mreq mreq;
1357 			if (length != sizeof(ip_mreq))
1358 				return B_BAD_VALUE;
1359 			if (user_memcpy(&mreq, value, sizeof(ip_mreq)) != B_OK)
1360 				return B_BAD_ADDRESS;
1361 
1362 			return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
1363 				&mreq.imr_multiaddr, NULL);
1364 		}
1365 		if (option == IP_BLOCK_SOURCE
1366 			|| option == IP_UNBLOCK_SOURCE
1367 			|| option == IP_ADD_SOURCE_MEMBERSHIP
1368 			|| option == IP_DROP_SOURCE_MEMBERSHIP) {
1369 			if (!isDgramOrRaw)
1370 				return B_NOT_SUPPORTED;
1371 			ip_mreq_source mreq;
1372 			if (length != sizeof(ip_mreq_source))
1373 				return B_BAD_VALUE;
1374 			if (user_memcpy(&mreq, value, sizeof(ip_mreq_source)) != B_OK)
1375 				return B_BAD_ADDRESS;
1376 
1377 			return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
1378 				&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
1379 		}
1380 		if (option == MCAST_LEAVE_GROUP || option == MCAST_JOIN_GROUP) {
1381 			if (!isDgramOrRaw)
1382 				return B_NOT_SUPPORTED;
1383 			group_req greq;
1384 			if (length != sizeof(group_req))
1385 				return B_BAD_VALUE;
1386 			if (user_memcpy(&greq, value, sizeof(group_req)) != B_OK)
1387 				return B_BAD_ADDRESS;
1388 
1389 			return ipv4_generic_delta_membership(protocol, option,
1390 				greq.gr_interface, &greq.gr_group, NULL);
1391 		}
1392 		if (option == MCAST_BLOCK_SOURCE
1393 			|| option == MCAST_UNBLOCK_SOURCE
1394 			|| option == MCAST_JOIN_SOURCE_GROUP
1395 			|| option == MCAST_LEAVE_SOURCE_GROUP) {
1396 			if (!isDgramOrRaw)
1397 				return B_NOT_SUPPORTED;
1398 			group_source_req greq;
1399 			if (length != sizeof(group_source_req))
1400 				return B_BAD_VALUE;
1401 			if (user_memcpy(&greq, value, sizeof(group_source_req)) != B_OK)
1402 				return B_BAD_ADDRESS;
1403 
1404 			return ipv4_generic_delta_membership(protocol, option,
1405 				greq.gsr_interface, &greq.gsr_group, &greq.gsr_source);
1406 		}
1407 
1408 		dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
1409 		return ENOPROTOOPT;
1410 	}
1411 
1412 	return sSocketModule->set_option(protocol->socket, level, option,
1413 		value, length);
1414 }
1415 
1416 
1417 status_t
1418 ipv4_bind(net_protocol* protocol, const struct sockaddr* address)
1419 {
1420 	if (address->sa_family != AF_INET)
1421 		return EAFNOSUPPORT;
1422 
1423 	// only INADDR_ANY and addresses of local interfaces are accepted:
1424 	if (((sockaddr_in*)address)->sin_addr.s_addr == INADDR_ANY
1425 		|| IN_MULTICAST(ntohl(((sockaddr_in*)address)->sin_addr.s_addr))
1426 		|| sDatalinkModule->is_local_address(sDomain, address, NULL, NULL)) {
1427 		memcpy(&protocol->socket->address, address, sizeof(struct sockaddr_in));
1428 		protocol->socket->address.ss_len = sizeof(struct sockaddr_in);
1429 			// explicitly set length, as our callers can't be trusted to
1430 			// always provide the correct length!
1431 		return B_OK;
1432 	}
1433 
1434 	return B_ERROR;
1435 		// address is unknown on this host
1436 }
1437 
1438 
1439 status_t
1440 ipv4_unbind(net_protocol* protocol, struct sockaddr* address)
1441 {
1442 	// nothing to do here
1443 	return B_OK;
1444 }
1445 
1446 
1447 status_t
1448 ipv4_listen(net_protocol* protocol, int count)
1449 {
1450 	return B_NOT_SUPPORTED;
1451 }
1452 
1453 
1454 status_t
1455 ipv4_shutdown(net_protocol* protocol, int direction)
1456 {
1457 	return B_NOT_SUPPORTED;
1458 }
1459 
1460 
1461 status_t
1462 ipv4_send_routed_data(net_protocol* _protocol, struct net_route* route,
1463 	net_buffer* buffer)
1464 {
1465 	if (route == NULL)
1466 		return B_BAD_VALUE;
1467 
1468 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1469 	net_interface_address* interfaceAddress = route->interface_address;
1470 	net_interface* interface = interfaceAddress->interface;
1471 
1472 	TRACE_SK(protocol, "SendRoutedData(%p, %p [%" B_PRIu32 " bytes])", route,
1473 		buffer, buffer->size);
1474 
1475 	sockaddr_in& source = *(sockaddr_in*)buffer->source;
1476 	sockaddr_in& destination = *(sockaddr_in*)buffer->destination;
1477 	sockaddr_in* broadcastAddress = (sockaddr_in*)interfaceAddress->destination;
1478 
1479 	bool checksumNeeded = true;
1480 	bool headerIncluded = false;
1481 	if (protocol != NULL)
1482 		headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0;
1483 
1484 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1485 
1486 	if (destination.sin_addr.s_addr == INADDR_ANY)
1487 		return EDESTADDRREQ;
1488 
1489 	if ((interface->device->flags & IFF_BROADCAST) != 0
1490 		&& (destination.sin_addr.s_addr == INADDR_BROADCAST
1491 			|| (broadcastAddress != NULL && destination.sin_addr.s_addr
1492 					== broadcastAddress->sin_addr.s_addr))) {
1493 		if (protocol && !(protocol->socket->options & SO_BROADCAST))
1494 			return B_BAD_VALUE;
1495 		buffer->flags |= MSG_BCAST;
1496 	} else if (IN_MULTICAST(ntohl(destination.sin_addr.s_addr)))
1497 		buffer->flags |= MSG_MCAST;
1498 
1499 	// Add IP header (if needed)
1500 
1501 	if (!headerIncluded) {
1502 		NetBufferPrepend<ipv4_header> header(buffer);
1503 		if (header.Status() != B_OK)
1504 			return header.Status();
1505 
1506 		header->version = IPV4_VERSION;
1507 		header->header_length = sizeof(ipv4_header) / 4;
1508 		header->service_type = protocol ? protocol->service_type : 0;
1509 		header->total_length = htons(buffer->size);
1510 		header->id = htons(atomic_add(&sPacketID, 1));
1511 		header->fragment_offset = 0;
1512 		if (protocol) {
1513 			header->time_to_live = (buffer->flags & MSG_MCAST) != 0
1514 				? protocol->multicast_time_to_live : protocol->time_to_live;
1515 		} else {
1516 			header->time_to_live = (buffer->flags & MSG_MCAST) != 0
1517 				? kDefaultMulticastTTL : kDefaultTTL;
1518 		}
1519 		header->protocol = protocol
1520 			? protocol->socket->protocol : buffer->protocol;
1521 		header->checksum = 0;
1522 
1523 		header->source = source.sin_addr.s_addr;
1524 		header->destination = destination.sin_addr.s_addr;
1525 
1526 		TRACE_ONLY(dump_ipv4_header(*header));
1527 	} else {
1528 		// if IP_HDRINCL, check if the source address is set
1529 		NetBufferHeaderReader<ipv4_header> header(buffer);
1530 		if (header.Status() != B_OK)
1531 			return header.Status();
1532 
1533 		if (header->source == 0) {
1534 			header->source = source.sin_addr.s_addr;
1535 			header->checksum = 0;
1536 			header.Sync();
1537 		} else
1538 			checksumNeeded = false;
1539 
1540 		TRACE("  Header was already supplied:");
1541 		TRACE_ONLY(dump_ipv4_header(*header));
1542 	}
1543 
1544 	if (buffer->size > 0xffff)
1545 		return EMSGSIZE;
1546 
1547 	if (checksumNeeded) {
1548 		*IPChecksumField(buffer) = gBufferModule->checksum(buffer, 0,
1549 			sizeof(ipv4_header), true);
1550 	}
1551 
1552 	if ((buffer->flags & MSG_MCAST) != 0
1553 		&& protocol->multicast_loopback) {
1554 		// copy an IP multicast packet to the input queue of the loopback
1555 		// interface
1556 		net_buffer *loopbackBuffer = gBufferModule->duplicate(buffer);
1557 
1558 		// get the IPv4 loopback address
1559 		struct sockaddr loopbackAddress;
1560 		gIPv4AddressModule.get_loopback_address(&loopbackAddress);
1561 
1562 		// get the matching interface address if any
1563 		net_interface_address* address =
1564 			sDatalinkModule->get_interface_address(&loopbackAddress);
1565 		if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
1566 			sDatalinkModule->put_interface_address(address);
1567 		} else {
1568 			sDatalinkModule->put_interface_address(
1569 				loopbackBuffer->interface_address);
1570 			loopbackBuffer->interface_address = address;
1571 			ipv4_receive_data(loopbackBuffer);
1572 		}
1573 	}
1574 
1575 	TRACE_SK(protocol, "  SendRoutedData(): header chksum: %" B_PRIu32
1576 		", buffer checksum: %" B_PRIu32,
1577 		gBufferModule->checksum(buffer, 0, sizeof(ipv4_header), true),
1578 		gBufferModule->checksum(buffer, 0, buffer->size, true));
1579 
1580 	TRACE_SK(protocol, "  SendRoutedData(): destination: %08x",
1581 		ntohl(destination.sin_addr.s_addr));
1582 
1583 	uint32 mtu = route->mtu ? route->mtu : interface->device->mtu;
1584 	if (buffer->size > mtu) {
1585 		// we need to fragment the packet
1586 		return send_fragments(protocol, route, buffer, mtu);
1587 	}
1588 
1589 	return sDatalinkModule->send_routed_data(route, buffer);
1590 }
1591 
1592 
1593 status_t
1594 ipv4_send_data(net_protocol* _protocol, net_buffer* buffer)
1595 {
1596 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1597 
1598 	TRACE_SK(protocol, "SendData(%p [%" B_PRIu32 " bytes])", buffer,
1599 		buffer->size);
1600 
1601 	if (protocol != NULL && (protocol->flags & IP_FLAG_HEADER_INCLUDED)) {
1602 		if (buffer->size < sizeof(ipv4_header))
1603 			return B_BAD_VALUE;
1604 
1605 		sockaddr_in* source = (sockaddr_in*)buffer->source;
1606 		sockaddr_in* destination = (sockaddr_in*)buffer->destination;
1607 
1608 		fill_sockaddr_in(source, *NetBufferField<in_addr_t,
1609 			offsetof(ipv4_header, source)>(buffer));
1610 		fill_sockaddr_in(destination, *NetBufferField<in_addr_t,
1611 			offsetof(ipv4_header, destination)>(buffer));
1612 	}
1613 
1614 	// handle IP_MULTICAST_IF
1615 	if (IN_MULTICAST(ntohl(
1616 			((sockaddr_in*)buffer->destination)->sin_addr.s_addr))
1617 		&& protocol != NULL && protocol->multicast_address != NULL) {
1618 		net_interface_address* address = sDatalinkModule->get_interface_address(
1619 			protocol->multicast_address);
1620 		if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
1621 			sDatalinkModule->put_interface_address(address);
1622 			return EADDRNOTAVAIL;
1623 		}
1624 
1625 		sDatalinkModule->put_interface_address(buffer->interface_address);
1626 		buffer->interface_address = address;
1627 			// the buffer takes over ownership of the address
1628 
1629 		net_route* route = sDatalinkModule->get_route(sDomain, address->local);
1630 		if (route == NULL)
1631 			return ENETUNREACH;
1632 
1633 		return sDatalinkModule->send_routed_data(route, buffer);
1634 	}
1635 
1636 	return sDatalinkModule->send_data(protocol, sDomain, buffer);
1637 }
1638 
1639 
1640 ssize_t
1641 ipv4_send_avail(net_protocol* protocol)
1642 {
1643 	return B_ERROR;
1644 }
1645 
1646 
1647 status_t
1648 ipv4_read_data(net_protocol* _protocol, size_t numBytes, uint32 flags,
1649 	net_buffer** _buffer)
1650 {
1651 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1652 	RawSocket* raw = protocol->raw;
1653 	if (raw == NULL)
1654 		return B_ERROR;
1655 
1656 	TRACE_SK(protocol, "ReadData(%lu, 0x%" B_PRIx32 ")", numBytes, flags);
1657 
1658 	return raw->Dequeue(flags, _buffer);
1659 }
1660 
1661 
1662 ssize_t
1663 ipv4_read_avail(net_protocol* _protocol)
1664 {
1665 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1666 	RawSocket* raw = protocol->raw;
1667 	if (raw == NULL)
1668 		return B_ERROR;
1669 
1670 	return raw->AvailableData();
1671 }
1672 
1673 
1674 struct net_domain*
1675 ipv4_get_domain(net_protocol* protocol)
1676 {
1677 	return sDomain;
1678 }
1679 
1680 
1681 size_t
1682 ipv4_get_mtu(net_protocol* protocol, const struct sockaddr* address)
1683 {
1684 	net_route* route = sDatalinkModule->get_route(sDomain, address);
1685 	if (route == NULL)
1686 		return 0;
1687 
1688 	size_t mtu;
1689 	if (route->mtu != 0)
1690 		mtu = route->mtu;
1691 	else
1692 		mtu = route->interface_address->interface->device->mtu;
1693 
1694 	sDatalinkModule->put_route(sDomain, route);
1695 	return mtu - sizeof(ipv4_header);
1696 }
1697 
1698 
1699 status_t
1700 ipv4_receive_data(net_buffer* buffer)
1701 {
1702 	TRACE("ipv4_receive_data(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1703 
1704 	NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
1705 	if (bufferHeader.Status() != B_OK)
1706 		return bufferHeader.Status();
1707 
1708 	ipv4_header& header = bufferHeader.Data();
1709 	TRACE_ONLY(dump_ipv4_header(header));
1710 
1711 	if (header.version != IPV4_VERSION)
1712 		return B_BAD_TYPE;
1713 
1714 	uint16 packetLength = header.TotalLength();
1715 	uint16 headerLength = header.HeaderLength();
1716 	if (packetLength > buffer->size
1717 		|| headerLength < sizeof(ipv4_header))
1718 		return B_BAD_DATA;
1719 
1720 	// TODO: would be nice to have a direct checksum function somewhere
1721 	if (gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
1722 		return B_BAD_DATA;
1723 
1724 	// lower layers notion of broadcast or multicast have no relevance to us
1725 	// other than deciding whether to send an ICMP error
1726 	bool wasMulticast = (buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0;
1727 	bool notForUs = false;
1728 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1729 
1730 	sockaddr_in destination;
1731 	fill_sockaddr_in(&destination, header.destination);
1732 
1733 	if (header.destination == INADDR_BROADCAST) {
1734 		buffer->flags |= MSG_BCAST;
1735 
1736 		// Find first interface with a matching family
1737 		if (!sDatalinkModule->is_local_link_address(sDomain, true,
1738 				buffer->destination, &buffer->interface_address))
1739 			notForUs = !wasMulticast;
1740 	} else if (IN_MULTICAST(ntohl(header.destination))) {
1741 		buffer->flags |= MSG_MCAST;
1742 	} else {
1743 		uint32 matchedAddressType = 0;
1744 
1745 		// test if the packet is really for us
1746 		if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
1747 				&buffer->interface_address, &matchedAddressType)
1748 			&& !sDatalinkModule->is_local_link_address(sDomain, true,
1749 				buffer->destination, &buffer->interface_address)) {
1750 			// if the buffer was a link layer multicast, regard it as a
1751 			// broadcast, and let the upper levels decide what to do with it
1752 			if (wasMulticast)
1753 				buffer->flags |= MSG_BCAST;
1754 			else
1755 				notForUs = true;
1756 		} else {
1757 			// copy over special address types (MSG_BCAST or MSG_MCAST):
1758 			buffer->flags |= matchedAddressType;
1759 		}
1760 	}
1761 
1762 	// set net_buffer's source/destination address
1763 	fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
1764 	memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
1765 
1766 	buffer->protocol = header.protocol;
1767 
1768 	if (notForUs) {
1769 		TRACE("  ipv4_receive_data(): packet was not for us %x -> %x",
1770 			ntohl(header.source), ntohl(header.destination));
1771 
1772 		if (!wasMulticast) {
1773 			// Send ICMP error: Host unreachable
1774 			sDomain->module->error_reply(NULL, buffer, B_NET_ERROR_UNREACH_HOST,
1775 				NULL);
1776 		}
1777 
1778 		return B_ERROR;
1779 	}
1780 
1781 	// remove any trailing/padding data
1782 	status_t status = gBufferModule->trim(buffer, packetLength);
1783 	if (status != B_OK)
1784 		return status;
1785 
1786 	// check for fragmentation
1787 	uint16 fragmentOffset = header.FragmentOffset();
1788 	if ((fragmentOffset & IP_MORE_FRAGMENTS) != 0
1789 		|| (fragmentOffset & IP_FRAGMENT_OFFSET_MASK) != 0) {
1790 		// this is a fragment
1791 		TRACE("  ipv4_receive_data(): Found a Fragment!");
1792 		status = reassemble_fragments(header, &buffer);
1793 		TRACE("  ipv4_receive_data():  -> %s", strerror(status));
1794 		if (status != B_OK)
1795 			return status;
1796 
1797 		if (buffer == NULL) {
1798 			// buffer was put into fragment packet
1799 			TRACE("  ipv4_receive_data(): Not yet assembled.");
1800 			return B_OK;
1801 		}
1802 	}
1803 
1804 	// Since the buffer might have been changed (reassembled fragment)
1805 	// we must no longer access bufferHeader or header anymore after
1806 	// this point
1807 
1808 	bool rawDelivered = raw_receive_data(buffer);
1809 
1810 	// Preserve the ipv4 header for ICMP processing
1811 	gBufferModule->store_header(buffer);
1812 
1813 	bufferHeader.Remove(headerLength);
1814 		// the header is of variable size and may include IP options
1815 		// (TODO: that we ignore for now)
1816 
1817 	net_protocol_module_info* module = receiving_protocol(buffer->protocol);
1818 	if (module == NULL) {
1819 		// no handler for this packet
1820 		if (!rawDelivered) {
1821 			sDomain->module->error_reply(NULL, buffer,
1822 				B_NET_ERROR_UNREACH_PROTOCOL, NULL);
1823 		}
1824 		return EAFNOSUPPORT;
1825 	}
1826 
1827 	if ((buffer->flags & MSG_MCAST) != 0) {
1828 		// Unfortunately historical reasons dictate that the IP multicast
1829 		// model be a little different from the unicast one. We deliver
1830 		// this frame directly to all sockets registered with interest
1831 		// for this multicast group.
1832 		deliver_multicast(module, buffer, false);
1833 		gBufferModule->free(buffer);
1834 		return B_OK;
1835 	}
1836 
1837 	return module->receive_data(buffer);
1838 }
1839 
1840 
1841 status_t
1842 ipv4_deliver_data(net_protocol* _protocol, net_buffer* buffer)
1843 {
1844 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1845 
1846 	if (protocol->raw == NULL)
1847 		return B_ERROR;
1848 
1849 	return protocol->raw->EnqueueClone(buffer);
1850 }
1851 
1852 
1853 status_t
1854 ipv4_error_received(net_error error, net_buffer* buffer)
1855 {
1856 	TRACE("  ipv4_error_received(error %d, buffer %p [%" B_PRIu32 " bytes])",
1857 		(int)error, buffer, buffer->size);
1858 
1859 	NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
1860 	if (bufferHeader.Status() != B_OK)
1861 		return bufferHeader.Status();
1862 
1863 	ipv4_header& header = bufferHeader.Data();
1864 	TRACE_ONLY(dump_ipv4_header(header));
1865 
1866 	// We do not check the packet length, as we usually only get a part of it
1867 	uint16 headerLength = header.HeaderLength();
1868 	if (header.version != IPV4_VERSION
1869 		|| headerLength < sizeof(ipv4_header)
1870 		|| gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
1871 		return B_BAD_DATA;
1872 
1873 	// Restore addresses of the original buffer
1874 
1875 	// lower layers notion of broadcast or multicast have no relevance to us
1876 	// TODO: they actually have when deciding whether to send an ICMP error
1877 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1878 
1879 	fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
1880 	fill_sockaddr_in((struct sockaddr_in*)buffer->destination,
1881 		header.destination);
1882 
1883 	if (header.destination == INADDR_BROADCAST)
1884 		buffer->flags |= MSG_BCAST;
1885 	else if (IN_MULTICAST(ntohl(header.destination)))
1886 		buffer->flags |= MSG_MCAST;
1887 
1888 	// test if the packet is really from us
1889 	if (!sDatalinkModule->is_local_address(sDomain, buffer->source, NULL,
1890 			NULL)) {
1891 		TRACE("  ipv4_error_received(): packet was not for us %x -> %x",
1892 			ntohl(header.source), ntohl(header.destination));
1893 		return B_ERROR;
1894 	}
1895 
1896 	buffer->protocol = header.protocol;
1897 
1898 	bufferHeader.Remove(headerLength);
1899 
1900 	net_protocol_module_info* protocol = receiving_protocol(buffer->protocol);
1901 	if (protocol == NULL)
1902 		return B_ERROR;
1903 
1904 	// propagate error
1905 	return protocol->error_received(error, buffer);
1906 }
1907 
1908 
1909 status_t
1910 ipv4_error_reply(net_protocol* protocol, net_buffer* cause, net_error error,
1911 	net_error_data* errorData)
1912 {
1913 	// Directly obtain the ICMP protocol module
1914 	net_protocol_module_info* icmp = receiving_protocol(IPPROTO_ICMP);
1915 	if (icmp == NULL)
1916 		return B_ERROR;
1917 
1918 	return icmp->error_reply(protocol, cause, error, errorData);
1919 }
1920 
1921 
1922 ssize_t
1923 ipv4_process_ancillary_data_no_container(net_protocol* protocol,
1924 	net_buffer* buffer, void* msgControl, size_t msgControlLen)
1925 {
1926 	ssize_t bytesWritten = 0;
1927 
1928 	if ((((ipv4_protocol*)protocol)->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0) {
1929 		if (msgControlLen < CMSG_SPACE(sizeof(struct in_addr)))
1930 			return B_NO_MEMORY;
1931 
1932 		cmsghdr* messageHeader = (cmsghdr*)msgControl;
1933 		messageHeader->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1934 		messageHeader->cmsg_level = IPPROTO_IP;
1935 		messageHeader->cmsg_type = IP_RECVDSTADDR;
1936 
1937 		memcpy(CMSG_DATA(messageHeader),
1938 		 	&((struct sockaddr_in*)buffer->destination)->sin_addr,
1939 		 	sizeof(struct in_addr));
1940 
1941 		bytesWritten += CMSG_SPACE(sizeof(struct in_addr));
1942 	}
1943 
1944 	return bytesWritten;
1945 }
1946 
1947 
1948 //	#pragma mark -
1949 
1950 
1951 status_t
1952 init_ipv4()
1953 {
1954 	sPacketID = (int32)system_time();
1955 
1956 	mutex_init(&sRawSocketsLock, "raw sockets");
1957 	mutex_init(&sFragmentLock, "IPv4 Fragments");
1958 	mutex_init(&sMulticastGroupsLock, "IPv4 multicast groups");
1959 	mutex_init(&sReceivingProtocolLock, "IPv4 receiving protocols");
1960 
1961 	status_t status;
1962 
1963 	sMulticastState = new MulticastState();
1964 	if (sMulticastState == NULL) {
1965 		status = B_NO_MEMORY;
1966 		goto err4;
1967 	}
1968 
1969 	status = sMulticastState->Init();
1970 	if (status != B_OK)
1971 		goto err5;
1972 
1973 	new (&sFragmentHash) FragmentTable();
1974 	status = sFragmentHash.Init(256);
1975 	if (status != B_OK)
1976 		goto err5;
1977 
1978 	new (&sRawSockets) RawSocketList;
1979 		// static initializers do not work in the kernel,
1980 		// so we have to do it here, manually
1981 		// TODO: for modules, this shouldn't be required
1982 
1983 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_RAW, 0,
1984 		"network/protocols/ipv4/v1", NULL);
1985 	if (status != B_OK)
1986 		goto err6;
1987 
1988 	status = gStackModule->register_domain(AF_INET, "internet", &gIPv4Module,
1989 		&gIPv4AddressModule, &sDomain);
1990 	if (status != B_OK)
1991 		goto err6;
1992 
1993 	add_debugger_command("ipv4_multicast", dump_ipv4_multicast,
1994 		"list all current IPv4 multicast states");
1995 
1996 	return B_OK;
1997 
1998 err6:
1999 	sFragmentHash.~FragmentTable();
2000 err5:
2001 	delete sMulticastState;
2002 err4:
2003 	mutex_destroy(&sReceivingProtocolLock);
2004 	mutex_destroy(&sMulticastGroupsLock);
2005 	mutex_destroy(&sFragmentLock);
2006 	mutex_destroy(&sRawSocketsLock);
2007 	return status;
2008 }
2009 
2010 
2011 status_t
2012 uninit_ipv4()
2013 {
2014 	mutex_lock(&sReceivingProtocolLock);
2015 
2016 	remove_debugger_command("ipv4_multicast", dump_ipv4_multicast);
2017 
2018 	// put all the domain receiving protocols we gathered so far
2019 	for (uint32 i = 0; i < 256; i++) {
2020 		if (sReceivingProtocol[i] != NULL)
2021 			gStackModule->put_domain_receiving_protocol(sDomain, i);
2022 	}
2023 
2024 	gStackModule->unregister_domain(sDomain);
2025 	mutex_unlock(&sReceivingProtocolLock);
2026 
2027 	delete sMulticastState;
2028 	sFragmentHash.~FragmentTable();
2029 
2030 	mutex_destroy(&sMulticastGroupsLock);
2031 	mutex_destroy(&sFragmentLock);
2032 	mutex_destroy(&sRawSocketsLock);
2033 	mutex_destroy(&sReceivingProtocolLock);
2034 
2035 	return B_OK;
2036 }
2037 
2038 
2039 static status_t
2040 ipv4_std_ops(int32 op, ...)
2041 {
2042 	switch (op) {
2043 		case B_MODULE_INIT:
2044 			return init_ipv4();
2045 		case B_MODULE_UNINIT:
2046 			return uninit_ipv4();
2047 
2048 		default:
2049 			return B_ERROR;
2050 	}
2051 }
2052 
2053 
2054 net_protocol_module_info gIPv4Module = {
2055 	{
2056 		"network/protocols/ipv4/v1",
2057 		0,
2058 		ipv4_std_ops
2059 	},
2060 	NET_PROTOCOL_ATOMIC_MESSAGES,
2061 
2062 	ipv4_init_protocol,
2063 	ipv4_uninit_protocol,
2064 	ipv4_open,
2065 	ipv4_close,
2066 	ipv4_free,
2067 	ipv4_connect,
2068 	ipv4_accept,
2069 	ipv4_control,
2070 	ipv4_getsockopt,
2071 	ipv4_setsockopt,
2072 	ipv4_bind,
2073 	ipv4_unbind,
2074 	ipv4_listen,
2075 	ipv4_shutdown,
2076 	ipv4_send_data,
2077 	ipv4_send_routed_data,
2078 	ipv4_send_avail,
2079 	ipv4_read_data,
2080 	ipv4_read_avail,
2081 	ipv4_get_domain,
2082 	ipv4_get_mtu,
2083 	ipv4_receive_data,
2084 	ipv4_deliver_data,
2085 	ipv4_error_received,
2086 	ipv4_error_reply,
2087 	NULL,		// add_ancillary_data()
2088 	NULL,		// process_ancillary_data()
2089 	ipv4_process_ancillary_data_no_container,
2090 	NULL,		// send_data_no_buffer()
2091 	NULL		// read_data_no_buffer()
2092 };
2093 
2094 module_dependency module_dependencies[] = {
2095 	{NET_STACK_MODULE_NAME, (module_info**)&gStackModule},
2096 	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
2097 	{NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule},
2098 	{NET_SOCKET_MODULE_NAME, (module_info**)&sSocketModule},
2099 	{}
2100 };
2101 
2102 module_info* modules[] = {
2103 	(module_info*)&gIPv4Module,
2104 	NULL
2105 };
2106