xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 			status = endpoint->LocalAddress().SetTo(
372 				routeToDestination->interface_address->local);
373 			gDatalinkModule->put_route(fDomain, routeToDestination);
374 			if (status < B_OK)
375 				return status;
376 		}
377 	}
378 
379 	// we need to activate no matter whether or not we have just disconnected,
380 	// as calling connect() always triggers an implicit bind():
381 	return _BindEndpoint(endpoint, *endpoint->LocalAddress());
382 }
383 
384 
385 status_t
386 UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
387 {
388 	MutexLocker _(fLock);
389 
390 	if (endpoint->IsActive())
391 		fActiveEndpoints.Remove(endpoint);
392 
393 	endpoint->SetActive(false);
394 
395 	return B_OK;
396 }
397 
398 
399 void
400 UdpDomainSupport::DumpEndpoints() const
401 {
402 	kprintf("-------- UDP Domain %p ---------\n", this);
403 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
404 
405 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
406 
407 	while (UdpEndpoint* endpoint = it.Next()) {
408 		endpoint->Dump();
409 	}
410 }
411 
412 
413 status_t
414 UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
415 	const sockaddr *address)
416 {
417 	if (AddressModule()->get_port(address) == 0)
418 		return _BindToEphemeral(endpoint, address);
419 
420 	return _Bind(endpoint, address);
421 }
422 
423 
424 status_t
425 UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
426 {
427 	int socketOptions = endpoint->Socket()->options;
428 
429 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
430 
431 	// Iterate over all active UDP-endpoints and check if the requested bind
432 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
433 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
434 		address, true).Data());
435 
436 	while (it.HasNext()) {
437 		UdpEndpoint *otherEndpoint = it.Next();
438 
439 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
440 			ntohs(otherEndpoint->LocalAddress().Port()));
441 
442 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
443 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
444 			if ((otherEndpoint->Socket()->options
445 					& (SO_REUSEADDR | SO_REUSEPORT)) == 0
446 				|| (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
447 				return EADDRINUSE;
448 
449 			// if both addresses are the same, SO_REUSEPORT is required:
450 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
451 				&& ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
452 					|| (socketOptions & SO_REUSEPORT) == 0))
453 				return EADDRINUSE;
454 		}
455 	}
456 
457 	return _FinishBind(endpoint, address);
458 }
459 
460 
461 status_t
462 UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
463 	const sockaddr *address)
464 {
465 	SocketAddressStorage newAddress(AddressModule());
466 	status_t status = newAddress.SetTo(address);
467 	if (status < B_OK)
468 		return status;
469 
470 	uint16 allocedPort = _GetNextEphemeral();
471 	if (allocedPort == 0)
472 		return ENOBUFS;
473 
474 	newAddress.SetPort(htons(allocedPort));
475 
476 	return _FinishBind(endpoint, *newAddress);
477 }
478 
479 
480 status_t
481 UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
482 {
483 	status_t status = endpoint->next->module->bind(endpoint->next, address);
484 	if (status < B_OK)
485 		return status;
486 
487 	fActiveEndpoints.Insert(endpoint);
488 	endpoint->SetActive(true);
489 
490 	return B_OK;
491 }
492 
493 
494 UdpEndpoint *
495 UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
496 	const sockaddr *peerAddress, uint32 index)
497 {
498 	ASSERT_LOCKED_MUTEX(&fLock);
499 
500 	TRACE_DOMAIN("finding Endpoint for %s <- %s",
501 		AddressString(fDomain, ourAddress, true).Data(),
502 		AddressString(fDomain, peerAddress, true).Data());
503 
504 	UdpEndpoint* endpoint = fActiveEndpoints.Lookup(
505 		std::make_pair(ourAddress, peerAddress));
506 
507 	// Make sure the bound_to_device constraint is fulfilled
508 	while (endpoint != NULL && endpoint->socket->bound_to_device != 0
509 		&& index != 0 && endpoint->socket->bound_to_device != index) {
510 		endpoint = endpoint->HashTableLink();
511 		if (endpoint != NULL
512 			&& (!endpoint->LocalAddress().EqualTo(ourAddress, true)
513 				|| !endpoint->PeerAddress().EqualTo(peerAddress, true)))
514 			return NULL;
515 	}
516 
517 	return endpoint;
518 }
519 
520 
521 status_t
522 UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
523 {
524 	sockaddr* peerAddr = buffer->source;
525 	sockaddr* broadcastAddr = buffer->destination;
526 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
527 
528 	sockaddr* mask = NULL;
529 	if (buffer->interface_address != NULL)
530 		mask = (sockaddr*)buffer->interface_address->mask;
531 
532 	TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
533 
534 	EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
535 
536 	while (UdpEndpoint* endpoint = iterator.Next()) {
537 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
538 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
539 
540 		if (endpoint->socket->bound_to_device != 0
541 			&& buffer->index != endpoint->socket->bound_to_device)
542 			continue;
543 
544 		if (endpoint->LocalAddress().Port() != incomingPort) {
545 			// ports don't match, so we do not dispatch to this endpoint...
546 			continue;
547 		}
548 
549 		if (!endpoint->PeerAddress().IsEmpty(true)) {
550 			// endpoint is connected to a specific destination, we check if
551 			// this datagram is from there:
552 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
553 				// no, datagram is from another peer, so we do not dispatch to
554 				// this endpoint...
555 				continue;
556 			}
557 		}
558 
559 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
560 			|| mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
561 			// address matches, dispatch to this endpoint:
562 			endpoint->StoreData(buffer);
563 		}
564 	}
565 
566 	return B_OK;
567 }
568 
569 
570 status_t
571 UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
572 {
573 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
574 
575 	const sockaddr* localAddress = buffer->destination;
576 	const sockaddr* peerAddress = buffer->source;
577 
578 	// look for full (most special) match:
579 	UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress,
580 		buffer->index);
581 	if (endpoint == NULL) {
582 		// look for endpoint matching local address & port:
583 		endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index);
584 		if (endpoint == NULL) {
585 			// look for endpoint matching peer address & port and local port:
586 			SocketAddressStorage local(AddressModule());
587 			local.SetToEmpty();
588 			local.SetPort(AddressModule()->get_port(localAddress));
589 			endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index);
590 			if (endpoint == NULL) {
591 				// last chance: look for endpoint matching local port only:
592 				endpoint = _FindActiveEndpoint(*local, NULL, buffer->index);
593 			}
594 		}
595 	}
596 
597 	if (endpoint == NULL) {
598 		TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
599 		return B_NAME_NOT_FOUND;
600 	}
601 
602 	endpoint->StoreData(buffer);
603 	return B_OK;
604 }
605 
606 
607 uint16
608 UdpDomainSupport::_GetNextEphemeral()
609 {
610 	uint16 stop, curr;
611 	if (fLastUsedEphemeral < kLast) {
612 		stop = fLastUsedEphemeral;
613 		curr = fLastUsedEphemeral + 1;
614 	} else {
615 		stop = kLast;
616 		curr = kFirst;
617 	}
618 
619 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
620 		fLastUsedEphemeral, curr, stop);
621 
622 	// TODO: a free list could be used to avoid the impact of these two
623 	//        nested loops most of the time... let's see how bad this really is
624 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
625 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
626 
627 		if (_EndpointWithPort(htons(curr)) == NULL) {
628 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
629 			fLastUsedEphemeral = curr;
630 			return curr;
631 		}
632 	}
633 
634 	return 0;
635 }
636 
637 
638 UdpEndpoint *
639 UdpDomainSupport::_EndpointWithPort(uint16 port) const
640 {
641 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
642 
643 	while (it.HasNext()) {
644 		UdpEndpoint *endpoint = it.Next();
645 		if (endpoint->LocalAddress().Port() == port)
646 			return endpoint;
647 	}
648 
649 	return NULL;
650 }
651 
652 
653 // #pragma mark -
654 
655 
656 UdpEndpointManager::UdpEndpointManager()
657 {
658 	mutex_init(&fLock, "UDP endpoints");
659 	fStatus = B_OK;
660 }
661 
662 
663 UdpEndpointManager::~UdpEndpointManager()
664 {
665 	mutex_destroy(&fLock);
666 }
667 
668 
669 status_t
670 UdpEndpointManager::InitCheck() const
671 {
672 	return fStatus;
673 }
674 
675 
676 int
677 UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
678 {
679 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
680 
681 	while (it.HasNext())
682 		it.Next()->DumpEndpoints();
683 
684 	return 0;
685 }
686 
687 
688 // #pragma mark - inbound
689 
690 
691 status_t
692 UdpEndpointManager::ReceiveData(net_buffer *buffer)
693 {
694 	TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
695 
696 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
697 	if (domainSupport == NULL) {
698 		// we don't instantiate domain supports in the receiving path, as
699 		// we are only interested in delivering data to existing sockets.
700 		return B_ERROR;
701 	}
702 
703 	status_t status = Deframe(buffer);
704 	if (status != B_OK)
705 		return status;
706 
707 	status = domainSupport->DemuxIncomingBuffer(buffer);
708 	if (status != B_OK) {
709 		TRACE_EPM("  ReceiveData(): no endpoint.");
710 		// Send port unreachable error
711 		domainSupport->Domain()->module->error_reply(NULL, buffer,
712 			B_NET_ERROR_UNREACH_PORT, NULL);
713 		return B_ERROR;
714 	}
715 
716 	gBufferModule->free(buffer);
717 	return B_OK;
718 }
719 
720 
721 status_t
722 UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
723 {
724 	TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
725 		error, buffer, buffer->size);
726 
727 	// We only really need the port information
728 	if (buffer->size < 4)
729 		return B_BAD_VALUE;
730 
731 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
732 	if (domainSupport == NULL) {
733 		// we don't instantiate domain supports in the receiving path, as
734 		// we are only interested in delivering data to existing sockets.
735 		return B_ERROR;
736 	}
737 
738 	// Deframe the buffer manually, as we usually only get 8 bytes from the
739 	// original packet
740 	udp_header header;
741 	if (gBufferModule->read(buffer, 0, &header,
742 			std::min((size_t)buffer->size, sizeof(udp_header))) != B_OK)
743 		return B_BAD_VALUE;
744 
745 	net_domain* domain = buffer->interface_address->domain;
746 	net_address_module_info* addressModule = domain->address_module;
747 
748 	SocketAddress source(addressModule, buffer->source);
749 	SocketAddress destination(addressModule, buffer->destination);
750 
751 	source.SetPort(header.source_port);
752 	destination.SetPort(header.destination_port);
753 
754 	return domainSupport->DeliverError(error, buffer);
755 }
756 
757 
758 status_t
759 UdpEndpointManager::Deframe(net_buffer* buffer)
760 {
761 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
762 
763 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
764 	if (bufferHeader.Status() != B_OK)
765 		return bufferHeader.Status();
766 
767 	udp_header& header = bufferHeader.Data();
768 
769 	net_domain* domain = _GetDomain(buffer);
770 	if (domain == NULL) {
771 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
772 			"specified (interface address %p).", buffer->interface_address);
773 		return B_BAD_VALUE;
774 	}
775 	net_address_module_info* addressModule = domain->address_module;
776 
777 	SocketAddress source(addressModule, buffer->source);
778 	SocketAddress destination(addressModule, buffer->destination);
779 
780 	source.SetPort(header.source_port);
781 	destination.SetPort(header.destination_port);
782 
783 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
784 		destination.AsString(true).Data());
785 
786 	uint16 udpLength = ntohs(header.udp_length);
787 	if (udpLength > buffer->size) {
788 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
789 			udpLength);
790 		return B_MISMATCHED_VALUES;
791 	}
792 
793 	if (buffer->size > udpLength)
794 		gBufferModule->trim(buffer, udpLength);
795 
796 	if (header.udp_checksum != 0) {
797 		// check UDP-checksum (simulating a so-called "pseudo-header"):
798 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
799 			buffer, IPPROTO_UDP);
800 		if (sum != 0) {
801 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
802 			return B_BAD_VALUE;
803 		}
804 	}
805 
806 	bufferHeader.Remove();
807 		// remove UDP-header from buffer before passing it on
808 
809 	return B_OK;
810 }
811 
812 
813 UdpDomainSupport *
814 UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
815 {
816 	MutexLocker _(fLock);
817 
818 	UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
819 	if (domain)
820 		domain->Ref();
821 	return domain;
822 }
823 
824 
825 status_t
826 UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
827 {
828 	MutexLocker _(fLock);
829 
830 	if (domain->Put()) {
831 		fDomains.Remove(domain);
832 		delete domain;
833 	}
834 
835 	return B_OK;
836 }
837 
838 
839 // #pragma mark -
840 
841 
842 inline net_domain*
843 UdpEndpointManager::_GetDomain(net_buffer* buffer)
844 {
845 	if (buffer->interface_address != NULL)
846 		return buffer->interface_address->domain;
847 
848 	return gStackModule->get_domain(buffer->destination->sa_family);
849 }
850 
851 
852 UdpDomainSupport*
853 UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create)
854 {
855 	ASSERT_LOCKED_MUTEX(&fLock);
856 
857 	if (domain == NULL)
858 		return NULL;
859 
860 	// TODO convert this into a Hashtable or install per-domain
861 	//      receiver handlers that forward the requests to the
862 	//      appropriate DemuxIncomingBuffer(). For instance, while
863 	//      being constructed UdpDomainSupport could call
864 	//      register_domain_receiving_protocol() with the right
865 	//      family.
866 	UdpDomainList::Iterator iterator = fDomains.GetIterator();
867 	while (UdpDomainSupport* domainSupport = iterator.Next()) {
868 		if (domainSupport->Domain() == domain)
869 			return domainSupport;
870 	}
871 
872 	if (!create)
873 		return NULL;
874 
875 	UdpDomainSupport* domainSupport
876 		= new (std::nothrow) UdpDomainSupport(domain);
877 	if (domainSupport == NULL || domainSupport->Init() < B_OK) {
878 		delete domainSupport;
879 		return NULL;
880 	}
881 
882 	fDomains.Add(domainSupport);
883 	return domainSupport;
884 }
885 
886 
887 /*!	Retrieves the UdpDomainSupport object responsible for this buffer, if the
888 	domain can be determined. This is only successful if the domain support is
889 	already existing, ie. there must already be an endpoint for the domain.
890 */
891 UdpDomainSupport*
892 UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
893 {
894 	MutexLocker _(fLock);
895 
896 	return _GetDomainSupport(_GetDomain(buffer), false);
897 		// TODO: we don't want to hold to the manager's lock during the
898 		// whole RX path, we may not hold an endpoint's lock with the
899 		// manager lock held.
900 		// But we should increase the domain's refcount here.
901 }
902 
903 
904 // #pragma mark -
905 
906 
907 UdpEndpoint::UdpEndpoint(net_socket *socket)
908 	:
909 	DatagramSocket<>("udp endpoint", socket),
910 	fActive(false)
911 {
912 }
913 
914 
915 // #pragma mark - activation
916 
917 
918 status_t
919 UdpEndpoint::Bind(const sockaddr *address)
920 {
921 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
922 	return fManager->BindEndpoint(this, address);
923 }
924 
925 
926 status_t
927 UdpEndpoint::Unbind(sockaddr *address)
928 {
929 	TRACE_EP("Unbind()");
930 	return fManager->UnbindEndpoint(this);
931 }
932 
933 
934 status_t
935 UdpEndpoint::Connect(const sockaddr *address)
936 {
937 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
938 	return fManager->ConnectEndpoint(this, address);
939 }
940 
941 
942 status_t
943 UdpEndpoint::Open()
944 {
945 	TRACE_EP("Open()");
946 
947 	AutoLocker _(fLock);
948 
949 	status_t status = ProtocolSocket::Open();
950 	if (status < B_OK)
951 		return status;
952 
953 	fManager = sUdpEndpointManager->OpenEndpoint(this);
954 	if (fManager == NULL)
955 		return EAFNOSUPPORT;
956 
957 	return B_OK;
958 }
959 
960 
961 status_t
962 UdpEndpoint::Close()
963 {
964 	TRACE_EP("Close()");
965 	return B_OK;
966 }
967 
968 
969 status_t
970 UdpEndpoint::Free()
971 {
972 	TRACE_EP("Free()");
973 	fManager->UnbindEndpoint(this);
974 	return sUdpEndpointManager->FreeEndpoint(fManager);
975 }
976 
977 
978 // #pragma mark - outbound
979 
980 
981 status_t
982 UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
983 {
984 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
985 
986 	if (buffer->size > (0xffff - sizeof(udp_header)))
987 		return EMSGSIZE;
988 
989 	buffer->protocol = IPPROTO_UDP;
990 
991 	// add and fill UDP-specific header:
992 	NetBufferPrepend<udp_header> header(buffer);
993 	if (header.Status() < B_OK)
994 		return header.Status();
995 
996 	header->source_port = AddressModule()->get_port(buffer->source);
997 	header->destination_port = AddressModule()->get_port(buffer->destination);
998 	header->udp_length = htons(buffer->size);
999 		// the udp-header is already included in the buffer-size
1000 	header->udp_checksum = 0;
1001 
1002 	header.Sync();
1003 
1004 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1005 		gBufferModule, buffer, IPPROTO_UDP);
1006 	if (calculatedChecksum == 0)
1007 		calculatedChecksum = 0xffff;
1008 
1009 	*UDPChecksumField(buffer) = calculatedChecksum;
1010 
1011 	return next->module->send_routed_data(next, route, buffer);
1012 }
1013 
1014 
1015 status_t
1016 UdpEndpoint::SendData(net_buffer *buffer)
1017 {
1018 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
1019 
1020 	return gDatalinkModule->send_data(this, NULL, buffer);
1021 }
1022 
1023 
1024 // #pragma mark - inbound
1025 
1026 
1027 ssize_t
1028 UdpEndpoint::BytesAvailable()
1029 {
1030 	size_t bytes = AvailableData();
1031 	TRACE_EP("BytesAvailable(): %lu", bytes);
1032 	return bytes;
1033 }
1034 
1035 
1036 status_t
1037 UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1038 {
1039 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
1040 
1041 	status_t status = Dequeue(flags, _buffer);
1042 	TRACE_EP("  FetchData(): returned from fifo status: %s", strerror(status));
1043 	if (status != B_OK)
1044 		return status;
1045 
1046 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
1047 	return B_OK;
1048 }
1049 
1050 
1051 status_t
1052 UdpEndpoint::StoreData(net_buffer *buffer)
1053 {
1054 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
1055 
1056 	return EnqueueClone(buffer);
1057 }
1058 
1059 
1060 status_t
1061 UdpEndpoint::DeliverData(net_buffer *_buffer)
1062 {
1063 	TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size);
1064 
1065 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
1066 	if (buffer == NULL)
1067 		return B_NO_MEMORY;
1068 
1069 	status_t status = sUdpEndpointManager->Deframe(buffer);
1070 	if (status < B_OK) {
1071 		gBufferModule->free(buffer);
1072 		return status;
1073 	}
1074 
1075 	return Enqueue(buffer);
1076 }
1077 
1078 
1079 void
1080 UdpEndpoint::Dump() const
1081 {
1082 	char local[64];
1083 	LocalAddress().AsString(local, sizeof(local), true);
1084 	char peer[64];
1085 	PeerAddress().AsString(peer, sizeof(peer), true);
1086 
1087 	kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1088 }
1089 
1090 
1091 // #pragma mark - protocol interface
1092 
1093 
1094 net_protocol *
1095 udp_init_protocol(net_socket *socket)
1096 {
1097 	socket->protocol = IPPROTO_UDP;
1098 
1099 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1100 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1101 		delete endpoint;
1102 		return NULL;
1103 	}
1104 
1105 	return endpoint;
1106 }
1107 
1108 
1109 status_t
1110 udp_uninit_protocol(net_protocol *protocol)
1111 {
1112 	delete (UdpEndpoint *)protocol;
1113 	return B_OK;
1114 }
1115 
1116 
1117 status_t
1118 udp_open(net_protocol *protocol)
1119 {
1120 	return ((UdpEndpoint *)protocol)->Open();
1121 }
1122 
1123 
1124 status_t
1125 udp_close(net_protocol *protocol)
1126 {
1127 	return ((UdpEndpoint *)protocol)->Close();
1128 }
1129 
1130 
1131 status_t
1132 udp_free(net_protocol *protocol)
1133 {
1134 	return ((UdpEndpoint *)protocol)->Free();
1135 }
1136 
1137 
1138 status_t
1139 udp_connect(net_protocol *protocol, const struct sockaddr *address)
1140 {
1141 	return ((UdpEndpoint *)protocol)->Connect(address);
1142 }
1143 
1144 
1145 status_t
1146 udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1147 {
1148 	return B_NOT_SUPPORTED;
1149 }
1150 
1151 
1152 status_t
1153 udp_control(net_protocol *protocol, int level, int option, void *value,
1154 	size_t *_length)
1155 {
1156 	return protocol->next->module->control(protocol->next, level, option,
1157 		value, _length);
1158 }
1159 
1160 
1161 status_t
1162 udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
1163 	int *length)
1164 {
1165 	return protocol->next->module->getsockopt(protocol->next, level, option,
1166 		value, length);
1167 }
1168 
1169 
1170 status_t
1171 udp_setsockopt(net_protocol *protocol, int level, int option,
1172 	const void *value, int length)
1173 {
1174 	return protocol->next->module->setsockopt(protocol->next, level, option,
1175 		value, length);
1176 }
1177 
1178 
1179 status_t
1180 udp_bind(net_protocol *protocol, const struct sockaddr *address)
1181 {
1182 	return ((UdpEndpoint *)protocol)->Bind(address);
1183 }
1184 
1185 
1186 status_t
1187 udp_unbind(net_protocol *protocol, struct sockaddr *address)
1188 {
1189 	return ((UdpEndpoint *)protocol)->Unbind(address);
1190 }
1191 
1192 
1193 status_t
1194 udp_listen(net_protocol *protocol, int count)
1195 {
1196 	return B_NOT_SUPPORTED;
1197 }
1198 
1199 
1200 status_t
1201 udp_shutdown(net_protocol *protocol, int direction)
1202 {
1203 	return B_NOT_SUPPORTED;
1204 }
1205 
1206 
1207 status_t
1208 udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1209 	net_buffer *buffer)
1210 {
1211 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1212 }
1213 
1214 
1215 status_t
1216 udp_send_data(net_protocol *protocol, net_buffer *buffer)
1217 {
1218 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1219 }
1220 
1221 
1222 ssize_t
1223 udp_send_avail(net_protocol *protocol)
1224 {
1225 	return protocol->socket->send.buffer_size;
1226 }
1227 
1228 
1229 status_t
1230 udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1231 	net_buffer **_buffer)
1232 {
1233 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1234 }
1235 
1236 
1237 ssize_t
1238 udp_read_avail(net_protocol *protocol)
1239 {
1240 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1241 }
1242 
1243 
1244 struct net_domain *
1245 udp_get_domain(net_protocol *protocol)
1246 {
1247 	return protocol->next->module->get_domain(protocol->next);
1248 }
1249 
1250 
1251 size_t
1252 udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1253 {
1254 	return protocol->next->module->get_mtu(protocol->next, address);
1255 }
1256 
1257 
1258 status_t
1259 udp_receive_data(net_buffer *buffer)
1260 {
1261 	return sUdpEndpointManager->ReceiveData(buffer);
1262 }
1263 
1264 
1265 status_t
1266 udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
1267 {
1268 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
1269 }
1270 
1271 
1272 status_t
1273 udp_error_received(net_error error, net_buffer* buffer)
1274 {
1275 	status_t notifyError = B_OK;
1276 
1277 	switch (error) {
1278 		case B_NET_ERROR_UNREACH_NET:
1279 			notifyError = ENETUNREACH;
1280 			break;
1281 		case B_NET_ERROR_UNREACH_HOST:
1282 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
1283 			notifyError = EHOSTUNREACH;
1284 			break;
1285 		case B_NET_ERROR_UNREACH_PROTOCOL:
1286 		case B_NET_ERROR_UNREACH_PORT:
1287 			notifyError = ECONNREFUSED;
1288 			break;
1289 		case B_NET_ERROR_MESSAGE_SIZE:
1290 			notifyError = EMSGSIZE;
1291 			break;
1292 		case B_NET_ERROR_PARAMETER_PROBLEM:
1293 			notifyError = ENOPROTOOPT;
1294 			break;
1295 
1296 		case B_NET_ERROR_QUENCH:
1297 		default:
1298 			// ignore them
1299 			gBufferModule->free(buffer);
1300 			return B_OK;
1301 	}
1302 
1303 	ASSERT(notifyError != B_OK);
1304 
1305 	return sUdpEndpointManager->ReceiveError(notifyError, buffer);
1306 }
1307 
1308 
1309 status_t
1310 udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
1311 	net_error_data *errorData)
1312 {
1313 	return B_ERROR;
1314 }
1315 
1316 
1317 ssize_t
1318 udp_process_ancillary_data_no_container(net_protocol *protocol,
1319 	net_buffer* buffer, void *data, size_t dataSize)
1320 {
1321 	return protocol->next->module->process_ancillary_data_no_container(
1322 		protocol, buffer, data, dataSize);
1323 }
1324 
1325 
1326 //	#pragma mark - module interface
1327 
1328 
1329 static status_t
1330 init_udp()
1331 {
1332 	status_t status;
1333 	TRACE_EPM("init_udp()");
1334 
1335 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1336 	if (sUdpEndpointManager == NULL)
1337 		return B_NO_MEMORY;
1338 
1339 	status = sUdpEndpointManager->InitCheck();
1340 	if (status != B_OK)
1341 		goto err1;
1342 
1343 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
1344 		IPPROTO_IP,
1345 		"network/protocols/udp/v1",
1346 		"network/protocols/ipv4/v1",
1347 		NULL);
1348 	if (status < B_OK)
1349 		goto err1;
1350 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
1351 		IPPROTO_IP,
1352 		"network/protocols/udp/v1",
1353 		"network/protocols/ipv6/v1",
1354 		NULL);
1355 	if (status < B_OK)
1356 		goto err1;
1357 
1358 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
1359 		IPPROTO_UDP,
1360 		"network/protocols/udp/v1",
1361 		"network/protocols/ipv4/v1",
1362 		NULL);
1363 	if (status < B_OK)
1364 		goto err1;
1365 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
1366 		IPPROTO_UDP,
1367 		"network/protocols/udp/v1",
1368 		"network/protocols/ipv6/v1",
1369 		NULL);
1370 	if (status < B_OK)
1371 		goto err1;
1372 
1373 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
1374 		IPPROTO_UDP, "network/protocols/udp/v1");
1375 	if (status < B_OK)
1376 		goto err1;
1377 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
1378 		IPPROTO_UDP, "network/protocols/udp/v1");
1379 	if (status < B_OK)
1380 		goto err1;
1381 
1382 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1383 		"lists all open UDP endpoints");
1384 
1385 	return B_OK;
1386 
1387 err1:
1388 	// TODO: shouldn't unregister the protocols here?
1389 	delete sUdpEndpointManager;
1390 
1391 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1392 	return status;
1393 }
1394 
1395 
1396 static status_t
1397 uninit_udp()
1398 {
1399 	TRACE_EPM("uninit_udp()");
1400 	remove_debugger_command("udp_endpoints",
1401 		UdpEndpointManager::DumpEndpoints);
1402 	delete sUdpEndpointManager;
1403 	return B_OK;
1404 }
1405 
1406 
1407 static status_t
1408 udp_std_ops(int32 op, ...)
1409 {
1410 	switch (op) {
1411 		case B_MODULE_INIT:
1412 			return init_udp();
1413 
1414 		case B_MODULE_UNINIT:
1415 			return uninit_udp();
1416 
1417 		default:
1418 			return B_ERROR;
1419 	}
1420 }
1421 
1422 
1423 net_protocol_module_info sUDPModule = {
1424 	{
1425 		"network/protocols/udp/v1",
1426 		0,
1427 		udp_std_ops
1428 	},
1429 	NET_PROTOCOL_ATOMIC_MESSAGES,
1430 
1431 	udp_init_protocol,
1432 	udp_uninit_protocol,
1433 	udp_open,
1434 	udp_close,
1435 	udp_free,
1436 	udp_connect,
1437 	udp_accept,
1438 	udp_control,
1439 	udp_getsockopt,
1440 	udp_setsockopt,
1441 	udp_bind,
1442 	udp_unbind,
1443 	udp_listen,
1444 	udp_shutdown,
1445 	udp_send_data,
1446 	udp_send_routed_data,
1447 	udp_send_avail,
1448 	udp_read_data,
1449 	udp_read_avail,
1450 	udp_get_domain,
1451 	udp_get_mtu,
1452 	udp_receive_data,
1453 	udp_deliver_data,
1454 	udp_error_received,
1455 	udp_error_reply,
1456 	NULL,		// add_ancillary_data()
1457 	NULL,		// process_ancillary_data()
1458 	udp_process_ancillary_data_no_container,
1459 	NULL,		// send_data_no_buffer()
1460 	NULL		// read_data_no_buffer()
1461 };
1462 
1463 module_dependency module_dependencies[] = {
1464 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1465 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1466 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1467 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1468 	{}
1469 };
1470 
1471 module_info *modules[] = {
1472 	(module_info *)&sUDPModule,
1473 	NULL
1474 };
1475