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