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