xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision a03ed4fa08bc9a276a8c52f3ca17aad29bad65ca)
1c22d69bfSAxel Dörfler /*
22bb43d82SAxel Dörfler  * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3c22d69bfSAxel Dörfler  * Distributed under the terms of the MIT License.
4c22d69bfSAxel Dörfler  *
5c22d69bfSAxel Dörfler  * Authors:
6c22d69bfSAxel Dörfler  *		Oliver Tappe, zooey@hirschkaefer.de
7c3e054c8SHugo Santos  *		Hugo Santos, hugosantos@gmail.com
8c22d69bfSAxel Dörfler  */
9c22d69bfSAxel Dörfler 
10c22d69bfSAxel Dörfler 
11c22d69bfSAxel Dörfler #include <net_buffer.h>
12c22d69bfSAxel Dörfler #include <net_datalink.h>
13c22d69bfSAxel Dörfler #include <net_protocol.h>
14c22d69bfSAxel Dörfler #include <net_stack.h>
15c22d69bfSAxel Dörfler 
16c22d69bfSAxel Dörfler #include <lock.h>
17c22d69bfSAxel Dörfler #include <util/AutoLock.h>
18bf48e753SHugo Santos #include <util/DoublyLinkedList.h>
1940bbf860SHugo Santos #include <util/OpenHashTable.h>
20c22d69bfSAxel Dörfler 
21c22d69bfSAxel Dörfler #include <KernelExport.h>
22c22d69bfSAxel Dörfler 
23c22d69bfSAxel Dörfler #include <NetBufferUtilities.h>
24c22d69bfSAxel Dörfler #include <NetUtilities.h>
25bfb45f71SHugo Santos #include <ProtocolUtilities.h>
26c22d69bfSAxel Dörfler 
272bb43d82SAxel Dörfler #include <algorithm>
28c22d69bfSAxel Dörfler #include <netinet/in.h>
292bb43d82SAxel Dörfler #include <netinet/ip.h>
30c22d69bfSAxel Dörfler #include <new>
31c22d69bfSAxel Dörfler #include <stdlib.h>
32c22d69bfSAxel Dörfler #include <string.h>
33c3e054c8SHugo Santos #include <utility>
34c22d69bfSAxel Dörfler 
35727ad0b0SHugo Santos 
36727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
37727ad0b0SHugo Santos //      lock before holding a child UdpEndpoint's lock. This restriction
38727ad0b0SHugo Santos //      is dictated by the receive path as blind access to the endpoint
39f861e599SFrançois Revol //      hash is required when holding the DomainSupport's lock.
40727ad0b0SHugo Santos 
41727ad0b0SHugo Santos 
42af3a31f7SAxel Dörfler //#define TRACE_UDP
43c22d69bfSAxel Dörfler #ifdef TRACE_UDP
44c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x) dump_block x
45bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this
46bf48e753SHugo Santos // to compile with gcc 2.95
47bf9a85cbSJérôme Duval #	define TRACE_EP(format, args...)	dprintf("UDP [%" B_PRIu64 ",%" \
48bf9a85cbSJérôme Duval 		B_PRIu32 "] %p " format "\n", system_time(), \
49bf9a85cbSJérôme Duval 		thread_get_current_thread_id(), this , ##args)
50bf9a85cbSJérôme Duval #	define TRACE_EPM(format, args...)	dprintf("UDP [%" B_PRIu64 ",%" \
51bf9a85cbSJérôme Duval 		B_PRIu32 "] " format "\n", system_time() , \
52bf9a85cbSJérôme Duval 		thread_get_current_thread_id() , ##args)
53bf9a85cbSJérôme Duval #	define TRACE_DOMAIN(format, args...)	dprintf("UDP [%" B_PRIu64 ",%" \
54bf9a85cbSJérôme Duval 		B_PRIu32 "] (%d) " format "\n", system_time(), \
55bf9a85cbSJérôme Duval 		thread_get_current_thread_id(), Domain()->family , ##args)
56c22d69bfSAxel Dörfler #else
57c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x)
58bf48e753SHugo Santos #	define TRACE_EP(args...)	do { } while (0)
59bf48e753SHugo Santos #	define TRACE_EPM(args...)	do { } while (0)
60bf48e753SHugo Santos #	define TRACE_DOMAIN(args...)	do { } while (0)
61c22d69bfSAxel Dörfler #endif
62c22d69bfSAxel Dörfler 
63c22d69bfSAxel Dörfler 
64c22d69bfSAxel Dörfler struct udp_header {
65c22d69bfSAxel Dörfler 	uint16 source_port;
66c22d69bfSAxel Dörfler 	uint16 destination_port;
67c22d69bfSAxel Dörfler 	uint16 udp_length;
68c22d69bfSAxel Dörfler 	uint16 udp_checksum;
69c22d69bfSAxel Dörfler } _PACKED;
70c22d69bfSAxel Dörfler 
71c22d69bfSAxel Dörfler 
726c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
736c353509SHugo Santos 	UDPChecksumField;
746c353509SHugo Santos 
75bf48e753SHugo Santos class UdpDomainSupport;
766c353509SHugo Santos 
77bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> {
78c22d69bfSAxel Dörfler public:
79c22d69bfSAxel Dörfler 								UdpEndpoint(net_socket* socket);
80bf48e753SHugo Santos 
8153f23f85SHugo Santos 			status_t			Bind(const sockaddr* newAddr);
82c22d69bfSAxel Dörfler 			status_t			Unbind(sockaddr* newAddr);
83c22d69bfSAxel Dörfler 			status_t			Connect(const sockaddr* newAddr);
84c22d69bfSAxel Dörfler 
85c22d69bfSAxel Dörfler 			status_t			Open();
86c22d69bfSAxel Dörfler 			status_t			Close();
87c22d69bfSAxel Dörfler 			status_t			Free();
88c22d69bfSAxel Dörfler 
8956f097ebSOliver Tappe 			status_t			SendRoutedData(net_buffer* buffer,
9056f097ebSOliver Tappe 									net_route* route);
91bf48e753SHugo Santos 			status_t			SendData(net_buffer* buffer);
92c22d69bfSAxel Dörfler 
93c22d69bfSAxel Dörfler 			ssize_t				BytesAvailable();
94c22d69bfSAxel Dörfler 			status_t			FetchData(size_t numBytes, uint32 flags,
95c22d69bfSAxel Dörfler 									net_buffer** _buffer);
96c22d69bfSAxel Dörfler 
97c22d69bfSAxel Dörfler 			status_t			StoreData(net_buffer* buffer);
986a606180SHugo Santos 			status_t			DeliverData(net_buffer* buffer);
99c22d69bfSAxel Dörfler 
100727ad0b0SHugo Santos 			// only the domain support will change/check the Active flag so
101727ad0b0SHugo Santos 			// we don't really need to protect it with the socket lock.
102727ad0b0SHugo Santos 			bool				IsActive() const { return fActive; }
103727ad0b0SHugo Santos 			void				SetActive(bool newValue) { fActive = newValue; }
104bf48e753SHugo Santos 
1055147963dSStephan Aßmus 			UdpEndpoint*&		HashTableLink() { return fLink; }
10640bbf860SHugo Santos 
107cb99c915SAxel Dörfler 			void				Dump() const;
108cb99c915SAxel Dörfler 
109c22d69bfSAxel Dörfler private:
110c72ab92dSHugo Santos 			UdpDomainSupport*	fManager;
111c22d69bfSAxel Dörfler 			bool				fActive;
11256f097ebSOliver Tappe 									// an active UdpEndpoint is part of the
113cb99c915SAxel Dörfler 									// endpoint hash (and it is bound and
114cb99c915SAxel Dörfler 									// optionally connected)
11540bbf860SHugo Santos 
1165147963dSStephan Aßmus 			UdpEndpoint*		fLink;
11740bbf860SHugo Santos };
11840bbf860SHugo Santos 
11940bbf860SHugo Santos 
12040bbf860SHugo Santos class UdpDomainSupport;
12140bbf860SHugo Santos 
12240bbf860SHugo Santos struct UdpHashDefinition {
12340bbf860SHugo Santos 	typedef net_address_module_info ParentType;
12440bbf860SHugo Santos 	typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
12540bbf860SHugo Santos 	typedef UdpEndpoint ValueType;
12640bbf860SHugo Santos 
12784052230SAxel Dörfler 	UdpHashDefinition(net_address_module_info *_module)
12884052230SAxel Dörfler 		: module(_module) {}
12984052230SAxel Dörfler 	UdpHashDefinition(const UdpHashDefinition& definition)
13084052230SAxel Dörfler 		: module(definition.module) {}
13140bbf860SHugo Santos 
13240bbf860SHugo Santos 	size_t HashKey(const KeyType &key) const
13340bbf860SHugo Santos 	{
13440bbf860SHugo Santos 		return _Mix(module->hash_address_pair(key.first, key.second));
13540bbf860SHugo Santos 	}
13640bbf860SHugo Santos 
13740bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
13840bbf860SHugo Santos 	{
13956f097ebSOliver Tappe 		return _Mix(endpoint->LocalAddress().HashPair(
14056f097ebSOliver Tappe 			*endpoint->PeerAddress()));
14140bbf860SHugo Santos 	}
14240bbf860SHugo Santos 
14340bbf860SHugo Santos 	static size_t _Mix(size_t hash)
14440bbf860SHugo Santos 	{
14556f097ebSOliver Tappe 		// move the bits into the relevant range (as defined by kNumHashBuckets)
14640bbf860SHugo Santos 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
14740bbf860SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
14840bbf860SHugo Santos 	}
14940bbf860SHugo Santos 
15040bbf860SHugo Santos 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
15140bbf860SHugo Santos 	{
15240bbf860SHugo Santos 		return endpoint->LocalAddress().EqualTo(key.first, true)
15340bbf860SHugo Santos 			&& endpoint->PeerAddress().EqualTo(key.second, true);
15440bbf860SHugo Santos 	}
15540bbf860SHugo Santos 
1565147963dSStephan Aßmus 	UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const
15740bbf860SHugo Santos 	{
15840bbf860SHugo Santos 		return endpoint->HashTableLink();
15940bbf860SHugo Santos 	}
16040bbf860SHugo Santos 
16140bbf860SHugo Santos 	net_address_module_info *module;
162c22d69bfSAxel Dörfler };
163c22d69bfSAxel Dörfler 
164c22d69bfSAxel Dörfler 
165bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
166c22d69bfSAxel Dörfler public:
167bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
168727ad0b0SHugo Santos 	~UdpDomainSupport();
169c22d69bfSAxel Dörfler 
170276aa463SIngo Weinhold 	status_t Init();
171bf48e753SHugo Santos 
172bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
173bf48e753SHugo Santos 
174bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
175727ad0b0SHugo Santos 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
176bf48e753SHugo Santos 
177bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer* buffer);
1782bb43d82SAxel Dörfler 	status_t DeliverError(status_t error, net_buffer* buffer);
179727ad0b0SHugo Santos 
180727ad0b0SHugo Santos 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
181727ad0b0SHugo Santos 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
182727ad0b0SHugo Santos 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
183727ad0b0SHugo Santos 
184cf5d9f4bSHugo Santos 	void DumpEndpoints() const;
185bf48e753SHugo Santos 
186c22d69bfSAxel Dörfler private:
187727ad0b0SHugo Santos 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
188727ad0b0SHugo Santos 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
189727ad0b0SHugo Santos 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
190727ad0b0SHugo Santos 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
191727ad0b0SHugo Santos 
19240bbf860SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
193bbbb5592SAxel Dörfler 		const sockaddr *peerAddress, uint32 index = 0);
194bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
195bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
196bf48e753SHugo Santos 
197bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
198727ad0b0SHugo Santos 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
199bf48e753SHugo Santos 
200bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
201727ad0b0SHugo Santos 		{ return fDomain->address_module; }
202bf48e753SHugo Santos 
2035147963dSStephan Aßmus 	typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable;
20440bbf860SHugo Santos 
2052b07b8e0SIngo Weinhold 	mutex			fLock;
206bf48e753SHugo Santos 	net_domain		*fDomain;
207bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
20840bbf860SHugo Santos 	EndpointTable	fActiveEndpoints;
209bf48e753SHugo Santos 	uint32			fEndpointCount;
210bf48e753SHugo Santos 
211bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
212bf48e753SHugo Santos 	static const uint16		kLast = 65535;
213bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
214bf48e753SHugo Santos 							// if you change this, adjust the shifting in
215bf48e753SHugo Santos 							// Hash() accordingly!
216bf48e753SHugo Santos };
217bf48e753SHugo Santos 
218bf48e753SHugo Santos 
219bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
220bf48e753SHugo Santos 
221bf48e753SHugo Santos 
222bf48e753SHugo Santos class UdpEndpointManager {
223c22d69bfSAxel Dörfler public:
224c22d69bfSAxel Dörfler 								UdpEndpointManager();
225c22d69bfSAxel Dörfler 								~UdpEndpointManager();
226c22d69bfSAxel Dörfler 
2272bb43d82SAxel Dörfler 			status_t			InitCheck() const;
2282bb43d82SAxel Dörfler 
22974e1a530SJérôme Duval 			status_t			ReceiveData(net_buffer* buffer);
2302bb43d82SAxel Dörfler 			status_t			ReceiveError(status_t error,
2312bb43d82SAxel Dörfler 									net_buffer* buffer);
23274e1a530SJérôme Duval 			status_t			Deframe(net_buffer* buffer);
233c22d69bfSAxel Dörfler 
234bf48e753SHugo Santos 			UdpDomainSupport*	OpenEndpoint(UdpEndpoint* endpoint);
235bf48e753SHugo Santos 			status_t			FreeEndpoint(UdpDomainSupport* domain);
236c22d69bfSAxel Dörfler 
237cf5d9f4bSHugo Santos 	static	int					DumpEndpoints(int argc, char *argv[]);
238cf5d9f4bSHugo Santos 
239c22d69bfSAxel Dörfler private:
2409d433190SAxel Dörfler 	inline	net_domain*			_GetDomain(net_buffer* buffer);
2419d433190SAxel Dörfler 			UdpDomainSupport*	_GetDomainSupport(net_domain* domain,
2429d433190SAxel Dörfler 									bool create);
2439d433190SAxel Dörfler 			UdpDomainSupport*	_GetDomainSupport(net_buffer* buffer);
244bf48e753SHugo Santos 
2452b07b8e0SIngo Weinhold 			mutex				fLock;
246c22d69bfSAxel Dörfler 			status_t			fStatus;
247bf48e753SHugo Santos 			UdpDomainList		fDomains;
248c22d69bfSAxel Dörfler };
249c22d69bfSAxel Dörfler 
250c22d69bfSAxel Dörfler 
251c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
252c22d69bfSAxel Dörfler 
253c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
254658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
255658a5506SHugo Santos net_stack_module_info *gStackModule;
2562bb43d82SAxel Dörfler net_socket_module_info *gSocketModule;
257c22d69bfSAxel Dörfler 
258c22d69bfSAxel Dörfler 
259c22d69bfSAxel Dörfler // #pragma mark -
260c22d69bfSAxel Dörfler 
261c22d69bfSAxel Dörfler 
262bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
263c22d69bfSAxel Dörfler 	:
264bf48e753SHugo Santos 	fDomain(domain),
265276aa463SIngo Weinhold 	fActiveEndpoints(domain->address_module),
266bf48e753SHugo Santos 	fEndpointCount(0)
267c22d69bfSAxel Dörfler {
2682b07b8e0SIngo Weinhold 	mutex_init(&fLock, "udp domain");
269727ad0b0SHugo Santos 
270727ad0b0SHugo Santos 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
271727ad0b0SHugo Santos }
272727ad0b0SHugo Santos 
273727ad0b0SHugo Santos 
274727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
275727ad0b0SHugo Santos {
2762b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
277bf48e753SHugo Santos }
278bf48e753SHugo Santos 
279bf48e753SHugo Santos 
280bf48e753SHugo Santos status_t
281276aa463SIngo Weinhold UdpDomainSupport::Init()
282bf48e753SHugo Santos {
283276aa463SIngo Weinhold 	return fActiveEndpoints.Init(kNumHashBuckets);
284bf48e753SHugo Santos }
285bf48e753SHugo Santos 
286bf48e753SHugo Santos 
287bf48e753SHugo Santos status_t
288bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
289bf48e753SHugo Santos {
2902bb43d82SAxel Dörfler 	// NOTE: multicast is delivered directly to the endpoint
2912b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
292727ad0b0SHugo Santos 
2932bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_BCAST) != 0)
294bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
2952bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_MCAST) != 0)
296727ad0b0SHugo Santos 		return B_ERROR;
297bf48e753SHugo Santos 
298bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
299bf48e753SHugo Santos }
300bf48e753SHugo Santos 
301bf48e753SHugo Santos 
302bf48e753SHugo Santos status_t
3032bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
3042bb43d82SAxel Dörfler {
3052bb43d82SAxel Dörfler 	if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0)
3062bb43d82SAxel Dörfler 		return B_ERROR;
3072bb43d82SAxel Dörfler 
3082bb43d82SAxel Dörfler 	MutexLocker _(fLock);
3092bb43d82SAxel Dörfler 
3102e1729d0SAxel Dörfler 	// Forward the error to the socket
3112e1729d0SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source,
3122e1729d0SAxel Dörfler 		buffer->destination);
3132e1729d0SAxel Dörfler 	if (endpoint != NULL) {
3142bb43d82SAxel Dörfler 		gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error);
3152e1729d0SAxel Dörfler 		endpoint->NotifyOne();
3162e1729d0SAxel Dörfler 	}
3172bb43d82SAxel Dörfler 
3182bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
3192bb43d82SAxel Dörfler 	return B_OK;
3202bb43d82SAxel Dörfler }
3212bb43d82SAxel Dörfler 
3222bb43d82SAxel Dörfler 
3232bb43d82SAxel Dörfler status_t
324727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
325727ad0b0SHugo Santos 	const sockaddr *address)
326727ad0b0SHugo Santos {
32756f097ebSOliver Tappe 	if (!AddressModule()->is_same_family(address))
32856f097ebSOliver Tappe 		return EAFNOSUPPORT;
32956f097ebSOliver Tappe 
3302b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
331727ad0b0SHugo Santos 
332727ad0b0SHugo Santos 	if (endpoint->IsActive())
333727ad0b0SHugo Santos 		return EINVAL;
334727ad0b0SHugo Santos 
335727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, address);
336727ad0b0SHugo Santos }
337727ad0b0SHugo Santos 
338727ad0b0SHugo Santos 
339727ad0b0SHugo Santos status_t
340727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
341727ad0b0SHugo Santos 	const sockaddr *address)
342727ad0b0SHugo Santos {
3432b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
344727ad0b0SHugo Santos 
345727ad0b0SHugo Santos 	if (endpoint->IsActive()) {
346727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
347727ad0b0SHugo Santos 		endpoint->SetActive(false);
348727ad0b0SHugo Santos 	}
349727ad0b0SHugo Santos 
350727ad0b0SHugo Santos 	if (address->sa_family == AF_UNSPEC) {
351727ad0b0SHugo Santos 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
352727ad0b0SHugo Santos 		// so we reset the peer address:
353727ad0b0SHugo Santos 		endpoint->PeerAddress().SetToEmpty();
354727ad0b0SHugo Santos 	} else {
35556f097ebSOliver Tappe 		if (!AddressModule()->is_same_family(address))
35656f097ebSOliver Tappe 			return EAFNOSUPPORT;
35756f097ebSOliver Tappe 
35856f097ebSOliver Tappe 		// consider destination address INADDR_ANY as INADDR_LOOPBACK
35956f097ebSOliver Tappe 		sockaddr_storage _address;
36056f097ebSOliver Tappe 		if (AddressModule()->is_empty_address(address, false)) {
36156f097ebSOliver Tappe 			AddressModule()->get_loopback_address((sockaddr *)&_address);
36256f097ebSOliver Tappe 			// for IPv4 and IPv6 the port is at the same offset
36356f097ebSOliver Tappe 			((sockaddr_in&)_address).sin_port
36456f097ebSOliver Tappe 				= ((sockaddr_in *)address)->sin_port;
36556f097ebSOliver Tappe 			address = (sockaddr *)&_address;
36656f097ebSOliver Tappe 		}
36756f097ebSOliver Tappe 
368727ad0b0SHugo Santos 		status_t status = endpoint->PeerAddress().SetTo(address);
369727ad0b0SHugo Santos 		if (status < B_OK)
370727ad0b0SHugo Santos 			return status;
3714e45de0eSOliver Tappe 		struct net_route *routeToDestination
3724e45de0eSOliver Tappe 			= gDatalinkModule->get_route(fDomain, address);
3734e45de0eSOliver Tappe 		if (routeToDestination) {
374184fada4SPhilippe Houdoin 			// stay bound to current local port, if any.
375184fada4SPhilippe Houdoin 			uint16 port = endpoint->LocalAddress().Port();
3764e45de0eSOliver Tappe 			status = endpoint->LocalAddress().SetTo(
37761729d93SAxel Dörfler 				routeToDestination->interface_address->local);
378184fada4SPhilippe Houdoin 			endpoint->LocalAddress().SetPort(port);
3794e45de0eSOliver Tappe 			gDatalinkModule->put_route(fDomain, routeToDestination);
3804e45de0eSOliver Tappe 			if (status < B_OK)
3814e45de0eSOliver Tappe 				return status;
3824e45de0eSOliver Tappe 		}
383727ad0b0SHugo Santos 	}
384727ad0b0SHugo Santos 
385727ad0b0SHugo Santos 	// we need to activate no matter whether or not we have just disconnected,
386727ad0b0SHugo Santos 	// as calling connect() always triggers an implicit bind():
387*a03ed4faSJérôme Duval 	status_t status = _BindEndpoint(endpoint, *endpoint->LocalAddress());
388*a03ed4faSJérôme Duval 	if (status == B_OK)
389*a03ed4faSJérôme Duval 		gSocketModule->set_connected(endpoint->Socket());
390*a03ed4faSJérôme Duval 	return status;
391727ad0b0SHugo Santos }
392727ad0b0SHugo Santos 
393727ad0b0SHugo Santos 
394727ad0b0SHugo Santos status_t
395727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
396727ad0b0SHugo Santos {
3972b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
398727ad0b0SHugo Santos 
399727ad0b0SHugo Santos 	if (endpoint->IsActive())
400727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
401727ad0b0SHugo Santos 
402727ad0b0SHugo Santos 	endpoint->SetActive(false);
403727ad0b0SHugo Santos 
404727ad0b0SHugo Santos 	return B_OK;
405727ad0b0SHugo Santos }
406727ad0b0SHugo Santos 
407727ad0b0SHugo Santos 
408cf5d9f4bSHugo Santos void
409cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
410cf5d9f4bSHugo Santos {
411cf5d9f4bSHugo Santos 	kprintf("-------- UDP Domain %p ---------\n", this);
412cf5d9f4bSHugo Santos 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
413cf5d9f4bSHugo Santos 
414cf5d9f4bSHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
415cf5d9f4bSHugo Santos 
416cb99c915SAxel Dörfler 	while (UdpEndpoint* endpoint = it.Next()) {
417cb99c915SAxel Dörfler 		endpoint->Dump();
418cf5d9f4bSHugo Santos 	}
419cf5d9f4bSHugo Santos }
420cf5d9f4bSHugo Santos 
421cf5d9f4bSHugo Santos 
422727ad0b0SHugo Santos status_t
423727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
424727ad0b0SHugo Santos 	const sockaddr *address)
425727ad0b0SHugo Santos {
426727ad0b0SHugo Santos 	if (AddressModule()->get_port(address) == 0)
427727ad0b0SHugo Santos 		return _BindToEphemeral(endpoint, address);
428727ad0b0SHugo Santos 
429727ad0b0SHugo Santos 	return _Bind(endpoint, address);
430727ad0b0SHugo Santos }
431727ad0b0SHugo Santos 
432727ad0b0SHugo Santos 
433727ad0b0SHugo Santos status_t
434727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
435727ad0b0SHugo Santos {
436727ad0b0SHugo Santos 	int socketOptions = endpoint->Socket()->options;
43740bbf860SHugo Santos 
43840bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
439bf48e753SHugo Santos 
440bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
441bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
442727ad0b0SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
443727ad0b0SHugo Santos 		address, true).Data());
444727ad0b0SHugo Santos 
44540bbf860SHugo Santos 	while (it.HasNext()) {
44640bbf860SHugo Santos 		UdpEndpoint *otherEndpoint = it.Next();
44725a2744fSHugo Santos 
448bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
4495084c839SHugo Santos 			ntohs(otherEndpoint->LocalAddress().Port()));
45025a2744fSHugo Santos 
45125a2744fSHugo Santos 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
452bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
45356f097ebSOliver Tappe 			if ((otherEndpoint->Socket()->options
45456f097ebSOliver Tappe 					& (SO_REUSEADDR | SO_REUSEPORT)) == 0
455d0eaec30SMichael Lotz 				|| (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
456727ad0b0SHugo Santos 				return EADDRINUSE;
45725a2744fSHugo Santos 
458bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
45925a2744fSHugo Santos 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
460d0eaec30SMichael Lotz 				&& ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
461d0eaec30SMichael Lotz 					|| (socketOptions & SO_REUSEPORT) == 0))
462727ad0b0SHugo Santos 				return EADDRINUSE;
463bf48e753SHugo Santos 		}
464bf48e753SHugo Santos 	}
465bf48e753SHugo Santos 
466727ad0b0SHugo Santos 	return _FinishBind(endpoint, address);
467bf48e753SHugo Santos }
468bf48e753SHugo Santos 
469bf48e753SHugo Santos 
470bf48e753SHugo Santos status_t
471727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
472727ad0b0SHugo Santos 	const sockaddr *address)
473727ad0b0SHugo Santos {
474727ad0b0SHugo Santos 	SocketAddressStorage newAddress(AddressModule());
475727ad0b0SHugo Santos 	status_t status = newAddress.SetTo(address);
476727ad0b0SHugo Santos 	if (status < B_OK)
477727ad0b0SHugo Santos 		return status;
478727ad0b0SHugo Santos 
479727ad0b0SHugo Santos 	uint16 allocedPort = _GetNextEphemeral();
480727ad0b0SHugo Santos 	if (allocedPort == 0)
481727ad0b0SHugo Santos 		return ENOBUFS;
482727ad0b0SHugo Santos 
4839e051839SOliver Tappe 	newAddress.SetPort(htons(allocedPort));
484727ad0b0SHugo Santos 
485727ad0b0SHugo Santos 	return _FinishBind(endpoint, *newAddress);
486727ad0b0SHugo Santos }
487727ad0b0SHugo Santos 
488727ad0b0SHugo Santos 
489727ad0b0SHugo Santos status_t
490727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
491727ad0b0SHugo Santos {
492727ad0b0SHugo Santos 	status_t status = endpoint->next->module->bind(endpoint->next, address);
493727ad0b0SHugo Santos 	if (status < B_OK)
494727ad0b0SHugo Santos 		return status;
49540bbf860SHugo Santos 
49640bbf860SHugo Santos 	fActiveEndpoints.Insert(endpoint);
497727ad0b0SHugo Santos 	endpoint->SetActive(true);
498727ad0b0SHugo Santos 
49940bbf860SHugo Santos 	return B_OK;
500bf48e753SHugo Santos }
501bf48e753SHugo Santos 
502bf48e753SHugo Santos 
503c22d69bfSAxel Dörfler UdpEndpoint *
50440bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
505bbbb5592SAxel Dörfler 	const sockaddr *peerAddress, uint32 index)
506c22d69bfSAxel Dörfler {
5072e1729d0SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
5082e1729d0SAxel Dörfler 
5099e051839SOliver Tappe 	TRACE_DOMAIN("finding Endpoint for %s <- %s",
510bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
511bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
512c3e054c8SHugo Santos 
513bbbb5592SAxel Dörfler 	UdpEndpoint* endpoint = fActiveEndpoints.Lookup(
514bbbb5592SAxel Dörfler 		std::make_pair(ourAddress, peerAddress));
515bbbb5592SAxel Dörfler 
516bbbb5592SAxel Dörfler 	// Make sure the bound_to_device constraint is fulfilled
517da0d7409SAxel Dörfler 	while (endpoint != NULL && endpoint->socket->bound_to_device != 0
518da0d7409SAxel Dörfler 		&& index != 0 && endpoint->socket->bound_to_device != index) {
519bbbb5592SAxel Dörfler 		endpoint = endpoint->HashTableLink();
520bbbb5592SAxel Dörfler 		if (endpoint != NULL
521bbbb5592SAxel Dörfler 			&& (!endpoint->LocalAddress().EqualTo(ourAddress, true)
522bbbb5592SAxel Dörfler 				|| !endpoint->PeerAddress().EqualTo(peerAddress, true)))
523bbbb5592SAxel Dörfler 			return NULL;
524bbbb5592SAxel Dörfler 	}
525bbbb5592SAxel Dörfler 
526bbbb5592SAxel Dörfler 	return endpoint;
527c22d69bfSAxel Dörfler }
528c22d69bfSAxel Dörfler 
529c22d69bfSAxel Dörfler 
530c22d69bfSAxel Dörfler status_t
531bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
532c22d69bfSAxel Dörfler {
53379a0d252SHugo Santos 	sockaddr* peerAddr = buffer->source;
53479a0d252SHugo Santos 	sockaddr* broadcastAddr = buffer->destination;
5359d433190SAxel Dörfler 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
5369d433190SAxel Dörfler 
537c22d69bfSAxel Dörfler 	sockaddr* mask = NULL;
53861729d93SAxel Dörfler 	if (buffer->interface_address != NULL)
53961729d93SAxel Dörfler 		mask = (sockaddr*)buffer->interface_address->mask;
540c22d69bfSAxel Dörfler 
5419d433190SAxel Dörfler 	TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
542c22d69bfSAxel Dörfler 
5439d433190SAxel Dörfler 	EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
544c22d69bfSAxel Dörfler 
5459d433190SAxel Dörfler 	while (UdpEndpoint* endpoint = iterator.Next()) {
54625a2744fSHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
54725a2744fSHugo Santos 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
54825a2744fSHugo Santos 
549bbbb5592SAxel Dörfler 		if (endpoint->socket->bound_to_device != 0
550bbbb5592SAxel Dörfler 			&& buffer->index != endpoint->socket->bound_to_device)
551bbbb5592SAxel Dörfler 			continue;
552bbbb5592SAxel Dörfler 
5535084c839SHugo Santos 		if (endpoint->LocalAddress().Port() != incomingPort) {
554c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
555c22d69bfSAxel Dörfler 			continue;
556c22d69bfSAxel Dörfler 		}
557c22d69bfSAxel Dörfler 
55825a2744fSHugo Santos 		if (!endpoint->PeerAddress().IsEmpty(true)) {
559c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
560c22d69bfSAxel Dörfler 			// this datagram is from there:
56125a2744fSHugo Santos 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
562c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
563c22d69bfSAxel Dörfler 				// this endpoint...
564c22d69bfSAxel Dörfler 				continue;
565c22d69bfSAxel Dörfler 			}
566c22d69bfSAxel Dörfler 		}
567c22d69bfSAxel Dörfler 
56825a2744fSHugo Santos 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
5699d433190SAxel Dörfler 			|| mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
570c22d69bfSAxel Dörfler 			// address matches, dispatch to this endpoint:
571c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
572c22d69bfSAxel Dörfler 		}
573c22d69bfSAxel Dörfler 	}
57440bbf860SHugo Santos 
575c22d69bfSAxel Dörfler 	return B_OK;
576c22d69bfSAxel Dörfler }
577c22d69bfSAxel Dörfler 
578c22d69bfSAxel Dörfler 
579c22d69bfSAxel Dörfler status_t
580bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
581c22d69bfSAxel Dörfler {
582bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
583c22d69bfSAxel Dörfler 
5842e1729d0SAxel Dörfler 	const sockaddr* localAddress = buffer->destination;
5852e1729d0SAxel Dörfler 	const sockaddr* peerAddress = buffer->source;
5862e1729d0SAxel Dörfler 
5872e1729d0SAxel Dörfler 	// look for full (most special) match:
588bbbb5592SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress,
589bbbb5592SAxel Dörfler 		buffer->index);
5902e1729d0SAxel Dörfler 	if (endpoint == NULL) {
5912e1729d0SAxel Dörfler 		// look for endpoint matching local address & port:
592bbbb5592SAxel Dörfler 		endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index);
5932e1729d0SAxel Dörfler 		if (endpoint == NULL) {
5942e1729d0SAxel Dörfler 			// look for endpoint matching peer address & port and local port:
5952e1729d0SAxel Dörfler 			SocketAddressStorage local(AddressModule());
5962e1729d0SAxel Dörfler 			local.SetToEmpty();
5972e1729d0SAxel Dörfler 			local.SetPort(AddressModule()->get_port(localAddress));
598bbbb5592SAxel Dörfler 			endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index);
5992e1729d0SAxel Dörfler 			if (endpoint == NULL) {
6002e1729d0SAxel Dörfler 				// last chance: look for endpoint matching local port only:
601bbbb5592SAxel Dörfler 				endpoint = _FindActiveEndpoint(*local, NULL, buffer->index);
6022e1729d0SAxel Dörfler 			}
6032e1729d0SAxel Dörfler 		}
6042e1729d0SAxel Dörfler 	}
6052e1729d0SAxel Dörfler 
6062bb43d82SAxel Dörfler 	if (endpoint == NULL) {
6072bb43d82SAxel Dörfler 		TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
608c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
6099e051839SOliver Tappe 	}
610c22d69bfSAxel Dörfler 
611c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
612c22d69bfSAxel Dörfler 	return B_OK;
613c22d69bfSAxel Dörfler }
614c22d69bfSAxel Dörfler 
615c22d69bfSAxel Dörfler 
616bf48e753SHugo Santos uint16
617bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
618c22d69bfSAxel Dörfler {
61940bbf860SHugo Santos 	uint16 stop, curr;
620bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
621bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
622bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
623bf48e753SHugo Santos 	} else {
624bf48e753SHugo Santos 		stop = kLast;
625bf48e753SHugo Santos 		curr = kFirst;
626bf48e753SHugo Santos 	}
627c22d69bfSAxel Dörfler 
628727ad0b0SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
629727ad0b0SHugo Santos 		fLastUsedEphemeral, curr, stop);
63040bbf860SHugo Santos 
6319e051839SOliver Tappe 	// TODO: a free list could be used to avoid the impact of these two
6329e051839SOliver Tappe 	//        nested loops most of the time... let's see how bad this really is
633727ad0b0SHugo Santos 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
634bf48e753SHugo Santos 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
63540bbf860SHugo Santos 
636727ad0b0SHugo Santos 		if (_EndpointWithPort(htons(curr)) == NULL) {
637bf48e753SHugo Santos 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
638bf48e753SHugo Santos 			fLastUsedEphemeral = curr;
639bf48e753SHugo Santos 			return curr;
640bf48e753SHugo Santos 		}
641727ad0b0SHugo Santos 	}
642727ad0b0SHugo Santos 
643727ad0b0SHugo Santos 	return 0;
644727ad0b0SHugo Santos }
645727ad0b0SHugo Santos 
646727ad0b0SHugo Santos 
647727ad0b0SHugo Santos UdpEndpoint *
648727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const
649727ad0b0SHugo Santos {
650727ad0b0SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
651727ad0b0SHugo Santos 
652727ad0b0SHugo Santos 	while (it.HasNext()) {
653727ad0b0SHugo Santos 		UdpEndpoint *endpoint = it.Next();
654727ad0b0SHugo Santos 		if (endpoint->LocalAddress().Port() == port)
655727ad0b0SHugo Santos 			return endpoint;
656727ad0b0SHugo Santos 	}
657727ad0b0SHugo Santos 
658727ad0b0SHugo Santos 	return NULL;
659727ad0b0SHugo Santos }
660c22d69bfSAxel Dörfler 
661bf48e753SHugo Santos 
662bf48e753SHugo Santos // #pragma mark -
663bf48e753SHugo Santos 
664bf48e753SHugo Santos 
665bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
666bf48e753SHugo Santos {
6672b07b8e0SIngo Weinhold 	mutex_init(&fLock, "UDP endpoints");
6682b07b8e0SIngo Weinhold 	fStatus = B_OK;
669bf48e753SHugo Santos }
670bf48e753SHugo Santos 
671bf48e753SHugo Santos 
672bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
673bf48e753SHugo Santos {
6742b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
675bf48e753SHugo Santos }
676bf48e753SHugo Santos 
677bf48e753SHugo Santos 
678bf48e753SHugo Santos status_t
679bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
680bf48e753SHugo Santos {
681bf48e753SHugo Santos 	return fStatus;
682bf48e753SHugo Santos }
683bf48e753SHugo Santos 
684bf48e753SHugo Santos 
685cf5d9f4bSHugo Santos int
686cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
687cf5d9f4bSHugo Santos {
688cf5d9f4bSHugo Santos 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
689cf5d9f4bSHugo Santos 
690eb5604bcSAdrien Destugues 	kprintf("===== UDP domain manager %p =====\n", sUdpEndpointManager);
691eb5604bcSAdrien Destugues 
692cf5d9f4bSHugo Santos 	while (it.HasNext())
693cf5d9f4bSHugo Santos 		it.Next()->DumpEndpoints();
694cf5d9f4bSHugo Santos 
695cf5d9f4bSHugo Santos 	return 0;
696cf5d9f4bSHugo Santos }
697cf5d9f4bSHugo Santos 
698cf5d9f4bSHugo Santos 
699bf48e753SHugo Santos // #pragma mark - inbound
700bf48e753SHugo Santos 
701bf48e753SHugo Santos 
702bf48e753SHugo Santos status_t
70374e1a530SJérôme Duval UdpEndpointManager::ReceiveData(net_buffer *buffer)
704c22d69bfSAxel Dörfler {
7052bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
7062bb43d82SAxel Dörfler 
7079d433190SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7082bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
7092bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
7102bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7112bb43d82SAxel Dörfler 		return B_ERROR;
7122bb43d82SAxel Dörfler 	}
7132bb43d82SAxel Dörfler 
71474e1a530SJérôme Duval 	status_t status = Deframe(buffer);
715eb5604bcSAdrien Destugues 	if (status != B_OK) {
716eb5604bcSAdrien Destugues 		sUdpEndpointManager->FreeEndpoint(domainSupport);
7176a606180SHugo Santos 		return status;
718eb5604bcSAdrien Destugues 	}
7196a606180SHugo Santos 
7202bb43d82SAxel Dörfler 	status = domainSupport->DemuxIncomingBuffer(buffer);
7212bb43d82SAxel Dörfler 	if (status != B_OK) {
7222bb43d82SAxel Dörfler 		TRACE_EPM("  ReceiveData(): no endpoint.");
7232bb43d82SAxel Dörfler 		// Send port unreachable error
7242bb43d82SAxel Dörfler 		domainSupport->Domain()->module->error_reply(NULL, buffer,
7252b415445SAxel Dörfler 			B_NET_ERROR_UNREACH_PORT, NULL);
726eb5604bcSAdrien Destugues 		sUdpEndpointManager->FreeEndpoint(domainSupport);
7272bb43d82SAxel Dörfler 		return B_ERROR;
7282bb43d82SAxel Dörfler 	}
7292bb43d82SAxel Dörfler 
7302bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
731eb5604bcSAdrien Destugues 	sUdpEndpointManager->FreeEndpoint(domainSupport);
7322bb43d82SAxel Dörfler 	return B_OK;
7332bb43d82SAxel Dörfler }
7342bb43d82SAxel Dörfler 
7352bb43d82SAxel Dörfler 
7362bb43d82SAxel Dörfler status_t
7372bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
7382bb43d82SAxel Dörfler {
7392bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
7402bb43d82SAxel Dörfler 		error, buffer, buffer->size);
7412bb43d82SAxel Dörfler 
7422bb43d82SAxel Dörfler 	// We only really need the port information
7432bb43d82SAxel Dörfler 	if (buffer->size < 4)
7442bb43d82SAxel Dörfler 		return B_BAD_VALUE;
7452bb43d82SAxel Dörfler 
7469d433190SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7472bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
7482bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
7492bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7502bb43d82SAxel Dörfler 		return B_ERROR;
7512bb43d82SAxel Dörfler 	}
7522bb43d82SAxel Dörfler 
7532bb43d82SAxel Dörfler 	// Deframe the buffer manually, as we usually only get 8 bytes from the
7542bb43d82SAxel Dörfler 	// original packet
7552bb43d82SAxel Dörfler 	udp_header header;
7562bb43d82SAxel Dörfler 	if (gBufferModule->read(buffer, 0, &header,
757eb5604bcSAdrien Destugues 			std::min((size_t)buffer->size, sizeof(udp_header))) != B_OK) {
758eb5604bcSAdrien Destugues 		sUdpEndpointManager->FreeEndpoint(domainSupport);
7592bb43d82SAxel Dörfler 		return B_BAD_VALUE;
760eb5604bcSAdrien Destugues 	}
761bf48e753SHugo Santos 
76261729d93SAxel Dörfler 	net_domain* domain = buffer->interface_address->domain;
7632bb43d82SAxel Dörfler 	net_address_module_info* addressModule = domain->address_module;
7646a606180SHugo Santos 
7652bb43d82SAxel Dörfler 	SocketAddress source(addressModule, buffer->source);
7662bb43d82SAxel Dörfler 	SocketAddress destination(addressModule, buffer->destination);
7676a606180SHugo Santos 
7682bb43d82SAxel Dörfler 	source.SetPort(header.source_port);
7692bb43d82SAxel Dörfler 	destination.SetPort(header.destination_port);
770727ad0b0SHugo Santos 
771eb5604bcSAdrien Destugues 	error = domainSupport->DeliverError(error, buffer);
772eb5604bcSAdrien Destugues 	sUdpEndpointManager->FreeEndpoint(domainSupport);
773eb5604bcSAdrien Destugues 	return error;
7746a606180SHugo Santos }
7756a606180SHugo Santos 
7766a606180SHugo Santos 
7776a606180SHugo Santos status_t
77874e1a530SJérôme Duval UdpEndpointManager::Deframe(net_buffer* buffer)
7796a606180SHugo Santos {
780bf9a85cbSJérôme Duval 	TRACE_EPM("Deframe(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
7816a606180SHugo Santos 
78287001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
7839d433190SAxel Dörfler 	if (bufferHeader.Status() != B_OK)
784c22d69bfSAxel Dörfler 		return bufferHeader.Status();
785c22d69bfSAxel Dörfler 
786c22d69bfSAxel Dörfler 	udp_header& header = bufferHeader.Data();
787c22d69bfSAxel Dörfler 
7889d433190SAxel Dörfler 	net_domain* domain = _GetDomain(buffer);
7899d433190SAxel Dörfler 	if (domain == NULL) {
7906a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
79161729d93SAxel Dörfler 			"specified (interface address %p).", buffer->interface_address);
792c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
793c22d69bfSAxel Dörfler 	}
794bf48e753SHugo Santos 	net_address_module_info* addressModule = domain->address_module;
795bf48e753SHugo Santos 
79679a0d252SHugo Santos 	SocketAddress source(addressModule, buffer->source);
79779a0d252SHugo Santos 	SocketAddress destination(addressModule, buffer->destination);
798bf48e753SHugo Santos 
7994e8a1b33SHugo Santos 	source.SetPort(header.source_port);
8004e8a1b33SHugo Santos 	destination.SetPort(header.destination_port);
8014e8a1b33SHugo Santos 
8024e8a1b33SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
8034e8a1b33SHugo Santos 		destination.AsString(true).Data());
804c22d69bfSAxel Dörfler 
805c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
806c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
8076a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
808bf48e753SHugo Santos 			udpLength);
809c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
810c22d69bfSAxel Dörfler 	}
811bf48e753SHugo Santos 
81274e1a530SJérôme Duval 	if (buffer->size > udpLength)
813c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
814c22d69bfSAxel Dörfler 
815c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
816c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
817d5b5a2c2SHugo Santos 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
81874e1a530SJérôme Duval 			buffer, IPPROTO_UDP);
819c22d69bfSAxel Dörfler 		if (sum != 0) {
8206a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
821c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
822c22d69bfSAxel Dörfler 		}
823c22d69bfSAxel Dörfler 	}
824c22d69bfSAxel Dörfler 
825c22d69bfSAxel Dörfler 	bufferHeader.Remove();
826c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
827c22d69bfSAxel Dörfler 
8286a606180SHugo Santos 	return B_OK;
829c22d69bfSAxel Dörfler }
830c22d69bfSAxel Dörfler 
831c22d69bfSAxel Dörfler 
832bf48e753SHugo Santos UdpDomainSupport *
833c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
834c22d69bfSAxel Dörfler {
8352b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
836bf48e753SHugo Santos 
8379d433190SAxel Dörfler 	UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
838bf48e753SHugo Santos 	if (domain)
839bf48e753SHugo Santos 		domain->Ref();
840bf48e753SHugo Santos 	return domain;
841bf48e753SHugo Santos }
842bf48e753SHugo Santos 
843bf48e753SHugo Santos 
844bf48e753SHugo Santos status_t
845bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
846bf48e753SHugo Santos {
8472b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
848bf48e753SHugo Santos 
849727ad0b0SHugo Santos 	if (domain->Put()) {
850bf48e753SHugo Santos 		fDomains.Remove(domain);
851bf48e753SHugo Santos 		delete domain;
852bf48e753SHugo Santos 	}
853bf48e753SHugo Santos 
854bf48e753SHugo Santos 	return B_OK;
855bf48e753SHugo Santos }
856bf48e753SHugo Santos 
857bf48e753SHugo Santos 
858bf48e753SHugo Santos // #pragma mark -
859bf48e753SHugo Santos 
860bf48e753SHugo Santos 
8619d433190SAxel Dörfler inline net_domain*
8629d433190SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer)
863bf48e753SHugo Santos {
8649d433190SAxel Dörfler 	if (buffer->interface_address != NULL)
8659d433190SAxel Dörfler 		return buffer->interface_address->domain;
8669d433190SAxel Dörfler 
8679d433190SAxel Dörfler 	return gStackModule->get_domain(buffer->destination->sa_family);
8689d433190SAxel Dörfler }
8699d433190SAxel Dörfler 
8709d433190SAxel Dörfler 
8719d433190SAxel Dörfler UdpDomainSupport*
8729d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create)
8739d433190SAxel Dörfler {
8749d433190SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
8759d433190SAxel Dörfler 
8769d433190SAxel Dörfler 	if (domain == NULL)
8779d433190SAxel Dörfler 		return NULL;
878bf48e753SHugo Santos 
879bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
880bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
881bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
882bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
883bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
884bf48e753SHugo Santos 	//      family.
8859d433190SAxel Dörfler 	UdpDomainList::Iterator iterator = fDomains.GetIterator();
8869d433190SAxel Dörfler 	while (UdpDomainSupport* domainSupport = iterator.Next()) {
887bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
888bf48e753SHugo Santos 			return domainSupport;
889bf48e753SHugo Santos 	}
890bf48e753SHugo Santos 
891bf48e753SHugo Santos 	if (!create)
892bf48e753SHugo Santos 		return NULL;
893bf48e753SHugo Santos 
8949d433190SAxel Dörfler 	UdpDomainSupport* domainSupport
8959d433190SAxel Dörfler 		= new (std::nothrow) UdpDomainSupport(domain);
896276aa463SIngo Weinhold 	if (domainSupport == NULL || domainSupport->Init() < B_OK) {
897bf48e753SHugo Santos 		delete domainSupport;
898bf48e753SHugo Santos 		return NULL;
899bf48e753SHugo Santos 	}
900bf48e753SHugo Santos 
901bf48e753SHugo Santos 	fDomains.Add(domainSupport);
902bf48e753SHugo Santos 	return domainSupport;
903c22d69bfSAxel Dörfler }
904c22d69bfSAxel Dörfler 
905c22d69bfSAxel Dörfler 
9069d433190SAxel Dörfler /*!	Retrieves the UdpDomainSupport object responsible for this buffer, if the
9079d433190SAxel Dörfler 	domain can be determined. This is only successful if the domain support is
9089d433190SAxel Dörfler 	already existing, ie. there must already be an endpoint for the domain.
9099d433190SAxel Dörfler */
9102bb43d82SAxel Dörfler UdpDomainSupport*
9119d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
9122bb43d82SAxel Dörfler {
9132bb43d82SAxel Dörfler 	MutexLocker _(fLock);
9149d433190SAxel Dörfler 
915eb5604bcSAdrien Destugues 	UdpDomainSupport* support = _GetDomainSupport(_GetDomain(buffer), false);
916eb5604bcSAdrien Destugues 	if (support)
917eb5604bcSAdrien Destugues 		support->Ref();
918eb5604bcSAdrien Destugues 	return support;
9192bb43d82SAxel Dörfler }
9202bb43d82SAxel Dörfler 
9212bb43d82SAxel Dörfler 
922c22d69bfSAxel Dörfler // #pragma mark -
923c22d69bfSAxel Dörfler 
924c22d69bfSAxel Dörfler 
925c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
926cb99c915SAxel Dörfler 	:
927cb99c915SAxel Dörfler 	DatagramSocket<>("udp endpoint", socket),
928cb99c915SAxel Dörfler 	fActive(false)
929cb99c915SAxel Dörfler {
930cb99c915SAxel Dörfler }
931bf48e753SHugo Santos 
932bf48e753SHugo Santos 
933c22d69bfSAxel Dörfler // #pragma mark - activation
934c22d69bfSAxel Dörfler 
935c22d69bfSAxel Dörfler 
936c22d69bfSAxel Dörfler status_t
93753f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
938c22d69bfSAxel Dörfler {
939bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
940727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
941c22d69bfSAxel Dörfler }
942c22d69bfSAxel Dörfler 
943c22d69bfSAxel Dörfler 
944c22d69bfSAxel Dörfler status_t
945c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
946c22d69bfSAxel Dörfler {
947bf48e753SHugo Santos 	TRACE_EP("Unbind()");
948727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
949c22d69bfSAxel Dörfler }
950c22d69bfSAxel Dörfler 
951c22d69bfSAxel Dörfler 
952c22d69bfSAxel Dörfler status_t
953c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
954c22d69bfSAxel Dörfler {
955bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
956727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
957c22d69bfSAxel Dörfler }
958c22d69bfSAxel Dörfler 
959c22d69bfSAxel Dörfler 
960c22d69bfSAxel Dörfler status_t
961c22d69bfSAxel Dörfler UdpEndpoint::Open()
962c22d69bfSAxel Dörfler {
963bf48e753SHugo Santos 	TRACE_EP("Open()");
964bf48e753SHugo Santos 
965119c6cddSIngo Weinhold 	AutoLocker _(fLock);
966727ad0b0SHugo Santos 
967c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
968c72ab92dSHugo Santos 	if (status < B_OK)
969c72ab92dSHugo Santos 		return status;
970bf48e753SHugo Santos 
971c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
972c72ab92dSHugo Santos 	if (fManager == NULL)
973bf48e753SHugo Santos 		return EAFNOSUPPORT;
974bf48e753SHugo Santos 
975bf48e753SHugo Santos 	return B_OK;
976c22d69bfSAxel Dörfler }
977c22d69bfSAxel Dörfler 
978c22d69bfSAxel Dörfler 
979c22d69bfSAxel Dörfler status_t
980c22d69bfSAxel Dörfler UdpEndpoint::Close()
981c22d69bfSAxel Dörfler {
982bf48e753SHugo Santos 	TRACE_EP("Close()");
98383fd8a61SPawel Dziepak 	fSocket->error = EBADF;
98483fd8a61SPawel Dziepak 	WakeAll();
985bf48e753SHugo Santos 	return B_OK;
986c22d69bfSAxel Dörfler }
987c22d69bfSAxel Dörfler 
988c22d69bfSAxel Dörfler 
989c22d69bfSAxel Dörfler status_t
990c22d69bfSAxel Dörfler UdpEndpoint::Free()
991c22d69bfSAxel Dörfler {
992bf48e753SHugo Santos 	TRACE_EP("Free()");
9930086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
994c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
995c22d69bfSAxel Dörfler }
996c22d69bfSAxel Dörfler 
997c22d69bfSAxel Dörfler 
998c22d69bfSAxel Dörfler // #pragma mark - outbound
999c22d69bfSAxel Dörfler 
1000c22d69bfSAxel Dörfler 
1001c22d69bfSAxel Dörfler status_t
1002bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
1003c22d69bfSAxel Dörfler {
1004bf9a85cbSJérôme Duval 	TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer,
1005bf9a85cbSJérôme Duval 		buffer->size, route);
1006bf48e753SHugo Santos 
1007d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
1008c22d69bfSAxel Dörfler 		return EMSGSIZE;
1009c22d69bfSAxel Dörfler 
101074e1a530SJérôme Duval 	buffer->protocol = IPPROTO_UDP;
1011c22d69bfSAxel Dörfler 
1012c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
10136c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
10146c353509SHugo Santos 	if (header.Status() < B_OK)
10156c353509SHugo Santos 		return header.Status();
1016c22d69bfSAxel Dörfler 
101779a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
101879a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
10196c353509SHugo Santos 	header->udp_length = htons(buffer->size);
1020c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
10216c353509SHugo Santos 	header->udp_checksum = 0;
10226c353509SHugo Santos 
10236c353509SHugo Santos 	header.Sync();
1024c22d69bfSAxel Dörfler 
1025d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1026d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
10276c353509SHugo Santos 	if (calculatedChecksum == 0)
10286c353509SHugo Santos 		calculatedChecksum = 0xffff;
10296c353509SHugo Santos 
10306c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
1031c22d69bfSAxel Dörfler 
1032c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
1033c22d69bfSAxel Dörfler }
1034c22d69bfSAxel Dörfler 
1035c22d69bfSAxel Dörfler 
1036bf48e753SHugo Santos status_t
1037bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
1038bf48e753SHugo Santos {
1039bf9a85cbSJérôme Duval 	TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1040bf48e753SHugo Santos 
10412651e51dSAxel Dörfler 	return gDatalinkModule->send_data(this, NULL, buffer);
1042bf48e753SHugo Santos }
1043bf48e753SHugo Santos 
1044bf48e753SHugo Santos 
1045c22d69bfSAxel Dörfler // #pragma mark - inbound
1046c22d69bfSAxel Dörfler 
1047c22d69bfSAxel Dörfler 
1048c22d69bfSAxel Dörfler ssize_t
1049c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
1050c22d69bfSAxel Dörfler {
1051bfb45f71SHugo Santos 	size_t bytes = AvailableData();
1052bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
1053bfb45f71SHugo Santos 	return bytes;
1054c22d69bfSAxel Dörfler }
1055c22d69bfSAxel Dörfler 
1056c22d69bfSAxel Dörfler 
1057c22d69bfSAxel Dörfler status_t
1058c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1059c22d69bfSAxel Dörfler {
1060bf9a85cbSJérôme Duval 	TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags);
1061bf48e753SHugo Santos 
10622651e51dSAxel Dörfler 	status_t status = Dequeue(flags, _buffer);
1063cb99c915SAxel Dörfler 	TRACE_EP("  FetchData(): returned from fifo status: %s", strerror(status));
10642651e51dSAxel Dörfler 	if (status != B_OK)
1065c22d69bfSAxel Dörfler 		return status;
1066c22d69bfSAxel Dörfler 
1067bf9a85cbSJérôme Duval 	TRACE_EP("  FetchData(): returns buffer with %" B_PRIu32 " bytes",
1068bf9a85cbSJérôme Duval 		(*_buffer)->size);
1069c22d69bfSAxel Dörfler 	return B_OK;
1070c22d69bfSAxel Dörfler }
1071c22d69bfSAxel Dörfler 
1072c22d69bfSAxel Dörfler 
1073c22d69bfSAxel Dörfler status_t
1074bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
1075c22d69bfSAxel Dörfler {
1076bf9a85cbSJérôme Duval 	TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1077c22d69bfSAxel Dörfler 
10782651e51dSAxel Dörfler 	return EnqueueClone(buffer);
1079c22d69bfSAxel Dörfler }
1080c22d69bfSAxel Dörfler 
1081c22d69bfSAxel Dörfler 
10826a606180SHugo Santos status_t
10836a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
10846a606180SHugo Santos {
1085bf9a85cbSJérôme Duval 	TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size);
1086f6cfc5afSHugo Santos 
10876a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
10886a606180SHugo Santos 	if (buffer == NULL)
10896a606180SHugo Santos 		return B_NO_MEMORY;
10906a606180SHugo Santos 
109174e1a530SJérôme Duval 	status_t status = sUdpEndpointManager->Deframe(buffer);
10926a606180SHugo Santos 	if (status < B_OK) {
10936a606180SHugo Santos 		gBufferModule->free(buffer);
10946a606180SHugo Santos 		return status;
10956a606180SHugo Santos 	}
10966a606180SHugo Santos 
10976a606180SHugo Santos 	return Enqueue(buffer);
10986a606180SHugo Santos }
10996a606180SHugo Santos 
11006a606180SHugo Santos 
1101cb99c915SAxel Dörfler void
1102cb99c915SAxel Dörfler UdpEndpoint::Dump() const
1103cb99c915SAxel Dörfler {
1104cb99c915SAxel Dörfler 	char local[64];
1105cb99c915SAxel Dörfler 	LocalAddress().AsString(local, sizeof(local), true);
1106cb99c915SAxel Dörfler 	char peer[64];
1107cb99c915SAxel Dörfler 	PeerAddress().AsString(peer, sizeof(peer), true);
1108cb99c915SAxel Dörfler 
1109cb99c915SAxel Dörfler 	kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1110cb99c915SAxel Dörfler }
1111cb99c915SAxel Dörfler 
1112cb99c915SAxel Dörfler 
1113c22d69bfSAxel Dörfler // #pragma mark - protocol interface
1114c22d69bfSAxel Dörfler 
1115c22d69bfSAxel Dörfler 
1116c22d69bfSAxel Dörfler net_protocol *
1117c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
1118c22d69bfSAxel Dörfler {
1119c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
1120c22d69bfSAxel Dörfler 
1121c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1122bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1123bf48e753SHugo Santos 		delete endpoint;
1124bf48e753SHugo Santos 		return NULL;
1125bf48e753SHugo Santos 	}
1126bf48e753SHugo Santos 
1127c22d69bfSAxel Dörfler 	return endpoint;
1128c22d69bfSAxel Dörfler }
1129c22d69bfSAxel Dörfler 
1130c22d69bfSAxel Dörfler 
1131c22d69bfSAxel Dörfler status_t
1132c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
1133c22d69bfSAxel Dörfler {
1134bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
1135c22d69bfSAxel Dörfler 	return B_OK;
1136c22d69bfSAxel Dörfler }
1137c22d69bfSAxel Dörfler 
1138c22d69bfSAxel Dörfler 
1139c22d69bfSAxel Dörfler status_t
1140c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1141c22d69bfSAxel Dörfler {
1142bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
1143c22d69bfSAxel Dörfler }
1144c22d69bfSAxel Dörfler 
1145c22d69bfSAxel Dörfler 
1146c22d69bfSAxel Dörfler status_t
1147c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1148c22d69bfSAxel Dörfler {
1149bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
1150c22d69bfSAxel Dörfler }
1151c22d69bfSAxel Dörfler 
1152c22d69bfSAxel Dörfler 
1153c22d69bfSAxel Dörfler status_t
1154c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1155c22d69bfSAxel Dörfler {
1156bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
1157c22d69bfSAxel Dörfler }
1158c22d69bfSAxel Dörfler 
1159c22d69bfSAxel Dörfler 
1160c22d69bfSAxel Dörfler status_t
1161c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1162c22d69bfSAxel Dörfler {
1163bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1164c22d69bfSAxel Dörfler }
1165c22d69bfSAxel Dörfler 
1166c22d69bfSAxel Dörfler 
1167c22d69bfSAxel Dörfler status_t
1168c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1169c22d69bfSAxel Dörfler {
1170ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1171c22d69bfSAxel Dörfler }
1172c22d69bfSAxel Dörfler 
1173c22d69bfSAxel Dörfler 
1174c22d69bfSAxel Dörfler status_t
1175c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1176c22d69bfSAxel Dörfler 	size_t *_length)
1177c22d69bfSAxel Dörfler {
1178c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1179c22d69bfSAxel Dörfler 		value, _length);
1180c22d69bfSAxel Dörfler }
1181c22d69bfSAxel Dörfler 
1182c22d69bfSAxel Dörfler 
1183c22d69bfSAxel Dörfler status_t
118445b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
118545b5203bSHugo Santos 	int *length)
118645b5203bSHugo Santos {
118745b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
118845b5203bSHugo Santos 		value, length);
118945b5203bSHugo Santos }
119045b5203bSHugo Santos 
119145b5203bSHugo Santos 
119245b5203bSHugo Santos status_t
119345b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
119445b5203bSHugo Santos 	const void *value, int length)
119545b5203bSHugo Santos {
119645b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
119745b5203bSHugo Santos 		value, length);
119845b5203bSHugo Santos }
119945b5203bSHugo Santos 
120045b5203bSHugo Santos 
120145b5203bSHugo Santos status_t
120253f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1203c22d69bfSAxel Dörfler {
1204bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1205c22d69bfSAxel Dörfler }
1206c22d69bfSAxel Dörfler 
1207c22d69bfSAxel Dörfler 
1208c22d69bfSAxel Dörfler status_t
1209c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1210c22d69bfSAxel Dörfler {
1211bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1212c22d69bfSAxel Dörfler }
1213c22d69bfSAxel Dörfler 
1214c22d69bfSAxel Dörfler 
1215c22d69bfSAxel Dörfler status_t
1216c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1217c22d69bfSAxel Dörfler {
1218ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1219c22d69bfSAxel Dörfler }
1220c22d69bfSAxel Dörfler 
1221c22d69bfSAxel Dörfler 
1222c22d69bfSAxel Dörfler status_t
1223c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1224c22d69bfSAxel Dörfler {
1225ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1226c22d69bfSAxel Dörfler }
1227c22d69bfSAxel Dörfler 
1228c22d69bfSAxel Dörfler 
1229c22d69bfSAxel Dörfler status_t
1230c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1231c22d69bfSAxel Dörfler 	net_buffer *buffer)
1232c22d69bfSAxel Dörfler {
1233bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1234c22d69bfSAxel Dörfler }
1235c22d69bfSAxel Dörfler 
1236c22d69bfSAxel Dörfler 
1237c22d69bfSAxel Dörfler status_t
1238c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1239c22d69bfSAxel Dörfler {
1240bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1241c22d69bfSAxel Dörfler }
1242c22d69bfSAxel Dörfler 
1243c22d69bfSAxel Dörfler 
1244c22d69bfSAxel Dörfler ssize_t
1245c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1246c22d69bfSAxel Dörfler {
1247bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1248c22d69bfSAxel Dörfler }
1249c22d69bfSAxel Dörfler 
1250c22d69bfSAxel Dörfler 
1251c22d69bfSAxel Dörfler status_t
1252c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1253c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1254c22d69bfSAxel Dörfler {
1255bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1256c22d69bfSAxel Dörfler }
1257c22d69bfSAxel Dörfler 
1258c22d69bfSAxel Dörfler 
1259c22d69bfSAxel Dörfler ssize_t
1260c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1261c22d69bfSAxel Dörfler {
1262bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1263c22d69bfSAxel Dörfler }
1264c22d69bfSAxel Dörfler 
1265c22d69bfSAxel Dörfler 
1266c22d69bfSAxel Dörfler struct net_domain *
1267c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1268c22d69bfSAxel Dörfler {
1269c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1270c22d69bfSAxel Dörfler }
1271c22d69bfSAxel Dörfler 
1272c22d69bfSAxel Dörfler 
1273c22d69bfSAxel Dörfler size_t
1274c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1275c22d69bfSAxel Dörfler {
1276c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1277c22d69bfSAxel Dörfler }
1278c22d69bfSAxel Dörfler 
1279c22d69bfSAxel Dörfler 
1280c22d69bfSAxel Dörfler status_t
1281c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1282c22d69bfSAxel Dörfler {
1283c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1284c22d69bfSAxel Dörfler }
1285c22d69bfSAxel Dörfler 
1286c22d69bfSAxel Dörfler 
1287c22d69bfSAxel Dörfler status_t
12886a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
12896a606180SHugo Santos {
12906a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
12916a606180SHugo Santos }
12926a606180SHugo Santos 
12936a606180SHugo Santos 
12946a606180SHugo Santos status_t
12952b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer)
1296c22d69bfSAxel Dörfler {
12972b415445SAxel Dörfler 	status_t notifyError = B_OK;
12982bb43d82SAxel Dörfler 
12992b415445SAxel Dörfler 	switch (error) {
13002b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_NET:
13012b415445SAxel Dörfler 			notifyError = ENETUNREACH;
13022bb43d82SAxel Dörfler 			break;
13032b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_HOST:
13042b415445SAxel Dörfler 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
13052b415445SAxel Dörfler 			notifyError = EHOSTUNREACH;
13062bb43d82SAxel Dörfler 			break;
13072b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PROTOCOL:
13082b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PORT:
13092b415445SAxel Dörfler 			notifyError = ECONNREFUSED;
13102bb43d82SAxel Dörfler 			break;
13112b415445SAxel Dörfler 		case B_NET_ERROR_MESSAGE_SIZE:
13122b415445SAxel Dörfler 			notifyError = EMSGSIZE;
13132b415445SAxel Dörfler 			break;
13142b415445SAxel Dörfler 		case B_NET_ERROR_PARAMETER_PROBLEM:
13152b415445SAxel Dörfler 			notifyError = ENOPROTOOPT;
13162b415445SAxel Dörfler 			break;
13172b415445SAxel Dörfler 
13182b415445SAxel Dörfler 		case B_NET_ERROR_QUENCH:
13192bb43d82SAxel Dörfler 		default:
13202bb43d82SAxel Dörfler 			// ignore them
13212bb43d82SAxel Dörfler 			gBufferModule->free(buffer);
13222bb43d82SAxel Dörfler 			return B_OK;
1323c22d69bfSAxel Dörfler 	}
1324c22d69bfSAxel Dörfler 
13257e046eabSAxel Dörfler 	ASSERT(notifyError != B_OK);
13267e046eabSAxel Dörfler 
13277e046eabSAxel Dörfler 	return sUdpEndpointManager->ReceiveError(notifyError, buffer);
13287e046eabSAxel Dörfler }
13297e046eabSAxel Dörfler 
1330c22d69bfSAxel Dörfler 
1331c22d69bfSAxel Dörfler status_t
13322b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
13332b415445SAxel Dörfler 	net_error_data *errorData)
1334c22d69bfSAxel Dörfler {
1335c22d69bfSAxel Dörfler 	return B_ERROR;
1336c22d69bfSAxel Dörfler }
1337c22d69bfSAxel Dörfler 
1338c22d69bfSAxel Dörfler 
133978888c44SAxel Dörfler ssize_t
134078888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol,
134178888c44SAxel Dörfler 	net_buffer* buffer, void *data, size_t dataSize)
134278888c44SAxel Dörfler {
134378888c44SAxel Dörfler 	return protocol->next->module->process_ancillary_data_no_container(
134478888c44SAxel Dörfler 		protocol, buffer, data, dataSize);
134578888c44SAxel Dörfler }
134678888c44SAxel Dörfler 
134778888c44SAxel Dörfler 
1348c22d69bfSAxel Dörfler //	#pragma mark - module interface
1349c22d69bfSAxel Dörfler 
1350c22d69bfSAxel Dörfler 
1351c22d69bfSAxel Dörfler static status_t
1352c22d69bfSAxel Dörfler init_udp()
1353c22d69bfSAxel Dörfler {
1354c22d69bfSAxel Dörfler 	status_t status;
1355bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1356c22d69bfSAxel Dörfler 
1357c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1358658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1359658a5506SHugo Santos 		return B_NO_MEMORY;
1360658a5506SHugo Santos 
1361c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1362c22d69bfSAxel Dörfler 	if (status != B_OK)
1363d438fa4cSHugo Santos 		goto err1;
1364c22d69bfSAxel Dörfler 
136561729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
136661729d93SAxel Dörfler 		IPPROTO_IP,
1367c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1368c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1369c22d69bfSAxel Dörfler 		NULL);
1370c22d69bfSAxel Dörfler 	if (status < B_OK)
1371658a5506SHugo Santos 		goto err1;
137261729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
137361729d93SAxel Dörfler 		IPPROTO_IP,
13748d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13758d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13768d1485faSAxel Dörfler 		NULL);
13778d1485faSAxel Dörfler 	if (status < B_OK)
13788d1485faSAxel Dörfler 		goto err1;
13798d1485faSAxel Dörfler 
138061729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
138161729d93SAxel Dörfler 		IPPROTO_UDP,
1382c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1383c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1384c22d69bfSAxel Dörfler 		NULL);
1385c22d69bfSAxel Dörfler 	if (status < B_OK)
1386658a5506SHugo Santos 		goto err1;
138761729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
138861729d93SAxel Dörfler 		IPPROTO_UDP,
13898d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13908d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13918d1485faSAxel Dörfler 		NULL);
13928d1485faSAxel Dörfler 	if (status < B_OK)
13938d1485faSAxel Dörfler 		goto err1;
1394c22d69bfSAxel Dörfler 
139561729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
139661729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
1397c22d69bfSAxel Dörfler 	if (status < B_OK)
1398658a5506SHugo Santos 		goto err1;
139961729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
140061729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
14018d1485faSAxel Dörfler 	if (status < B_OK)
14028d1485faSAxel Dörfler 		goto err1;
1403c22d69bfSAxel Dörfler 
1404cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1405cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1406cf5d9f4bSHugo Santos 
1407c22d69bfSAxel Dörfler 	return B_OK;
1408c22d69bfSAxel Dörfler 
1409c22d69bfSAxel Dörfler err1:
14108d1485faSAxel Dörfler 	// TODO: shouldn't unregister the protocols here?
1411658a5506SHugo Santos 	delete sUdpEndpointManager;
1412c22d69bfSAxel Dörfler 
1413bf9a85cbSJérôme Duval 	TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status,
1414bf9a85cbSJérôme Duval 		strerror(status));
1415c22d69bfSAxel Dörfler 	return status;
1416c22d69bfSAxel Dörfler }
1417c22d69bfSAxel Dörfler 
1418c22d69bfSAxel Dörfler 
1419c22d69bfSAxel Dörfler static status_t
1420c22d69bfSAxel Dörfler uninit_udp()
1421c22d69bfSAxel Dörfler {
1422bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1423cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1424cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1425c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1426c22d69bfSAxel Dörfler 	return B_OK;
1427c22d69bfSAxel Dörfler }
1428c22d69bfSAxel Dörfler 
1429c22d69bfSAxel Dörfler 
1430c22d69bfSAxel Dörfler static status_t
1431c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1432c22d69bfSAxel Dörfler {
1433c22d69bfSAxel Dörfler 	switch (op) {
1434c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1435c22d69bfSAxel Dörfler 			return init_udp();
1436c22d69bfSAxel Dörfler 
1437c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1438c22d69bfSAxel Dörfler 			return uninit_udp();
1439c22d69bfSAxel Dörfler 
1440c22d69bfSAxel Dörfler 		default:
1441c22d69bfSAxel Dörfler 			return B_ERROR;
1442c22d69bfSAxel Dörfler 	}
1443c22d69bfSAxel Dörfler }
1444c22d69bfSAxel Dörfler 
1445c22d69bfSAxel Dörfler 
1446c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1447c22d69bfSAxel Dörfler 	{
1448c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1449c22d69bfSAxel Dörfler 		0,
1450c22d69bfSAxel Dörfler 		udp_std_ops
1451c22d69bfSAxel Dörfler 	},
14526f58064fSAxel Dörfler 	NET_PROTOCOL_ATOMIC_MESSAGES,
14536f58064fSAxel Dörfler 
1454c22d69bfSAxel Dörfler 	udp_init_protocol,
1455c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1456c22d69bfSAxel Dörfler 	udp_open,
1457c22d69bfSAxel Dörfler 	udp_close,
1458c22d69bfSAxel Dörfler 	udp_free,
1459c22d69bfSAxel Dörfler 	udp_connect,
1460c22d69bfSAxel Dörfler 	udp_accept,
1461c22d69bfSAxel Dörfler 	udp_control,
146245b5203bSHugo Santos 	udp_getsockopt,
146345b5203bSHugo Santos 	udp_setsockopt,
1464c22d69bfSAxel Dörfler 	udp_bind,
1465c22d69bfSAxel Dörfler 	udp_unbind,
1466c22d69bfSAxel Dörfler 	udp_listen,
1467c22d69bfSAxel Dörfler 	udp_shutdown,
1468c22d69bfSAxel Dörfler 	udp_send_data,
1469c22d69bfSAxel Dörfler 	udp_send_routed_data,
1470c22d69bfSAxel Dörfler 	udp_send_avail,
1471c22d69bfSAxel Dörfler 	udp_read_data,
1472c22d69bfSAxel Dörfler 	udp_read_avail,
1473c22d69bfSAxel Dörfler 	udp_get_domain,
1474c22d69bfSAxel Dörfler 	udp_get_mtu,
1475c22d69bfSAxel Dörfler 	udp_receive_data,
14766a606180SHugo Santos 	udp_deliver_data,
14772bb43d82SAxel Dörfler 	udp_error_received,
1478c22d69bfSAxel Dörfler 	udp_error_reply,
14799871124eSAxel Dörfler 	NULL,		// add_ancillary_data()
14809871124eSAxel Dörfler 	NULL,		// process_ancillary_data()
148178888c44SAxel Dörfler 	udp_process_ancillary_data_no_container,
14829871124eSAxel Dörfler 	NULL,		// send_data_no_buffer()
14839871124eSAxel Dörfler 	NULL		// read_data_no_buffer()
1484c22d69bfSAxel Dörfler };
1485c22d69bfSAxel Dörfler 
1486658a5506SHugo Santos module_dependency module_dependencies[] = {
1487658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1488658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1489658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
14902bb43d82SAxel Dörfler 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1491658a5506SHugo Santos 	{}
1492658a5506SHugo Santos };
1493658a5506SHugo Santos 
1494c22d69bfSAxel Dörfler module_info *modules[] = {
1495c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1496c22d69bfSAxel Dörfler 	NULL
1497c22d69bfSAxel Dörfler };
1498