xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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.InsertBefore(next, previous);
335 			return status;
336 		}
337 
338 		fFragments.InsertBefore(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.InsertBefore(afterNext, next);
363 			return status;
364 		}
365 
366 		fFragments.InsertBefore(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.InsertBefore(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 EADDRNOTAVAIL;
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 != NULL && 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 		if (loopbackBuffer == NULL)
1558 			return B_NO_MEMORY;
1559 		status_t status = B_ERROR;
1560 
1561 		// get the IPv4 loopback address
1562 		struct sockaddr loopbackAddress;
1563 		gIPv4AddressModule.get_loopback_address(&loopbackAddress);
1564 
1565 		// get the matching interface address if any
1566 		net_interface_address* address =
1567 			sDatalinkModule->get_interface_address(&loopbackAddress);
1568 		if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
1569 			sDatalinkModule->put_interface_address(address);
1570 		} else {
1571 			sDatalinkModule->put_interface_address(
1572 				loopbackBuffer->interface_address);
1573 			loopbackBuffer->interface_address = address;
1574 			status = ipv4_receive_data(loopbackBuffer);
1575 		}
1576 
1577 		if (status != B_OK)
1578 			gBufferModule->free(loopbackBuffer);
1579 	}
1580 
1581 	TRACE_SK(protocol, "  SendRoutedData(): header chksum: %" B_PRIu32
1582 		", buffer checksum: %" B_PRIu32,
1583 		gBufferModule->checksum(buffer, 0, sizeof(ipv4_header), true),
1584 		gBufferModule->checksum(buffer, 0, buffer->size, true));
1585 
1586 	TRACE_SK(protocol, "  SendRoutedData(): destination: %08x",
1587 		ntohl(destination.sin_addr.s_addr));
1588 
1589 	uint32 mtu = route->mtu ? route->mtu : interface->device->mtu;
1590 	if (buffer->size > mtu) {
1591 		// we need to fragment the packet
1592 		return send_fragments(protocol, route, buffer, mtu);
1593 	}
1594 
1595 	return sDatalinkModule->send_routed_data(route, buffer);
1596 }
1597 
1598 
1599 status_t
1600 ipv4_send_data(net_protocol* _protocol, net_buffer* buffer)
1601 {
1602 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1603 
1604 	TRACE_SK(protocol, "SendData(%p [%" B_PRIu32 " bytes])", buffer,
1605 		buffer->size);
1606 
1607 	if (protocol != NULL && (protocol->flags & IP_FLAG_HEADER_INCLUDED)) {
1608 		if (buffer->size < sizeof(ipv4_header))
1609 			return B_BAD_VALUE;
1610 
1611 		sockaddr_in* source = (sockaddr_in*)buffer->source;
1612 		sockaddr_in* destination = (sockaddr_in*)buffer->destination;
1613 
1614 		fill_sockaddr_in(source, *NetBufferField<in_addr_t,
1615 			offsetof(ipv4_header, source)>(buffer));
1616 		fill_sockaddr_in(destination, *NetBufferField<in_addr_t,
1617 			offsetof(ipv4_header, destination)>(buffer));
1618 	}
1619 
1620 	// handle IP_MULTICAST_IF
1621 	if (IN_MULTICAST(ntohl(
1622 			((sockaddr_in*)buffer->destination)->sin_addr.s_addr))
1623 		&& protocol != NULL && protocol->multicast_address != NULL) {
1624 		net_interface_address* address = sDatalinkModule->get_interface_address(
1625 			protocol->multicast_address);
1626 		if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
1627 			sDatalinkModule->put_interface_address(address);
1628 			return EADDRNOTAVAIL;
1629 		}
1630 
1631 		sDatalinkModule->put_interface_address(buffer->interface_address);
1632 		buffer->interface_address = address;
1633 			// the buffer takes over ownership of the address
1634 
1635 		net_route* route = sDatalinkModule->get_route(sDomain, address->local);
1636 		if (route == NULL)
1637 			return ENETUNREACH;
1638 
1639 		return sDatalinkModule->send_routed_data(route, buffer);
1640 	}
1641 
1642 	return sDatalinkModule->send_data(protocol, sDomain, buffer);
1643 }
1644 
1645 
1646 ssize_t
1647 ipv4_send_avail(net_protocol* protocol)
1648 {
1649 	return B_ERROR;
1650 }
1651 
1652 
1653 status_t
1654 ipv4_read_data(net_protocol* _protocol, size_t numBytes, uint32 flags,
1655 	net_buffer** _buffer)
1656 {
1657 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1658 	RawSocket* raw = protocol->raw;
1659 	if (raw == NULL)
1660 		return B_ERROR;
1661 
1662 	TRACE_SK(protocol, "ReadData(%lu, 0x%" B_PRIx32 ")", numBytes, flags);
1663 
1664 	return raw->Dequeue(flags, _buffer);
1665 }
1666 
1667 
1668 ssize_t
1669 ipv4_read_avail(net_protocol* _protocol)
1670 {
1671 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1672 	RawSocket* raw = protocol->raw;
1673 	if (raw == NULL)
1674 		return B_ERROR;
1675 
1676 	return raw->AvailableData();
1677 }
1678 
1679 
1680 struct net_domain*
1681 ipv4_get_domain(net_protocol* protocol)
1682 {
1683 	return sDomain;
1684 }
1685 
1686 
1687 size_t
1688 ipv4_get_mtu(net_protocol* protocol, const struct sockaddr* address)
1689 {
1690 	net_route* route = sDatalinkModule->get_route(sDomain, address);
1691 	if (route == NULL)
1692 		return 0;
1693 
1694 	size_t mtu;
1695 	if (route->mtu != 0)
1696 		mtu = route->mtu;
1697 	else
1698 		mtu = route->interface_address->interface->device->mtu;
1699 
1700 	sDatalinkModule->put_route(sDomain, route);
1701 	return mtu - sizeof(ipv4_header);
1702 }
1703 
1704 
1705 status_t
1706 ipv4_receive_data(net_buffer* buffer)
1707 {
1708 	TRACE("ipv4_receive_data(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1709 
1710 	NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
1711 	if (bufferHeader.Status() != B_OK)
1712 		return bufferHeader.Status();
1713 
1714 	ipv4_header& header = bufferHeader.Data();
1715 	TRACE_ONLY(dump_ipv4_header(header));
1716 
1717 	if (header.version != IPV4_VERSION)
1718 		return B_BAD_TYPE;
1719 
1720 	uint16 packetLength = header.TotalLength();
1721 	uint16 headerLength = header.HeaderLength();
1722 	if (packetLength > buffer->size
1723 		|| headerLength < sizeof(ipv4_header))
1724 		return B_BAD_DATA;
1725 
1726 	// TODO: would be nice to have a direct checksum function somewhere
1727 	if (gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
1728 		return B_BAD_DATA;
1729 
1730 	// lower layers notion of broadcast or multicast have no relevance to us
1731 	// other than deciding whether to send an ICMP error
1732 	bool wasMulticast = (buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0;
1733 	bool notForUs = false;
1734 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1735 
1736 	sockaddr_in destination;
1737 	fill_sockaddr_in(&destination, header.destination);
1738 
1739 	if (header.destination == INADDR_BROADCAST) {
1740 		buffer->flags |= MSG_BCAST;
1741 
1742 		// Find first interface with a matching family
1743 		if (!sDatalinkModule->is_local_link_address(sDomain, true,
1744 				buffer->destination, &buffer->interface_address))
1745 			notForUs = !wasMulticast;
1746 	} else if (IN_MULTICAST(ntohl(header.destination))) {
1747 		buffer->flags |= MSG_MCAST;
1748 	} else {
1749 		uint32 matchedAddressType = 0;
1750 
1751 		// test if the packet is really for us
1752 		if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
1753 				&buffer->interface_address, &matchedAddressType)
1754 			&& !sDatalinkModule->is_local_link_address(sDomain, true,
1755 				buffer->destination, &buffer->interface_address)) {
1756 			// if the buffer was a link layer multicast, regard it as a
1757 			// broadcast, and let the upper levels decide what to do with it
1758 			if (wasMulticast)
1759 				buffer->flags |= MSG_BCAST;
1760 			else
1761 				notForUs = true;
1762 		} else {
1763 			// copy over special address types (MSG_BCAST or MSG_MCAST):
1764 			buffer->flags |= matchedAddressType;
1765 		}
1766 	}
1767 
1768 	// set net_buffer's source/destination address
1769 	fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
1770 	memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
1771 
1772 	buffer->protocol = header.protocol;
1773 
1774 	if (notForUs) {
1775 		TRACE("  ipv4_receive_data(): packet was not for us %x -> %x",
1776 			ntohl(header.source), ntohl(header.destination));
1777 
1778 		if (!wasMulticast) {
1779 			// Send ICMP error: Host unreachable
1780 			sDomain->module->error_reply(NULL, buffer, B_NET_ERROR_UNREACH_HOST,
1781 				NULL);
1782 		}
1783 
1784 		return B_ERROR;
1785 	}
1786 
1787 	// remove any trailing/padding data
1788 	status_t status = gBufferModule->trim(buffer, packetLength);
1789 	if (status != B_OK)
1790 		return status;
1791 
1792 	// check for fragmentation
1793 	uint16 fragmentOffset = header.FragmentOffset();
1794 	if ((fragmentOffset & IP_MORE_FRAGMENTS) != 0
1795 		|| (fragmentOffset & IP_FRAGMENT_OFFSET_MASK) != 0) {
1796 		// this is a fragment
1797 		TRACE("  ipv4_receive_data(): Found a Fragment!");
1798 		status = reassemble_fragments(header, &buffer);
1799 		TRACE("  ipv4_receive_data():  -> %s", strerror(status));
1800 		if (status != B_OK)
1801 			return status;
1802 
1803 		if (buffer == NULL) {
1804 			// buffer was put into fragment packet
1805 			TRACE("  ipv4_receive_data(): Not yet assembled.");
1806 			return B_OK;
1807 		}
1808 	}
1809 
1810 	// Since the buffer might have been changed (reassembled fragment)
1811 	// we must no longer access bufferHeader or header anymore after
1812 	// this point
1813 
1814 	bool rawDelivered = raw_receive_data(buffer);
1815 
1816 	// Preserve the ipv4 header for ICMP processing
1817 	gBufferModule->store_header(buffer);
1818 
1819 	bufferHeader.Remove(headerLength);
1820 		// the header is of variable size and may include IP options
1821 		// (TODO: that we ignore for now)
1822 
1823 	net_protocol_module_info* module = receiving_protocol(buffer->protocol);
1824 	if (module == NULL) {
1825 		// no handler for this packet
1826 		if (!rawDelivered) {
1827 			sDomain->module->error_reply(NULL, buffer,
1828 				B_NET_ERROR_UNREACH_PROTOCOL, NULL);
1829 		}
1830 		return EAFNOSUPPORT;
1831 	}
1832 
1833 	if ((buffer->flags & MSG_MCAST) != 0) {
1834 		// Unfortunately historical reasons dictate that the IP multicast
1835 		// model be a little different from the unicast one. We deliver
1836 		// this frame directly to all sockets registered with interest
1837 		// for this multicast group.
1838 		deliver_multicast(module, buffer, false);
1839 		gBufferModule->free(buffer);
1840 		return B_OK;
1841 	}
1842 
1843 	return module->receive_data(buffer);
1844 }
1845 
1846 
1847 status_t
1848 ipv4_deliver_data(net_protocol* _protocol, net_buffer* buffer)
1849 {
1850 	ipv4_protocol* protocol = (ipv4_protocol*)_protocol;
1851 
1852 	if (protocol->raw == NULL)
1853 		return B_ERROR;
1854 
1855 	return protocol->raw->EnqueueClone(buffer);
1856 }
1857 
1858 
1859 status_t
1860 ipv4_error_received(net_error error, net_buffer* buffer)
1861 {
1862 	TRACE("  ipv4_error_received(error %d, buffer %p [%" B_PRIu32 " bytes])",
1863 		(int)error, buffer, buffer->size);
1864 
1865 	NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
1866 	if (bufferHeader.Status() != B_OK)
1867 		return bufferHeader.Status();
1868 
1869 	ipv4_header& header = bufferHeader.Data();
1870 	TRACE_ONLY(dump_ipv4_header(header));
1871 
1872 	// We do not check the packet length, as we usually only get a part of it
1873 	uint16 headerLength = header.HeaderLength();
1874 	if (header.version != IPV4_VERSION
1875 		|| headerLength < sizeof(ipv4_header)
1876 		|| gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
1877 		return B_BAD_DATA;
1878 
1879 	// Restore addresses of the original buffer
1880 
1881 	// lower layers notion of broadcast or multicast have no relevance to us
1882 	// TODO: they actually have when deciding whether to send an ICMP error
1883 	buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
1884 
1885 	fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
1886 	fill_sockaddr_in((struct sockaddr_in*)buffer->destination,
1887 		header.destination);
1888 
1889 	if (header.destination == INADDR_BROADCAST)
1890 		buffer->flags |= MSG_BCAST;
1891 	else if (IN_MULTICAST(ntohl(header.destination)))
1892 		buffer->flags |= MSG_MCAST;
1893 
1894 	// test if the packet is really from us
1895 	if (!sDatalinkModule->is_local_address(sDomain, buffer->source, NULL,
1896 			NULL)) {
1897 		TRACE("  ipv4_error_received(): packet was not for us %x -> %x",
1898 			ntohl(header.source), ntohl(header.destination));
1899 		return B_ERROR;
1900 	}
1901 
1902 	buffer->protocol = header.protocol;
1903 
1904 	bufferHeader.Remove(headerLength);
1905 
1906 	net_protocol_module_info* protocol = receiving_protocol(buffer->protocol);
1907 	if (protocol == NULL)
1908 		return B_ERROR;
1909 
1910 	// propagate error
1911 	return protocol->error_received(error, buffer);
1912 }
1913 
1914 
1915 status_t
1916 ipv4_error_reply(net_protocol* protocol, net_buffer* cause, net_error error,
1917 	net_error_data* errorData)
1918 {
1919 	// Directly obtain the ICMP protocol module
1920 	net_protocol_module_info* icmp = receiving_protocol(IPPROTO_ICMP);
1921 	if (icmp == NULL)
1922 		return B_ERROR;
1923 
1924 	return icmp->error_reply(protocol, cause, error, errorData);
1925 }
1926 
1927 
1928 ssize_t
1929 ipv4_process_ancillary_data_no_container(net_protocol* protocol,
1930 	net_buffer* buffer, void* msgControl, size_t msgControlLen)
1931 {
1932 	ssize_t bytesWritten = 0;
1933 
1934 	if ((((ipv4_protocol*)protocol)->flags & IP_FLAG_RECEIVE_DEST_ADDR) != 0) {
1935 		if (msgControlLen < CMSG_SPACE(sizeof(struct in_addr)))
1936 			return B_NO_MEMORY;
1937 
1938 		cmsghdr* messageHeader = (cmsghdr*)msgControl;
1939 		messageHeader->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1940 		messageHeader->cmsg_level = IPPROTO_IP;
1941 		messageHeader->cmsg_type = IP_RECVDSTADDR;
1942 
1943 		memcpy(CMSG_DATA(messageHeader),
1944 		 	&((struct sockaddr_in*)buffer->destination)->sin_addr,
1945 		 	sizeof(struct in_addr));
1946 
1947 		bytesWritten += CMSG_SPACE(sizeof(struct in_addr));
1948 	}
1949 
1950 	return bytesWritten;
1951 }
1952 
1953 
1954 //	#pragma mark -
1955 
1956 
1957 status_t
1958 init_ipv4()
1959 {
1960 	sPacketID = (int32)system_time();
1961 
1962 	mutex_init(&sRawSocketsLock, "raw sockets");
1963 	mutex_init(&sFragmentLock, "IPv4 Fragments");
1964 	mutex_init(&sMulticastGroupsLock, "IPv4 multicast groups");
1965 	mutex_init(&sReceivingProtocolLock, "IPv4 receiving protocols");
1966 
1967 	status_t status;
1968 
1969 	sMulticastState = new MulticastState();
1970 	if (sMulticastState == NULL) {
1971 		status = B_NO_MEMORY;
1972 		goto err4;
1973 	}
1974 
1975 	status = sMulticastState->Init();
1976 	if (status != B_OK)
1977 		goto err5;
1978 
1979 	new (&sFragmentHash) FragmentTable();
1980 	status = sFragmentHash.Init(256);
1981 	if (status != B_OK)
1982 		goto err5;
1983 
1984 	new (&sRawSockets) RawSocketList;
1985 		// static initializers do not work in the kernel,
1986 		// so we have to do it here, manually
1987 		// TODO: for modules, this shouldn't be required
1988 
1989 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_RAW, 0,
1990 		"network/protocols/ipv4/v1", NULL);
1991 	if (status != B_OK)
1992 		goto err6;
1993 
1994 	status = gStackModule->register_domain(AF_INET, "internet", &gIPv4Module,
1995 		&gIPv4AddressModule, &sDomain);
1996 	if (status != B_OK)
1997 		goto err6;
1998 
1999 	add_debugger_command("ipv4_multicast", dump_ipv4_multicast,
2000 		"list all current IPv4 multicast states");
2001 
2002 	return B_OK;
2003 
2004 err6:
2005 	sFragmentHash.~FragmentTable();
2006 err5:
2007 	delete sMulticastState;
2008 err4:
2009 	mutex_destroy(&sReceivingProtocolLock);
2010 	mutex_destroy(&sMulticastGroupsLock);
2011 	mutex_destroy(&sFragmentLock);
2012 	mutex_destroy(&sRawSocketsLock);
2013 	return status;
2014 }
2015 
2016 
2017 status_t
2018 uninit_ipv4()
2019 {
2020 	mutex_lock(&sReceivingProtocolLock);
2021 
2022 	remove_debugger_command("ipv4_multicast", dump_ipv4_multicast);
2023 
2024 	// put all the domain receiving protocols we gathered so far
2025 	for (uint32 i = 0; i < 256; i++) {
2026 		if (sReceivingProtocol[i] != NULL)
2027 			gStackModule->put_domain_receiving_protocol(sDomain, i);
2028 	}
2029 
2030 	gStackModule->unregister_domain(sDomain);
2031 	mutex_unlock(&sReceivingProtocolLock);
2032 
2033 	delete sMulticastState;
2034 	sFragmentHash.~FragmentTable();
2035 
2036 	mutex_destroy(&sMulticastGroupsLock);
2037 	mutex_destroy(&sFragmentLock);
2038 	mutex_destroy(&sRawSocketsLock);
2039 	mutex_destroy(&sReceivingProtocolLock);
2040 
2041 	return B_OK;
2042 }
2043 
2044 
2045 static status_t
2046 ipv4_std_ops(int32 op, ...)
2047 {
2048 	switch (op) {
2049 		case B_MODULE_INIT:
2050 			return init_ipv4();
2051 		case B_MODULE_UNINIT:
2052 			return uninit_ipv4();
2053 
2054 		default:
2055 			return B_ERROR;
2056 	}
2057 }
2058 
2059 
2060 net_protocol_module_info gIPv4Module = {
2061 	{
2062 		"network/protocols/ipv4/v1",
2063 		0,
2064 		ipv4_std_ops
2065 	},
2066 	NET_PROTOCOL_ATOMIC_MESSAGES,
2067 
2068 	ipv4_init_protocol,
2069 	ipv4_uninit_protocol,
2070 	ipv4_open,
2071 	ipv4_close,
2072 	ipv4_free,
2073 	ipv4_connect,
2074 	ipv4_accept,
2075 	ipv4_control,
2076 	ipv4_getsockopt,
2077 	ipv4_setsockopt,
2078 	ipv4_bind,
2079 	ipv4_unbind,
2080 	ipv4_listen,
2081 	ipv4_shutdown,
2082 	ipv4_send_data,
2083 	ipv4_send_routed_data,
2084 	ipv4_send_avail,
2085 	ipv4_read_data,
2086 	ipv4_read_avail,
2087 	ipv4_get_domain,
2088 	ipv4_get_mtu,
2089 	ipv4_receive_data,
2090 	ipv4_deliver_data,
2091 	ipv4_error_received,
2092 	ipv4_error_reply,
2093 	NULL,		// add_ancillary_data()
2094 	NULL,		// process_ancillary_data()
2095 	ipv4_process_ancillary_data_no_container,
2096 	NULL,		// send_data_no_buffer()
2097 	NULL		// read_data_no_buffer()
2098 };
2099 
2100 module_dependency module_dependencies[] = {
2101 	{NET_STACK_MODULE_NAME, (module_info**)&gStackModule},
2102 	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
2103 	{NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule},
2104 	{NET_SOCKET_MODULE_NAME, (module_info**)&sSocketModule},
2105 	{}
2106 };
2107 
2108 module_info* modules[] = {
2109 	(module_info*)&gIPv4Module,
2110 	NULL
2111 };
2112