xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 2a2f213fde24ac9ae1debc2c1c5beb30e8736bb0)
1c22d69bfSAxel Dörfler /*
2cb319968SAdrien 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 
21cb319968SAdrien 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.
IsActive() const103727ad0b0SHugo Santos 			bool				IsActive() const { return fActive; }
SetActive(bool newValue)104727ad0b0SHugo Santos 			void				SetActive(bool newValue) { fActive = newValue; }
105bf48e753SHugo Santos 
HashTableLink()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 
UdpHashDefinitionUdpHashDefinition12884052230SAxel Dörfler 	UdpHashDefinition(net_address_module_info *_module)
12984052230SAxel Dörfler 		: module(_module) {}
UdpHashDefinitionUdpHashDefinition13084052230SAxel Dörfler 	UdpHashDefinition(const UdpHashDefinition& definition)
13184052230SAxel Dörfler 		: module(definition.module) {}
13240bbf860SHugo Santos 
HashKeyUdpHashDefinition13340bbf860SHugo 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 
HashUdpHashDefinition13840bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
13940bbf860SHugo Santos 	{
14056f097ebSOliver Tappe 		return _Mix(endpoint->LocalAddress().HashPair(
14156f097ebSOliver Tappe 			*endpoint->PeerAddress()));
14240bbf860SHugo Santos 	}
14340bbf860SHugo Santos 
_MixUdpHashDefinition14440bbf860SHugo 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 
CompareUdpHashDefinition15140bbf860SHugo 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 
GetLinkUdpHashDefinition1575147963dSStephan 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 
Domain() const173bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
174bf48e753SHugo Santos 
Ref()175bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
Put()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 
AddressModule() const201bf48e753SHugo 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 
UdpDomainSupport(net_domain * domain)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 
~UdpDomainSupport()275727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
276727ad0b0SHugo Santos {
2772b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
278bf48e753SHugo Santos }
279bf48e753SHugo Santos 
280bf48e753SHugo Santos 
281bf48e753SHugo Santos status_t
Init()282276aa463SIngo Weinhold UdpDomainSupport::Init()
283bf48e753SHugo Santos {
284276aa463SIngo Weinhold 	return fActiveEndpoints.Init(kNumHashBuckets);
285bf48e753SHugo Santos }
286bf48e753SHugo Santos 
287bf48e753SHugo Santos 
288bf48e753SHugo Santos status_t
DemuxIncomingBuffer(net_buffer * buffer)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 
294e864e939SAugustin Cavalier 	if ((buffer->msg_flags & MSG_BCAST) != 0)
295bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
296e864e939SAugustin Cavalier 	if ((buffer->msg_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
DeliverError(status_t error,net_buffer * buffer)3042bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
3052bb43d82SAxel Dörfler {
306e864e939SAugustin Cavalier 	if ((buffer->msg_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
BindEndpoint(UdpEndpoint * endpoint,const sockaddr * address)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
ConnectEndpoint(UdpEndpoint * endpoint,const sockaddr * address)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
UnbindEndpoint(UdpEndpoint * endpoint)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
DumpEndpoints() const410cf5d9f4bSHugo 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
_BindEndpoint(UdpEndpoint * endpoint,const sockaddr * address)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
_Bind(UdpEndpoint * endpoint,const sockaddr * address)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
_BindToEphemeral(UdpEndpoint * endpoint,const sockaddr * address)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
_FinishBind(UdpEndpoint * endpoint,const sockaddr * address)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 *
_FindActiveEndpoint(const sockaddr * ourAddress,const sockaddr * peerAddress,uint32 index)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
_DemuxBroadcast(net_buffer * buffer)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
_DemuxUnicast(net_buffer * buffer)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
_GetNextEphemeral()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 *
_EndpointWithPort(uint16 port) const649727ad0b0SHugo 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 
UdpEndpointManager()666bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
667bf48e753SHugo Santos {
6682b07b8e0SIngo Weinhold 	mutex_init(&fLock, "UDP endpoints");
6692b07b8e0SIngo Weinhold 	fStatus = B_OK;
670bf48e753SHugo Santos }
671bf48e753SHugo Santos 
672bf48e753SHugo Santos 
~UdpEndpointManager()673bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
674bf48e753SHugo Santos {
6752b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
676bf48e753SHugo Santos }
677bf48e753SHugo Santos 
678bf48e753SHugo Santos 
679bf48e753SHugo Santos status_t
InitCheck() const680bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
681bf48e753SHugo Santos {
682bf48e753SHugo Santos 	return fStatus;
683bf48e753SHugo Santos }
684bf48e753SHugo Santos 
685bf48e753SHugo Santos 
686cf5d9f4bSHugo Santos int
DumpEndpoints(int argc,char * argv[])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 
703cb319968SAdrien Destugues struct DomainSupportDelete
704cb319968SAdrien Destugues {
operator ()DomainSupportDelete705cb319968SAdrien Destugues 	inline void operator()(UdpDomainSupport* object)
706cb319968SAdrien Destugues 	{
707cb319968SAdrien Destugues 		sUdpEndpointManager->FreeEndpoint(object);
708cb319968SAdrien Destugues 	}
709cb319968SAdrien Destugues };
710cb319968SAdrien Destugues 
711cb319968SAdrien Destugues 
712cb319968SAdrien Destugues struct DomainSupportDeleter
713cb319968SAdrien Destugues 	: BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>
714cb319968SAdrien Destugues {
DomainSupportDeleterDomainSupportDeleter715cb319968SAdrien Destugues 	DomainSupportDeleter(UdpDomainSupport* object)
716cb319968SAdrien Destugues 		: BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>(object)
717cb319968SAdrien Destugues 	{}
718cb319968SAdrien Destugues };
719cb319968SAdrien Destugues 
720cb319968SAdrien Destugues 
721bf48e753SHugo Santos status_t
ReceiveData(net_buffer * buffer)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 	}
732cb319968SAdrien 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
ReceiveError(status_t error,net_buffer * buffer)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 	}
769cb319968SAdrien 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
Deframe(net_buffer * buffer)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 
831*2a2f213fSAugustin Cavalier 	if (header.udp_checksum != 0 && (buffer->buffer_flags & NET_BUFFER_L4_CHECKSUM_VALID) == 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 *
OpenEndpoint(UdpEndpoint * endpoint)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
FreeEndpoint(UdpDomainSupport * domain)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*
_GetDomain(net_buffer * buffer)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*
_GetDomainSupport(net_domain * domain,bool create)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()) {
901cb319968SAdrien Destugues 		if (domainSupport->Domain() == domain) {
902cb319968SAdrien Destugues 			domainSupport->Ref();
903bf48e753SHugo Santos 			return domainSupport;
904bf48e753SHugo Santos 		}
905cb319968SAdrien 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);
918cb319968SAdrien 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*
_GetDomainSupport(net_buffer * buffer)9289d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
9292bb43d82SAxel Dörfler {
9302bb43d82SAxel Dörfler 	MutexLocker _(fLock);
9319d433190SAxel Dörfler 
932e94ea7bcSAugustin Cavalier 	return _GetDomainSupport(_GetDomain(buffer), false);
9332bb43d82SAxel Dörfler }
9342bb43d82SAxel Dörfler 
9352bb43d82SAxel Dörfler 
936c22d69bfSAxel Dörfler // #pragma mark -
937c22d69bfSAxel Dörfler 
938c22d69bfSAxel Dörfler 
UdpEndpoint(net_socket * socket)939c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
940cb99c915SAxel Dörfler 	:
941cb99c915SAxel Dörfler 	DatagramSocket<>("udp endpoint", socket),
942cb99c915SAxel Dörfler 	fActive(false)
943cb99c915SAxel Dörfler {
944cb99c915SAxel Dörfler }
945bf48e753SHugo Santos 
946bf48e753SHugo Santos 
947c22d69bfSAxel Dörfler // #pragma mark - activation
948c22d69bfSAxel Dörfler 
949c22d69bfSAxel Dörfler 
950c22d69bfSAxel Dörfler status_t
Bind(const sockaddr * address)95153f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
952c22d69bfSAxel Dörfler {
953bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
954727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
955c22d69bfSAxel Dörfler }
956c22d69bfSAxel Dörfler 
957c22d69bfSAxel Dörfler 
958c22d69bfSAxel Dörfler status_t
Unbind(sockaddr * address)959c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
960c22d69bfSAxel Dörfler {
961bf48e753SHugo Santos 	TRACE_EP("Unbind()");
962727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
963c22d69bfSAxel Dörfler }
964c22d69bfSAxel Dörfler 
965c22d69bfSAxel Dörfler 
966c22d69bfSAxel Dörfler status_t
Connect(const sockaddr * address)967c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
968c22d69bfSAxel Dörfler {
969bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
970727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
971c22d69bfSAxel Dörfler }
972c22d69bfSAxel Dörfler 
973c22d69bfSAxel Dörfler 
974c22d69bfSAxel Dörfler status_t
Open()975c22d69bfSAxel Dörfler UdpEndpoint::Open()
976c22d69bfSAxel Dörfler {
977bf48e753SHugo Santos 	TRACE_EP("Open()");
978bf48e753SHugo Santos 
979119c6cddSIngo Weinhold 	AutoLocker _(fLock);
980727ad0b0SHugo Santos 
981c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
982c72ab92dSHugo Santos 	if (status < B_OK)
983c72ab92dSHugo Santos 		return status;
984bf48e753SHugo Santos 
985c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
986c72ab92dSHugo Santos 	if (fManager == NULL)
987bf48e753SHugo Santos 		return EAFNOSUPPORT;
988bf48e753SHugo Santos 
989bf48e753SHugo Santos 	return B_OK;
990c22d69bfSAxel Dörfler }
991c22d69bfSAxel Dörfler 
992c22d69bfSAxel Dörfler 
993c22d69bfSAxel Dörfler status_t
Close()994c22d69bfSAxel Dörfler UdpEndpoint::Close()
995c22d69bfSAxel Dörfler {
996bf48e753SHugo Santos 	TRACE_EP("Close()");
99783fd8a61SPawel Dziepak 	fSocket->error = EBADF;
99883fd8a61SPawel Dziepak 	WakeAll();
999bf48e753SHugo Santos 	return B_OK;
1000c22d69bfSAxel Dörfler }
1001c22d69bfSAxel Dörfler 
1002c22d69bfSAxel Dörfler 
1003c22d69bfSAxel Dörfler status_t
Free()1004c22d69bfSAxel Dörfler UdpEndpoint::Free()
1005c22d69bfSAxel Dörfler {
1006bf48e753SHugo Santos 	TRACE_EP("Free()");
10070086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
1008c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
1009c22d69bfSAxel Dörfler }
1010c22d69bfSAxel Dörfler 
1011c22d69bfSAxel Dörfler 
1012c22d69bfSAxel Dörfler // #pragma mark - outbound
1013c22d69bfSAxel Dörfler 
1014c22d69bfSAxel Dörfler 
1015c22d69bfSAxel Dörfler status_t
SendRoutedData(net_buffer * buffer,net_route * route)1016bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
1017c22d69bfSAxel Dörfler {
1018bf9a85cbSJérôme Duval 	TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer,
1019bf9a85cbSJérôme Duval 		buffer->size, route);
1020bf48e753SHugo Santos 
1021d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
1022c22d69bfSAxel Dörfler 		return EMSGSIZE;
1023c22d69bfSAxel Dörfler 
102474e1a530SJérôme Duval 	buffer->protocol = IPPROTO_UDP;
1025c22d69bfSAxel Dörfler 
1026c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
10276c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
10286c353509SHugo Santos 	if (header.Status() < B_OK)
10296c353509SHugo Santos 		return header.Status();
1030c22d69bfSAxel Dörfler 
103179a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
103279a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
10336c353509SHugo Santos 	header->udp_length = htons(buffer->size);
1034c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
10356c353509SHugo Santos 	header->udp_checksum = 0;
10366c353509SHugo Santos 
10376c353509SHugo Santos 	header.Sync();
1038c22d69bfSAxel Dörfler 
1039d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1040d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
10416c353509SHugo Santos 	if (calculatedChecksum == 0)
10426c353509SHugo Santos 		calculatedChecksum = 0xffff;
10436c353509SHugo Santos 
10446c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
1045*2a2f213fSAugustin Cavalier 	buffer->buffer_flags |= NET_BUFFER_L4_CHECKSUM_VALID;
1046c22d69bfSAxel Dörfler 
1047c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
1048c22d69bfSAxel Dörfler }
1049c22d69bfSAxel Dörfler 
1050c22d69bfSAxel Dörfler 
1051bf48e753SHugo Santos status_t
SendData(net_buffer * buffer)1052bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
1053bf48e753SHugo Santos {
1054bf9a85cbSJérôme Duval 	TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1055bf48e753SHugo Santos 
10562651e51dSAxel Dörfler 	return gDatalinkModule->send_data(this, NULL, buffer);
1057bf48e753SHugo Santos }
1058bf48e753SHugo Santos 
1059bf48e753SHugo Santos 
1060c22d69bfSAxel Dörfler // #pragma mark - inbound
1061c22d69bfSAxel Dörfler 
1062c22d69bfSAxel Dörfler 
1063c22d69bfSAxel Dörfler ssize_t
BytesAvailable()1064c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
1065c22d69bfSAxel Dörfler {
1066bfb45f71SHugo Santos 	size_t bytes = AvailableData();
1067bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
1068bfb45f71SHugo Santos 	return bytes;
1069c22d69bfSAxel Dörfler }
1070c22d69bfSAxel Dörfler 
1071c22d69bfSAxel Dörfler 
1072c22d69bfSAxel Dörfler status_t
FetchData(size_t numBytes,uint32 flags,net_buffer ** _buffer)1073c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1074c22d69bfSAxel Dörfler {
1075bf9a85cbSJérôme Duval 	TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags);
1076bf48e753SHugo Santos 
10772651e51dSAxel Dörfler 	status_t status = Dequeue(flags, _buffer);
1078cb99c915SAxel Dörfler 	TRACE_EP("  FetchData(): returned from fifo status: %s", strerror(status));
10792651e51dSAxel Dörfler 	if (status != B_OK)
1080c22d69bfSAxel Dörfler 		return status;
1081c22d69bfSAxel Dörfler 
1082bf9a85cbSJérôme Duval 	TRACE_EP("  FetchData(): returns buffer with %" B_PRIu32 " bytes",
1083bf9a85cbSJérôme Duval 		(*_buffer)->size);
1084c22d69bfSAxel Dörfler 	return B_OK;
1085c22d69bfSAxel Dörfler }
1086c22d69bfSAxel Dörfler 
1087c22d69bfSAxel Dörfler 
1088c22d69bfSAxel Dörfler status_t
StoreData(net_buffer * buffer)1089bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
1090c22d69bfSAxel Dörfler {
1091bf9a85cbSJérôme Duval 	TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1092c22d69bfSAxel Dörfler 
10932651e51dSAxel Dörfler 	return EnqueueClone(buffer);
1094c22d69bfSAxel Dörfler }
1095c22d69bfSAxel Dörfler 
1096c22d69bfSAxel Dörfler 
10976a606180SHugo Santos status_t
DeliverData(net_buffer * _buffer)10986a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
10996a606180SHugo Santos {
1100bf9a85cbSJérôme Duval 	TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size);
1101f6cfc5afSHugo Santos 
11026a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
11036a606180SHugo Santos 	if (buffer == NULL)
11046a606180SHugo Santos 		return B_NO_MEMORY;
11056a606180SHugo Santos 
110674e1a530SJérôme Duval 	status_t status = sUdpEndpointManager->Deframe(buffer);
11076a606180SHugo Santos 	if (status < B_OK) {
11086a606180SHugo Santos 		gBufferModule->free(buffer);
11096a606180SHugo Santos 		return status;
11106a606180SHugo Santos 	}
11116a606180SHugo Santos 
11126a606180SHugo Santos 	return Enqueue(buffer);
11136a606180SHugo Santos }
11146a606180SHugo Santos 
11156a606180SHugo Santos 
1116cb99c915SAxel Dörfler void
Dump() const1117cb99c915SAxel Dörfler UdpEndpoint::Dump() const
1118cb99c915SAxel Dörfler {
1119cb99c915SAxel Dörfler 	char local[64];
1120cb99c915SAxel Dörfler 	LocalAddress().AsString(local, sizeof(local), true);
1121cb99c915SAxel Dörfler 	char peer[64];
1122cb99c915SAxel Dörfler 	PeerAddress().AsString(peer, sizeof(peer), true);
1123cb99c915SAxel Dörfler 
1124cb99c915SAxel Dörfler 	kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1125cb99c915SAxel Dörfler }
1126cb99c915SAxel Dörfler 
1127cb99c915SAxel Dörfler 
1128c22d69bfSAxel Dörfler // #pragma mark - protocol interface
1129c22d69bfSAxel Dörfler 
1130c22d69bfSAxel Dörfler 
1131c22d69bfSAxel Dörfler net_protocol *
udp_init_protocol(net_socket * socket)1132c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
1133c22d69bfSAxel Dörfler {
1134c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
1135c22d69bfSAxel Dörfler 
1136c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1137bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1138bf48e753SHugo Santos 		delete endpoint;
1139bf48e753SHugo Santos 		return NULL;
1140bf48e753SHugo Santos 	}
1141bf48e753SHugo Santos 
1142c22d69bfSAxel Dörfler 	return endpoint;
1143c22d69bfSAxel Dörfler }
1144c22d69bfSAxel Dörfler 
1145c22d69bfSAxel Dörfler 
1146c22d69bfSAxel Dörfler status_t
udp_uninit_protocol(net_protocol * protocol)1147c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
1148c22d69bfSAxel Dörfler {
1149bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
1150c22d69bfSAxel Dörfler 	return B_OK;
1151c22d69bfSAxel Dörfler }
1152c22d69bfSAxel Dörfler 
1153c22d69bfSAxel Dörfler 
1154c22d69bfSAxel Dörfler status_t
udp_open(net_protocol * protocol)1155c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1156c22d69bfSAxel Dörfler {
1157bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
1158c22d69bfSAxel Dörfler }
1159c22d69bfSAxel Dörfler 
1160c22d69bfSAxel Dörfler 
1161c22d69bfSAxel Dörfler status_t
udp_close(net_protocol * protocol)1162c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1163c22d69bfSAxel Dörfler {
1164bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
1165c22d69bfSAxel Dörfler }
1166c22d69bfSAxel Dörfler 
1167c22d69bfSAxel Dörfler 
1168c22d69bfSAxel Dörfler status_t
udp_free(net_protocol * protocol)1169c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1170c22d69bfSAxel Dörfler {
1171bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
1172c22d69bfSAxel Dörfler }
1173c22d69bfSAxel Dörfler 
1174c22d69bfSAxel Dörfler 
1175c22d69bfSAxel Dörfler status_t
udp_connect(net_protocol * protocol,const struct sockaddr * address)1176c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1177c22d69bfSAxel Dörfler {
1178bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1179c22d69bfSAxel Dörfler }
1180c22d69bfSAxel Dörfler 
1181c22d69bfSAxel Dörfler 
1182c22d69bfSAxel Dörfler status_t
udp_accept(net_protocol * protocol,struct net_socket ** _acceptedSocket)1183c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1184c22d69bfSAxel Dörfler {
1185ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1186c22d69bfSAxel Dörfler }
1187c22d69bfSAxel Dörfler 
1188c22d69bfSAxel Dörfler 
1189c22d69bfSAxel Dörfler status_t
udp_control(net_protocol * protocol,int level,int option,void * value,size_t * _length)1190c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1191c22d69bfSAxel Dörfler 	size_t *_length)
1192c22d69bfSAxel Dörfler {
1193c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1194c22d69bfSAxel Dörfler 		value, _length);
1195c22d69bfSAxel Dörfler }
1196c22d69bfSAxel Dörfler 
1197c22d69bfSAxel Dörfler 
1198c22d69bfSAxel Dörfler status_t
udp_getsockopt(net_protocol * protocol,int level,int option,void * value,int * length)119945b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
120045b5203bSHugo Santos 	int *length)
120145b5203bSHugo Santos {
120245b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
120345b5203bSHugo Santos 		value, length);
120445b5203bSHugo Santos }
120545b5203bSHugo Santos 
120645b5203bSHugo Santos 
120745b5203bSHugo Santos status_t
udp_setsockopt(net_protocol * protocol,int level,int option,const void * value,int length)120845b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
120945b5203bSHugo Santos 	const void *value, int length)
121045b5203bSHugo Santos {
121145b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
121245b5203bSHugo Santos 		value, length);
121345b5203bSHugo Santos }
121445b5203bSHugo Santos 
121545b5203bSHugo Santos 
121645b5203bSHugo Santos status_t
udp_bind(net_protocol * protocol,const struct sockaddr * address)121753f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1218c22d69bfSAxel Dörfler {
1219bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1220c22d69bfSAxel Dörfler }
1221c22d69bfSAxel Dörfler 
1222c22d69bfSAxel Dörfler 
1223c22d69bfSAxel Dörfler status_t
udp_unbind(net_protocol * protocol,struct sockaddr * address)1224c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1225c22d69bfSAxel Dörfler {
1226bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1227c22d69bfSAxel Dörfler }
1228c22d69bfSAxel Dörfler 
1229c22d69bfSAxel Dörfler 
1230c22d69bfSAxel Dörfler status_t
udp_listen(net_protocol * protocol,int count)1231c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1232c22d69bfSAxel Dörfler {
1233ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1234c22d69bfSAxel Dörfler }
1235c22d69bfSAxel Dörfler 
1236c22d69bfSAxel Dörfler 
1237c22d69bfSAxel Dörfler status_t
udp_shutdown(net_protocol * protocol,int direction)1238c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1239c22d69bfSAxel Dörfler {
1240ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1241c22d69bfSAxel Dörfler }
1242c22d69bfSAxel Dörfler 
1243c22d69bfSAxel Dörfler 
1244c22d69bfSAxel Dörfler status_t
udp_send_routed_data(net_protocol * protocol,struct net_route * route,net_buffer * buffer)1245c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1246c22d69bfSAxel Dörfler 	net_buffer *buffer)
1247c22d69bfSAxel Dörfler {
1248bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1249c22d69bfSAxel Dörfler }
1250c22d69bfSAxel Dörfler 
1251c22d69bfSAxel Dörfler 
1252c22d69bfSAxel Dörfler status_t
udp_send_data(net_protocol * protocol,net_buffer * buffer)1253c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1254c22d69bfSAxel Dörfler {
1255bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1256c22d69bfSAxel Dörfler }
1257c22d69bfSAxel Dörfler 
1258c22d69bfSAxel Dörfler 
1259c22d69bfSAxel Dörfler ssize_t
udp_send_avail(net_protocol * protocol)1260c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1261c22d69bfSAxel Dörfler {
1262bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1263c22d69bfSAxel Dörfler }
1264c22d69bfSAxel Dörfler 
1265c22d69bfSAxel Dörfler 
1266c22d69bfSAxel Dörfler status_t
udp_read_data(net_protocol * protocol,size_t numBytes,uint32 flags,net_buffer ** _buffer)1267c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1268c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1269c22d69bfSAxel Dörfler {
1270bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1271c22d69bfSAxel Dörfler }
1272c22d69bfSAxel Dörfler 
1273c22d69bfSAxel Dörfler 
1274c22d69bfSAxel Dörfler ssize_t
udp_read_avail(net_protocol * protocol)1275c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1276c22d69bfSAxel Dörfler {
1277bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1278c22d69bfSAxel Dörfler }
1279c22d69bfSAxel Dörfler 
1280c22d69bfSAxel Dörfler 
1281c22d69bfSAxel Dörfler struct net_domain *
udp_get_domain(net_protocol * protocol)1282c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1283c22d69bfSAxel Dörfler {
1284c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1285c22d69bfSAxel Dörfler }
1286c22d69bfSAxel Dörfler 
1287c22d69bfSAxel Dörfler 
1288c22d69bfSAxel Dörfler size_t
udp_get_mtu(net_protocol * protocol,const struct sockaddr * address)1289c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1290c22d69bfSAxel Dörfler {
1291c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1292c22d69bfSAxel Dörfler }
1293c22d69bfSAxel Dörfler 
1294c22d69bfSAxel Dörfler 
1295c22d69bfSAxel Dörfler status_t
udp_receive_data(net_buffer * buffer)1296c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1297c22d69bfSAxel Dörfler {
1298c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1299c22d69bfSAxel Dörfler }
1300c22d69bfSAxel Dörfler 
1301c22d69bfSAxel Dörfler 
1302c22d69bfSAxel Dörfler status_t
udp_deliver_data(net_protocol * protocol,net_buffer * buffer)13036a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
13046a606180SHugo Santos {
13056a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
13066a606180SHugo Santos }
13076a606180SHugo Santos 
13086a606180SHugo Santos 
13096a606180SHugo Santos status_t
udp_error_received(net_error error,net_buffer * buffer)13102b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer)
1311c22d69bfSAxel Dörfler {
13122b415445SAxel Dörfler 	status_t notifyError = B_OK;
13132bb43d82SAxel Dörfler 
13142b415445SAxel Dörfler 	switch (error) {
13152b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_NET:
13162b415445SAxel Dörfler 			notifyError = ENETUNREACH;
13172bb43d82SAxel Dörfler 			break;
13182b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_HOST:
13192b415445SAxel Dörfler 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
13202b415445SAxel Dörfler 			notifyError = EHOSTUNREACH;
13212bb43d82SAxel Dörfler 			break;
13222b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PROTOCOL:
13232b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PORT:
13242b415445SAxel Dörfler 			notifyError = ECONNREFUSED;
13252bb43d82SAxel Dörfler 			break;
13262b415445SAxel Dörfler 		case B_NET_ERROR_MESSAGE_SIZE:
13272b415445SAxel Dörfler 			notifyError = EMSGSIZE;
13282b415445SAxel Dörfler 			break;
13292b415445SAxel Dörfler 		case B_NET_ERROR_PARAMETER_PROBLEM:
13302b415445SAxel Dörfler 			notifyError = ENOPROTOOPT;
13312b415445SAxel Dörfler 			break;
13322b415445SAxel Dörfler 
13332b415445SAxel Dörfler 		case B_NET_ERROR_QUENCH:
13342bb43d82SAxel Dörfler 		default:
13352bb43d82SAxel Dörfler 			// ignore them
13362bb43d82SAxel Dörfler 			gBufferModule->free(buffer);
13372bb43d82SAxel Dörfler 			return B_OK;
1338c22d69bfSAxel Dörfler 	}
1339c22d69bfSAxel Dörfler 
13407e046eabSAxel Dörfler 	ASSERT(notifyError != B_OK);
13417e046eabSAxel Dörfler 
13427e046eabSAxel Dörfler 	return sUdpEndpointManager->ReceiveError(notifyError, buffer);
13437e046eabSAxel Dörfler }
13447e046eabSAxel Dörfler 
1345c22d69bfSAxel Dörfler 
1346c22d69bfSAxel Dörfler status_t
udp_error_reply(net_protocol * protocol,net_buffer * cause,net_error error,net_error_data * errorData)13472b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
13482b415445SAxel Dörfler 	net_error_data *errorData)
1349c22d69bfSAxel Dörfler {
1350c22d69bfSAxel Dörfler 	return B_ERROR;
1351c22d69bfSAxel Dörfler }
1352c22d69bfSAxel Dörfler 
1353c22d69bfSAxel Dörfler 
135478888c44SAxel Dörfler ssize_t
udp_process_ancillary_data_no_container(net_protocol * protocol,net_buffer * buffer,void * data,size_t dataSize)135578888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol,
135678888c44SAxel Dörfler 	net_buffer* buffer, void *data, size_t dataSize)
135778888c44SAxel Dörfler {
135878888c44SAxel Dörfler 	return protocol->next->module->process_ancillary_data_no_container(
135978888c44SAxel Dörfler 		protocol, buffer, data, dataSize);
136078888c44SAxel Dörfler }
136178888c44SAxel Dörfler 
136278888c44SAxel Dörfler 
1363c22d69bfSAxel Dörfler //	#pragma mark - module interface
1364c22d69bfSAxel Dörfler 
1365c22d69bfSAxel Dörfler 
1366c22d69bfSAxel Dörfler static status_t
init_udp()1367c22d69bfSAxel Dörfler init_udp()
1368c22d69bfSAxel Dörfler {
1369c22d69bfSAxel Dörfler 	status_t status;
1370bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1371c22d69bfSAxel Dörfler 
1372c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1373658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1374658a5506SHugo Santos 		return B_NO_MEMORY;
1375658a5506SHugo Santos 
1376c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1377c22d69bfSAxel Dörfler 	if (status != B_OK)
1378d438fa4cSHugo Santos 		goto err1;
1379c22d69bfSAxel Dörfler 
138061729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
138161729d93SAxel Dörfler 		IPPROTO_IP,
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_IP,
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;
13948d1485faSAxel Dörfler 
139561729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
139661729d93SAxel Dörfler 		IPPROTO_UDP,
1397c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1398c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1399c22d69bfSAxel Dörfler 		NULL);
1400c22d69bfSAxel Dörfler 	if (status < B_OK)
1401658a5506SHugo Santos 		goto err1;
140261729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
140361729d93SAxel Dörfler 		IPPROTO_UDP,
14048d1485faSAxel Dörfler 		"network/protocols/udp/v1",
14058d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
14068d1485faSAxel Dörfler 		NULL);
14078d1485faSAxel Dörfler 	if (status < B_OK)
14088d1485faSAxel Dörfler 		goto err1;
1409c22d69bfSAxel Dörfler 
141061729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
141161729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
1412c22d69bfSAxel Dörfler 	if (status < B_OK)
1413658a5506SHugo Santos 		goto err1;
141461729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
141561729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
14168d1485faSAxel Dörfler 	if (status < B_OK)
14178d1485faSAxel Dörfler 		goto err1;
1418c22d69bfSAxel Dörfler 
1419cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1420cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1421cf5d9f4bSHugo Santos 
1422c22d69bfSAxel Dörfler 	return B_OK;
1423c22d69bfSAxel Dörfler 
1424c22d69bfSAxel Dörfler err1:
14258d1485faSAxel Dörfler 	// TODO: shouldn't unregister the protocols here?
1426658a5506SHugo Santos 	delete sUdpEndpointManager;
1427c22d69bfSAxel Dörfler 
1428bf9a85cbSJérôme Duval 	TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status,
1429bf9a85cbSJérôme Duval 		strerror(status));
1430c22d69bfSAxel Dörfler 	return status;
1431c22d69bfSAxel Dörfler }
1432c22d69bfSAxel Dörfler 
1433c22d69bfSAxel Dörfler 
1434c22d69bfSAxel Dörfler static status_t
uninit_udp()1435c22d69bfSAxel Dörfler uninit_udp()
1436c22d69bfSAxel Dörfler {
1437bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1438cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1439cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1440c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1441c22d69bfSAxel Dörfler 	return B_OK;
1442c22d69bfSAxel Dörfler }
1443c22d69bfSAxel Dörfler 
1444c22d69bfSAxel Dörfler 
1445c22d69bfSAxel Dörfler static status_t
udp_std_ops(int32 op,...)1446c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1447c22d69bfSAxel Dörfler {
1448c22d69bfSAxel Dörfler 	switch (op) {
1449c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1450c22d69bfSAxel Dörfler 			return init_udp();
1451c22d69bfSAxel Dörfler 
1452c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1453c22d69bfSAxel Dörfler 			return uninit_udp();
1454c22d69bfSAxel Dörfler 
1455c22d69bfSAxel Dörfler 		default:
1456c22d69bfSAxel Dörfler 			return B_ERROR;
1457c22d69bfSAxel Dörfler 	}
1458c22d69bfSAxel Dörfler }
1459c22d69bfSAxel Dörfler 
1460c22d69bfSAxel Dörfler 
1461c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1462c22d69bfSAxel Dörfler 	{
1463c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1464c22d69bfSAxel Dörfler 		0,
1465c22d69bfSAxel Dörfler 		udp_std_ops
1466c22d69bfSAxel Dörfler 	},
14676f58064fSAxel Dörfler 	NET_PROTOCOL_ATOMIC_MESSAGES,
14686f58064fSAxel Dörfler 
1469c22d69bfSAxel Dörfler 	udp_init_protocol,
1470c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1471c22d69bfSAxel Dörfler 	udp_open,
1472c22d69bfSAxel Dörfler 	udp_close,
1473c22d69bfSAxel Dörfler 	udp_free,
1474c22d69bfSAxel Dörfler 	udp_connect,
1475c22d69bfSAxel Dörfler 	udp_accept,
1476c22d69bfSAxel Dörfler 	udp_control,
147745b5203bSHugo Santos 	udp_getsockopt,
147845b5203bSHugo Santos 	udp_setsockopt,
1479c22d69bfSAxel Dörfler 	udp_bind,
1480c22d69bfSAxel Dörfler 	udp_unbind,
1481c22d69bfSAxel Dörfler 	udp_listen,
1482c22d69bfSAxel Dörfler 	udp_shutdown,
1483c22d69bfSAxel Dörfler 	udp_send_data,
1484c22d69bfSAxel Dörfler 	udp_send_routed_data,
1485c22d69bfSAxel Dörfler 	udp_send_avail,
1486c22d69bfSAxel Dörfler 	udp_read_data,
1487c22d69bfSAxel Dörfler 	udp_read_avail,
1488c22d69bfSAxel Dörfler 	udp_get_domain,
1489c22d69bfSAxel Dörfler 	udp_get_mtu,
1490c22d69bfSAxel Dörfler 	udp_receive_data,
14916a606180SHugo Santos 	udp_deliver_data,
14922bb43d82SAxel Dörfler 	udp_error_received,
1493c22d69bfSAxel Dörfler 	udp_error_reply,
14949871124eSAxel Dörfler 	NULL,		// add_ancillary_data()
14959871124eSAxel Dörfler 	NULL,		// process_ancillary_data()
149678888c44SAxel Dörfler 	udp_process_ancillary_data_no_container,
14979871124eSAxel Dörfler 	NULL,		// send_data_no_buffer()
14989871124eSAxel Dörfler 	NULL		// read_data_no_buffer()
1499c22d69bfSAxel Dörfler };
1500c22d69bfSAxel Dörfler 
1501658a5506SHugo Santos module_dependency module_dependencies[] = {
1502658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1503658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1504658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
15052bb43d82SAxel Dörfler 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1506658a5506SHugo Santos 	{}
1507658a5506SHugo Santos };
1508658a5506SHugo Santos 
1509c22d69bfSAxel Dörfler module_info *modules[] = {
1510c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1511c22d69bfSAxel Dörfler 	NULL
1512c22d69bfSAxel Dörfler };
1513