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