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