xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 9e25244c5e9051f6cd333820d6332397361abd6c)
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 	return _GetDomainSupport(_GetDomain(buffer), false);
933 }
934 
935 
936 // #pragma mark -
937 
938 
939 UdpEndpoint::UdpEndpoint(net_socket *socket)
940 	:
941 	DatagramSocket<>("udp endpoint", socket),
942 	fActive(false)
943 {
944 }
945 
946 
947 // #pragma mark - activation
948 
949 
950 status_t
951 UdpEndpoint::Bind(const sockaddr *address)
952 {
953 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
954 	return fManager->BindEndpoint(this, address);
955 }
956 
957 
958 status_t
959 UdpEndpoint::Unbind(sockaddr *address)
960 {
961 	TRACE_EP("Unbind()");
962 	return fManager->UnbindEndpoint(this);
963 }
964 
965 
966 status_t
967 UdpEndpoint::Connect(const sockaddr *address)
968 {
969 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
970 	return fManager->ConnectEndpoint(this, address);
971 }
972 
973 
974 status_t
975 UdpEndpoint::Open()
976 {
977 	TRACE_EP("Open()");
978 
979 	AutoLocker _(fLock);
980 
981 	status_t status = ProtocolSocket::Open();
982 	if (status < B_OK)
983 		return status;
984 
985 	fManager = sUdpEndpointManager->OpenEndpoint(this);
986 	if (fManager == NULL)
987 		return EAFNOSUPPORT;
988 
989 	return B_OK;
990 }
991 
992 
993 status_t
994 UdpEndpoint::Close()
995 {
996 	TRACE_EP("Close()");
997 	fSocket->error = EBADF;
998 	WakeAll();
999 	return B_OK;
1000 }
1001 
1002 
1003 status_t
1004 UdpEndpoint::Free()
1005 {
1006 	TRACE_EP("Free()");
1007 	fManager->UnbindEndpoint(this);
1008 	return sUdpEndpointManager->FreeEndpoint(fManager);
1009 }
1010 
1011 
1012 // #pragma mark - outbound
1013 
1014 
1015 status_t
1016 UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
1017 {
1018 	TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer,
1019 		buffer->size, route);
1020 
1021 	if (buffer->size > (0xffff - sizeof(udp_header)))
1022 		return EMSGSIZE;
1023 
1024 	buffer->protocol = IPPROTO_UDP;
1025 
1026 	// add and fill UDP-specific header:
1027 	NetBufferPrepend<udp_header> header(buffer);
1028 	if (header.Status() < B_OK)
1029 		return header.Status();
1030 
1031 	header->source_port = AddressModule()->get_port(buffer->source);
1032 	header->destination_port = AddressModule()->get_port(buffer->destination);
1033 	header->udp_length = htons(buffer->size);
1034 		// the udp-header is already included in the buffer-size
1035 	header->udp_checksum = 0;
1036 
1037 	header.Sync();
1038 
1039 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1040 		gBufferModule, buffer, IPPROTO_UDP);
1041 	if (calculatedChecksum == 0)
1042 		calculatedChecksum = 0xffff;
1043 
1044 	*UDPChecksumField(buffer) = calculatedChecksum;
1045 
1046 	return next->module->send_routed_data(next, route, buffer);
1047 }
1048 
1049 
1050 status_t
1051 UdpEndpoint::SendData(net_buffer *buffer)
1052 {
1053 	TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1054 
1055 	return gDatalinkModule->send_data(this, NULL, buffer);
1056 }
1057 
1058 
1059 // #pragma mark - inbound
1060 
1061 
1062 ssize_t
1063 UdpEndpoint::BytesAvailable()
1064 {
1065 	size_t bytes = AvailableData();
1066 	TRACE_EP("BytesAvailable(): %lu", bytes);
1067 	return bytes;
1068 }
1069 
1070 
1071 status_t
1072 UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1073 {
1074 	TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags);
1075 
1076 	status_t status = Dequeue(flags, _buffer);
1077 	TRACE_EP("  FetchData(): returned from fifo status: %s", strerror(status));
1078 	if (status != B_OK)
1079 		return status;
1080 
1081 	TRACE_EP("  FetchData(): returns buffer with %" B_PRIu32 " bytes",
1082 		(*_buffer)->size);
1083 	return B_OK;
1084 }
1085 
1086 
1087 status_t
1088 UdpEndpoint::StoreData(net_buffer *buffer)
1089 {
1090 	TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1091 
1092 	return EnqueueClone(buffer);
1093 }
1094 
1095 
1096 status_t
1097 UdpEndpoint::DeliverData(net_buffer *_buffer)
1098 {
1099 	TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size);
1100 
1101 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
1102 	if (buffer == NULL)
1103 		return B_NO_MEMORY;
1104 
1105 	status_t status = sUdpEndpointManager->Deframe(buffer);
1106 	if (status < B_OK) {
1107 		gBufferModule->free(buffer);
1108 		return status;
1109 	}
1110 
1111 	return Enqueue(buffer);
1112 }
1113 
1114 
1115 void
1116 UdpEndpoint::Dump() const
1117 {
1118 	char local[64];
1119 	LocalAddress().AsString(local, sizeof(local), true);
1120 	char peer[64];
1121 	PeerAddress().AsString(peer, sizeof(peer), true);
1122 
1123 	kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1124 }
1125 
1126 
1127 // #pragma mark - protocol interface
1128 
1129 
1130 net_protocol *
1131 udp_init_protocol(net_socket *socket)
1132 {
1133 	socket->protocol = IPPROTO_UDP;
1134 
1135 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1136 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1137 		delete endpoint;
1138 		return NULL;
1139 	}
1140 
1141 	return endpoint;
1142 }
1143 
1144 
1145 status_t
1146 udp_uninit_protocol(net_protocol *protocol)
1147 {
1148 	delete (UdpEndpoint *)protocol;
1149 	return B_OK;
1150 }
1151 
1152 
1153 status_t
1154 udp_open(net_protocol *protocol)
1155 {
1156 	return ((UdpEndpoint *)protocol)->Open();
1157 }
1158 
1159 
1160 status_t
1161 udp_close(net_protocol *protocol)
1162 {
1163 	return ((UdpEndpoint *)protocol)->Close();
1164 }
1165 
1166 
1167 status_t
1168 udp_free(net_protocol *protocol)
1169 {
1170 	return ((UdpEndpoint *)protocol)->Free();
1171 }
1172 
1173 
1174 status_t
1175 udp_connect(net_protocol *protocol, const struct sockaddr *address)
1176 {
1177 	return ((UdpEndpoint *)protocol)->Connect(address);
1178 }
1179 
1180 
1181 status_t
1182 udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1183 {
1184 	return B_NOT_SUPPORTED;
1185 }
1186 
1187 
1188 status_t
1189 udp_control(net_protocol *protocol, int level, int option, void *value,
1190 	size_t *_length)
1191 {
1192 	return protocol->next->module->control(protocol->next, level, option,
1193 		value, _length);
1194 }
1195 
1196 
1197 status_t
1198 udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
1199 	int *length)
1200 {
1201 	return protocol->next->module->getsockopt(protocol->next, level, option,
1202 		value, length);
1203 }
1204 
1205 
1206 status_t
1207 udp_setsockopt(net_protocol *protocol, int level, int option,
1208 	const void *value, int length)
1209 {
1210 	return protocol->next->module->setsockopt(protocol->next, level, option,
1211 		value, length);
1212 }
1213 
1214 
1215 status_t
1216 udp_bind(net_protocol *protocol, const struct sockaddr *address)
1217 {
1218 	return ((UdpEndpoint *)protocol)->Bind(address);
1219 }
1220 
1221 
1222 status_t
1223 udp_unbind(net_protocol *protocol, struct sockaddr *address)
1224 {
1225 	return ((UdpEndpoint *)protocol)->Unbind(address);
1226 }
1227 
1228 
1229 status_t
1230 udp_listen(net_protocol *protocol, int count)
1231 {
1232 	return B_NOT_SUPPORTED;
1233 }
1234 
1235 
1236 status_t
1237 udp_shutdown(net_protocol *protocol, int direction)
1238 {
1239 	return B_NOT_SUPPORTED;
1240 }
1241 
1242 
1243 status_t
1244 udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1245 	net_buffer *buffer)
1246 {
1247 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1248 }
1249 
1250 
1251 status_t
1252 udp_send_data(net_protocol *protocol, net_buffer *buffer)
1253 {
1254 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1255 }
1256 
1257 
1258 ssize_t
1259 udp_send_avail(net_protocol *protocol)
1260 {
1261 	return protocol->socket->send.buffer_size;
1262 }
1263 
1264 
1265 status_t
1266 udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1267 	net_buffer **_buffer)
1268 {
1269 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1270 }
1271 
1272 
1273 ssize_t
1274 udp_read_avail(net_protocol *protocol)
1275 {
1276 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1277 }
1278 
1279 
1280 struct net_domain *
1281 udp_get_domain(net_protocol *protocol)
1282 {
1283 	return protocol->next->module->get_domain(protocol->next);
1284 }
1285 
1286 
1287 size_t
1288 udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1289 {
1290 	return protocol->next->module->get_mtu(protocol->next, address);
1291 }
1292 
1293 
1294 status_t
1295 udp_receive_data(net_buffer *buffer)
1296 {
1297 	return sUdpEndpointManager->ReceiveData(buffer);
1298 }
1299 
1300 
1301 status_t
1302 udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
1303 {
1304 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
1305 }
1306 
1307 
1308 status_t
1309 udp_error_received(net_error error, net_buffer* buffer)
1310 {
1311 	status_t notifyError = B_OK;
1312 
1313 	switch (error) {
1314 		case B_NET_ERROR_UNREACH_NET:
1315 			notifyError = ENETUNREACH;
1316 			break;
1317 		case B_NET_ERROR_UNREACH_HOST:
1318 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
1319 			notifyError = EHOSTUNREACH;
1320 			break;
1321 		case B_NET_ERROR_UNREACH_PROTOCOL:
1322 		case B_NET_ERROR_UNREACH_PORT:
1323 			notifyError = ECONNREFUSED;
1324 			break;
1325 		case B_NET_ERROR_MESSAGE_SIZE:
1326 			notifyError = EMSGSIZE;
1327 			break;
1328 		case B_NET_ERROR_PARAMETER_PROBLEM:
1329 			notifyError = ENOPROTOOPT;
1330 			break;
1331 
1332 		case B_NET_ERROR_QUENCH:
1333 		default:
1334 			// ignore them
1335 			gBufferModule->free(buffer);
1336 			return B_OK;
1337 	}
1338 
1339 	ASSERT(notifyError != B_OK);
1340 
1341 	return sUdpEndpointManager->ReceiveError(notifyError, buffer);
1342 }
1343 
1344 
1345 status_t
1346 udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
1347 	net_error_data *errorData)
1348 {
1349 	return B_ERROR;
1350 }
1351 
1352 
1353 ssize_t
1354 udp_process_ancillary_data_no_container(net_protocol *protocol,
1355 	net_buffer* buffer, void *data, size_t dataSize)
1356 {
1357 	return protocol->next->module->process_ancillary_data_no_container(
1358 		protocol, buffer, data, dataSize);
1359 }
1360 
1361 
1362 //	#pragma mark - module interface
1363 
1364 
1365 static status_t
1366 init_udp()
1367 {
1368 	status_t status;
1369 	TRACE_EPM("init_udp()");
1370 
1371 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1372 	if (sUdpEndpointManager == NULL)
1373 		return B_NO_MEMORY;
1374 
1375 	status = sUdpEndpointManager->InitCheck();
1376 	if (status != B_OK)
1377 		goto err1;
1378 
1379 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
1380 		IPPROTO_IP,
1381 		"network/protocols/udp/v1",
1382 		"network/protocols/ipv4/v1",
1383 		NULL);
1384 	if (status < B_OK)
1385 		goto err1;
1386 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
1387 		IPPROTO_IP,
1388 		"network/protocols/udp/v1",
1389 		"network/protocols/ipv6/v1",
1390 		NULL);
1391 	if (status < B_OK)
1392 		goto err1;
1393 
1394 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
1395 		IPPROTO_UDP,
1396 		"network/protocols/udp/v1",
1397 		"network/protocols/ipv4/v1",
1398 		NULL);
1399 	if (status < B_OK)
1400 		goto err1;
1401 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
1402 		IPPROTO_UDP,
1403 		"network/protocols/udp/v1",
1404 		"network/protocols/ipv6/v1",
1405 		NULL);
1406 	if (status < B_OK)
1407 		goto err1;
1408 
1409 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
1410 		IPPROTO_UDP, "network/protocols/udp/v1");
1411 	if (status < B_OK)
1412 		goto err1;
1413 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
1414 		IPPROTO_UDP, "network/protocols/udp/v1");
1415 	if (status < B_OK)
1416 		goto err1;
1417 
1418 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1419 		"lists all open UDP endpoints");
1420 
1421 	return B_OK;
1422 
1423 err1:
1424 	// TODO: shouldn't unregister the protocols here?
1425 	delete sUdpEndpointManager;
1426 
1427 	TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status,
1428 		strerror(status));
1429 	return status;
1430 }
1431 
1432 
1433 static status_t
1434 uninit_udp()
1435 {
1436 	TRACE_EPM("uninit_udp()");
1437 	remove_debugger_command("udp_endpoints",
1438 		UdpEndpointManager::DumpEndpoints);
1439 	delete sUdpEndpointManager;
1440 	return B_OK;
1441 }
1442 
1443 
1444 static status_t
1445 udp_std_ops(int32 op, ...)
1446 {
1447 	switch (op) {
1448 		case B_MODULE_INIT:
1449 			return init_udp();
1450 
1451 		case B_MODULE_UNINIT:
1452 			return uninit_udp();
1453 
1454 		default:
1455 			return B_ERROR;
1456 	}
1457 }
1458 
1459 
1460 net_protocol_module_info sUDPModule = {
1461 	{
1462 		"network/protocols/udp/v1",
1463 		0,
1464 		udp_std_ops
1465 	},
1466 	NET_PROTOCOL_ATOMIC_MESSAGES,
1467 
1468 	udp_init_protocol,
1469 	udp_uninit_protocol,
1470 	udp_open,
1471 	udp_close,
1472 	udp_free,
1473 	udp_connect,
1474 	udp_accept,
1475 	udp_control,
1476 	udp_getsockopt,
1477 	udp_setsockopt,
1478 	udp_bind,
1479 	udp_unbind,
1480 	udp_listen,
1481 	udp_shutdown,
1482 	udp_send_data,
1483 	udp_send_routed_data,
1484 	udp_send_avail,
1485 	udp_read_data,
1486 	udp_read_avail,
1487 	udp_get_domain,
1488 	udp_get_mtu,
1489 	udp_receive_data,
1490 	udp_deliver_data,
1491 	udp_error_received,
1492 	udp_error_reply,
1493 	NULL,		// add_ancillary_data()
1494 	NULL,		// process_ancillary_data()
1495 	udp_process_ancillary_data_no_container,
1496 	NULL,		// send_data_no_buffer()
1497 	NULL		// read_data_no_buffer()
1498 };
1499 
1500 module_dependency module_dependencies[] = {
1501 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1502 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1503 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1504 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1505 	{}
1506 };
1507 
1508 module_info *modules[] = {
1509 	(module_info *)&sUDPModule,
1510 	NULL
1511 };
1512