xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp (revision 8eafd6cd04e4d540cbad2ef07f9eb58a297a3b30)
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 /*!	Delivers the provided \a buffer to all listeners of this multicast group.
689 	Does not take over ownership of the buffer.
690 */
691 static bool
692 deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
693 	bool deliverToRaw)
694 {
695 	if (module->deliver_data == NULL)
696 		return false;
697 
698 	// TODO: fix multicast!
699 	return false;
700 	MutexLocker _(sMulticastGroupsLock);
701 
702 	sockaddr_in* multicastAddr = (sockaddr_in*)buffer->destination;
703 
704 	MulticastState::ValueIterator it = sMulticastState->Lookup(std::make_pair(
705 		&multicastAddr->sin_addr, buffer->interface_address->interface->index));
706 
707 	size_t count = 0;
708 
709 	while (it.HasNext()) {
710 		IPv4GroupInterface* state = it.Next();
711 
712 		ipv4_protocol* ipProtocol = state->Parent()->Socket();
713 		if (deliverToRaw && (ipProtocol->raw == NULL
714 				|| ipProtocol->socket->protocol != buffer->protocol))
715 			continue;
716 
717 		if (state->FilterAccepts(buffer)) {
718 			net_protocol* protocol = ipProtocol;
719 			if (protocol->module != module) {
720 				// as multicast filters are installed with an IPv4 protocol
721 				// reference, we need to go and find the appropriate instance
722 				// related to the 'receiving protocol' with module 'module'.
723 				net_protocol* protocol = ipProtocol->socket->first_protocol;
724 
725 				while (protocol != NULL && protocol->module != module)
726 					protocol = protocol->next;
727 			}
728 
729 			if (protocol != NULL) {
730 				module->deliver_data(protocol, buffer);
731 				count++;
732 			}
733 		}
734 	}
735 
736 	return count > 0;
737 }
738 
739 
740 /*!	Delivers the buffer to all listening raw sockets without taking ownership of
741 	the provided \a buffer.
742 	Returns \c true if there was any receiver, \c false if not.
743 */
744 static bool
745 raw_receive_data(net_buffer* buffer)
746 {
747 	MutexLocker locker(sRawSocketsLock);
748 
749 	if (sRawSockets.IsEmpty())
750 		return false;
751 
752 	TRACE("RawReceiveData(%i)", buffer->protocol);
753 
754 	if ((buffer->flags & MSG_MCAST) != 0) {
755 		// we need to call deliver_multicast here separately as
756 		// buffer still has the IP header, and it won't in the
757 		// next call. This isn't very optimized but works for now.
758 		// A better solution would be to hold separate hash tables
759 		// and lists for RAW and non-RAW sockets.
760 		return deliver_multicast(&gIPv4Module, buffer, true);
761 	}
762 
763 	RawSocketList::Iterator iterator = sRawSockets.GetIterator();
764 	size_t count = 0;
765 
766 	while (iterator.HasNext()) {
767 		RawSocket* raw = iterator.Next();
768 
769 		if (raw->Socket()->protocol == buffer->protocol) {
770 			raw->EnqueueClone(buffer);
771 			count++;
772 		}
773 	}
774 
775 	return count > 0;
776 }
777 
778 
779 static inline sockaddr*
780 fill_sockaddr_in(sockaddr_in* target, in_addr_t address)
781 {
782 	target->sin_family = AF_INET;
783 	target->sin_len = sizeof(sockaddr_in);
784 	target->sin_port = 0;
785 	target->sin_addr.s_addr = address;
786 	return (sockaddr*)target;
787 }
788 
789 
790 static status_t
791 get_int_option(void* target, size_t length, int value)
792 {
793 	if (length != sizeof(int))
794 		return B_BAD_VALUE;
795 
796 	return user_memcpy(target, &value, sizeof(int));
797 }
798 
799 
800 static status_t
801 get_char_int_option(void* target, size_t length, int value)
802 {
803 	if (length == sizeof(int))
804 		return user_memcpy(target, &value, sizeof(int));
805 	if (length == sizeof(unsigned char)) {
806 		unsigned char uvalue = value;
807 		return user_memcpy(target, &uvalue, sizeof(uvalue));
808 	}
809 	return B_BAD_VALUE;
810 }
811 
812 
813 template<typename Type> static status_t
814 set_int_option(Type &target, const void* _value, size_t length)
815 {
816 	int value;
817 
818 	if (length != sizeof(int))
819 		return B_BAD_VALUE;
820 
821 	if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
822 		return B_BAD_ADDRESS;
823 
824 	target = value;
825 	return B_OK;
826 }
827 
828 
829 template<typename Type> static status_t
830 set_char_int_option(Type &target, const void* _value, size_t length)
831 {
832 	if (length == sizeof(int)) {
833 		int value;
834 		if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
835 			return B_BAD_ADDRESS;
836 		if (value > 255)
837 			return B_BAD_VALUE;
838 		target = value;
839 		return B_OK;
840 	}
841 	if (length == sizeof(unsigned char)) {
842 		unsigned char value;
843 		if (user_memcpy(&value, _value, sizeof(value)) != B_OK)
844 			return B_BAD_ADDRESS;
845 
846 		target = value;
847 		return B_OK;
848 	}
849 	return B_BAD_VALUE;
850 }
851 
852 
853 static net_protocol_module_info*
854 receiving_protocol(uint8 protocol)
855 {
856 	net_protocol_module_info* module = sReceivingProtocol[protocol];
857 	if (module != NULL)
858 		return module;
859 
860 	MutexLocker locker(sReceivingProtocolLock);
861 
862 	module = sReceivingProtocol[protocol];
863 	if (module != NULL)
864 		return module;
865 
866 	if (gStackModule->get_domain_receiving_protocol(sDomain, protocol,
867 			&module) == B_OK)
868 		sReceivingProtocol[protocol] = module;
869 
870 	return module;
871 }
872 
873 
874 // #pragma mark - multicast
875 
876 
877 status_t
878 IPv4Multicast::JoinGroup(IPv4GroupInterface* state)
879 {
880 	MutexLocker _(sMulticastGroupsLock);
881 
882 	sockaddr_in groupAddr;
883 	status_t status = sDatalinkModule->join_multicast(state->Interface(),
884 		sDomain, fill_sockaddr_in(&groupAddr, state->Address().s_addr));
885 	if (status != B_OK)
886 		return status;
887 
888 	sMulticastState->Insert(state);
889 	return B_OK;
890 }
891 
892 
893 status_t
894 IPv4Multicast::LeaveGroup(IPv4GroupInterface* state)
895 {
896 	MutexLocker _(sMulticastGroupsLock);
897 
898 	sMulticastState->Remove(state);
899 
900 	sockaddr_in groupAddr;
901 	return sDatalinkModule->leave_multicast(state->Interface(), sDomain,
902 		fill_sockaddr_in(&groupAddr, state->Address().s_addr));
903 }
904 
905 
906 static status_t
907 ipv4_delta_group(IPv4GroupInterface* group, int option,
908 	net_interface* interface, const in_addr* sourceAddr)
909 {
910 	switch (option) {
911 		case IP_ADD_MEMBERSHIP:
912 			return group->Add();
913 		case IP_DROP_MEMBERSHIP:
914 			return group->Drop();
915 		case IP_BLOCK_SOURCE:
916 			return group->BlockSource(*sourceAddr);
917 		case IP_UNBLOCK_SOURCE:
918 			return group->UnblockSource(*sourceAddr);
919 		case IP_ADD_SOURCE_MEMBERSHIP:
920 			return group->AddSSM(*sourceAddr);
921 		case IP_DROP_SOURCE_MEMBERSHIP:
922 			return group->DropSSM(*sourceAddr);
923 	}
924 
925 	return B_ERROR;
926 }
927 
928 
929 static status_t
930 ipv4_delta_membership(ipv4_protocol* protocol, int option,
931 	net_interface* interface, const in_addr* groupAddr,
932 	const in_addr* sourceAddr)
933 {
934 	IPv4MulticastFilter& filter = protocol->multicast_filter;
935 	IPv4GroupInterface* state = NULL;
936 	status_t status = B_OK;
937 
938 	switch (option) {
939 		case IP_ADD_MEMBERSHIP:
940 		case IP_ADD_SOURCE_MEMBERSHIP:
941 			status = filter.GetState(*groupAddr, interface, state, true);
942 			break;
943 
944 		case IP_DROP_MEMBERSHIP:
945 		case IP_BLOCK_SOURCE:
946 		case IP_UNBLOCK_SOURCE:
947 		case IP_DROP_SOURCE_MEMBERSHIP:
948 			filter.GetState(*groupAddr, interface, state, false);
949 			if (state == NULL) {
950 				if (option == IP_DROP_MEMBERSHIP
951 					|| option == IP_DROP_SOURCE_MEMBERSHIP)
952 					return EADDRNOTAVAIL;
953 
954 				return B_BAD_VALUE;
955 			}
956 			break;
957 	}
958 
959 	if (status != B_OK)
960 		return status;
961 
962 	status = ipv4_delta_group(state, option, interface, sourceAddr);
963 	filter.ReturnState(state);
964 	return status;
965 }
966 
967 
968 static int
969 generic_to_ipv4(int option)
970 {
971 	switch (option) {
972 		case MCAST_JOIN_GROUP:
973 			return IP_ADD_MEMBERSHIP;
974 		case MCAST_JOIN_SOURCE_GROUP:
975 			return IP_ADD_SOURCE_MEMBERSHIP;
976 		case MCAST_LEAVE_GROUP:
977 			return IP_DROP_MEMBERSHIP;
978 		case MCAST_BLOCK_SOURCE:
979 			return IP_BLOCK_SOURCE;
980 		case MCAST_UNBLOCK_SOURCE:
981 			return IP_UNBLOCK_SOURCE;
982 		case MCAST_LEAVE_SOURCE_GROUP:
983 			return IP_DROP_SOURCE_MEMBERSHIP;
984 	}
985 
986 	return -1;
987 }
988 
989 
990 static net_interface*
991 get_multicast_interface(ipv4_protocol* protocol, const in_addr* address)
992 {
993 	// TODO: this is broken and leaks references
994 	sockaddr_in groupAddr;
995 	net_route* route = sDatalinkModule->get_route(sDomain,
996 		fill_sockaddr_in(&groupAddr, address ? address->s_addr : INADDR_ANY));
997 	if (route == NULL)
998 		return NULL;
999 
1000 	return route->interface_address->interface;
1001 }
1002 
1003 
1004 static status_t
1005 ipv4_delta_membership(ipv4_protocol* protocol, int option,
1006 	in_addr* interfaceAddr, in_addr* groupAddr, in_addr* sourceAddr)
1007 {
1008 	net_interface* interface = NULL;
1009 
1010 	if (interfaceAddr->s_addr == INADDR_ANY) {
1011 		interface = get_multicast_interface(protocol, groupAddr);
1012 	} else {
1013 		sockaddr_in address;
1014 		interface = sDatalinkModule->get_interface_with_address(
1015 			fill_sockaddr_in(&address, interfaceAddr->s_addr));
1016 	}
1017 
1018 	if (interface == NULL)
1019 		return B_DEVICE_NOT_FOUND;
1020 
1021 	return ipv4_delta_membership(protocol, option, interface,
1022 		groupAddr, sourceAddr);
1023 }
1024 
1025 
1026 static status_t
1027 ipv4_generic_delta_membership(ipv4_protocol* protocol, int option,
1028 	uint32 index, const sockaddr_storage* _groupAddr,
1029 	const sockaddr_storage* _sourceAddr)
1030 {
1031 	if (_groupAddr->ss_family != AF_INET
1032 		|| (_sourceAddr != NULL && _sourceAddr->ss_family != AF_INET))
1033 		return B_BAD_VALUE;
1034 
1035 	const in_addr* groupAddr = &((const sockaddr_in*)_groupAddr)->sin_addr;
1036 
1037 	// TODO: this is broken and leaks references
1038 	net_interface* interface;
1039 	if (index == 0)
1040 		interface = get_multicast_interface(protocol, groupAddr);
1041 	else
1042 		interface = sDatalinkModule->get_interface(sDomain, index);
1043 
1044 	if (interface == NULL)
1045 		return B_DEVICE_NOT_FOUND;
1046 
1047 	const in_addr* sourceAddr = NULL;
1048 	if (_sourceAddr != NULL)
1049 		sourceAddr = &((const sockaddr_in*)_sourceAddr)->sin_addr;
1050 
1051 	return ipv4_delta_membership(protocol, generic_to_ipv4(option), interface,
1052 		groupAddr, sourceAddr);
1053 }
1054 
1055 
1056 //	#pragma mark - module interface
1057 
1058 
1059 net_protocol*
1060 ipv4_init_protocol(net_socket* socket)
1061 {
1062 	ipv4_protocol* protocol = new (std::nothrow) ipv4_protocol();
1063 	if (protocol == NULL)
1064 		return NULL;
1065 
1066 	protocol->raw = NULL;
1067 	protocol->service_type = 0;
1068 	protocol->time_to_live = kDefaultTTL;
1069 	protocol->multicast_time_to_live = kDefaultMulticastTTL;
1070 	protocol->multicast_loopback = kDefaultMulticastLoopback;
1071 	protocol->flags = 0;
1072 	protocol->multicast_address = NULL;
1073 	return protocol;
1074 }
1075 
1076 
1077 status_t
1078 ipv4_uninit_protocol(net_protocol* _protocol)
1079 {
1080 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1081 
1082 	delete protocol;
1083 
1084 	return B_OK;
1085 }
1086 
1087 
1088 /*!	Since open() is only called on the top level protocol, when we get here
1089 	it means we are on a SOCK_RAW socket.
1090 */
1091 status_t
1092 ipv4_open(net_protocol* _protocol)
1093 {
1094 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1095 
1096 	// Only root may open raw sockets
1097 	if (geteuid() != 0)
1098 		return B_NOT_ALLOWED;
1099 
1100 	RawSocket* raw = new (std::nothrow) RawSocket(protocol->socket);
1101 	if (raw == NULL)
1102 		return B_NO_MEMORY;
1103 
1104 	status_t status = raw->InitCheck();
1105 	if (status != B_OK) {
1106 		delete raw;
1107 		return status;
1108 	}
1109 
1110 	TRACE_SK(protocol, "Open()");
1111 
1112 	protocol->raw = raw;
1113 
1114 	MutexLocker locker(sRawSocketsLock);
1115 	sRawSockets.Add(raw);
1116 	return B_OK;
1117 }
1118 
1119 
1120 status_t
1121 ipv4_close(net_protocol* _protocol)
1122 {
1123 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1124 	RawSocket* raw = protocol->raw;
1125 	if (raw == NULL)
1126 		return B_ERROR;
1127 
1128 	TRACE_SK(protocol, "Close()");
1129 
1130 	MutexLocker locker(sRawSocketsLock);
1131 	sRawSockets.Remove(raw);
1132 	delete raw;
1133 	protocol->raw = NULL;
1134 
1135 	return B_OK;
1136 }
1137 
1138 
1139 status_t
1140 ipv4_free(net_protocol* protocol)
1141 {
1142 	return B_OK;
1143 }
1144 
1145 
1146 status_t
1147 ipv4_connect(net_protocol* protocol, const struct sockaddr* address)
1148 {
1149 	return B_ERROR;
1150 }
1151 
1152 
1153 status_t
1154 ipv4_accept(net_protocol* protocol, struct net_socket** _acceptedSocket)
1155 {
1156 	return B_NOT_SUPPORTED;
1157 }
1158 
1159 
1160 status_t
1161 ipv4_control(net_protocol* _protocol, int level, int option, void* value,
1162 	size_t* _length)
1163 {
1164 	if ((level & LEVEL_MASK) != IPPROTO_IP)
1165 		return sDatalinkModule->control(sDomain, option, value, _length);
1166 
1167 	return B_BAD_VALUE;
1168 }
1169 
1170 
1171 status_t
1172 ipv4_getsockopt(net_protocol* _protocol, int level, int option, void* value,
1173 	int* _length)
1174 {
1175 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1176 
1177 	if (level == IPPROTO_IP) {
1178 		bool isDgramOrRaw = protocol->socket->type == SOCK_DGRAM
1179 			|| protocol->socket->type == SOCK_RAW;
1180 		if (option == IP_HDRINCL) {
1181 			return get_int_option(value, *_length,
1182 				(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
1183 		}
1184 		if (option == IP_RECVDSTADDR) {
1185 			return get_int_option(value, *_length,
1186 				(protocol->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0);
1187 		}
1188 		if (option == IP_TTL)
1189 			return get_int_option(value, *_length, protocol->time_to_live);
1190 		if (option == IP_TOS)
1191 			return get_int_option(value, *_length, protocol->service_type);
1192 		if (option == IP_MULTICAST_IF) {
1193 			if (*_length != sizeof(struct in_addr))
1194 				return B_BAD_VALUE;
1195 			if (!isDgramOrRaw)
1196 				return B_NOT_SUPPORTED;
1197 			struct sockaddr_in defaultAddress;
1198 			defaultAddress.sin_addr.s_addr = htonl(INADDR_ANY);
1199 			struct sockaddr_in* address =
1200 				(struct sockaddr_in*)protocol->multicast_address;
1201 			if (address == NULL)
1202 				address = &defaultAddress;
1203 			if (user_memcpy(value, &address->sin_addr, sizeof(struct in_addr))
1204 					!= B_OK) {
1205 				return B_BAD_ADDRESS;
1206 			}
1207 			return B_OK;
1208 		}
1209 		if (option == IP_MULTICAST_TTL) {
1210 			if (!isDgramOrRaw)
1211 				return B_NOT_SUPPORTED;
1212 			return get_char_int_option(value, *_length,
1213 				protocol->multicast_time_to_live);
1214 		}
1215 		if (option == IP_MULTICAST_LOOP) {
1216 			if (!isDgramOrRaw)
1217 				return B_NOT_SUPPORTED;
1218 			return get_char_int_option(value, *_length,
1219 				protocol->multicast_loopback ? 1 : 0);
1220 		}
1221 		if (option == IP_ADD_MEMBERSHIP
1222 			|| option == IP_DROP_MEMBERSHIP
1223 			|| option == IP_BLOCK_SOURCE
1224 			|| option == IP_UNBLOCK_SOURCE
1225 			|| option == IP_ADD_SOURCE_MEMBERSHIP
1226 			|| option == IP_DROP_SOURCE_MEMBERSHIP
1227 			|| option == MCAST_JOIN_GROUP
1228 			|| option == MCAST_LEAVE_GROUP
1229 			|| option == MCAST_BLOCK_SOURCE
1230 			|| option == MCAST_UNBLOCK_SOURCE
1231 			|| option == MCAST_JOIN_SOURCE_GROUP
1232 			|| option == MCAST_LEAVE_SOURCE_GROUP) {
1233 			// RFC 3678, Section 4.1:
1234 			// ``An error of EOPNOTSUPP is returned if these options are
1235 			// used with getsockopt().''
1236 			return B_NOT_SUPPORTED;
1237 		}
1238 
1239 		dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
1240 		return ENOPROTOOPT;
1241 	}
1242 
1243 	return sSocketModule->get_option(protocol->socket, level, option, value,
1244 		_length);
1245 }
1246 
1247 
1248 status_t
1249 ipv4_setsockopt(net_protocol* _protocol, int level, int option,
1250 	const void* value, int length)
1251 {
1252 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1253 
1254 	if (level == IPPROTO_IP) {
1255 		bool isDgramOrRaw = protocol->socket->type == SOCK_DGRAM
1256 			|| protocol->socket->type == SOCK_RAW;
1257 		if (option == IP_HDRINCL) {
1258 			int headerIncluded;
1259 			if (length != sizeof(int))
1260 				return B_BAD_VALUE;
1261 			if (user_memcpy(&headerIncluded, value, sizeof(headerIncluded))
1262 					!= B_OK)
1263 				return B_BAD_ADDRESS;
1264 
1265 			if (headerIncluded)
1266 				protocol->flags |= IP_FLAG_HEADER_INCLUDED;
1267 			else
1268 				protocol->flags &= ~IP_FLAG_HEADER_INCLUDED;
1269 
1270 			return B_OK;
1271 		}
1272 		if (option == IP_RECVDSTADDR) {
1273 			int getAddress;
1274 			if (length != sizeof(int))
1275 				return B_BAD_VALUE;
1276 			if (user_memcpy(&getAddress, value, sizeof(int)) != B_OK)
1277 				return B_BAD_ADDRESS;
1278 
1279 			if (getAddress && (protocol->socket->type == SOCK_DGRAM
1280 					|| protocol->socket->type == SOCK_RAW))
1281 				protocol->flags |= IP_FLAG_RECEIVE_DEST_ADDR;
1282 			else
1283 				protocol->flags &= ~IP_FLAG_RECEIVE_DEST_ADDR;
1284 
1285 			return B_OK;
1286 		}
1287 		if (option == IP_TTL)
1288 			return set_int_option(protocol->time_to_live, value, length);
1289 		if (option == IP_TOS)
1290 			return set_int_option(protocol->service_type, value, length);
1291 		if (option == IP_MULTICAST_IF) {
1292 			if (length != sizeof(struct in_addr))
1293 				return B_BAD_VALUE;
1294 			if (!isDgramOrRaw)
1295 				return B_NOT_SUPPORTED;
1296 
1297 			struct sockaddr_in* address = new (std::nothrow) sockaddr_in;
1298 			if (address == NULL)
1299 				return B_NO_MEMORY;
1300 
1301 			struct in_addr sin_addr;
1302 			if (user_memcpy(&sin_addr, value, sizeof(struct in_addr))
1303 					!= B_OK) {
1304 				delete address;
1305 				return B_BAD_ADDRESS;
1306 			}
1307 			fill_sockaddr_in(address, sin_addr.s_addr);
1308 
1309 			// Using INADDR_ANY to remove the previous setting.
1310 			if (address->sin_addr.s_addr == htonl(INADDR_ANY)) {
1311 				delete address;
1312 				delete protocol->multicast_address;
1313 				protocol->multicast_address = NULL;
1314 				return B_OK;
1315 			}
1316 
1317 			struct net_interface* interface
1318 				= sDatalinkModule->get_interface_with_address(
1319 					(sockaddr*)address);
1320 			if (interface == NULL) {
1321 				delete address;
1322 				return EADDRNOTAVAIL;
1323 			}
1324 
1325 			delete protocol->multicast_address;
1326 			protocol->multicast_address = (struct sockaddr*)address;
1327 
1328 			sDatalinkModule->put_interface(interface);
1329 			return B_OK;
1330 		}
1331 		if (option == IP_MULTICAST_TTL) {
1332 			if (!isDgramOrRaw)
1333 				return B_NOT_SUPPORTED;
1334 			return set_char_int_option(protocol->multicast_time_to_live, value,
1335 				length);
1336 		}
1337 		if (option == IP_MULTICAST_LOOP) {
1338 			if (!isDgramOrRaw)
1339 				return B_NOT_SUPPORTED;
1340 			uint8 multicast_loopback;
1341 			status_t status = set_char_int_option(multicast_loopback, value,
1342 				length);
1343 			if (status == B_OK)
1344 				protocol->multicast_loopback = multicast_loopback != 0;
1345 			return status;
1346 		}
1347 		if (option == IP_ADD_MEMBERSHIP || option == IP_DROP_MEMBERSHIP) {
1348 			if (!isDgramOrRaw)
1349 				return B_NOT_SUPPORTED;
1350 			ip_mreq mreq;
1351 			if (length != sizeof(ip_mreq))
1352 				return B_BAD_VALUE;
1353 			if (user_memcpy(&mreq, value, sizeof(ip_mreq)) != B_OK)
1354 				return B_BAD_ADDRESS;
1355 
1356 			return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
1357 				&mreq.imr_multiaddr, NULL);
1358 		}
1359 		if (option == IP_BLOCK_SOURCE
1360 			|| option == IP_UNBLOCK_SOURCE
1361 			|| option == IP_ADD_SOURCE_MEMBERSHIP
1362 			|| option == IP_DROP_SOURCE_MEMBERSHIP) {
1363 			if (!isDgramOrRaw)
1364 				return B_NOT_SUPPORTED;
1365 			ip_mreq_source mreq;
1366 			if (length != sizeof(ip_mreq_source))
1367 				return B_BAD_VALUE;
1368 			if (user_memcpy(&mreq, value, sizeof(ip_mreq_source)) != B_OK)
1369 				return B_BAD_ADDRESS;
1370 
1371 			return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
1372 				&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
1373 		}
1374 		if (option == MCAST_LEAVE_GROUP || option == MCAST_JOIN_GROUP) {
1375 			if (!isDgramOrRaw)
1376 				return B_NOT_SUPPORTED;
1377 			group_req greq;
1378 			if (length != sizeof(group_req))
1379 				return B_BAD_VALUE;
1380 			if (user_memcpy(&greq, value, sizeof(group_req)) != B_OK)
1381 				return B_BAD_ADDRESS;
1382 
1383 			return ipv4_generic_delta_membership(protocol, option,
1384 				greq.gr_interface, &greq.gr_group, NULL);
1385 		}
1386 		if (option == MCAST_BLOCK_SOURCE
1387 			|| option == MCAST_UNBLOCK_SOURCE
1388 			|| option == MCAST_JOIN_SOURCE_GROUP
1389 			|| option == MCAST_LEAVE_SOURCE_GROUP) {
1390 			if (!isDgramOrRaw)
1391 				return B_NOT_SUPPORTED;
1392 			group_source_req greq;
1393 			if (length != sizeof(group_source_req))
1394 				return B_BAD_VALUE;
1395 			if (user_memcpy(&greq, value, sizeof(group_source_req)) != B_OK)
1396 				return B_BAD_ADDRESS;
1397 
1398 			return ipv4_generic_delta_membership(protocol, option,
1399 				greq.gsr_interface, &greq.gsr_group, &greq.gsr_source);
1400 		}
1401 
1402 		dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
1403 		return ENOPROTOOPT;
1404 	}
1405 
1406 	return sSocketModule->set_option(protocol->socket, level, option,
1407 		value, length);
1408 }
1409 
1410 
1411 status_t
1412 ipv4_bind(net_protocol* protocol, const struct sockaddr* address)
1413 {
1414 	if (address->sa_family != AF_INET)
1415 		return EAFNOSUPPORT;
1416 
1417 	// only INADDR_ANY and addresses of local interfaces are accepted:
1418 	if (((sockaddr_in*)address)->sin_addr.s_addr == INADDR_ANY
1419 		|| IN_MULTICAST(ntohl(((sockaddr_in*)address)->sin_addr.s_addr))
1420 		|| sDatalinkModule->is_local_address(sDomain, address, NULL, NULL)) {
1421 		memcpy(&protocol->socket->address, address, sizeof(struct sockaddr_in));
1422 		protocol->socket->address.ss_len = sizeof(struct sockaddr_in);
1423 			// explicitly set length, as our callers can't be trusted to
1424 			// always provide the correct length!
1425 		return B_OK;
1426 	}
1427 
1428 	return B_ERROR;
1429 		// address is unknown on this host
1430 }
1431 
1432 
1433 status_t
1434 ipv4_unbind(net_protocol* protocol, struct sockaddr* address)
1435 {
1436 	// nothing to do here
1437 	return B_OK;
1438 }
1439 
1440 
1441 status_t
1442 ipv4_listen(net_protocol* protocol, int count)
1443 {
1444 	return B_NOT_SUPPORTED;
1445 }
1446 
1447 
1448 status_t
1449 ipv4_shutdown(net_protocol* protocol, int direction)
1450 {
1451 	return B_NOT_SUPPORTED;
1452 }
1453 
1454 
1455 status_t
1456 ipv4_send_routed_data(net_protocol* _protocol, struct net_route* route,
1457 	net_buffer* buffer)
1458 {
1459 	if (route == NULL)
1460 		return B_BAD_VALUE;
1461 
1462 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1463 	net_interface_address* interfaceAddress = route->interface_address;
1464 	net_interface* interface = interfaceAddress->interface;
1465 
1466 	TRACE_SK(protocol, "SendRoutedData(%p, %p [%" B_PRIu32 " bytes])", route,
1467 		buffer, buffer->size);
1468 
1469 	sockaddr_in& source = *(sockaddr_in*)buffer->source;
1470 	sockaddr_in& destination = *(sockaddr_in*)buffer->destination;
1471 	sockaddr_in* broadcastAddress = (sockaddr_in*)interfaceAddress->destination;
1472 
1473 	bool checksumNeeded = true;
1474 	bool headerIncluded = false;
1475 	if (protocol != NULL)
1476 		headerIncluded = (protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0;
1477 
1478 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1479 
1480 	if (destination.sin_addr.s_addr == INADDR_ANY)
1481 		return EDESTADDRREQ;
1482 
1483 	if ((interface->device->flags & IFF_BROADCAST) != 0
1484 		&& (destination.sin_addr.s_addr == INADDR_BROADCAST
1485 			|| (broadcastAddress != NULL && destination.sin_addr.s_addr
1486 					== broadcastAddress->sin_addr.s_addr))) {
1487 		if (protocol && !(protocol->socket->options & SO_BROADCAST))
1488 			return B_BAD_VALUE;
1489 		buffer->flags |= MSG_BCAST;
1490 	} else if (IN_MULTICAST(ntohl(destination.sin_addr.s_addr)))
1491 		buffer->flags |= MSG_MCAST;
1492 
1493 	// Add IP header (if needed)
1494 
1495 	if (!headerIncluded) {
1496 		NetBufferPrepend<ipv4_header> header(buffer);
1497 		if (header.Status() != B_OK)
1498 			return header.Status();
1499 
1500 		header->version = IPV4_VERSION;
1501 		header->header_length = sizeof(ipv4_header) / 4;
1502 		header->service_type = protocol ? protocol->service_type : 0;
1503 		header->total_length = htons(buffer->size);
1504 		header->id = htons(atomic_add(&sPacketID, 1));
1505 		header->fragment_offset = 0;
1506 		if (protocol) {
1507 			header->time_to_live = (buffer->flags & MSG_MCAST) != 0
1508 				? protocol->multicast_time_to_live : protocol->time_to_live;
1509 		} else {
1510 			header->time_to_live = (buffer->flags & MSG_MCAST) != 0
1511 				? kDefaultMulticastTTL : kDefaultTTL;
1512 		}
1513 		header->protocol = protocol
1514 			? protocol->socket->protocol : buffer->protocol;
1515 		header->checksum = 0;
1516 
1517 		header->source = source.sin_addr.s_addr;
1518 		header->destination = destination.sin_addr.s_addr;
1519 
1520 		TRACE_ONLY(dump_ipv4_header(*header));
1521 	} else {
1522 		// if IP_HDRINCL, check if the source address is set
1523 		NetBufferHeaderReader<ipv4_header> header(buffer);
1524 		if (header.Status() != B_OK)
1525 			return header.Status();
1526 
1527 		if (header->source == 0) {
1528 			header->source = source.sin_addr.s_addr;
1529 			header->checksum = 0;
1530 			header.Sync();
1531 		} else
1532 			checksumNeeded = false;
1533 
1534 		TRACE("  Header was already supplied:");
1535 		TRACE_ONLY(dump_ipv4_header(*header));
1536 	}
1537 
1538 	if (buffer->size > 0xffff)
1539 		return EMSGSIZE;
1540 
1541 	if (checksumNeeded) {
1542 		*IPChecksumField(buffer) = gBufferModule->checksum(buffer, 0,
1543 			sizeof(ipv4_header), true);
1544 	}
1545 
1546 	TRACE_SK(protocol, "  SendRoutedData(): header chksum: %" B_PRIu32
1547 		", buffer checksum: %" B_PRIu32,
1548 		gBufferModule->checksum(buffer, 0, sizeof(ipv4_header), true),
1549 		gBufferModule->checksum(buffer, 0, buffer->size, true));
1550 
1551 	TRACE_SK(protocol, "  SendRoutedData(): destination: %08x",
1552 		ntohl(destination.sin_addr.s_addr));
1553 
1554 	uint32 mtu = route->mtu ? route->mtu : interface->mtu;
1555 	if (buffer->size > mtu) {
1556 		// we need to fragment the packet
1557 		return send_fragments(protocol, route, buffer, mtu);
1558 	}
1559 
1560 	return sDatalinkModule->send_routed_data(route, buffer);
1561 }
1562 
1563 
1564 status_t
1565 ipv4_send_data(net_protocol* _protocol, net_buffer* buffer)
1566 {
1567 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1568 
1569 	TRACE_SK(protocol, "SendData(%p [%" B_PRIu32 " bytes])", buffer,
1570 		buffer->size);
1571 
1572 	if (protocol != NULL && (protocol->flags & IP_FLAG_HEADER_INCLUDED)) {
1573 		if (buffer->size < sizeof(ipv4_header))
1574 			return B_BAD_VALUE;
1575 
1576 		sockaddr_in* source = (sockaddr_in*)buffer->source;
1577 		sockaddr_in* destination = (sockaddr_in*)buffer->destination;
1578 
1579 		fill_sockaddr_in(source, *NetBufferField<in_addr_t,
1580 			offsetof(ipv4_header, source)>(buffer));
1581 		fill_sockaddr_in(destination, *NetBufferField<in_addr_t,
1582 			offsetof(ipv4_header, destination)>(buffer));
1583 	}
1584 
1585 	// handle IP_MULTICAST_IF
1586 	if (IN_MULTICAST(ntohl(
1587 			((sockaddr_in*)buffer->destination)->sin_addr.s_addr))
1588 		&& protocol != NULL && protocol->multicast_address != NULL) {
1589 		net_interface_address* address = sDatalinkModule->get_interface_address(
1590 			protocol->multicast_address);
1591 		if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
1592 			sDatalinkModule->put_interface_address(address);
1593 			return EADDRNOTAVAIL;
1594 		}
1595 
1596 		sDatalinkModule->put_interface_address(buffer->interface_address);
1597 		buffer->interface_address = address;
1598 			// the buffer takes over ownership of the address
1599 
1600 		net_route* route = sDatalinkModule->get_route(sDomain, address->local);
1601 		if (route == NULL)
1602 			return ENETUNREACH;
1603 
1604 		return sDatalinkModule->send_routed_data(route, buffer);
1605 	}
1606 
1607 	return sDatalinkModule->send_data(protocol, sDomain, buffer);
1608 }
1609 
1610 
1611 ssize_t
1612 ipv4_send_avail(net_protocol* protocol)
1613 {
1614 	return B_ERROR;
1615 }
1616 
1617 
1618 status_t
1619 ipv4_read_data(net_protocol* _protocol, size_t numBytes, uint32 flags,
1620 	net_buffer** _buffer)
1621 {
1622 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1623 	RawSocket* raw = protocol->raw;
1624 	if (raw == NULL)
1625 		return B_ERROR;
1626 
1627 	TRACE_SK(protocol, "ReadData(%lu, 0x%" B_PRIx32 ")", numBytes, flags);
1628 
1629 	return raw->Dequeue(flags, _buffer);
1630 }
1631 
1632 
1633 ssize_t
1634 ipv4_read_avail(net_protocol* _protocol)
1635 {
1636 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1637 	RawSocket* raw = protocol->raw;
1638 	if (raw == NULL)
1639 		return B_ERROR;
1640 
1641 	return raw->AvailableData();
1642 }
1643 
1644 
1645 struct net_domain*
1646 ipv4_get_domain(net_protocol* protocol)
1647 {
1648 	return sDomain;
1649 }
1650 
1651 
1652 size_t
1653 ipv4_get_mtu(net_protocol* protocol, const struct sockaddr* address)
1654 {
1655 	net_route* route = sDatalinkModule->get_route(sDomain, address);
1656 	if (route == NULL)
1657 		return 0;
1658 
1659 	size_t mtu;
1660 	if (route->mtu != 0)
1661 		mtu = route->mtu;
1662 	else
1663 		mtu = route->interface_address->interface->mtu;
1664 
1665 	sDatalinkModule->put_route(sDomain, route);
1666 	return mtu - sizeof(ipv4_header);
1667 }
1668 
1669 
1670 status_t
1671 ipv4_receive_data(net_buffer* buffer)
1672 {
1673 	TRACE("ipv4_receive_data(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1674 
1675 	NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
1676 	if (bufferHeader.Status() != B_OK)
1677 		return bufferHeader.Status();
1678 
1679 	ipv4_header& header = bufferHeader.Data();
1680 	TRACE_ONLY(dump_ipv4_header(header));
1681 
1682 	if (header.version != IPV4_VERSION)
1683 		return B_BAD_TYPE;
1684 
1685 	uint16 packetLength = header.TotalLength();
1686 	uint16 headerLength = header.HeaderLength();
1687 	if (packetLength > buffer->size
1688 		|| headerLength < sizeof(ipv4_header))
1689 		return B_BAD_DATA;
1690 
1691 	// TODO: would be nice to have a direct checksum function somewhere
1692 	if (gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
1693 		return B_BAD_DATA;
1694 
1695 	// lower layers notion of broadcast or multicast have no relevance to us
1696 	// other than deciding whether to send an ICMP error
1697 	bool wasMulticast = (buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0;
1698 	bool notForUs = false;
1699 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1700 
1701 	sockaddr_in destination;
1702 	fill_sockaddr_in(&destination, header.destination);
1703 
1704 	if (header.destination == INADDR_BROADCAST) {
1705 		buffer->flags |= MSG_BCAST;
1706 
1707 		// Find first interface with a matching family
1708 		if (!sDatalinkModule->is_local_link_address(sDomain, true,
1709 				buffer->destination, &buffer->interface_address))
1710 			notForUs = !wasMulticast;
1711 	} else if (IN_MULTICAST(ntohl(header.destination))) {
1712 		buffer->flags |= MSG_MCAST;
1713 	} else {
1714 		uint32 matchedAddressType = 0;
1715 
1716 		// test if the packet is really for us
1717 		if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
1718 				&buffer->interface_address, &matchedAddressType)
1719 			&& !sDatalinkModule->is_local_link_address(sDomain, true,
1720 				buffer->destination, &buffer->interface_address)) {
1721 			// if the buffer was a link layer multicast, regard it as a
1722 			// broadcast, and let the upper levels decide what to do with it
1723 			if (wasMulticast)
1724 				buffer->flags |= MSG_BCAST;
1725 			else
1726 				notForUs = true;
1727 		} else {
1728 			// copy over special address types (MSG_BCAST or MSG_MCAST):
1729 			buffer->flags |= matchedAddressType;
1730 		}
1731 	}
1732 
1733 	// set net_buffer's source/destination address
1734 	fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
1735 	memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
1736 
1737 	buffer->protocol = header.protocol;
1738 
1739 	if (notForUs) {
1740 		TRACE("  ipv4_receive_data(): packet was not for us %x -> %x",
1741 			ntohl(header.source), ntohl(header.destination));
1742 
1743 		if (!wasMulticast) {
1744 			// Send ICMP error: Host unreachable
1745 			sDomain->module->error_reply(NULL, buffer, B_NET_ERROR_UNREACH_HOST,
1746 				NULL);
1747 		}
1748 
1749 		return B_ERROR;
1750 	}
1751 
1752 	// remove any trailing/padding data
1753 	status_t status = gBufferModule->trim(buffer, packetLength);
1754 	if (status != B_OK)
1755 		return status;
1756 
1757 	// check for fragmentation
1758 	uint16 fragmentOffset = header.FragmentOffset();
1759 	if ((fragmentOffset & IP_MORE_FRAGMENTS) != 0
1760 		|| (fragmentOffset & IP_FRAGMENT_OFFSET_MASK) != 0) {
1761 		// this is a fragment
1762 		TRACE("  ipv4_receive_data(): Found a Fragment!");
1763 		status = reassemble_fragments(header, &buffer);
1764 		TRACE("  ipv4_receive_data():  -> %s", strerror(status));
1765 		if (status != B_OK)
1766 			return status;
1767 
1768 		if (buffer == NULL) {
1769 			// buffer was put into fragment packet
1770 			TRACE("  ipv4_receive_data(): Not yet assembled.");
1771 			return B_OK;
1772 		}
1773 	}
1774 
1775 	// Since the buffer might have been changed (reassembled fragment)
1776 	// we must no longer access bufferHeader or header anymore after
1777 	// this point
1778 
1779 	bool rawDelivered = raw_receive_data(buffer);
1780 
1781 	// Preserve the ipv4 header for ICMP processing
1782 	gBufferModule->store_header(buffer);
1783 
1784 	bufferHeader.Remove(headerLength);
1785 		// the header is of variable size and may include IP options
1786 		// (TODO: that we ignore for now)
1787 
1788 	net_protocol_module_info* module = receiving_protocol(buffer->protocol);
1789 	if (module == NULL) {
1790 		// no handler for this packet
1791 		if (!rawDelivered) {
1792 			sDomain->module->error_reply(NULL, buffer,
1793 				B_NET_ERROR_UNREACH_PROTOCOL, NULL);
1794 		}
1795 		return EAFNOSUPPORT;
1796 	}
1797 
1798 	if ((buffer->flags & MSG_MCAST) != 0) {
1799 		// Unfortunately historical reasons dictate that the IP multicast
1800 		// model be a little different from the unicast one. We deliver
1801 		// this frame directly to all sockets registered with interest
1802 		// for this multicast group.
1803 		deliver_multicast(module, buffer, false);
1804 		gBufferModule->free(buffer);
1805 		return B_OK;
1806 	}
1807 
1808 	return module->receive_data(buffer);
1809 }
1810 
1811 
1812 status_t
1813 ipv4_deliver_data(net_protocol* _protocol, net_buffer* buffer)
1814 {
1815 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1816 
1817 	if (protocol->raw == NULL)
1818 		return B_ERROR;
1819 
1820 	return protocol->raw->EnqueueClone(buffer);
1821 }
1822 
1823 
1824 status_t
1825 ipv4_error_received(net_error error, net_buffer* buffer)
1826 {
1827 	TRACE("  ipv4_error_received(error %d, buffer %p [%" B_PRIu32 " bytes])",
1828 		(int)error, buffer, buffer->size);
1829 
1830 	NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
1831 	if (bufferHeader.Status() != B_OK)
1832 		return bufferHeader.Status();
1833 
1834 	ipv4_header& header = bufferHeader.Data();
1835 	TRACE_ONLY(dump_ipv4_header(header));
1836 
1837 	// We do not check the packet length, as we usually only get a part of it
1838 	uint16 headerLength = header.HeaderLength();
1839 	if (header.version != IPV4_VERSION
1840 		|| headerLength < sizeof(ipv4_header)
1841 		|| gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
1842 		return B_BAD_DATA;
1843 
1844 	// Restore addresses of the original buffer
1845 
1846 	// lower layers notion of broadcast or multicast have no relevance to us
1847 	// TODO: they actually have when deciding whether to send an ICMP error
1848 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1849 
1850 	fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
1851 	fill_sockaddr_in((struct sockaddr_in*)buffer->destination,
1852 		header.destination);
1853 
1854 	if (header.destination == INADDR_BROADCAST)
1855 		buffer->flags |= MSG_BCAST;
1856 	else if (IN_MULTICAST(ntohl(header.destination)))
1857 		buffer->flags |= MSG_MCAST;
1858 
1859 	// test if the packet is really from us
1860 	if (!sDatalinkModule->is_local_address(sDomain, buffer->source, NULL,
1861 			NULL)) {
1862 		TRACE("  ipv4_error_received(): packet was not for us %x -> %x",
1863 			ntohl(header.source), ntohl(header.destination));
1864 		return B_ERROR;
1865 	}
1866 
1867 	buffer->protocol = header.protocol;
1868 
1869 	bufferHeader.Remove(headerLength);
1870 
1871 	net_protocol_module_info* protocol = receiving_protocol(buffer->protocol);
1872 	if (protocol == NULL)
1873 		return B_ERROR;
1874 
1875 	// propagate error
1876 	return protocol->error_received(error, buffer);
1877 }
1878 
1879 
1880 status_t
1881 ipv4_error_reply(net_protocol* protocol, net_buffer* cause, net_error error,
1882 	net_error_data* errorData)
1883 {
1884 	// Directly obtain the ICMP protocol module
1885 	net_protocol_module_info* icmp = receiving_protocol(IPPROTO_ICMP);
1886 	if (icmp == NULL)
1887 		return B_ERROR;
1888 
1889 	return icmp->error_reply(protocol, cause, error, errorData);
1890 }
1891 
1892 
1893 ssize_t
1894 ipv4_process_ancillary_data_no_container(net_protocol* protocol,
1895 	net_buffer* buffer, void* msgControl, size_t msgControlLen)
1896 {
1897 	ssize_t bytesWritten = 0;
1898 
1899 	if ((((ipv4_protocol*)protocol)->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0) {
1900 		if (msgControlLen < CMSG_SPACE(sizeof(struct in_addr)))
1901 			return B_NO_MEMORY;
1902 
1903 		cmsghdr* messageHeader = (cmsghdr*)msgControl;
1904 		messageHeader->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1905 		messageHeader->cmsg_level = IPPROTO_IP;
1906 		messageHeader->cmsg_type = IP_RECVDSTADDR;
1907 
1908 		memcpy(CMSG_DATA(messageHeader),
1909 		 	&((struct sockaddr_in*)buffer->destination)->sin_addr,
1910 		 	sizeof(struct in_addr));
1911 
1912 		bytesWritten += CMSG_SPACE(sizeof(struct in_addr));
1913 	}
1914 
1915 	return bytesWritten;
1916 }
1917 
1918 
1919 //	#pragma mark -
1920 
1921 
1922 status_t
1923 init_ipv4()
1924 {
1925 	sPacketID = (int32)system_time();
1926 
1927 	mutex_init(&sRawSocketsLock, "raw sockets");
1928 	mutex_init(&sFragmentLock, "IPv4 Fragments");
1929 	mutex_init(&sMulticastGroupsLock, "IPv4 multicast groups");
1930 	mutex_init(&sReceivingProtocolLock, "IPv4 receiving protocols");
1931 
1932 	status_t status;
1933 
1934 	sMulticastState = new MulticastState();
1935 	if (sMulticastState == NULL) {
1936 		status = B_NO_MEMORY;
1937 		goto err4;
1938 	}
1939 
1940 	status = sMulticastState->Init();
1941 	if (status != B_OK)
1942 		goto err5;
1943 
1944 	new (&sFragmentHash) FragmentTable();
1945 	status = sFragmentHash.Init(256);
1946 	if (status != B_OK)
1947 		goto err5;
1948 
1949 	new (&sRawSockets) RawSocketList;
1950 		// static initializers do not work in the kernel,
1951 		// so we have to do it here, manually
1952 		// TODO: for modules, this shouldn't be required
1953 
1954 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_RAW, 0,
1955 		"network/protocols/ipv4/v1", NULL);
1956 	if (status != B_OK)
1957 		goto err6;
1958 
1959 	status = gStackModule->register_domain(AF_INET, "internet", &gIPv4Module,
1960 		&gIPv4AddressModule, &sDomain);
1961 	if (status != B_OK)
1962 		goto err6;
1963 
1964 	add_debugger_command("ipv4_multicast", dump_ipv4_multicast,
1965 		"list all current IPv4 multicast states");
1966 
1967 	return B_OK;
1968 
1969 err6:
1970 	sFragmentHash.~FragmentTable();
1971 err5:
1972 	delete sMulticastState;
1973 err4:
1974 	mutex_destroy(&sReceivingProtocolLock);
1975 	mutex_destroy(&sMulticastGroupsLock);
1976 	mutex_destroy(&sFragmentLock);
1977 	mutex_destroy(&sRawSocketsLock);
1978 	return status;
1979 }
1980 
1981 
1982 status_t
1983 uninit_ipv4()
1984 {
1985 	mutex_lock(&sReceivingProtocolLock);
1986 
1987 	remove_debugger_command("ipv4_multicast", dump_ipv4_multicast);
1988 
1989 	// put all the domain receiving protocols we gathered so far
1990 	for (uint32 i = 0; i < 256; i++) {
1991 		if (sReceivingProtocol[i] != NULL)
1992 			gStackModule->put_domain_receiving_protocol(sDomain, i);
1993 	}
1994 
1995 	gStackModule->unregister_domain(sDomain);
1996 	mutex_unlock(&sReceivingProtocolLock);
1997 
1998 	delete sMulticastState;
1999 	sFragmentHash.~FragmentTable();
2000 
2001 	mutex_destroy(&sMulticastGroupsLock);
2002 	mutex_destroy(&sFragmentLock);
2003 	mutex_destroy(&sRawSocketsLock);
2004 	mutex_destroy(&sReceivingProtocolLock);
2005 
2006 	return B_OK;
2007 }
2008 
2009 
2010 static status_t
2011 ipv4_std_ops(int32 op, ...)
2012 {
2013 	switch (op) {
2014 		case B_MODULE_INIT:
2015 			return init_ipv4();
2016 		case B_MODULE_UNINIT:
2017 			return uninit_ipv4();
2018 
2019 		default:
2020 			return B_ERROR;
2021 	}
2022 }
2023 
2024 
2025 net_protocol_module_info gIPv4Module = {
2026 	{
2027 		"network/protocols/ipv4/v1",
2028 		0,
2029 		ipv4_std_ops
2030 	},
2031 	NET_PROTOCOL_ATOMIC_MESSAGES,
2032 
2033 	ipv4_init_protocol,
2034 	ipv4_uninit_protocol,
2035 	ipv4_open,
2036 	ipv4_close,
2037 	ipv4_free,
2038 	ipv4_connect,
2039 	ipv4_accept,
2040 	ipv4_control,
2041 	ipv4_getsockopt,
2042 	ipv4_setsockopt,
2043 	ipv4_bind,
2044 	ipv4_unbind,
2045 	ipv4_listen,
2046 	ipv4_shutdown,
2047 	ipv4_send_data,
2048 	ipv4_send_routed_data,
2049 	ipv4_send_avail,
2050 	ipv4_read_data,
2051 	ipv4_read_avail,
2052 	ipv4_get_domain,
2053 	ipv4_get_mtu,
2054 	ipv4_receive_data,
2055 	ipv4_deliver_data,
2056 	ipv4_error_received,
2057 	ipv4_error_reply,
2058 	NULL,		// add_ancillary_data()
2059 	NULL,		// process_ancillary_data()
2060 	ipv4_process_ancillary_data_no_container,
2061 	NULL,		// send_data_no_buffer()
2062 	NULL		// read_data_no_buffer()
2063 };
2064 
2065 module_dependency module_dependencies[] = {
2066 	{NET_STACK_MODULE_NAME, (module_info**)&gStackModule},
2067 	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
2068 	{NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule},
2069 	{NET_SOCKET_MODULE_NAME, (module_info**)&sSocketModule},
2070 	{}
2071 };
2072 
2073 module_info* modules[] = {
2074 	(module_info*)&gIPv4Module,
2075 	NULL
2076 };
2077