xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 4b3b81da9e459443d75329cfd08bc9a57ad02653)
1 /*
2  * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe, zooey@hirschkaefer.de
7  *		Hugo Santos, hugosantos@gmail.com
8  */
9 
10 
11 #include <net_buffer.h>
12 #include <net_datalink.h>
13 #include <net_protocol.h>
14 #include <net_stack.h>
15 
16 #include <lock.h>
17 #include <util/AutoLock.h>
18 #include <util/DoublyLinkedList.h>
19 #include <util/OpenHashTable.h>
20 
21 #include <KernelExport.h>
22 
23 #include <NetBufferUtilities.h>
24 #include <NetUtilities.h>
25 #include <ProtocolUtilities.h>
26 
27 #include <netinet/in.h>
28 #include <new>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <utility>
32 
33 
34 // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
35 //      lock before holding a child UdpEndpoint's lock. This restriction
36 //      is dictated by the receive path as blind access to the endpoint
37 //      hash is required when holding the DomainSuppport's lock.
38 
39 
40 //#define TRACE_UDP
41 #ifdef TRACE_UDP
42 #	define TRACE_BLOCK(x) dump_block x
43 // do not remove the space before ', ##args' if you want this
44 // to compile with gcc 2.95
45 #	define TRACE_EP(format, args...)	dprintf("UDP [%llu] %p " format "\n", \
46 		system_time(), this , ##args)
47 #	define TRACE_EPM(format, args...)	dprintf("UDP [%llu] " format "\n", \
48 		system_time() , ##args)
49 #	define TRACE_DOMAIN(format, args...)	dprintf("UDP [%llu] (%d) " format \
50 		"\n", system_time(), Domain()->family , ##args)
51 #else
52 #	define TRACE_BLOCK(x)
53 #	define TRACE_EP(args...)	do { } while (0)
54 #	define TRACE_EPM(args...)	do { } while (0)
55 #	define TRACE_DOMAIN(args...)	do { } while (0)
56 #endif
57 
58 
59 struct udp_header {
60 	uint16 source_port;
61 	uint16 destination_port;
62 	uint16 udp_length;
63 	uint16 udp_checksum;
64 } _PACKED;
65 
66 
67 typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
68 	UDPChecksumField;
69 
70 class UdpDomainSupport;
71 
72 class UdpEndpoint : public net_protocol, public DatagramSocket<> {
73 public:
74 	UdpEndpoint(net_socket *socket);
75 
76 	status_t				Bind(const sockaddr *newAddr);
77 	status_t				Unbind(sockaddr *newAddr);
78 	status_t				Connect(const sockaddr *newAddr);
79 
80 	status_t				Open();
81 	status_t				Close();
82 	status_t				Free();
83 
84 	status_t				SendRoutedData(net_buffer *buffer, net_route *route);
85 	status_t				SendData(net_buffer *buffer);
86 
87 	ssize_t					BytesAvailable();
88 	status_t				FetchData(size_t numBytes, uint32 flags,
89 								net_buffer **_buffer);
90 
91 	status_t				StoreData(net_buffer *buffer);
92 	status_t				DeliverData(net_buffer *buffer);
93 
94 	// only the domain support will change/check the Active flag so
95 	// we don't really need to protect it with the socket lock.
96 	bool					IsActive() const { return fActive; }
97 	void					SetActive(bool newValue) { fActive = newValue; }
98 
99 	HashTableLink<UdpEndpoint> *HashTableLink() { return &fLink; }
100 
101 private:
102 	UdpDomainSupport		*fManager;
103 	bool					fActive;
104 								// an active UdpEndpoint is part of the endpoint
105 								// hash (and it is bound and optionally connected)
106 
107 	::HashTableLink<UdpEndpoint> fLink;
108 };
109 
110 
111 class UdpDomainSupport;
112 
113 struct UdpHashDefinition {
114 	typedef net_address_module_info ParentType;
115 	typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
116 	typedef UdpEndpoint ValueType;
117 
118 	UdpHashDefinition(net_address_module_info *_module)
119 		: module(_module) {}
120 	UdpHashDefinition(const UdpHashDefinition& definition)
121 		: module(definition.module) {}
122 
123 	size_t HashKey(const KeyType &key) const
124 	{
125 		return _Mix(module->hash_address_pair(key.first, key.second));
126 	}
127 
128 	size_t Hash(UdpEndpoint *endpoint) const
129 	{
130 		return _Mix(endpoint->LocalAddress().HashPair(*endpoint->PeerAddress()));
131 	}
132 
133 	static size_t _Mix(size_t hash)
134 	{
135 		// move the bits into the relevant range (as defined by kNumHashBuckets):
136 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
137 			^ (hash & 0xFFC00000UL) >> 22;
138 	}
139 
140 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
141 	{
142 		return endpoint->LocalAddress().EqualTo(key.first, true)
143 			&& endpoint->PeerAddress().EqualTo(key.second, true);
144 	}
145 
146 	HashTableLink<UdpEndpoint> *GetLink(UdpEndpoint *endpoint) const
147 	{
148 		return endpoint->HashTableLink();
149 	}
150 
151 	net_address_module_info *module;
152 };
153 
154 
155 class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
156 public:
157 	UdpDomainSupport(net_domain *domain);
158 	~UdpDomainSupport();
159 
160 	status_t InitCheck() const;
161 
162 	net_domain *Domain() const { return fDomain; }
163 
164 	void Ref() { fEndpointCount++; }
165 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
166 
167 	status_t DemuxIncomingBuffer(net_buffer *buffer);
168 
169 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
170 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
171 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
172 
173 	void DumpEndpoints() const;
174 
175 private:
176 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
177 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
178 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
179 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
180 
181 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
182 		const sockaddr *peerAddress);
183 	status_t _DemuxBroadcast(net_buffer *buffer);
184 	status_t _DemuxUnicast(net_buffer *buffer);
185 
186 	uint16 _GetNextEphemeral();
187 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
188 
189 	net_address_module_info *AddressModule() const
190 		{ return fDomain->address_module; }
191 
192 	typedef OpenHashTable<UdpHashDefinition, false> EndpointTable;
193 
194 	benaphore		fLock;
195 	net_domain		*fDomain;
196 	uint16			fLastUsedEphemeral;
197 	EndpointTable	fActiveEndpoints;
198 	uint32			fEndpointCount;
199 
200 	static const uint16		kFirst = 49152;
201 	static const uint16		kLast = 65535;
202 	static const uint32		kNumHashBuckets = 0x800;
203 							// if you change this, adjust the shifting in
204 							// Hash() accordingly!
205 };
206 
207 
208 typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
209 
210 
211 class UdpEndpointManager {
212 public:
213 	UdpEndpointManager();
214 	~UdpEndpointManager();
215 
216 	status_t		ReceiveData(net_buffer *buffer);
217 	status_t		Deframe(net_buffer *buffer);
218 
219 	UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
220 	status_t FreeEndpoint(UdpDomainSupport *domain);
221 
222 	status_t		InitCheck() const;
223 
224 	static int DumpEndpoints(int argc, char *argv[]);
225 
226 private:
227 	UdpDomainSupport *_GetDomain(net_domain *domain, bool create);
228 
229 	benaphore		fLock;
230 	status_t		fStatus;
231 	UdpDomainList	fDomains;
232 };
233 
234 
235 static UdpEndpointManager *sUdpEndpointManager;
236 
237 net_buffer_module_info *gBufferModule;
238 net_datalink_module_info *gDatalinkModule;
239 net_stack_module_info *gStackModule;
240 
241 
242 // #pragma mark -
243 
244 
245 UdpDomainSupport::UdpDomainSupport(net_domain *domain)
246 	:
247 	fDomain(domain),
248 	fActiveEndpoints(domain->address_module, kNumHashBuckets),
249 	fEndpointCount(0)
250 {
251 	benaphore_init(&fLock, "udp domain");
252 
253 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
254 }
255 
256 
257 UdpDomainSupport::~UdpDomainSupport()
258 {
259 	benaphore_destroy(&fLock);
260 }
261 
262 
263 status_t
264 UdpDomainSupport::InitCheck() const
265 {
266 	if (fLock.sem < B_OK)
267 		return fLock.sem;
268 
269 	return fActiveEndpoints.InitCheck();
270 }
271 
272 
273 status_t
274 UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
275 {
276 	// NOTE multicast is delivered directly to the endpoint
277 
278 	BenaphoreLocker _(fLock);
279 
280 	if (buffer->flags & MSG_BCAST)
281 		return _DemuxBroadcast(buffer);
282 	else if (buffer->flags & MSG_MCAST)
283 		return B_ERROR;
284 
285 	return _DemuxUnicast(buffer);
286 }
287 
288 
289 status_t
290 UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
291 	const sockaddr *address)
292 {
293 	BenaphoreLocker _(fLock);
294 
295 	if (endpoint->IsActive())
296 		return EINVAL;
297 
298 	return _BindEndpoint(endpoint, address);
299 }
300 
301 
302 status_t
303 UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
304 	const sockaddr *address)
305 {
306 	BenaphoreLocker _(fLock);
307 
308 	if (endpoint->IsActive()) {
309 		fActiveEndpoints.Remove(endpoint);
310 		endpoint->SetActive(false);
311 	}
312 
313 	if (address->sa_family == AF_UNSPEC) {
314 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
315 		// so we reset the peer address:
316 		endpoint->PeerAddress().SetToEmpty();
317 	} else {
318 		status_t status = endpoint->PeerAddress().SetTo(address);
319 		if (status < B_OK)
320 			return status;
321 	}
322 
323 	// we need to activate no matter whether or not we have just disconnected,
324 	// as calling connect() always triggers an implicit bind():
325 	return _BindEndpoint(endpoint, *endpoint->LocalAddress());
326 }
327 
328 
329 status_t
330 UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
331 {
332 	BenaphoreLocker _(fLock);
333 
334 	if (endpoint->IsActive())
335 		fActiveEndpoints.Remove(endpoint);
336 
337 	endpoint->SetActive(false);
338 
339 	return B_OK;
340 }
341 
342 
343 void
344 UdpDomainSupport::DumpEndpoints() const
345 {
346 	kprintf("-------- UDP Domain %p ---------\n", this);
347 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
348 
349 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
350 
351 	while (it.HasNext()) {
352 		UdpEndpoint *endpoint = it.Next();
353 
354 		char localBuf[64], peerBuf[64];
355 		endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true);
356 		endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true);
357 
358 		kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf,
359 			endpoint->AvailableData());
360 	}
361 }
362 
363 
364 status_t
365 UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
366 	const sockaddr *address)
367 {
368 	if (AddressModule()->get_port(address) == 0)
369 		return _BindToEphemeral(endpoint, address);
370 
371 	return _Bind(endpoint, address);
372 }
373 
374 
375 status_t
376 UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
377 {
378 	int socketOptions = endpoint->Socket()->options;
379 
380 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
381 
382 	// Iterate over all active UDP-endpoints and check if the requested bind
383 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
384 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
385 		address, true).Data());
386 
387 	while (it.HasNext()) {
388 		UdpEndpoint *otherEndpoint = it.Next();
389 
390 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
391 			ntohs(otherEndpoint->LocalAddress().Port()));
392 
393 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
394 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
395 			if (otherEndpoint->Socket()->options & (SO_REUSEADDR | SO_REUSEPORT) == 0
396 				|| socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0)
397 				return EADDRINUSE;
398 
399 			// if both addresses are the same, SO_REUSEPORT is required:
400 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
401 				&& (otherEndpoint->Socket()->options & SO_REUSEPORT == 0
402 					|| socketOptions & SO_REUSEPORT == 0))
403 				return EADDRINUSE;
404 		}
405 	}
406 
407 	return _FinishBind(endpoint, address);
408 }
409 
410 
411 status_t
412 UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
413 	const sockaddr *address)
414 {
415 	SocketAddressStorage newAddress(AddressModule());
416 	status_t status = newAddress.SetTo(address);
417 	if (status < B_OK)
418 		return status;
419 
420 	uint16 allocedPort = _GetNextEphemeral();
421 	if (allocedPort == 0)
422 		return ENOBUFS;
423 
424 	newAddress.SetPort(allocedPort);
425 
426 	return _FinishBind(endpoint, *newAddress);
427 }
428 
429 
430 status_t
431 UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
432 {
433 	status_t status = endpoint->next->module->bind(endpoint->next, address);
434 	if (status < B_OK)
435 		return status;
436 
437 	fActiveEndpoints.Insert(endpoint);
438 	endpoint->SetActive(true);
439 
440 	return B_OK;
441 }
442 
443 
444 UdpEndpoint *
445 UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
446 	const sockaddr *peerAddress)
447 {
448 	TRACE_DOMAIN("finding Endpoint for %s -> %s",
449 		AddressString(fDomain, ourAddress, true).Data(),
450 		AddressString(fDomain, peerAddress, true).Data());
451 
452 	return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress));
453 }
454 
455 
456 status_t
457 UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer)
458 {
459 	sockaddr *peerAddr = buffer->source;
460 	sockaddr *broadcastAddr = buffer->destination;
461 	sockaddr *mask = NULL;
462 	if (buffer->interface)
463 		mask = (sockaddr *)buffer->interface->mask;
464 
465 	TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer);
466 
467 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
468 
469 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
470 
471 	while (it.HasNext()) {
472 		UdpEndpoint *endpoint = it.Next();
473 
474 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
475 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
476 
477 		if (endpoint->LocalAddress().Port() != incomingPort) {
478 			// ports don't match, so we do not dispatch to this endpoint...
479 			continue;
480 		}
481 
482 		if (!endpoint->PeerAddress().IsEmpty(true)) {
483 			// endpoint is connected to a specific destination, we check if
484 			// this datagram is from there:
485 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
486 				// no, datagram is from another peer, so we do not dispatch to
487 				// this endpoint...
488 				continue;
489 			}
490 		}
491 
492 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
493 			|| endpoint->LocalAddress().IsEmpty(false)) {
494 			// address matches, dispatch to this endpoint:
495 			endpoint->StoreData(buffer);
496 		}
497 	}
498 
499 	return B_OK;
500 }
501 
502 
503 status_t
504 UdpDomainSupport::_DemuxUnicast(net_buffer *buffer)
505 {
506 	struct sockaddr *peerAddr = buffer->source;
507 	struct sockaddr *localAddr = buffer->destination;
508 
509 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
510 
511 	UdpEndpoint *endpoint;
512 	// look for full (most special) match:
513 	endpoint = _FindActiveEndpoint(localAddr, peerAddr);
514 	if (!endpoint) {
515 		// look for endpoint matching local address & port:
516 		endpoint = _FindActiveEndpoint(localAddr, NULL);
517 		if (!endpoint) {
518 			// look for endpoint matching peer address & port and local port:
519 			SocketAddressStorage local(AddressModule());
520 			local.SetToEmpty();
521 			local.SetPort(AddressModule()->get_port(localAddr));
522 			endpoint = _FindActiveEndpoint(*local, peerAddr);
523 			if (!endpoint) {
524 				// last chance: look for endpoint matching local port only:
525 				endpoint = _FindActiveEndpoint(*local, NULL);
526 			}
527 		}
528 	}
529 
530 	if (!endpoint)
531 		return B_NAME_NOT_FOUND;
532 
533 	endpoint->StoreData(buffer);
534 	return B_OK;
535 }
536 
537 
538 uint16
539 UdpDomainSupport::_GetNextEphemeral()
540 {
541 	uint16 stop, curr;
542 	if (fLastUsedEphemeral < kLast) {
543 		stop = fLastUsedEphemeral;
544 		curr = fLastUsedEphemeral + 1;
545 	} else {
546 		stop = kLast;
547 		curr = kFirst;
548 	}
549 
550 	// TODO: a free list could be used to avoid the impact of these
551 	//       two nested loops most of the time... let's see how bad this really is
552 
553 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
554 		fLastUsedEphemeral, curr, stop);
555 
556 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
557 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
558 
559 		if (_EndpointWithPort(htons(curr)) == NULL) {
560 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
561 			fLastUsedEphemeral = curr;
562 			return curr;
563 		}
564 	}
565 
566 	return 0;
567 }
568 
569 
570 UdpEndpoint *
571 UdpDomainSupport::_EndpointWithPort(uint16 port) const
572 {
573 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
574 
575 	while (it.HasNext()) {
576 		UdpEndpoint *endpoint = it.Next();
577 		if (endpoint->LocalAddress().Port() == port)
578 			return endpoint;
579 	}
580 
581 	return NULL;
582 }
583 
584 
585 // #pragma mark -
586 
587 
588 UdpEndpointManager::UdpEndpointManager()
589 {
590 	fStatus = benaphore_init(&fLock, "UDP endpoints");
591 }
592 
593 
594 UdpEndpointManager::~UdpEndpointManager()
595 {
596 	benaphore_destroy(&fLock);
597 }
598 
599 
600 status_t
601 UdpEndpointManager::InitCheck() const
602 {
603 	return fStatus;
604 }
605 
606 
607 int
608 UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
609 {
610 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
611 
612 	while (it.HasNext())
613 		it.Next()->DumpEndpoints();
614 
615 	return 0;
616 }
617 
618 
619 // #pragma mark - inbound
620 
621 
622 status_t
623 UdpEndpointManager::ReceiveData(net_buffer *buffer)
624 {
625 	status_t status = Deframe(buffer);
626 	if (status < B_OK)
627 		return status;
628 
629 	TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
630 
631 	net_domain *domain = buffer->interface->domain;
632 
633 	UdpDomainSupport *domainSupport = NULL;
634 
635 	{
636 		BenaphoreLocker _(fLock);
637 		domainSupport = _GetDomain(domain, false);
638 		// TODO we don't want to hold to the manager's lock
639 		//      during the whole RX path, we may not hold an
640 		//      endpoint's lock with the manager lock held.
641 		//      But we should increase the domain's refcount
642 		//      here.
643 	}
644 
645 	if (domainSupport == NULL) {
646 		// we don't instantiate domain supports in the
647 		// RX path as we are only interested in delivering
648 		// data to existing sockets.
649 		return B_ERROR;
650 	}
651 
652 	status = domainSupport->DemuxIncomingBuffer(buffer);
653 	if (status < B_OK) {
654 		TRACE_EPM("  ReceiveData(): no endpoint.");
655 		// TODO: send ICMP-error
656 		return B_ERROR;
657 	}
658 
659 	gBufferModule->free(buffer);
660 	return B_OK;
661 }
662 
663 
664 status_t
665 UdpEndpointManager::Deframe(net_buffer *buffer)
666 {
667 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
668 
669 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
670 	if (bufferHeader.Status() < B_OK)
671 		return bufferHeader.Status();
672 
673 	udp_header &header = bufferHeader.Data();
674 
675 	if (buffer->interface == NULL || buffer->interface->domain == NULL) {
676 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
677 			"specified (interface %p).", buffer->interface);
678 		return B_BAD_VALUE;
679 	}
680 
681 	net_domain *domain = buffer->interface->domain;
682 	net_address_module_info *addressModule = domain->address_module;
683 
684 	SocketAddress source(addressModule, buffer->source);
685 	SocketAddress destination(addressModule, buffer->destination);
686 
687 	source.SetPort(header.source_port);
688 	destination.SetPort(header.destination_port);
689 
690 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
691 		destination.AsString(true).Data());
692 
693 	uint16 udpLength = ntohs(header.udp_length);
694 	if (udpLength > buffer->size) {
695 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
696 			udpLength);
697 		return B_MISMATCHED_VALUES;
698 	}
699 
700 	if (buffer->size > udpLength)
701 		gBufferModule->trim(buffer, udpLength);
702 
703 	if (header.udp_checksum != 0) {
704 		// check UDP-checksum (simulating a so-called "pseudo-header"):
705 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
706 			buffer, IPPROTO_UDP);
707 		if (sum != 0) {
708 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
709 			return B_BAD_VALUE;
710 		}
711 	}
712 
713 	bufferHeader.Remove();
714 		// remove UDP-header from buffer before passing it on
715 
716 	return B_OK;
717 }
718 
719 
720 UdpDomainSupport *
721 UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
722 {
723 	BenaphoreLocker _(fLock);
724 
725 	UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true);
726 	if (domain)
727 		domain->Ref();
728 	return domain;
729 }
730 
731 
732 status_t
733 UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
734 {
735 	BenaphoreLocker _(fLock);
736 
737 	if (domain->Put()) {
738 		fDomains.Remove(domain);
739 		delete domain;
740 	}
741 
742 	return B_OK;
743 }
744 
745 
746 // #pragma mark -
747 
748 
749 UdpDomainSupport *
750 UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
751 {
752 	UdpDomainList::Iterator it = fDomains.GetIterator();
753 
754 	// TODO convert this into a Hashtable or install per-domain
755 	//      receiver handlers that forward the requests to the
756 	//      appropriate DemuxIncomingBuffer(). For instance, while
757 	//      being constructed UdpDomainSupport could call
758 	//      register_domain_receiving_protocol() with the right
759 	//      family.
760 	while (it.HasNext()) {
761 		UdpDomainSupport *domainSupport = it.Next();
762 		if (domainSupport->Domain() == domain)
763 			return domainSupport;
764 	}
765 
766 	if (!create)
767 		return NULL;
768 
769 	UdpDomainSupport *domainSupport =
770 		new (std::nothrow) UdpDomainSupport(domain);
771 	if (domainSupport == NULL || domainSupport->InitCheck() < B_OK) {
772 		delete domainSupport;
773 		return NULL;
774 	}
775 
776 	fDomains.Add(domainSupport);
777 	return domainSupport;
778 }
779 
780 
781 // #pragma mark -
782 
783 
784 UdpEndpoint::UdpEndpoint(net_socket *socket)
785 	: DatagramSocket<>("udp endpoint", socket), fActive(false) {}
786 
787 
788 // #pragma mark - activation
789 
790 
791 status_t
792 UdpEndpoint::Bind(const sockaddr *address)
793 {
794 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
795 	return fManager->BindEndpoint(this, address);
796 }
797 
798 
799 status_t
800 UdpEndpoint::Unbind(sockaddr *address)
801 {
802 	TRACE_EP("Unbind()");
803 	return fManager->UnbindEndpoint(this);
804 }
805 
806 
807 status_t
808 UdpEndpoint::Connect(const sockaddr *address)
809 {
810 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
811 	return fManager->ConnectEndpoint(this, address);
812 }
813 
814 
815 status_t
816 UdpEndpoint::Open()
817 {
818 	TRACE_EP("Open()");
819 
820 	AutoLocker _(fLock);
821 
822 	status_t status = ProtocolSocket::Open();
823 	if (status < B_OK)
824 		return status;
825 
826 	fManager = sUdpEndpointManager->OpenEndpoint(this);
827 	if (fManager == NULL)
828 		return EAFNOSUPPORT;
829 
830 	return B_OK;
831 }
832 
833 
834 status_t
835 UdpEndpoint::Close()
836 {
837 	TRACE_EP("Close()");
838 	return B_OK;
839 }
840 
841 
842 status_t
843 UdpEndpoint::Free()
844 {
845 	TRACE_EP("Free()");
846 	fManager->UnbindEndpoint(this);
847 	return sUdpEndpointManager->FreeEndpoint(fManager);
848 }
849 
850 
851 // #pragma mark - outbound
852 
853 
854 status_t
855 UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
856 {
857 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
858 
859 	if (buffer->size > (0xffff - sizeof(udp_header)))
860 		return EMSGSIZE;
861 
862 	buffer->protocol = IPPROTO_UDP;
863 
864 	// add and fill UDP-specific header:
865 	NetBufferPrepend<udp_header> header(buffer);
866 	if (header.Status() < B_OK)
867 		return header.Status();
868 
869 	header->source_port = AddressModule()->get_port(buffer->source);
870 	header->destination_port = AddressModule()->get_port(buffer->destination);
871 	header->udp_length = htons(buffer->size);
872 		// the udp-header is already included in the buffer-size
873 	header->udp_checksum = 0;
874 
875 	header.Sync();
876 
877 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
878 		gBufferModule, buffer, IPPROTO_UDP);
879 	if (calculatedChecksum == 0)
880 		calculatedChecksum = 0xffff;
881 
882 	*UDPChecksumField(buffer) = calculatedChecksum;
883 
884 	TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: "));
885 
886 	return next->module->send_routed_data(next, route, buffer);
887 }
888 
889 
890 status_t
891 UdpEndpoint::SendData(net_buffer *buffer)
892 {
893 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
894 
895 	return gDatalinkModule->send_datagram(this, NULL, buffer);
896 }
897 
898 
899 // #pragma mark - inbound
900 
901 
902 ssize_t
903 UdpEndpoint::BytesAvailable()
904 {
905 	size_t bytes = AvailableData();
906 	TRACE_EP("BytesAvailable(): %lu", bytes);
907 	return bytes;
908 }
909 
910 
911 status_t
912 UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
913 {
914 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
915 
916 	status_t status = SocketDequeue(flags, _buffer);
917 	TRACE_EP("  FetchData(): returned from fifo status=0x%lx", status);
918 	if (status < B_OK)
919 		return status;
920 
921 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
922 	return B_OK;
923 }
924 
925 
926 status_t
927 UdpEndpoint::StoreData(net_buffer *buffer)
928 {
929 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
930 
931 	return SocketEnqueue(buffer);
932 }
933 
934 
935 status_t
936 UdpEndpoint::DeliverData(net_buffer *_buffer)
937 {
938 	TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size);
939 
940 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
941 	if (buffer == NULL)
942 		return B_NO_MEMORY;
943 
944 	status_t status = sUdpEndpointManager->Deframe(buffer);
945 	if (status < B_OK) {
946 		gBufferModule->free(buffer);
947 		return status;
948 	}
949 
950 	// we call Enqueue() instead of SocketEnqueue() as there is
951 	// no need to clone the buffer again.
952 	return Enqueue(buffer);
953 }
954 
955 
956 // #pragma mark - protocol interface
957 
958 
959 net_protocol *
960 udp_init_protocol(net_socket *socket)
961 {
962 	socket->protocol = IPPROTO_UDP;
963 
964 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
965 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
966 		delete endpoint;
967 		return NULL;
968 	}
969 
970 	return endpoint;
971 }
972 
973 
974 status_t
975 udp_uninit_protocol(net_protocol *protocol)
976 {
977 	delete (UdpEndpoint *)protocol;
978 	return B_OK;
979 }
980 
981 
982 status_t
983 udp_open(net_protocol *protocol)
984 {
985 	return ((UdpEndpoint *)protocol)->Open();
986 }
987 
988 
989 status_t
990 udp_close(net_protocol *protocol)
991 {
992 	return ((UdpEndpoint *)protocol)->Close();
993 }
994 
995 
996 status_t
997 udp_free(net_protocol *protocol)
998 {
999 	return ((UdpEndpoint *)protocol)->Free();
1000 }
1001 
1002 
1003 status_t
1004 udp_connect(net_protocol *protocol, const struct sockaddr *address)
1005 {
1006 	return ((UdpEndpoint *)protocol)->Connect(address);
1007 }
1008 
1009 
1010 status_t
1011 udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1012 {
1013 	return EOPNOTSUPP;
1014 }
1015 
1016 
1017 status_t
1018 udp_control(net_protocol *protocol, int level, int option, void *value,
1019 	size_t *_length)
1020 {
1021 	return protocol->next->module->control(protocol->next, level, option,
1022 		value, _length);
1023 }
1024 
1025 
1026 status_t
1027 udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
1028 	int *length)
1029 {
1030 	return protocol->next->module->getsockopt(protocol->next, level, option,
1031 		value, length);
1032 }
1033 
1034 
1035 status_t
1036 udp_setsockopt(net_protocol *protocol, int level, int option,
1037 	const void *value, int length)
1038 {
1039 	return protocol->next->module->setsockopt(protocol->next, level, option,
1040 		value, length);
1041 }
1042 
1043 
1044 status_t
1045 udp_bind(net_protocol *protocol, const struct sockaddr *address)
1046 {
1047 	return ((UdpEndpoint *)protocol)->Bind(address);
1048 }
1049 
1050 
1051 status_t
1052 udp_unbind(net_protocol *protocol, struct sockaddr *address)
1053 {
1054 	return ((UdpEndpoint *)protocol)->Unbind(address);
1055 }
1056 
1057 
1058 status_t
1059 udp_listen(net_protocol *protocol, int count)
1060 {
1061 	return EOPNOTSUPP;
1062 }
1063 
1064 
1065 status_t
1066 udp_shutdown(net_protocol *protocol, int direction)
1067 {
1068 	return EOPNOTSUPP;
1069 }
1070 
1071 
1072 status_t
1073 udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1074 	net_buffer *buffer)
1075 {
1076 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1077 }
1078 
1079 
1080 status_t
1081 udp_send_data(net_protocol *protocol, net_buffer *buffer)
1082 {
1083 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1084 }
1085 
1086 
1087 ssize_t
1088 udp_send_avail(net_protocol *protocol)
1089 {
1090 	return protocol->socket->send.buffer_size;
1091 }
1092 
1093 
1094 status_t
1095 udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1096 	net_buffer **_buffer)
1097 {
1098 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1099 }
1100 
1101 
1102 ssize_t
1103 udp_read_avail(net_protocol *protocol)
1104 {
1105 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1106 }
1107 
1108 
1109 struct net_domain *
1110 udp_get_domain(net_protocol *protocol)
1111 {
1112 	return protocol->next->module->get_domain(protocol->next);
1113 }
1114 
1115 
1116 size_t
1117 udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1118 {
1119 	return protocol->next->module->get_mtu(protocol->next, address);
1120 }
1121 
1122 
1123 status_t
1124 udp_receive_data(net_buffer *buffer)
1125 {
1126 	return sUdpEndpointManager->ReceiveData(buffer);
1127 }
1128 
1129 
1130 status_t
1131 udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
1132 {
1133 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
1134 }
1135 
1136 
1137 status_t
1138 udp_error(uint32 code, net_buffer *data)
1139 {
1140 	return B_ERROR;
1141 }
1142 
1143 
1144 status_t
1145 udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
1146 	void *errorData)
1147 {
1148 	return B_ERROR;
1149 }
1150 
1151 
1152 //	#pragma mark - module interface
1153 
1154 
1155 static status_t
1156 init_udp()
1157 {
1158 	status_t status;
1159 	TRACE_EPM("init_udp()");
1160 
1161 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1162 	if (sUdpEndpointManager == NULL)
1163 		return B_NO_MEMORY;
1164 
1165 	status = sUdpEndpointManager->InitCheck();
1166 	if (status != B_OK)
1167 		goto err1;
1168 
1169 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP,
1170 		"network/protocols/udp/v1",
1171 		"network/protocols/ipv4/v1",
1172 		NULL);
1173 	if (status < B_OK)
1174 		goto err1;
1175 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
1176 		"network/protocols/udp/v1",
1177 		"network/protocols/ipv4/v1",
1178 		NULL);
1179 	if (status < B_OK)
1180 		goto err1;
1181 
1182 	status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
1183 		"network/protocols/udp/v1");
1184 	if (status < B_OK)
1185 		goto err1;
1186 
1187 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1188 		"lists all open UDP endpoints");
1189 
1190 	return B_OK;
1191 
1192 err1:
1193 	delete sUdpEndpointManager;
1194 
1195 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1196 	return status;
1197 }
1198 
1199 
1200 static status_t
1201 uninit_udp()
1202 {
1203 	TRACE_EPM("uninit_udp()");
1204 	remove_debugger_command("udp_endpoints",
1205 		UdpEndpointManager::DumpEndpoints);
1206 	delete sUdpEndpointManager;
1207 	return B_OK;
1208 }
1209 
1210 
1211 static status_t
1212 udp_std_ops(int32 op, ...)
1213 {
1214 	switch (op) {
1215 		case B_MODULE_INIT:
1216 			return init_udp();
1217 
1218 		case B_MODULE_UNINIT:
1219 			return uninit_udp();
1220 
1221 		default:
1222 			return B_ERROR;
1223 	}
1224 }
1225 
1226 
1227 net_protocol_module_info sUDPModule = {
1228 	{
1229 		"network/protocols/udp/v1",
1230 		0,
1231 		udp_std_ops
1232 	},
1233 	NET_PROTOCOL_ATOMIC_MESSAGES,
1234 
1235 	udp_init_protocol,
1236 	udp_uninit_protocol,
1237 	udp_open,
1238 	udp_close,
1239 	udp_free,
1240 	udp_connect,
1241 	udp_accept,
1242 	udp_control,
1243 	udp_getsockopt,
1244 	udp_setsockopt,
1245 	udp_bind,
1246 	udp_unbind,
1247 	udp_listen,
1248 	udp_shutdown,
1249 	udp_send_data,
1250 	udp_send_routed_data,
1251 	udp_send_avail,
1252 	udp_read_data,
1253 	udp_read_avail,
1254 	udp_get_domain,
1255 	udp_get_mtu,
1256 	udp_receive_data,
1257 	udp_deliver_data,
1258 	udp_error,
1259 	udp_error_reply,
1260 };
1261 
1262 module_dependency module_dependencies[] = {
1263 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1264 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1265 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1266 	{}
1267 };
1268 
1269 module_info *modules[] = {
1270 	(module_info *)&sUDPModule,
1271 	NULL
1272 };
1273