xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision cb3199681eb2ed53850595d374e4989dbd62a3fa)
1c22d69bfSAxel Dörfler /*
2*cb319968SAdrien Destugues  * Copyright 2006-2021, 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 
21*cb319968SAdrien Destugues #include <AutoDeleter.h>
22c22d69bfSAxel Dörfler #include <KernelExport.h>
23c22d69bfSAxel Dörfler 
24c22d69bfSAxel Dörfler #include <NetBufferUtilities.h>
25c22d69bfSAxel Dörfler #include <NetUtilities.h>
26bfb45f71SHugo Santos #include <ProtocolUtilities.h>
27c22d69bfSAxel Dörfler 
282bb43d82SAxel Dörfler #include <algorithm>
29c22d69bfSAxel Dörfler #include <netinet/in.h>
302bb43d82SAxel Dörfler #include <netinet/ip.h>
31c22d69bfSAxel Dörfler #include <new>
32c22d69bfSAxel Dörfler #include <stdlib.h>
33c22d69bfSAxel Dörfler #include <string.h>
34c3e054c8SHugo Santos #include <utility>
35c22d69bfSAxel Dörfler 
36727ad0b0SHugo Santos 
37727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
38727ad0b0SHugo Santos //      lock before holding a child UdpEndpoint's lock. This restriction
39727ad0b0SHugo Santos //      is dictated by the receive path as blind access to the endpoint
40f861e599SFrançois Revol //      hash is required when holding the DomainSupport's lock.
41727ad0b0SHugo Santos 
42727ad0b0SHugo Santos 
43af3a31f7SAxel Dörfler //#define TRACE_UDP
44c22d69bfSAxel Dörfler #ifdef TRACE_UDP
45c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x) dump_block x
46bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this
47bf48e753SHugo Santos // to compile with gcc 2.95
48bf9a85cbSJérôme Duval #	define TRACE_EP(format, args...)	dprintf("UDP [%" B_PRIu64 ",%" \
49bf9a85cbSJérôme Duval 		B_PRIu32 "] %p " format "\n", system_time(), \
50bf9a85cbSJérôme Duval 		thread_get_current_thread_id(), this , ##args)
51bf9a85cbSJérôme Duval #	define TRACE_EPM(format, args...)	dprintf("UDP [%" B_PRIu64 ",%" \
52bf9a85cbSJérôme Duval 		B_PRIu32 "] " format "\n", system_time() , \
53bf9a85cbSJérôme Duval 		thread_get_current_thread_id() , ##args)
54bf9a85cbSJérôme Duval #	define TRACE_DOMAIN(format, args...)	dprintf("UDP [%" B_PRIu64 ",%" \
55bf9a85cbSJérôme Duval 		B_PRIu32 "] (%d) " format "\n", system_time(), \
56bf9a85cbSJérôme Duval 		thread_get_current_thread_id(), Domain()->family , ##args)
57c22d69bfSAxel Dörfler #else
58c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x)
59bf48e753SHugo Santos #	define TRACE_EP(args...)	do { } while (0)
60bf48e753SHugo Santos #	define TRACE_EPM(args...)	do { } while (0)
61bf48e753SHugo Santos #	define TRACE_DOMAIN(args...)	do { } while (0)
62c22d69bfSAxel Dörfler #endif
63c22d69bfSAxel Dörfler 
64c22d69bfSAxel Dörfler 
65c22d69bfSAxel Dörfler struct udp_header {
66c22d69bfSAxel Dörfler 	uint16 source_port;
67c22d69bfSAxel Dörfler 	uint16 destination_port;
68c22d69bfSAxel Dörfler 	uint16 udp_length;
69c22d69bfSAxel Dörfler 	uint16 udp_checksum;
70c22d69bfSAxel Dörfler } _PACKED;
71c22d69bfSAxel Dörfler 
72c22d69bfSAxel Dörfler 
736c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
746c353509SHugo Santos 	UDPChecksumField;
756c353509SHugo Santos 
76bf48e753SHugo Santos class UdpDomainSupport;
776c353509SHugo Santos 
78bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> {
79c22d69bfSAxel Dörfler public:
80c22d69bfSAxel Dörfler 								UdpEndpoint(net_socket* socket);
81bf48e753SHugo Santos 
8253f23f85SHugo Santos 			status_t			Bind(const sockaddr* newAddr);
83c22d69bfSAxel Dörfler 			status_t			Unbind(sockaddr* newAddr);
84c22d69bfSAxel Dörfler 			status_t			Connect(const sockaddr* newAddr);
85c22d69bfSAxel Dörfler 
86c22d69bfSAxel Dörfler 			status_t			Open();
87c22d69bfSAxel Dörfler 			status_t			Close();
88c22d69bfSAxel Dörfler 			status_t			Free();
89c22d69bfSAxel Dörfler 
9056f097ebSOliver Tappe 			status_t			SendRoutedData(net_buffer* buffer,
9156f097ebSOliver Tappe 									net_route* route);
92bf48e753SHugo Santos 			status_t			SendData(net_buffer* buffer);
93c22d69bfSAxel Dörfler 
94c22d69bfSAxel Dörfler 			ssize_t				BytesAvailable();
95c22d69bfSAxel Dörfler 			status_t			FetchData(size_t numBytes, uint32 flags,
96c22d69bfSAxel Dörfler 									net_buffer** _buffer);
97c22d69bfSAxel Dörfler 
98c22d69bfSAxel Dörfler 			status_t			StoreData(net_buffer* buffer);
996a606180SHugo Santos 			status_t			DeliverData(net_buffer* buffer);
100c22d69bfSAxel Dörfler 
101727ad0b0SHugo Santos 			// only the domain support will change/check the Active flag so
102727ad0b0SHugo Santos 			// we don't really need to protect it with the socket lock.
103727ad0b0SHugo Santos 			bool				IsActive() const { return fActive; }
104727ad0b0SHugo Santos 			void				SetActive(bool newValue) { fActive = newValue; }
105bf48e753SHugo Santos 
1065147963dSStephan Aßmus 			UdpEndpoint*&		HashTableLink() { return fLink; }
10740bbf860SHugo Santos 
108cb99c915SAxel Dörfler 			void				Dump() const;
109cb99c915SAxel Dörfler 
110c22d69bfSAxel Dörfler private:
111c72ab92dSHugo Santos 			UdpDomainSupport*	fManager;
112c22d69bfSAxel Dörfler 			bool				fActive;
11356f097ebSOliver Tappe 									// an active UdpEndpoint is part of the
114cb99c915SAxel Dörfler 									// endpoint hash (and it is bound and
115cb99c915SAxel Dörfler 									// optionally connected)
11640bbf860SHugo Santos 
1175147963dSStephan Aßmus 			UdpEndpoint*		fLink;
11840bbf860SHugo Santos };
11940bbf860SHugo Santos 
12040bbf860SHugo Santos 
12140bbf860SHugo Santos class UdpDomainSupport;
12240bbf860SHugo Santos 
12340bbf860SHugo Santos struct UdpHashDefinition {
12440bbf860SHugo Santos 	typedef net_address_module_info ParentType;
12540bbf860SHugo Santos 	typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
12640bbf860SHugo Santos 	typedef UdpEndpoint ValueType;
12740bbf860SHugo Santos 
12884052230SAxel Dörfler 	UdpHashDefinition(net_address_module_info *_module)
12984052230SAxel Dörfler 		: module(_module) {}
13084052230SAxel Dörfler 	UdpHashDefinition(const UdpHashDefinition& definition)
13184052230SAxel Dörfler 		: module(definition.module) {}
13240bbf860SHugo Santos 
13340bbf860SHugo Santos 	size_t HashKey(const KeyType &key) const
13440bbf860SHugo Santos 	{
13540bbf860SHugo Santos 		return _Mix(module->hash_address_pair(key.first, key.second));
13640bbf860SHugo Santos 	}
13740bbf860SHugo Santos 
13840bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
13940bbf860SHugo Santos 	{
14056f097ebSOliver Tappe 		return _Mix(endpoint->LocalAddress().HashPair(
14156f097ebSOliver Tappe 			*endpoint->PeerAddress()));
14240bbf860SHugo Santos 	}
14340bbf860SHugo Santos 
14440bbf860SHugo Santos 	static size_t _Mix(size_t hash)
14540bbf860SHugo Santos 	{
14656f097ebSOliver Tappe 		// move the bits into the relevant range (as defined by kNumHashBuckets)
14740bbf860SHugo Santos 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
14840bbf860SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
14940bbf860SHugo Santos 	}
15040bbf860SHugo Santos 
15140bbf860SHugo Santos 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
15240bbf860SHugo Santos 	{
15340bbf860SHugo Santos 		return endpoint->LocalAddress().EqualTo(key.first, true)
15440bbf860SHugo Santos 			&& endpoint->PeerAddress().EqualTo(key.second, true);
15540bbf860SHugo Santos 	}
15640bbf860SHugo Santos 
1575147963dSStephan Aßmus 	UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const
15840bbf860SHugo Santos 	{
15940bbf860SHugo Santos 		return endpoint->HashTableLink();
16040bbf860SHugo Santos 	}
16140bbf860SHugo Santos 
16240bbf860SHugo Santos 	net_address_module_info *module;
163c22d69bfSAxel Dörfler };
164c22d69bfSAxel Dörfler 
165c22d69bfSAxel Dörfler 
166bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
167c22d69bfSAxel Dörfler public:
168bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
169727ad0b0SHugo Santos 	~UdpDomainSupport();
170c22d69bfSAxel Dörfler 
171276aa463SIngo Weinhold 	status_t Init();
172bf48e753SHugo Santos 
173bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
174bf48e753SHugo Santos 
175bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
176727ad0b0SHugo Santos 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
177bf48e753SHugo Santos 
178bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer* buffer);
1792bb43d82SAxel Dörfler 	status_t DeliverError(status_t error, net_buffer* buffer);
180727ad0b0SHugo Santos 
181727ad0b0SHugo Santos 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
182727ad0b0SHugo Santos 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
183727ad0b0SHugo Santos 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
184727ad0b0SHugo Santos 
185cf5d9f4bSHugo Santos 	void DumpEndpoints() const;
186bf48e753SHugo Santos 
187c22d69bfSAxel Dörfler private:
188727ad0b0SHugo Santos 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
189727ad0b0SHugo Santos 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
190727ad0b0SHugo Santos 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
191727ad0b0SHugo Santos 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
192727ad0b0SHugo Santos 
19340bbf860SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
194bbbb5592SAxel Dörfler 		const sockaddr *peerAddress, uint32 index = 0);
195bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
196bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
197bf48e753SHugo Santos 
198bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
199727ad0b0SHugo Santos 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
200bf48e753SHugo Santos 
201bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
202727ad0b0SHugo Santos 		{ return fDomain->address_module; }
203bf48e753SHugo Santos 
2045147963dSStephan Aßmus 	typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable;
20540bbf860SHugo Santos 
2062b07b8e0SIngo Weinhold 	mutex			fLock;
207bf48e753SHugo Santos 	net_domain		*fDomain;
208bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
20940bbf860SHugo Santos 	EndpointTable	fActiveEndpoints;
210bf48e753SHugo Santos 	uint32			fEndpointCount;
211bf48e753SHugo Santos 
212bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
213bf48e753SHugo Santos 	static const uint16		kLast = 65535;
214bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
215bf48e753SHugo Santos 							// if you change this, adjust the shifting in
216bf48e753SHugo Santos 							// Hash() accordingly!
217bf48e753SHugo Santos };
218bf48e753SHugo Santos 
219bf48e753SHugo Santos 
220bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
221bf48e753SHugo Santos 
222bf48e753SHugo Santos 
223bf48e753SHugo Santos class UdpEndpointManager {
224c22d69bfSAxel Dörfler public:
225c22d69bfSAxel Dörfler 								UdpEndpointManager();
226c22d69bfSAxel Dörfler 								~UdpEndpointManager();
227c22d69bfSAxel Dörfler 
2282bb43d82SAxel Dörfler 			status_t			InitCheck() const;
2292bb43d82SAxel Dörfler 
23074e1a530SJérôme Duval 			status_t			ReceiveData(net_buffer* buffer);
2312bb43d82SAxel Dörfler 			status_t			ReceiveError(status_t error,
2322bb43d82SAxel Dörfler 									net_buffer* buffer);
23374e1a530SJérôme Duval 			status_t			Deframe(net_buffer* buffer);
234c22d69bfSAxel Dörfler 
235bf48e753SHugo Santos 			UdpDomainSupport*	OpenEndpoint(UdpEndpoint* endpoint);
236bf48e753SHugo Santos 			status_t			FreeEndpoint(UdpDomainSupport* domain);
237c22d69bfSAxel Dörfler 
238cf5d9f4bSHugo Santos 	static	int					DumpEndpoints(int argc, char *argv[]);
239cf5d9f4bSHugo Santos 
240c22d69bfSAxel Dörfler private:
2419d433190SAxel Dörfler 	inline	net_domain*			_GetDomain(net_buffer* buffer);
2429d433190SAxel Dörfler 			UdpDomainSupport*	_GetDomainSupport(net_domain* domain,
2439d433190SAxel Dörfler 									bool create);
2449d433190SAxel Dörfler 			UdpDomainSupport*	_GetDomainSupport(net_buffer* buffer);
245bf48e753SHugo Santos 
2462b07b8e0SIngo Weinhold 			mutex				fLock;
247c22d69bfSAxel Dörfler 			status_t			fStatus;
248bf48e753SHugo Santos 			UdpDomainList		fDomains;
249c22d69bfSAxel Dörfler };
250c22d69bfSAxel Dörfler 
251c22d69bfSAxel Dörfler 
252c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
253c22d69bfSAxel Dörfler 
254c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
255658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
256658a5506SHugo Santos net_stack_module_info *gStackModule;
2572bb43d82SAxel Dörfler net_socket_module_info *gSocketModule;
258c22d69bfSAxel Dörfler 
259c22d69bfSAxel Dörfler 
260c22d69bfSAxel Dörfler // #pragma mark -
261c22d69bfSAxel Dörfler 
262c22d69bfSAxel Dörfler 
263bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
264c22d69bfSAxel Dörfler 	:
265bf48e753SHugo Santos 	fDomain(domain),
266276aa463SIngo Weinhold 	fActiveEndpoints(domain->address_module),
267bf48e753SHugo Santos 	fEndpointCount(0)
268c22d69bfSAxel Dörfler {
2692b07b8e0SIngo Weinhold 	mutex_init(&fLock, "udp domain");
270727ad0b0SHugo Santos 
271727ad0b0SHugo Santos 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
272727ad0b0SHugo Santos }
273727ad0b0SHugo Santos 
274727ad0b0SHugo Santos 
275727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
276727ad0b0SHugo Santos {
2772b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
278bf48e753SHugo Santos }
279bf48e753SHugo Santos 
280bf48e753SHugo Santos 
281bf48e753SHugo Santos status_t
282276aa463SIngo Weinhold UdpDomainSupport::Init()
283bf48e753SHugo Santos {
284276aa463SIngo Weinhold 	return fActiveEndpoints.Init(kNumHashBuckets);
285bf48e753SHugo Santos }
286bf48e753SHugo Santos 
287bf48e753SHugo Santos 
288bf48e753SHugo Santos status_t
289bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
290bf48e753SHugo Santos {
2912bb43d82SAxel Dörfler 	// NOTE: multicast is delivered directly to the endpoint
2922b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
293727ad0b0SHugo Santos 
2942bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_BCAST) != 0)
295bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
2962bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_MCAST) != 0)
297727ad0b0SHugo Santos 		return B_ERROR;
298bf48e753SHugo Santos 
299bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
300bf48e753SHugo Santos }
301bf48e753SHugo Santos 
302bf48e753SHugo Santos 
303bf48e753SHugo Santos status_t
3042bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
3052bb43d82SAxel Dörfler {
3062bb43d82SAxel Dörfler 	if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0)
3072bb43d82SAxel Dörfler 		return B_ERROR;
3082bb43d82SAxel Dörfler 
3092bb43d82SAxel Dörfler 	MutexLocker _(fLock);
3102bb43d82SAxel Dörfler 
3112e1729d0SAxel Dörfler 	// Forward the error to the socket
3122e1729d0SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source,
3132e1729d0SAxel Dörfler 		buffer->destination);
3142e1729d0SAxel Dörfler 	if (endpoint != NULL) {
3152bb43d82SAxel Dörfler 		gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error);
3162e1729d0SAxel Dörfler 		endpoint->NotifyOne();
3172e1729d0SAxel Dörfler 	}
3182bb43d82SAxel Dörfler 
3192bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
3202bb43d82SAxel Dörfler 	return B_OK;
3212bb43d82SAxel Dörfler }
3222bb43d82SAxel Dörfler 
3232bb43d82SAxel Dörfler 
3242bb43d82SAxel Dörfler status_t
325727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
326727ad0b0SHugo Santos 	const sockaddr *address)
327727ad0b0SHugo Santos {
32856f097ebSOliver Tappe 	if (!AddressModule()->is_same_family(address))
32956f097ebSOliver Tappe 		return EAFNOSUPPORT;
33056f097ebSOliver Tappe 
3312b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
332727ad0b0SHugo Santos 
333727ad0b0SHugo Santos 	if (endpoint->IsActive())
334727ad0b0SHugo Santos 		return EINVAL;
335727ad0b0SHugo Santos 
336727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, address);
337727ad0b0SHugo Santos }
338727ad0b0SHugo Santos 
339727ad0b0SHugo Santos 
340727ad0b0SHugo Santos status_t
341727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
342727ad0b0SHugo Santos 	const sockaddr *address)
343727ad0b0SHugo Santos {
3442b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
345727ad0b0SHugo Santos 
346727ad0b0SHugo Santos 	if (endpoint->IsActive()) {
347727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
348727ad0b0SHugo Santos 		endpoint->SetActive(false);
349727ad0b0SHugo Santos 	}
350727ad0b0SHugo Santos 
351727ad0b0SHugo Santos 	if (address->sa_family == AF_UNSPEC) {
352727ad0b0SHugo Santos 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
353727ad0b0SHugo Santos 		// so we reset the peer address:
354727ad0b0SHugo Santos 		endpoint->PeerAddress().SetToEmpty();
355727ad0b0SHugo Santos 	} else {
35656f097ebSOliver Tappe 		if (!AddressModule()->is_same_family(address))
35756f097ebSOliver Tappe 			return EAFNOSUPPORT;
35856f097ebSOliver Tappe 
35956f097ebSOliver Tappe 		// consider destination address INADDR_ANY as INADDR_LOOPBACK
36056f097ebSOliver Tappe 		sockaddr_storage _address;
36156f097ebSOliver Tappe 		if (AddressModule()->is_empty_address(address, false)) {
36256f097ebSOliver Tappe 			AddressModule()->get_loopback_address((sockaddr *)&_address);
36356f097ebSOliver Tappe 			// for IPv4 and IPv6 the port is at the same offset
36456f097ebSOliver Tappe 			((sockaddr_in&)_address).sin_port
36556f097ebSOliver Tappe 				= ((sockaddr_in *)address)->sin_port;
36656f097ebSOliver Tappe 			address = (sockaddr *)&_address;
36756f097ebSOliver Tappe 		}
36856f097ebSOliver Tappe 
369727ad0b0SHugo Santos 		status_t status = endpoint->PeerAddress().SetTo(address);
370727ad0b0SHugo Santos 		if (status < B_OK)
371727ad0b0SHugo Santos 			return status;
3724e45de0eSOliver Tappe 		struct net_route *routeToDestination
3734e45de0eSOliver Tappe 			= gDatalinkModule->get_route(fDomain, address);
3744e45de0eSOliver Tappe 		if (routeToDestination) {
375184fada4SPhilippe Houdoin 			// stay bound to current local port, if any.
376184fada4SPhilippe Houdoin 			uint16 port = endpoint->LocalAddress().Port();
3774e45de0eSOliver Tappe 			status = endpoint->LocalAddress().SetTo(
37861729d93SAxel Dörfler 				routeToDestination->interface_address->local);
379184fada4SPhilippe Houdoin 			endpoint->LocalAddress().SetPort(port);
3804e45de0eSOliver Tappe 			gDatalinkModule->put_route(fDomain, routeToDestination);
3814e45de0eSOliver Tappe 			if (status < B_OK)
3824e45de0eSOliver Tappe 				return status;
3834e45de0eSOliver Tappe 		}
384727ad0b0SHugo Santos 	}
385727ad0b0SHugo Santos 
386727ad0b0SHugo Santos 	// we need to activate no matter whether or not we have just disconnected,
387727ad0b0SHugo Santos 	// as calling connect() always triggers an implicit bind():
388a03ed4faSJérôme Duval 	status_t status = _BindEndpoint(endpoint, *endpoint->LocalAddress());
389a03ed4faSJérôme Duval 	if (status == B_OK)
390a03ed4faSJérôme Duval 		gSocketModule->set_connected(endpoint->Socket());
391a03ed4faSJérôme Duval 	return status;
392727ad0b0SHugo Santos }
393727ad0b0SHugo Santos 
394727ad0b0SHugo Santos 
395727ad0b0SHugo Santos status_t
396727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
397727ad0b0SHugo Santos {
3982b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
399727ad0b0SHugo Santos 
400727ad0b0SHugo Santos 	if (endpoint->IsActive())
401727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
402727ad0b0SHugo Santos 
403727ad0b0SHugo Santos 	endpoint->SetActive(false);
404727ad0b0SHugo Santos 
405727ad0b0SHugo Santos 	return B_OK;
406727ad0b0SHugo Santos }
407727ad0b0SHugo Santos 
408727ad0b0SHugo Santos 
409cf5d9f4bSHugo Santos void
410cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
411cf5d9f4bSHugo Santos {
412cf5d9f4bSHugo Santos 	kprintf("-------- UDP Domain %p ---------\n", this);
413cf5d9f4bSHugo Santos 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
414cf5d9f4bSHugo Santos 
415cf5d9f4bSHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
416cf5d9f4bSHugo Santos 
417cb99c915SAxel Dörfler 	while (UdpEndpoint* endpoint = it.Next()) {
418cb99c915SAxel Dörfler 		endpoint->Dump();
419cf5d9f4bSHugo Santos 	}
420cf5d9f4bSHugo Santos }
421cf5d9f4bSHugo Santos 
422cf5d9f4bSHugo Santos 
423727ad0b0SHugo Santos status_t
424727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
425727ad0b0SHugo Santos 	const sockaddr *address)
426727ad0b0SHugo Santos {
427727ad0b0SHugo Santos 	if (AddressModule()->get_port(address) == 0)
428727ad0b0SHugo Santos 		return _BindToEphemeral(endpoint, address);
429727ad0b0SHugo Santos 
430727ad0b0SHugo Santos 	return _Bind(endpoint, address);
431727ad0b0SHugo Santos }
432727ad0b0SHugo Santos 
433727ad0b0SHugo Santos 
434727ad0b0SHugo Santos status_t
435727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
436727ad0b0SHugo Santos {
437727ad0b0SHugo Santos 	int socketOptions = endpoint->Socket()->options;
43840bbf860SHugo Santos 
43940bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
440bf48e753SHugo Santos 
441bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
442bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
443727ad0b0SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
444727ad0b0SHugo Santos 		address, true).Data());
445727ad0b0SHugo Santos 
44640bbf860SHugo Santos 	while (it.HasNext()) {
44740bbf860SHugo Santos 		UdpEndpoint *otherEndpoint = it.Next();
44825a2744fSHugo Santos 
449bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
4505084c839SHugo Santos 			ntohs(otherEndpoint->LocalAddress().Port()));
45125a2744fSHugo Santos 
45225a2744fSHugo Santos 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
453bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
45456f097ebSOliver Tappe 			if ((otherEndpoint->Socket()->options
45556f097ebSOliver Tappe 					& (SO_REUSEADDR | SO_REUSEPORT)) == 0
456d0eaec30SMichael Lotz 				|| (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
457727ad0b0SHugo Santos 				return EADDRINUSE;
45825a2744fSHugo Santos 
459bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
46025a2744fSHugo Santos 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
461d0eaec30SMichael Lotz 				&& ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
462d0eaec30SMichael Lotz 					|| (socketOptions & SO_REUSEPORT) == 0))
463727ad0b0SHugo Santos 				return EADDRINUSE;
464bf48e753SHugo Santos 		}
465bf48e753SHugo Santos 	}
466bf48e753SHugo Santos 
467727ad0b0SHugo Santos 	return _FinishBind(endpoint, address);
468bf48e753SHugo Santos }
469bf48e753SHugo Santos 
470bf48e753SHugo Santos 
471bf48e753SHugo Santos status_t
472727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
473727ad0b0SHugo Santos 	const sockaddr *address)
474727ad0b0SHugo Santos {
475727ad0b0SHugo Santos 	SocketAddressStorage newAddress(AddressModule());
476727ad0b0SHugo Santos 	status_t status = newAddress.SetTo(address);
477727ad0b0SHugo Santos 	if (status < B_OK)
478727ad0b0SHugo Santos 		return status;
479727ad0b0SHugo Santos 
480727ad0b0SHugo Santos 	uint16 allocedPort = _GetNextEphemeral();
481727ad0b0SHugo Santos 	if (allocedPort == 0)
482727ad0b0SHugo Santos 		return ENOBUFS;
483727ad0b0SHugo Santos 
4849e051839SOliver Tappe 	newAddress.SetPort(htons(allocedPort));
485727ad0b0SHugo Santos 
486727ad0b0SHugo Santos 	return _FinishBind(endpoint, *newAddress);
487727ad0b0SHugo Santos }
488727ad0b0SHugo Santos 
489727ad0b0SHugo Santos 
490727ad0b0SHugo Santos status_t
491727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
492727ad0b0SHugo Santos {
493727ad0b0SHugo Santos 	status_t status = endpoint->next->module->bind(endpoint->next, address);
494727ad0b0SHugo Santos 	if (status < B_OK)
495727ad0b0SHugo Santos 		return status;
49640bbf860SHugo Santos 
49740bbf860SHugo Santos 	fActiveEndpoints.Insert(endpoint);
498727ad0b0SHugo Santos 	endpoint->SetActive(true);
499727ad0b0SHugo Santos 
50040bbf860SHugo Santos 	return B_OK;
501bf48e753SHugo Santos }
502bf48e753SHugo Santos 
503bf48e753SHugo Santos 
504c22d69bfSAxel Dörfler UdpEndpoint *
50540bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
506bbbb5592SAxel Dörfler 	const sockaddr *peerAddress, uint32 index)
507c22d69bfSAxel Dörfler {
5082e1729d0SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
5092e1729d0SAxel Dörfler 
5109e051839SOliver Tappe 	TRACE_DOMAIN("finding Endpoint for %s <- %s",
511bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
512bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
513c3e054c8SHugo Santos 
514bbbb5592SAxel Dörfler 	UdpEndpoint* endpoint = fActiveEndpoints.Lookup(
515bbbb5592SAxel Dörfler 		std::make_pair(ourAddress, peerAddress));
516bbbb5592SAxel Dörfler 
517bbbb5592SAxel Dörfler 	// Make sure the bound_to_device constraint is fulfilled
518da0d7409SAxel Dörfler 	while (endpoint != NULL && endpoint->socket->bound_to_device != 0
519da0d7409SAxel Dörfler 		&& index != 0 && endpoint->socket->bound_to_device != index) {
520bbbb5592SAxel Dörfler 		endpoint = endpoint->HashTableLink();
521bbbb5592SAxel Dörfler 		if (endpoint != NULL
522bbbb5592SAxel Dörfler 			&& (!endpoint->LocalAddress().EqualTo(ourAddress, true)
523bbbb5592SAxel Dörfler 				|| !endpoint->PeerAddress().EqualTo(peerAddress, true)))
524bbbb5592SAxel Dörfler 			return NULL;
525bbbb5592SAxel Dörfler 	}
526bbbb5592SAxel Dörfler 
527bbbb5592SAxel Dörfler 	return endpoint;
528c22d69bfSAxel Dörfler }
529c22d69bfSAxel Dörfler 
530c22d69bfSAxel Dörfler 
531c22d69bfSAxel Dörfler status_t
532bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
533c22d69bfSAxel Dörfler {
53479a0d252SHugo Santos 	sockaddr* peerAddr = buffer->source;
53579a0d252SHugo Santos 	sockaddr* broadcastAddr = buffer->destination;
5369d433190SAxel Dörfler 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
5379d433190SAxel Dörfler 
538c22d69bfSAxel Dörfler 	sockaddr* mask = NULL;
53961729d93SAxel Dörfler 	if (buffer->interface_address != NULL)
54061729d93SAxel Dörfler 		mask = (sockaddr*)buffer->interface_address->mask;
541c22d69bfSAxel Dörfler 
5429d433190SAxel Dörfler 	TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
543c22d69bfSAxel Dörfler 
5449d433190SAxel Dörfler 	EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
545c22d69bfSAxel Dörfler 
5469d433190SAxel Dörfler 	while (UdpEndpoint* endpoint = iterator.Next()) {
54725a2744fSHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
54825a2744fSHugo Santos 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
54925a2744fSHugo Santos 
550bbbb5592SAxel Dörfler 		if (endpoint->socket->bound_to_device != 0
551bbbb5592SAxel Dörfler 			&& buffer->index != endpoint->socket->bound_to_device)
552bbbb5592SAxel Dörfler 			continue;
553bbbb5592SAxel Dörfler 
5545084c839SHugo Santos 		if (endpoint->LocalAddress().Port() != incomingPort) {
555c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
556c22d69bfSAxel Dörfler 			continue;
557c22d69bfSAxel Dörfler 		}
558c22d69bfSAxel Dörfler 
55925a2744fSHugo Santos 		if (!endpoint->PeerAddress().IsEmpty(true)) {
560c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
561c22d69bfSAxel Dörfler 			// this datagram is from there:
56225a2744fSHugo Santos 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
563c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
564c22d69bfSAxel Dörfler 				// this endpoint...
565c22d69bfSAxel Dörfler 				continue;
566c22d69bfSAxel Dörfler 			}
567c22d69bfSAxel Dörfler 		}
568c22d69bfSAxel Dörfler 
56925a2744fSHugo Santos 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
5709d433190SAxel Dörfler 			|| mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
571c22d69bfSAxel Dörfler 			// address matches, dispatch to this endpoint:
572c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
573c22d69bfSAxel Dörfler 		}
574c22d69bfSAxel Dörfler 	}
57540bbf860SHugo Santos 
576c22d69bfSAxel Dörfler 	return B_OK;
577c22d69bfSAxel Dörfler }
578c22d69bfSAxel Dörfler 
579c22d69bfSAxel Dörfler 
580c22d69bfSAxel Dörfler status_t
581bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
582c22d69bfSAxel Dörfler {
583bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
584c22d69bfSAxel Dörfler 
5852e1729d0SAxel Dörfler 	const sockaddr* localAddress = buffer->destination;
5862e1729d0SAxel Dörfler 	const sockaddr* peerAddress = buffer->source;
5872e1729d0SAxel Dörfler 
5882e1729d0SAxel Dörfler 	// look for full (most special) match:
589bbbb5592SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress,
590bbbb5592SAxel Dörfler 		buffer->index);
5912e1729d0SAxel Dörfler 	if (endpoint == NULL) {
5922e1729d0SAxel Dörfler 		// look for endpoint matching local address & port:
593bbbb5592SAxel Dörfler 		endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index);
5942e1729d0SAxel Dörfler 		if (endpoint == NULL) {
5952e1729d0SAxel Dörfler 			// look for endpoint matching peer address & port and local port:
5962e1729d0SAxel Dörfler 			SocketAddressStorage local(AddressModule());
5972e1729d0SAxel Dörfler 			local.SetToEmpty();
5982e1729d0SAxel Dörfler 			local.SetPort(AddressModule()->get_port(localAddress));
599bbbb5592SAxel Dörfler 			endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index);
6002e1729d0SAxel Dörfler 			if (endpoint == NULL) {
6012e1729d0SAxel Dörfler 				// last chance: look for endpoint matching local port only:
602bbbb5592SAxel Dörfler 				endpoint = _FindActiveEndpoint(*local, NULL, buffer->index);
6032e1729d0SAxel Dörfler 			}
6042e1729d0SAxel Dörfler 		}
6052e1729d0SAxel Dörfler 	}
6062e1729d0SAxel Dörfler 
6072bb43d82SAxel Dörfler 	if (endpoint == NULL) {
6082bb43d82SAxel Dörfler 		TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
609c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
6109e051839SOliver Tappe 	}
611c22d69bfSAxel Dörfler 
612c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
613c22d69bfSAxel Dörfler 	return B_OK;
614c22d69bfSAxel Dörfler }
615c22d69bfSAxel Dörfler 
616c22d69bfSAxel Dörfler 
617bf48e753SHugo Santos uint16
618bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
619c22d69bfSAxel Dörfler {
62040bbf860SHugo Santos 	uint16 stop, curr;
621bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
622bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
623bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
624bf48e753SHugo Santos 	} else {
625bf48e753SHugo Santos 		stop = kLast;
626bf48e753SHugo Santos 		curr = kFirst;
627bf48e753SHugo Santos 	}
628c22d69bfSAxel Dörfler 
629727ad0b0SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
630727ad0b0SHugo Santos 		fLastUsedEphemeral, curr, stop);
63140bbf860SHugo Santos 
6329e051839SOliver Tappe 	// TODO: a free list could be used to avoid the impact of these two
6339e051839SOliver Tappe 	//        nested loops most of the time... let's see how bad this really is
634727ad0b0SHugo Santos 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
635bf48e753SHugo Santos 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
63640bbf860SHugo Santos 
637727ad0b0SHugo Santos 		if (_EndpointWithPort(htons(curr)) == NULL) {
638bf48e753SHugo Santos 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
639bf48e753SHugo Santos 			fLastUsedEphemeral = curr;
640bf48e753SHugo Santos 			return curr;
641bf48e753SHugo Santos 		}
642727ad0b0SHugo Santos 	}
643727ad0b0SHugo Santos 
644727ad0b0SHugo Santos 	return 0;
645727ad0b0SHugo Santos }
646727ad0b0SHugo Santos 
647727ad0b0SHugo Santos 
648727ad0b0SHugo Santos UdpEndpoint *
649727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const
650727ad0b0SHugo Santos {
651727ad0b0SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
652727ad0b0SHugo Santos 
653727ad0b0SHugo Santos 	while (it.HasNext()) {
654727ad0b0SHugo Santos 		UdpEndpoint *endpoint = it.Next();
655727ad0b0SHugo Santos 		if (endpoint->LocalAddress().Port() == port)
656727ad0b0SHugo Santos 			return endpoint;
657727ad0b0SHugo Santos 	}
658727ad0b0SHugo Santos 
659727ad0b0SHugo Santos 	return NULL;
660727ad0b0SHugo Santos }
661c22d69bfSAxel Dörfler 
662bf48e753SHugo Santos 
663bf48e753SHugo Santos // #pragma mark -
664bf48e753SHugo Santos 
665bf48e753SHugo Santos 
666bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
667bf48e753SHugo Santos {
6682b07b8e0SIngo Weinhold 	mutex_init(&fLock, "UDP endpoints");
6692b07b8e0SIngo Weinhold 	fStatus = B_OK;
670bf48e753SHugo Santos }
671bf48e753SHugo Santos 
672bf48e753SHugo Santos 
673bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
674bf48e753SHugo Santos {
6752b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
676bf48e753SHugo Santos }
677bf48e753SHugo Santos 
678bf48e753SHugo Santos 
679bf48e753SHugo Santos status_t
680bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
681bf48e753SHugo Santos {
682bf48e753SHugo Santos 	return fStatus;
683bf48e753SHugo Santos }
684bf48e753SHugo Santos 
685bf48e753SHugo Santos 
686cf5d9f4bSHugo Santos int
687cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
688cf5d9f4bSHugo Santos {
689cf5d9f4bSHugo Santos 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
690cf5d9f4bSHugo Santos 
691eb5604bcSAdrien Destugues 	kprintf("===== UDP domain manager %p =====\n", sUdpEndpointManager);
692eb5604bcSAdrien Destugues 
693cf5d9f4bSHugo Santos 	while (it.HasNext())
694cf5d9f4bSHugo Santos 		it.Next()->DumpEndpoints();
695cf5d9f4bSHugo Santos 
696cf5d9f4bSHugo Santos 	return 0;
697cf5d9f4bSHugo Santos }
698cf5d9f4bSHugo Santos 
699cf5d9f4bSHugo Santos 
700bf48e753SHugo Santos // #pragma mark - inbound
701bf48e753SHugo Santos 
702bf48e753SHugo Santos 
703*cb319968SAdrien Destugues struct DomainSupportDelete
704*cb319968SAdrien Destugues {
705*cb319968SAdrien Destugues 	inline void operator()(UdpDomainSupport* object)
706*cb319968SAdrien Destugues 	{
707*cb319968SAdrien Destugues 		sUdpEndpointManager->FreeEndpoint(object);
708*cb319968SAdrien Destugues 	}
709*cb319968SAdrien Destugues };
710*cb319968SAdrien Destugues 
711*cb319968SAdrien Destugues 
712*cb319968SAdrien Destugues struct DomainSupportDeleter
713*cb319968SAdrien Destugues 	: BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>
714*cb319968SAdrien Destugues {
715*cb319968SAdrien Destugues 	DomainSupportDeleter(UdpDomainSupport* object)
716*cb319968SAdrien Destugues 		: BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>(object)
717*cb319968SAdrien Destugues 	{}
718*cb319968SAdrien Destugues };
719*cb319968SAdrien Destugues 
720*cb319968SAdrien Destugues 
721bf48e753SHugo Santos status_t
72274e1a530SJérôme Duval UdpEndpointManager::ReceiveData(net_buffer *buffer)
723c22d69bfSAxel Dörfler {
7242bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
7252bb43d82SAxel Dörfler 
7269d433190SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7272bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
7282bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
7292bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7302bb43d82SAxel Dörfler 		return B_ERROR;
7312bb43d82SAxel Dörfler 	}
732*cb319968SAdrien Destugues 	DomainSupportDeleter deleter(domainSupport);
7332bb43d82SAxel Dörfler 
73474e1a530SJérôme Duval 	status_t status = Deframe(buffer);
735eb5604bcSAdrien Destugues 	if (status != B_OK) {
7366a606180SHugo Santos 		return status;
737eb5604bcSAdrien Destugues 	}
7386a606180SHugo Santos 
7392bb43d82SAxel Dörfler 	status = domainSupport->DemuxIncomingBuffer(buffer);
7402bb43d82SAxel Dörfler 	if (status != B_OK) {
7412bb43d82SAxel Dörfler 		TRACE_EPM("  ReceiveData(): no endpoint.");
7422bb43d82SAxel Dörfler 		// Send port unreachable error
7432bb43d82SAxel Dörfler 		domainSupport->Domain()->module->error_reply(NULL, buffer,
7442b415445SAxel Dörfler 			B_NET_ERROR_UNREACH_PORT, NULL);
7452bb43d82SAxel Dörfler 		return B_ERROR;
7462bb43d82SAxel Dörfler 	}
7472bb43d82SAxel Dörfler 
7482bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
7492bb43d82SAxel Dörfler 	return B_OK;
7502bb43d82SAxel Dörfler }
7512bb43d82SAxel Dörfler 
7522bb43d82SAxel Dörfler 
7532bb43d82SAxel Dörfler status_t
7542bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
7552bb43d82SAxel Dörfler {
7562bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
7572bb43d82SAxel Dörfler 		error, buffer, buffer->size);
7582bb43d82SAxel Dörfler 
7592bb43d82SAxel Dörfler 	// We only really need the port information
7602bb43d82SAxel Dörfler 	if (buffer->size < 4)
7612bb43d82SAxel Dörfler 		return B_BAD_VALUE;
7622bb43d82SAxel Dörfler 
7639d433190SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7642bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
7652bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
7662bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7672bb43d82SAxel Dörfler 		return B_ERROR;
7682bb43d82SAxel Dörfler 	}
769*cb319968SAdrien Destugues 	DomainSupportDeleter deleter(domainSupport);
7702bb43d82SAxel Dörfler 
7712bb43d82SAxel Dörfler 	// Deframe the buffer manually, as we usually only get 8 bytes from the
7722bb43d82SAxel Dörfler 	// original packet
7732bb43d82SAxel Dörfler 	udp_header header;
7742bb43d82SAxel Dörfler 	if (gBufferModule->read(buffer, 0, &header,
775eb5604bcSAdrien Destugues 			std::min((size_t)buffer->size, sizeof(udp_header))) != B_OK) {
7762bb43d82SAxel Dörfler 		return B_BAD_VALUE;
777eb5604bcSAdrien Destugues 	}
778bf48e753SHugo Santos 
77961729d93SAxel Dörfler 	net_domain* domain = buffer->interface_address->domain;
7802bb43d82SAxel Dörfler 	net_address_module_info* addressModule = domain->address_module;
7816a606180SHugo Santos 
7822bb43d82SAxel Dörfler 	SocketAddress source(addressModule, buffer->source);
7832bb43d82SAxel Dörfler 	SocketAddress destination(addressModule, buffer->destination);
7846a606180SHugo Santos 
7852bb43d82SAxel Dörfler 	source.SetPort(header.source_port);
7862bb43d82SAxel Dörfler 	destination.SetPort(header.destination_port);
787727ad0b0SHugo Santos 
788eb5604bcSAdrien Destugues 	error = domainSupport->DeliverError(error, buffer);
789eb5604bcSAdrien Destugues 	return error;
7906a606180SHugo Santos }
7916a606180SHugo Santos 
7926a606180SHugo Santos 
7936a606180SHugo Santos status_t
79474e1a530SJérôme Duval UdpEndpointManager::Deframe(net_buffer* buffer)
7956a606180SHugo Santos {
796bf9a85cbSJérôme Duval 	TRACE_EPM("Deframe(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
7976a606180SHugo Santos 
79887001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
7999d433190SAxel Dörfler 	if (bufferHeader.Status() != B_OK)
800c22d69bfSAxel Dörfler 		return bufferHeader.Status();
801c22d69bfSAxel Dörfler 
802c22d69bfSAxel Dörfler 	udp_header& header = bufferHeader.Data();
803c22d69bfSAxel Dörfler 
8049d433190SAxel Dörfler 	net_domain* domain = _GetDomain(buffer);
8059d433190SAxel Dörfler 	if (domain == NULL) {
8066a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
80761729d93SAxel Dörfler 			"specified (interface address %p).", buffer->interface_address);
808c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
809c22d69bfSAxel Dörfler 	}
810bf48e753SHugo Santos 	net_address_module_info* addressModule = domain->address_module;
811bf48e753SHugo Santos 
81279a0d252SHugo Santos 	SocketAddress source(addressModule, buffer->source);
81379a0d252SHugo Santos 	SocketAddress destination(addressModule, buffer->destination);
814bf48e753SHugo Santos 
8154e8a1b33SHugo Santos 	source.SetPort(header.source_port);
8164e8a1b33SHugo Santos 	destination.SetPort(header.destination_port);
8174e8a1b33SHugo Santos 
8184e8a1b33SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
8194e8a1b33SHugo Santos 		destination.AsString(true).Data());
820c22d69bfSAxel Dörfler 
821c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
822c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
8236a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
824bf48e753SHugo Santos 			udpLength);
825c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
826c22d69bfSAxel Dörfler 	}
827bf48e753SHugo Santos 
82874e1a530SJérôme Duval 	if (buffer->size > udpLength)
829c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
830c22d69bfSAxel Dörfler 
831c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
832c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
833d5b5a2c2SHugo Santos 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
83474e1a530SJérôme Duval 			buffer, IPPROTO_UDP);
835c22d69bfSAxel Dörfler 		if (sum != 0) {
8366a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
837c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
838c22d69bfSAxel Dörfler 		}
839c22d69bfSAxel Dörfler 	}
840c22d69bfSAxel Dörfler 
841c22d69bfSAxel Dörfler 	bufferHeader.Remove();
842c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
843c22d69bfSAxel Dörfler 
8446a606180SHugo Santos 	return B_OK;
845c22d69bfSAxel Dörfler }
846c22d69bfSAxel Dörfler 
847c22d69bfSAxel Dörfler 
848bf48e753SHugo Santos UdpDomainSupport *
849c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
850c22d69bfSAxel Dörfler {
8512b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
852bf48e753SHugo Santos 
8539d433190SAxel Dörfler 	UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
854bf48e753SHugo Santos 	return domain;
855bf48e753SHugo Santos }
856bf48e753SHugo Santos 
857bf48e753SHugo Santos 
858bf48e753SHugo Santos status_t
859bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
860bf48e753SHugo Santos {
8612b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
862bf48e753SHugo Santos 
863727ad0b0SHugo Santos 	if (domain->Put()) {
864bf48e753SHugo Santos 		fDomains.Remove(domain);
865bf48e753SHugo Santos 		delete domain;
866bf48e753SHugo Santos 	}
867bf48e753SHugo Santos 
868bf48e753SHugo Santos 	return B_OK;
869bf48e753SHugo Santos }
870bf48e753SHugo Santos 
871bf48e753SHugo Santos 
872bf48e753SHugo Santos // #pragma mark -
873bf48e753SHugo Santos 
874bf48e753SHugo Santos 
8759d433190SAxel Dörfler inline net_domain*
8769d433190SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer)
877bf48e753SHugo Santos {
8789d433190SAxel Dörfler 	if (buffer->interface_address != NULL)
8799d433190SAxel Dörfler 		return buffer->interface_address->domain;
8809d433190SAxel Dörfler 
8819d433190SAxel Dörfler 	return gStackModule->get_domain(buffer->destination->sa_family);
8829d433190SAxel Dörfler }
8839d433190SAxel Dörfler 
8849d433190SAxel Dörfler 
8859d433190SAxel Dörfler UdpDomainSupport*
8869d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create)
8879d433190SAxel Dörfler {
8889d433190SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
8899d433190SAxel Dörfler 
8909d433190SAxel Dörfler 	if (domain == NULL)
8919d433190SAxel Dörfler 		return NULL;
892bf48e753SHugo Santos 
893bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
894bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
895bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
896bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
897bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
898bf48e753SHugo Santos 	//      family.
8999d433190SAxel Dörfler 	UdpDomainList::Iterator iterator = fDomains.GetIterator();
9009d433190SAxel Dörfler 	while (UdpDomainSupport* domainSupport = iterator.Next()) {
901*cb319968SAdrien Destugues 		if (domainSupport->Domain() == domain) {
902*cb319968SAdrien Destugues 			domainSupport->Ref();
903bf48e753SHugo Santos 			return domainSupport;
904bf48e753SHugo Santos 		}
905*cb319968SAdrien Destugues 	}
906bf48e753SHugo Santos 
907bf48e753SHugo Santos 	if (!create)
908bf48e753SHugo Santos 		return NULL;
909bf48e753SHugo Santos 
9109d433190SAxel Dörfler 	UdpDomainSupport* domainSupport
9119d433190SAxel Dörfler 		= new (std::nothrow) UdpDomainSupport(domain);
912276aa463SIngo Weinhold 	if (domainSupport == NULL || domainSupport->Init() < B_OK) {
913bf48e753SHugo Santos 		delete domainSupport;
914bf48e753SHugo Santos 		return NULL;
915bf48e753SHugo Santos 	}
916bf48e753SHugo Santos 
917bf48e753SHugo Santos 	fDomains.Add(domainSupport);
918*cb319968SAdrien Destugues 	domainSupport->Ref();
919bf48e753SHugo Santos 	return domainSupport;
920c22d69bfSAxel Dörfler }
921c22d69bfSAxel Dörfler 
922c22d69bfSAxel Dörfler 
9239d433190SAxel Dörfler /*!	Retrieves the UdpDomainSupport object responsible for this buffer, if the
9249d433190SAxel Dörfler 	domain can be determined. This is only successful if the domain support is
9259d433190SAxel Dörfler 	already existing, ie. there must already be an endpoint for the domain.
9269d433190SAxel Dörfler */
9272bb43d82SAxel Dörfler UdpDomainSupport*
9289d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
9292bb43d82SAxel Dörfler {
9302bb43d82SAxel Dörfler 	MutexLocker _(fLock);
9319d433190SAxel Dörfler 
932eb5604bcSAdrien Destugues 	UdpDomainSupport* support = _GetDomainSupport(_GetDomain(buffer), false);
933*cb319968SAdrien Destugues 	if (support != NULL)
934eb5604bcSAdrien Destugues 		support->Ref();
935eb5604bcSAdrien Destugues 	return support;
9362bb43d82SAxel Dörfler }
9372bb43d82SAxel Dörfler 
9382bb43d82SAxel Dörfler 
939c22d69bfSAxel Dörfler // #pragma mark -
940c22d69bfSAxel Dörfler 
941c22d69bfSAxel Dörfler 
942c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
943cb99c915SAxel Dörfler 	:
944cb99c915SAxel Dörfler 	DatagramSocket<>("udp endpoint", socket),
945cb99c915SAxel Dörfler 	fActive(false)
946cb99c915SAxel Dörfler {
947cb99c915SAxel Dörfler }
948bf48e753SHugo Santos 
949bf48e753SHugo Santos 
950c22d69bfSAxel Dörfler // #pragma mark - activation
951c22d69bfSAxel Dörfler 
952c22d69bfSAxel Dörfler 
953c22d69bfSAxel Dörfler status_t
95453f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
955c22d69bfSAxel Dörfler {
956bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
957727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
958c22d69bfSAxel Dörfler }
959c22d69bfSAxel Dörfler 
960c22d69bfSAxel Dörfler 
961c22d69bfSAxel Dörfler status_t
962c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
963c22d69bfSAxel Dörfler {
964bf48e753SHugo Santos 	TRACE_EP("Unbind()");
965727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
966c22d69bfSAxel Dörfler }
967c22d69bfSAxel Dörfler 
968c22d69bfSAxel Dörfler 
969c22d69bfSAxel Dörfler status_t
970c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
971c22d69bfSAxel Dörfler {
972bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
973727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
974c22d69bfSAxel Dörfler }
975c22d69bfSAxel Dörfler 
976c22d69bfSAxel Dörfler 
977c22d69bfSAxel Dörfler status_t
978c22d69bfSAxel Dörfler UdpEndpoint::Open()
979c22d69bfSAxel Dörfler {
980bf48e753SHugo Santos 	TRACE_EP("Open()");
981bf48e753SHugo Santos 
982119c6cddSIngo Weinhold 	AutoLocker _(fLock);
983727ad0b0SHugo Santos 
984c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
985c72ab92dSHugo Santos 	if (status < B_OK)
986c72ab92dSHugo Santos 		return status;
987bf48e753SHugo Santos 
988c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
989c72ab92dSHugo Santos 	if (fManager == NULL)
990bf48e753SHugo Santos 		return EAFNOSUPPORT;
991bf48e753SHugo Santos 
992bf48e753SHugo Santos 	return B_OK;
993c22d69bfSAxel Dörfler }
994c22d69bfSAxel Dörfler 
995c22d69bfSAxel Dörfler 
996c22d69bfSAxel Dörfler status_t
997c22d69bfSAxel Dörfler UdpEndpoint::Close()
998c22d69bfSAxel Dörfler {
999bf48e753SHugo Santos 	TRACE_EP("Close()");
100083fd8a61SPawel Dziepak 	fSocket->error = EBADF;
100183fd8a61SPawel Dziepak 	WakeAll();
1002bf48e753SHugo Santos 	return B_OK;
1003c22d69bfSAxel Dörfler }
1004c22d69bfSAxel Dörfler 
1005c22d69bfSAxel Dörfler 
1006c22d69bfSAxel Dörfler status_t
1007c22d69bfSAxel Dörfler UdpEndpoint::Free()
1008c22d69bfSAxel Dörfler {
1009bf48e753SHugo Santos 	TRACE_EP("Free()");
10100086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
1011c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
1012c22d69bfSAxel Dörfler }
1013c22d69bfSAxel Dörfler 
1014c22d69bfSAxel Dörfler 
1015c22d69bfSAxel Dörfler // #pragma mark - outbound
1016c22d69bfSAxel Dörfler 
1017c22d69bfSAxel Dörfler 
1018c22d69bfSAxel Dörfler status_t
1019bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
1020c22d69bfSAxel Dörfler {
1021bf9a85cbSJérôme Duval 	TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer,
1022bf9a85cbSJérôme Duval 		buffer->size, route);
1023bf48e753SHugo Santos 
1024d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
1025c22d69bfSAxel Dörfler 		return EMSGSIZE;
1026c22d69bfSAxel Dörfler 
102774e1a530SJérôme Duval 	buffer->protocol = IPPROTO_UDP;
1028c22d69bfSAxel Dörfler 
1029c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
10306c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
10316c353509SHugo Santos 	if (header.Status() < B_OK)
10326c353509SHugo Santos 		return header.Status();
1033c22d69bfSAxel Dörfler 
103479a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
103579a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
10366c353509SHugo Santos 	header->udp_length = htons(buffer->size);
1037c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
10386c353509SHugo Santos 	header->udp_checksum = 0;
10396c353509SHugo Santos 
10406c353509SHugo Santos 	header.Sync();
1041c22d69bfSAxel Dörfler 
1042d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1043d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
10446c353509SHugo Santos 	if (calculatedChecksum == 0)
10456c353509SHugo Santos 		calculatedChecksum = 0xffff;
10466c353509SHugo Santos 
10476c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
1048c22d69bfSAxel Dörfler 
1049c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
1050c22d69bfSAxel Dörfler }
1051c22d69bfSAxel Dörfler 
1052c22d69bfSAxel Dörfler 
1053bf48e753SHugo Santos status_t
1054bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
1055bf48e753SHugo Santos {
1056bf9a85cbSJérôme Duval 	TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1057bf48e753SHugo Santos 
10582651e51dSAxel Dörfler 	return gDatalinkModule->send_data(this, NULL, buffer);
1059bf48e753SHugo Santos }
1060bf48e753SHugo Santos 
1061bf48e753SHugo Santos 
1062c22d69bfSAxel Dörfler // #pragma mark - inbound
1063c22d69bfSAxel Dörfler 
1064c22d69bfSAxel Dörfler 
1065c22d69bfSAxel Dörfler ssize_t
1066c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
1067c22d69bfSAxel Dörfler {
1068bfb45f71SHugo Santos 	size_t bytes = AvailableData();
1069bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
1070bfb45f71SHugo Santos 	return bytes;
1071c22d69bfSAxel Dörfler }
1072c22d69bfSAxel Dörfler 
1073c22d69bfSAxel Dörfler 
1074c22d69bfSAxel Dörfler status_t
1075c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1076c22d69bfSAxel Dörfler {
1077bf9a85cbSJérôme Duval 	TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags);
1078bf48e753SHugo Santos 
10792651e51dSAxel Dörfler 	status_t status = Dequeue(flags, _buffer);
1080cb99c915SAxel Dörfler 	TRACE_EP("  FetchData(): returned from fifo status: %s", strerror(status));
10812651e51dSAxel Dörfler 	if (status != B_OK)
1082c22d69bfSAxel Dörfler 		return status;
1083c22d69bfSAxel Dörfler 
1084bf9a85cbSJérôme Duval 	TRACE_EP("  FetchData(): returns buffer with %" B_PRIu32 " bytes",
1085bf9a85cbSJérôme Duval 		(*_buffer)->size);
1086c22d69bfSAxel Dörfler 	return B_OK;
1087c22d69bfSAxel Dörfler }
1088c22d69bfSAxel Dörfler 
1089c22d69bfSAxel Dörfler 
1090c22d69bfSAxel Dörfler status_t
1091bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
1092c22d69bfSAxel Dörfler {
1093bf9a85cbSJérôme Duval 	TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1094c22d69bfSAxel Dörfler 
10952651e51dSAxel Dörfler 	return EnqueueClone(buffer);
1096c22d69bfSAxel Dörfler }
1097c22d69bfSAxel Dörfler 
1098c22d69bfSAxel Dörfler 
10996a606180SHugo Santos status_t
11006a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
11016a606180SHugo Santos {
1102bf9a85cbSJérôme Duval 	TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size);
1103f6cfc5afSHugo Santos 
11046a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
11056a606180SHugo Santos 	if (buffer == NULL)
11066a606180SHugo Santos 		return B_NO_MEMORY;
11076a606180SHugo Santos 
110874e1a530SJérôme Duval 	status_t status = sUdpEndpointManager->Deframe(buffer);
11096a606180SHugo Santos 	if (status < B_OK) {
11106a606180SHugo Santos 		gBufferModule->free(buffer);
11116a606180SHugo Santos 		return status;
11126a606180SHugo Santos 	}
11136a606180SHugo Santos 
11146a606180SHugo Santos 	return Enqueue(buffer);
11156a606180SHugo Santos }
11166a606180SHugo Santos 
11176a606180SHugo Santos 
1118cb99c915SAxel Dörfler void
1119cb99c915SAxel Dörfler UdpEndpoint::Dump() const
1120cb99c915SAxel Dörfler {
1121cb99c915SAxel Dörfler 	char local[64];
1122cb99c915SAxel Dörfler 	LocalAddress().AsString(local, sizeof(local), true);
1123cb99c915SAxel Dörfler 	char peer[64];
1124cb99c915SAxel Dörfler 	PeerAddress().AsString(peer, sizeof(peer), true);
1125cb99c915SAxel Dörfler 
1126cb99c915SAxel Dörfler 	kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1127cb99c915SAxel Dörfler }
1128cb99c915SAxel Dörfler 
1129cb99c915SAxel Dörfler 
1130c22d69bfSAxel Dörfler // #pragma mark - protocol interface
1131c22d69bfSAxel Dörfler 
1132c22d69bfSAxel Dörfler 
1133c22d69bfSAxel Dörfler net_protocol *
1134c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
1135c22d69bfSAxel Dörfler {
1136c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
1137c22d69bfSAxel Dörfler 
1138c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1139bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1140bf48e753SHugo Santos 		delete endpoint;
1141bf48e753SHugo Santos 		return NULL;
1142bf48e753SHugo Santos 	}
1143bf48e753SHugo Santos 
1144c22d69bfSAxel Dörfler 	return endpoint;
1145c22d69bfSAxel Dörfler }
1146c22d69bfSAxel Dörfler 
1147c22d69bfSAxel Dörfler 
1148c22d69bfSAxel Dörfler status_t
1149c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
1150c22d69bfSAxel Dörfler {
1151bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
1152c22d69bfSAxel Dörfler 	return B_OK;
1153c22d69bfSAxel Dörfler }
1154c22d69bfSAxel Dörfler 
1155c22d69bfSAxel Dörfler 
1156c22d69bfSAxel Dörfler status_t
1157c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1158c22d69bfSAxel Dörfler {
1159bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
1160c22d69bfSAxel Dörfler }
1161c22d69bfSAxel Dörfler 
1162c22d69bfSAxel Dörfler 
1163c22d69bfSAxel Dörfler status_t
1164c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1165c22d69bfSAxel Dörfler {
1166bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
1167c22d69bfSAxel Dörfler }
1168c22d69bfSAxel Dörfler 
1169c22d69bfSAxel Dörfler 
1170c22d69bfSAxel Dörfler status_t
1171c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1172c22d69bfSAxel Dörfler {
1173bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
1174c22d69bfSAxel Dörfler }
1175c22d69bfSAxel Dörfler 
1176c22d69bfSAxel Dörfler 
1177c22d69bfSAxel Dörfler status_t
1178c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1179c22d69bfSAxel Dörfler {
1180bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1181c22d69bfSAxel Dörfler }
1182c22d69bfSAxel Dörfler 
1183c22d69bfSAxel Dörfler 
1184c22d69bfSAxel Dörfler status_t
1185c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1186c22d69bfSAxel Dörfler {
1187ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1188c22d69bfSAxel Dörfler }
1189c22d69bfSAxel Dörfler 
1190c22d69bfSAxel Dörfler 
1191c22d69bfSAxel Dörfler status_t
1192c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1193c22d69bfSAxel Dörfler 	size_t *_length)
1194c22d69bfSAxel Dörfler {
1195c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1196c22d69bfSAxel Dörfler 		value, _length);
1197c22d69bfSAxel Dörfler }
1198c22d69bfSAxel Dörfler 
1199c22d69bfSAxel Dörfler 
1200c22d69bfSAxel Dörfler status_t
120145b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
120245b5203bSHugo Santos 	int *length)
120345b5203bSHugo Santos {
120445b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
120545b5203bSHugo Santos 		value, length);
120645b5203bSHugo Santos }
120745b5203bSHugo Santos 
120845b5203bSHugo Santos 
120945b5203bSHugo Santos status_t
121045b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
121145b5203bSHugo Santos 	const void *value, int length)
121245b5203bSHugo Santos {
121345b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
121445b5203bSHugo Santos 		value, length);
121545b5203bSHugo Santos }
121645b5203bSHugo Santos 
121745b5203bSHugo Santos 
121845b5203bSHugo Santos status_t
121953f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1220c22d69bfSAxel Dörfler {
1221bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1222c22d69bfSAxel Dörfler }
1223c22d69bfSAxel Dörfler 
1224c22d69bfSAxel Dörfler 
1225c22d69bfSAxel Dörfler status_t
1226c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1227c22d69bfSAxel Dörfler {
1228bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1229c22d69bfSAxel Dörfler }
1230c22d69bfSAxel Dörfler 
1231c22d69bfSAxel Dörfler 
1232c22d69bfSAxel Dörfler status_t
1233c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1234c22d69bfSAxel Dörfler {
1235ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1236c22d69bfSAxel Dörfler }
1237c22d69bfSAxel Dörfler 
1238c22d69bfSAxel Dörfler 
1239c22d69bfSAxel Dörfler status_t
1240c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1241c22d69bfSAxel Dörfler {
1242ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1243c22d69bfSAxel Dörfler }
1244c22d69bfSAxel Dörfler 
1245c22d69bfSAxel Dörfler 
1246c22d69bfSAxel Dörfler status_t
1247c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1248c22d69bfSAxel Dörfler 	net_buffer *buffer)
1249c22d69bfSAxel Dörfler {
1250bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1251c22d69bfSAxel Dörfler }
1252c22d69bfSAxel Dörfler 
1253c22d69bfSAxel Dörfler 
1254c22d69bfSAxel Dörfler status_t
1255c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1256c22d69bfSAxel Dörfler {
1257bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1258c22d69bfSAxel Dörfler }
1259c22d69bfSAxel Dörfler 
1260c22d69bfSAxel Dörfler 
1261c22d69bfSAxel Dörfler ssize_t
1262c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1263c22d69bfSAxel Dörfler {
1264bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1265c22d69bfSAxel Dörfler }
1266c22d69bfSAxel Dörfler 
1267c22d69bfSAxel Dörfler 
1268c22d69bfSAxel Dörfler status_t
1269c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1270c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1271c22d69bfSAxel Dörfler {
1272bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1273c22d69bfSAxel Dörfler }
1274c22d69bfSAxel Dörfler 
1275c22d69bfSAxel Dörfler 
1276c22d69bfSAxel Dörfler ssize_t
1277c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1278c22d69bfSAxel Dörfler {
1279bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1280c22d69bfSAxel Dörfler }
1281c22d69bfSAxel Dörfler 
1282c22d69bfSAxel Dörfler 
1283c22d69bfSAxel Dörfler struct net_domain *
1284c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1285c22d69bfSAxel Dörfler {
1286c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1287c22d69bfSAxel Dörfler }
1288c22d69bfSAxel Dörfler 
1289c22d69bfSAxel Dörfler 
1290c22d69bfSAxel Dörfler size_t
1291c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1292c22d69bfSAxel Dörfler {
1293c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1294c22d69bfSAxel Dörfler }
1295c22d69bfSAxel Dörfler 
1296c22d69bfSAxel Dörfler 
1297c22d69bfSAxel Dörfler status_t
1298c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1299c22d69bfSAxel Dörfler {
1300c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1301c22d69bfSAxel Dörfler }
1302c22d69bfSAxel Dörfler 
1303c22d69bfSAxel Dörfler 
1304c22d69bfSAxel Dörfler status_t
13056a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
13066a606180SHugo Santos {
13076a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
13086a606180SHugo Santos }
13096a606180SHugo Santos 
13106a606180SHugo Santos 
13116a606180SHugo Santos status_t
13122b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer)
1313c22d69bfSAxel Dörfler {
13142b415445SAxel Dörfler 	status_t notifyError = B_OK;
13152bb43d82SAxel Dörfler 
13162b415445SAxel Dörfler 	switch (error) {
13172b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_NET:
13182b415445SAxel Dörfler 			notifyError = ENETUNREACH;
13192bb43d82SAxel Dörfler 			break;
13202b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_HOST:
13212b415445SAxel Dörfler 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
13222b415445SAxel Dörfler 			notifyError = EHOSTUNREACH;
13232bb43d82SAxel Dörfler 			break;
13242b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PROTOCOL:
13252b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PORT:
13262b415445SAxel Dörfler 			notifyError = ECONNREFUSED;
13272bb43d82SAxel Dörfler 			break;
13282b415445SAxel Dörfler 		case B_NET_ERROR_MESSAGE_SIZE:
13292b415445SAxel Dörfler 			notifyError = EMSGSIZE;
13302b415445SAxel Dörfler 			break;
13312b415445SAxel Dörfler 		case B_NET_ERROR_PARAMETER_PROBLEM:
13322b415445SAxel Dörfler 			notifyError = ENOPROTOOPT;
13332b415445SAxel Dörfler 			break;
13342b415445SAxel Dörfler 
13352b415445SAxel Dörfler 		case B_NET_ERROR_QUENCH:
13362bb43d82SAxel Dörfler 		default:
13372bb43d82SAxel Dörfler 			// ignore them
13382bb43d82SAxel Dörfler 			gBufferModule->free(buffer);
13392bb43d82SAxel Dörfler 			return B_OK;
1340c22d69bfSAxel Dörfler 	}
1341c22d69bfSAxel Dörfler 
13427e046eabSAxel Dörfler 	ASSERT(notifyError != B_OK);
13437e046eabSAxel Dörfler 
13447e046eabSAxel Dörfler 	return sUdpEndpointManager->ReceiveError(notifyError, buffer);
13457e046eabSAxel Dörfler }
13467e046eabSAxel Dörfler 
1347c22d69bfSAxel Dörfler 
1348c22d69bfSAxel Dörfler status_t
13492b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
13502b415445SAxel Dörfler 	net_error_data *errorData)
1351c22d69bfSAxel Dörfler {
1352c22d69bfSAxel Dörfler 	return B_ERROR;
1353c22d69bfSAxel Dörfler }
1354c22d69bfSAxel Dörfler 
1355c22d69bfSAxel Dörfler 
135678888c44SAxel Dörfler ssize_t
135778888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol,
135878888c44SAxel Dörfler 	net_buffer* buffer, void *data, size_t dataSize)
135978888c44SAxel Dörfler {
136078888c44SAxel Dörfler 	return protocol->next->module->process_ancillary_data_no_container(
136178888c44SAxel Dörfler 		protocol, buffer, data, dataSize);
136278888c44SAxel Dörfler }
136378888c44SAxel Dörfler 
136478888c44SAxel Dörfler 
1365c22d69bfSAxel Dörfler //	#pragma mark - module interface
1366c22d69bfSAxel Dörfler 
1367c22d69bfSAxel Dörfler 
1368c22d69bfSAxel Dörfler static status_t
1369c22d69bfSAxel Dörfler init_udp()
1370c22d69bfSAxel Dörfler {
1371c22d69bfSAxel Dörfler 	status_t status;
1372bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1373c22d69bfSAxel Dörfler 
1374c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1375658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1376658a5506SHugo Santos 		return B_NO_MEMORY;
1377658a5506SHugo Santos 
1378c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1379c22d69bfSAxel Dörfler 	if (status != B_OK)
1380d438fa4cSHugo Santos 		goto err1;
1381c22d69bfSAxel Dörfler 
138261729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
138361729d93SAxel Dörfler 		IPPROTO_IP,
1384c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1385c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1386c22d69bfSAxel Dörfler 		NULL);
1387c22d69bfSAxel Dörfler 	if (status < B_OK)
1388658a5506SHugo Santos 		goto err1;
138961729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
139061729d93SAxel Dörfler 		IPPROTO_IP,
13918d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13928d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13938d1485faSAxel Dörfler 		NULL);
13948d1485faSAxel Dörfler 	if (status < B_OK)
13958d1485faSAxel Dörfler 		goto err1;
13968d1485faSAxel Dörfler 
139761729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
139861729d93SAxel Dörfler 		IPPROTO_UDP,
1399c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1400c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1401c22d69bfSAxel Dörfler 		NULL);
1402c22d69bfSAxel Dörfler 	if (status < B_OK)
1403658a5506SHugo Santos 		goto err1;
140461729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
140561729d93SAxel Dörfler 		IPPROTO_UDP,
14068d1485faSAxel Dörfler 		"network/protocols/udp/v1",
14078d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
14088d1485faSAxel Dörfler 		NULL);
14098d1485faSAxel Dörfler 	if (status < B_OK)
14108d1485faSAxel Dörfler 		goto err1;
1411c22d69bfSAxel Dörfler 
141261729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
141361729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
1414c22d69bfSAxel Dörfler 	if (status < B_OK)
1415658a5506SHugo Santos 		goto err1;
141661729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
141761729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
14188d1485faSAxel Dörfler 	if (status < B_OK)
14198d1485faSAxel Dörfler 		goto err1;
1420c22d69bfSAxel Dörfler 
1421cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1422cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1423cf5d9f4bSHugo Santos 
1424c22d69bfSAxel Dörfler 	return B_OK;
1425c22d69bfSAxel Dörfler 
1426c22d69bfSAxel Dörfler err1:
14278d1485faSAxel Dörfler 	// TODO: shouldn't unregister the protocols here?
1428658a5506SHugo Santos 	delete sUdpEndpointManager;
1429c22d69bfSAxel Dörfler 
1430bf9a85cbSJérôme Duval 	TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status,
1431bf9a85cbSJérôme Duval 		strerror(status));
1432c22d69bfSAxel Dörfler 	return status;
1433c22d69bfSAxel Dörfler }
1434c22d69bfSAxel Dörfler 
1435c22d69bfSAxel Dörfler 
1436c22d69bfSAxel Dörfler static status_t
1437c22d69bfSAxel Dörfler uninit_udp()
1438c22d69bfSAxel Dörfler {
1439bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1440cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1441cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1442c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1443c22d69bfSAxel Dörfler 	return B_OK;
1444c22d69bfSAxel Dörfler }
1445c22d69bfSAxel Dörfler 
1446c22d69bfSAxel Dörfler 
1447c22d69bfSAxel Dörfler static status_t
1448c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1449c22d69bfSAxel Dörfler {
1450c22d69bfSAxel Dörfler 	switch (op) {
1451c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1452c22d69bfSAxel Dörfler 			return init_udp();
1453c22d69bfSAxel Dörfler 
1454c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1455c22d69bfSAxel Dörfler 			return uninit_udp();
1456c22d69bfSAxel Dörfler 
1457c22d69bfSAxel Dörfler 		default:
1458c22d69bfSAxel Dörfler 			return B_ERROR;
1459c22d69bfSAxel Dörfler 	}
1460c22d69bfSAxel Dörfler }
1461c22d69bfSAxel Dörfler 
1462c22d69bfSAxel Dörfler 
1463c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1464c22d69bfSAxel Dörfler 	{
1465c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1466c22d69bfSAxel Dörfler 		0,
1467c22d69bfSAxel Dörfler 		udp_std_ops
1468c22d69bfSAxel Dörfler 	},
14696f58064fSAxel Dörfler 	NET_PROTOCOL_ATOMIC_MESSAGES,
14706f58064fSAxel Dörfler 
1471c22d69bfSAxel Dörfler 	udp_init_protocol,
1472c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1473c22d69bfSAxel Dörfler 	udp_open,
1474c22d69bfSAxel Dörfler 	udp_close,
1475c22d69bfSAxel Dörfler 	udp_free,
1476c22d69bfSAxel Dörfler 	udp_connect,
1477c22d69bfSAxel Dörfler 	udp_accept,
1478c22d69bfSAxel Dörfler 	udp_control,
147945b5203bSHugo Santos 	udp_getsockopt,
148045b5203bSHugo Santos 	udp_setsockopt,
1481c22d69bfSAxel Dörfler 	udp_bind,
1482c22d69bfSAxel Dörfler 	udp_unbind,
1483c22d69bfSAxel Dörfler 	udp_listen,
1484c22d69bfSAxel Dörfler 	udp_shutdown,
1485c22d69bfSAxel Dörfler 	udp_send_data,
1486c22d69bfSAxel Dörfler 	udp_send_routed_data,
1487c22d69bfSAxel Dörfler 	udp_send_avail,
1488c22d69bfSAxel Dörfler 	udp_read_data,
1489c22d69bfSAxel Dörfler 	udp_read_avail,
1490c22d69bfSAxel Dörfler 	udp_get_domain,
1491c22d69bfSAxel Dörfler 	udp_get_mtu,
1492c22d69bfSAxel Dörfler 	udp_receive_data,
14936a606180SHugo Santos 	udp_deliver_data,
14942bb43d82SAxel Dörfler 	udp_error_received,
1495c22d69bfSAxel Dörfler 	udp_error_reply,
14969871124eSAxel Dörfler 	NULL,		// add_ancillary_data()
14979871124eSAxel Dörfler 	NULL,		// process_ancillary_data()
149878888c44SAxel Dörfler 	udp_process_ancillary_data_no_container,
14999871124eSAxel Dörfler 	NULL,		// send_data_no_buffer()
15009871124eSAxel Dörfler 	NULL		// read_data_no_buffer()
1501c22d69bfSAxel Dörfler };
1502c22d69bfSAxel Dörfler 
1503658a5506SHugo Santos module_dependency module_dependencies[] = {
1504658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1505658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1506658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
15072bb43d82SAxel Dörfler 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1508658a5506SHugo Santos 	{}
1509658a5506SHugo Santos };
1510658a5506SHugo Santos 
1511c22d69bfSAxel Dörfler module_info *modules[] = {
1512c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1513c22d69bfSAxel Dörfler 	NULL
1514c22d69bfSAxel Dörfler };
1515