xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision da0d740954abc809592ebf0b3cebbf78cf200d39)
1c22d69bfSAxel Dörfler /*
22bb43d82SAxel Dörfler  * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3c22d69bfSAxel Dörfler  * Distributed under the terms of the MIT License.
4c22d69bfSAxel Dörfler  *
5c22d69bfSAxel Dörfler  * Authors:
6c22d69bfSAxel Dörfler  *		Oliver Tappe, zooey@hirschkaefer.de
7c3e054c8SHugo Santos  *		Hugo Santos, hugosantos@gmail.com
8c22d69bfSAxel Dörfler  */
9c22d69bfSAxel Dörfler 
10c22d69bfSAxel Dörfler 
11c22d69bfSAxel Dörfler #include <net_buffer.h>
12c22d69bfSAxel Dörfler #include <net_datalink.h>
13c22d69bfSAxel Dörfler #include <net_protocol.h>
14c22d69bfSAxel Dörfler #include <net_stack.h>
15c22d69bfSAxel Dörfler 
16c22d69bfSAxel Dörfler #include <lock.h>
17c22d69bfSAxel Dörfler #include <util/AutoLock.h>
18bf48e753SHugo Santos #include <util/DoublyLinkedList.h>
1940bbf860SHugo Santos #include <util/OpenHashTable.h>
20c22d69bfSAxel Dörfler 
21c22d69bfSAxel Dörfler #include <KernelExport.h>
22c22d69bfSAxel Dörfler 
23c22d69bfSAxel Dörfler #include <NetBufferUtilities.h>
24c22d69bfSAxel Dörfler #include <NetUtilities.h>
25bfb45f71SHugo Santos #include <ProtocolUtilities.h>
26c22d69bfSAxel Dörfler 
272bb43d82SAxel Dörfler #include <algorithm>
28c22d69bfSAxel Dörfler #include <netinet/in.h>
292bb43d82SAxel Dörfler #include <netinet/ip.h>
30c22d69bfSAxel Dörfler #include <new>
31c22d69bfSAxel Dörfler #include <stdlib.h>
32c22d69bfSAxel Dörfler #include <string.h>
33c3e054c8SHugo Santos #include <utility>
34c22d69bfSAxel Dörfler 
35727ad0b0SHugo Santos 
36727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
37727ad0b0SHugo Santos //      lock before holding a child UdpEndpoint's lock. This restriction
38727ad0b0SHugo Santos //      is dictated by the receive path as blind access to the endpoint
39f861e599SFrançois Revol //      hash is required when holding the DomainSupport's lock.
40727ad0b0SHugo Santos 
41727ad0b0SHugo Santos 
42af3a31f7SAxel Dörfler //#define TRACE_UDP
43c22d69bfSAxel Dörfler #ifdef TRACE_UDP
44c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x) dump_block x
45bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this
46bf48e753SHugo Santos // to compile with gcc 2.95
47bf48e753SHugo Santos #	define TRACE_EP(format, args...)	dprintf("UDP [%llu] %p " format "\n", \
48bf48e753SHugo Santos 		system_time(), this , ##args)
49bf48e753SHugo Santos #	define TRACE_EPM(format, args...)	dprintf("UDP [%llu] " format "\n", \
50bf48e753SHugo Santos 		system_time() , ##args)
51bf48e753SHugo Santos #	define TRACE_DOMAIN(format, args...)	dprintf("UDP [%llu] (%d) " format \
52bf48e753SHugo Santos 		"\n", system_time(), Domain()->family , ##args)
53c22d69bfSAxel Dörfler #else
54c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x)
55bf48e753SHugo Santos #	define TRACE_EP(args...)	do { } while (0)
56bf48e753SHugo Santos #	define TRACE_EPM(args...)	do { } while (0)
57bf48e753SHugo Santos #	define TRACE_DOMAIN(args...)	do { } while (0)
58c22d69bfSAxel Dörfler #endif
59c22d69bfSAxel Dörfler 
60c22d69bfSAxel Dörfler 
61c22d69bfSAxel Dörfler struct udp_header {
62c22d69bfSAxel Dörfler 	uint16 source_port;
63c22d69bfSAxel Dörfler 	uint16 destination_port;
64c22d69bfSAxel Dörfler 	uint16 udp_length;
65c22d69bfSAxel Dörfler 	uint16 udp_checksum;
66c22d69bfSAxel Dörfler } _PACKED;
67c22d69bfSAxel Dörfler 
68c22d69bfSAxel Dörfler 
696c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
706c353509SHugo Santos 	UDPChecksumField;
716c353509SHugo Santos 
72bf48e753SHugo Santos class UdpDomainSupport;
736c353509SHugo Santos 
74bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> {
75c22d69bfSAxel Dörfler public:
76c22d69bfSAxel Dörfler 								UdpEndpoint(net_socket* socket);
77bf48e753SHugo Santos 
7853f23f85SHugo Santos 			status_t			Bind(const sockaddr* newAddr);
79c22d69bfSAxel Dörfler 			status_t			Unbind(sockaddr* newAddr);
80c22d69bfSAxel Dörfler 			status_t			Connect(const sockaddr* newAddr);
81c22d69bfSAxel Dörfler 
82c22d69bfSAxel Dörfler 			status_t			Open();
83c22d69bfSAxel Dörfler 			status_t			Close();
84c22d69bfSAxel Dörfler 			status_t			Free();
85c22d69bfSAxel Dörfler 
8656f097ebSOliver Tappe 			status_t			SendRoutedData(net_buffer* buffer,
8756f097ebSOliver Tappe 									net_route* route);
88bf48e753SHugo Santos 			status_t			SendData(net_buffer* buffer);
89c22d69bfSAxel Dörfler 
90c22d69bfSAxel Dörfler 			ssize_t				BytesAvailable();
91c22d69bfSAxel Dörfler 			status_t			FetchData(size_t numBytes, uint32 flags,
92c22d69bfSAxel Dörfler 									net_buffer** _buffer);
93c22d69bfSAxel Dörfler 
94c22d69bfSAxel Dörfler 			status_t			StoreData(net_buffer* buffer);
956a606180SHugo Santos 			status_t			DeliverData(net_buffer* buffer);
96c22d69bfSAxel Dörfler 
97727ad0b0SHugo Santos 			// only the domain support will change/check the Active flag so
98727ad0b0SHugo Santos 			// we don't really need to protect it with the socket lock.
99727ad0b0SHugo Santos 			bool				IsActive() const { return fActive; }
100727ad0b0SHugo Santos 			void				SetActive(bool newValue) { fActive = newValue; }
101bf48e753SHugo Santos 
1025147963dSStephan Aßmus 			UdpEndpoint*&		HashTableLink() { return fLink; }
10340bbf860SHugo Santos 
104cb99c915SAxel Dörfler 			void				Dump() const;
105cb99c915SAxel Dörfler 
106c22d69bfSAxel Dörfler private:
107c72ab92dSHugo Santos 			UdpDomainSupport*	fManager;
108c22d69bfSAxel Dörfler 			bool				fActive;
10956f097ebSOliver Tappe 									// an active UdpEndpoint is part of the
110cb99c915SAxel Dörfler 									// endpoint hash (and it is bound and
111cb99c915SAxel Dörfler 									// optionally connected)
11240bbf860SHugo Santos 
1135147963dSStephan Aßmus 			UdpEndpoint*		fLink;
11440bbf860SHugo Santos };
11540bbf860SHugo Santos 
11640bbf860SHugo Santos 
11740bbf860SHugo Santos class UdpDomainSupport;
11840bbf860SHugo Santos 
11940bbf860SHugo Santos struct UdpHashDefinition {
12040bbf860SHugo Santos 	typedef net_address_module_info ParentType;
12140bbf860SHugo Santos 	typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
12240bbf860SHugo Santos 	typedef UdpEndpoint ValueType;
12340bbf860SHugo Santos 
12484052230SAxel Dörfler 	UdpHashDefinition(net_address_module_info *_module)
12584052230SAxel Dörfler 		: module(_module) {}
12684052230SAxel Dörfler 	UdpHashDefinition(const UdpHashDefinition& definition)
12784052230SAxel Dörfler 		: module(definition.module) {}
12840bbf860SHugo Santos 
12940bbf860SHugo Santos 	size_t HashKey(const KeyType &key) const
13040bbf860SHugo Santos 	{
13140bbf860SHugo Santos 		return _Mix(module->hash_address_pair(key.first, key.second));
13240bbf860SHugo Santos 	}
13340bbf860SHugo Santos 
13440bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
13540bbf860SHugo Santos 	{
13656f097ebSOliver Tappe 		return _Mix(endpoint->LocalAddress().HashPair(
13756f097ebSOliver Tappe 			*endpoint->PeerAddress()));
13840bbf860SHugo Santos 	}
13940bbf860SHugo Santos 
14040bbf860SHugo Santos 	static size_t _Mix(size_t hash)
14140bbf860SHugo Santos 	{
14256f097ebSOliver Tappe 		// move the bits into the relevant range (as defined by kNumHashBuckets)
14340bbf860SHugo Santos 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
14440bbf860SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
14540bbf860SHugo Santos 	}
14640bbf860SHugo Santos 
14740bbf860SHugo Santos 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
14840bbf860SHugo Santos 	{
14940bbf860SHugo Santos 		return endpoint->LocalAddress().EqualTo(key.first, true)
15040bbf860SHugo Santos 			&& endpoint->PeerAddress().EqualTo(key.second, true);
15140bbf860SHugo Santos 	}
15240bbf860SHugo Santos 
1535147963dSStephan Aßmus 	UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const
15440bbf860SHugo Santos 	{
15540bbf860SHugo Santos 		return endpoint->HashTableLink();
15640bbf860SHugo Santos 	}
15740bbf860SHugo Santos 
15840bbf860SHugo Santos 	net_address_module_info *module;
159c22d69bfSAxel Dörfler };
160c22d69bfSAxel Dörfler 
161c22d69bfSAxel Dörfler 
162bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
163c22d69bfSAxel Dörfler public:
164bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
165727ad0b0SHugo Santos 	~UdpDomainSupport();
166c22d69bfSAxel Dörfler 
167276aa463SIngo Weinhold 	status_t Init();
168bf48e753SHugo Santos 
169bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
170bf48e753SHugo Santos 
171bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
172727ad0b0SHugo Santos 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
173bf48e753SHugo Santos 
174bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer* buffer);
1752bb43d82SAxel Dörfler 	status_t DeliverError(status_t error, net_buffer* buffer);
176727ad0b0SHugo Santos 
177727ad0b0SHugo Santos 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
178727ad0b0SHugo Santos 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
179727ad0b0SHugo Santos 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
180727ad0b0SHugo Santos 
181cf5d9f4bSHugo Santos 	void DumpEndpoints() const;
182bf48e753SHugo Santos 
183c22d69bfSAxel Dörfler private:
184727ad0b0SHugo Santos 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
185727ad0b0SHugo Santos 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
186727ad0b0SHugo Santos 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
187727ad0b0SHugo Santos 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
188727ad0b0SHugo Santos 
18940bbf860SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
190bbbb5592SAxel Dörfler 		const sockaddr *peerAddress, uint32 index = 0);
191bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
192bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
193bf48e753SHugo Santos 
194bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
195727ad0b0SHugo Santos 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
196bf48e753SHugo Santos 
197bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
198727ad0b0SHugo Santos 		{ return fDomain->address_module; }
199bf48e753SHugo Santos 
2005147963dSStephan Aßmus 	typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable;
20140bbf860SHugo Santos 
2022b07b8e0SIngo Weinhold 	mutex			fLock;
203bf48e753SHugo Santos 	net_domain		*fDomain;
204bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
20540bbf860SHugo Santos 	EndpointTable	fActiveEndpoints;
206bf48e753SHugo Santos 	uint32			fEndpointCount;
207bf48e753SHugo Santos 
208bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
209bf48e753SHugo Santos 	static const uint16		kLast = 65535;
210bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
211bf48e753SHugo Santos 							// if you change this, adjust the shifting in
212bf48e753SHugo Santos 							// Hash() accordingly!
213bf48e753SHugo Santos };
214bf48e753SHugo Santos 
215bf48e753SHugo Santos 
216bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
217bf48e753SHugo Santos 
218bf48e753SHugo Santos 
219bf48e753SHugo Santos class UdpEndpointManager {
220c22d69bfSAxel Dörfler public:
221c22d69bfSAxel Dörfler 								UdpEndpointManager();
222c22d69bfSAxel Dörfler 								~UdpEndpointManager();
223c22d69bfSAxel Dörfler 
2242bb43d82SAxel Dörfler 			status_t			InitCheck() const;
2252bb43d82SAxel Dörfler 
226c22d69bfSAxel Dörfler 			status_t			ReceiveData(net_buffer* buffer);
2272bb43d82SAxel Dörfler 			status_t			ReceiveError(status_t error,
2282bb43d82SAxel Dörfler 									net_buffer* buffer);
2296a606180SHugo Santos 			status_t			Deframe(net_buffer* buffer);
230c22d69bfSAxel Dörfler 
231bf48e753SHugo Santos 			UdpDomainSupport*	OpenEndpoint(UdpEndpoint* endpoint);
232bf48e753SHugo Santos 			status_t			FreeEndpoint(UdpDomainSupport* domain);
233c22d69bfSAxel Dörfler 
234cf5d9f4bSHugo Santos 	static	int					DumpEndpoints(int argc, char *argv[]);
235cf5d9f4bSHugo Santos 
236c22d69bfSAxel Dörfler private:
2379d433190SAxel Dörfler 	inline	net_domain*			_GetDomain(net_buffer* buffer);
2389d433190SAxel Dörfler 			UdpDomainSupport*	_GetDomainSupport(net_domain* domain,
2399d433190SAxel Dörfler 									bool create);
2409d433190SAxel Dörfler 			UdpDomainSupport*	_GetDomainSupport(net_buffer* buffer);
241bf48e753SHugo Santos 
2422b07b8e0SIngo Weinhold 			mutex				fLock;
243c22d69bfSAxel Dörfler 			status_t			fStatus;
244bf48e753SHugo Santos 			UdpDomainList		fDomains;
245c22d69bfSAxel Dörfler };
246c22d69bfSAxel Dörfler 
247c22d69bfSAxel Dörfler 
248c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
249c22d69bfSAxel Dörfler 
250c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
251658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
252658a5506SHugo Santos net_stack_module_info *gStackModule;
2532bb43d82SAxel Dörfler net_socket_module_info *gSocketModule;
254c22d69bfSAxel Dörfler 
255c22d69bfSAxel Dörfler 
256c22d69bfSAxel Dörfler // #pragma mark -
257c22d69bfSAxel Dörfler 
258c22d69bfSAxel Dörfler 
259bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
260c22d69bfSAxel Dörfler 	:
261bf48e753SHugo Santos 	fDomain(domain),
262276aa463SIngo Weinhold 	fActiveEndpoints(domain->address_module),
263bf48e753SHugo Santos 	fEndpointCount(0)
264c22d69bfSAxel Dörfler {
2652b07b8e0SIngo Weinhold 	mutex_init(&fLock, "udp domain");
266727ad0b0SHugo Santos 
267727ad0b0SHugo Santos 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
268727ad0b0SHugo Santos }
269727ad0b0SHugo Santos 
270727ad0b0SHugo Santos 
271727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
272727ad0b0SHugo Santos {
2732b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
274bf48e753SHugo Santos }
275bf48e753SHugo Santos 
276bf48e753SHugo Santos 
277bf48e753SHugo Santos status_t
278276aa463SIngo Weinhold UdpDomainSupport::Init()
279bf48e753SHugo Santos {
280276aa463SIngo Weinhold 	return fActiveEndpoints.Init(kNumHashBuckets);
281bf48e753SHugo Santos }
282bf48e753SHugo Santos 
283bf48e753SHugo Santos 
284bf48e753SHugo Santos status_t
285bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
286bf48e753SHugo Santos {
2872bb43d82SAxel Dörfler 	// NOTE: multicast is delivered directly to the endpoint
2882b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
289727ad0b0SHugo Santos 
2902bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_BCAST) != 0)
291bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
2922bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_MCAST) != 0)
293727ad0b0SHugo Santos 		return B_ERROR;
294bf48e753SHugo Santos 
295bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
296bf48e753SHugo Santos }
297bf48e753SHugo Santos 
298bf48e753SHugo Santos 
299bf48e753SHugo Santos status_t
3002bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
3012bb43d82SAxel Dörfler {
3022bb43d82SAxel Dörfler 	if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0)
3032bb43d82SAxel Dörfler 		return B_ERROR;
3042bb43d82SAxel Dörfler 
3052bb43d82SAxel Dörfler 	MutexLocker _(fLock);
3062bb43d82SAxel Dörfler 
3072e1729d0SAxel Dörfler 	// Forward the error to the socket
3082e1729d0SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source,
3092e1729d0SAxel Dörfler 		buffer->destination);
3102e1729d0SAxel Dörfler 	if (endpoint != NULL) {
3112bb43d82SAxel Dörfler 		gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error);
3122e1729d0SAxel Dörfler 		endpoint->NotifyOne();
3132e1729d0SAxel Dörfler 	}
3142bb43d82SAxel Dörfler 
3152bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
3162bb43d82SAxel Dörfler 	return B_OK;
3172bb43d82SAxel Dörfler }
3182bb43d82SAxel Dörfler 
3192bb43d82SAxel Dörfler 
3202bb43d82SAxel Dörfler status_t
321727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
322727ad0b0SHugo Santos 	const sockaddr *address)
323727ad0b0SHugo Santos {
32456f097ebSOliver Tappe 	if (!AddressModule()->is_same_family(address))
32556f097ebSOliver Tappe 		return EAFNOSUPPORT;
32656f097ebSOliver Tappe 
3272b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
328727ad0b0SHugo Santos 
329727ad0b0SHugo Santos 	if (endpoint->IsActive())
330727ad0b0SHugo Santos 		return EINVAL;
331727ad0b0SHugo Santos 
332727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, address);
333727ad0b0SHugo Santos }
334727ad0b0SHugo Santos 
335727ad0b0SHugo Santos 
336727ad0b0SHugo Santos status_t
337727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
338727ad0b0SHugo Santos 	const sockaddr *address)
339727ad0b0SHugo Santos {
3402b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
341727ad0b0SHugo Santos 
342727ad0b0SHugo Santos 	if (endpoint->IsActive()) {
343727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
344727ad0b0SHugo Santos 		endpoint->SetActive(false);
345727ad0b0SHugo Santos 	}
346727ad0b0SHugo Santos 
347727ad0b0SHugo Santos 	if (address->sa_family == AF_UNSPEC) {
348727ad0b0SHugo Santos 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
349727ad0b0SHugo Santos 		// so we reset the peer address:
350727ad0b0SHugo Santos 		endpoint->PeerAddress().SetToEmpty();
351727ad0b0SHugo Santos 	} else {
35256f097ebSOliver Tappe 		if (!AddressModule()->is_same_family(address))
35356f097ebSOliver Tappe 			return EAFNOSUPPORT;
35456f097ebSOliver Tappe 
35556f097ebSOliver Tappe 		// consider destination address INADDR_ANY as INADDR_LOOPBACK
35656f097ebSOliver Tappe 		sockaddr_storage _address;
35756f097ebSOliver Tappe 		if (AddressModule()->is_empty_address(address, false)) {
35856f097ebSOliver Tappe 			AddressModule()->get_loopback_address((sockaddr *)&_address);
35956f097ebSOliver Tappe 			// for IPv4 and IPv6 the port is at the same offset
36056f097ebSOliver Tappe 			((sockaddr_in&)_address).sin_port
36156f097ebSOliver Tappe 				= ((sockaddr_in *)address)->sin_port;
36256f097ebSOliver Tappe 			address = (sockaddr *)&_address;
36356f097ebSOliver Tappe 		}
36456f097ebSOliver Tappe 
365727ad0b0SHugo Santos 		status_t status = endpoint->PeerAddress().SetTo(address);
366727ad0b0SHugo Santos 		if (status < B_OK)
367727ad0b0SHugo Santos 			return status;
3684e45de0eSOliver Tappe 		struct net_route *routeToDestination
3694e45de0eSOliver Tappe 			= gDatalinkModule->get_route(fDomain, address);
3704e45de0eSOliver Tappe 		if (routeToDestination) {
3714e45de0eSOliver Tappe 			status = endpoint->LocalAddress().SetTo(
37261729d93SAxel Dörfler 				routeToDestination->interface_address->local);
3734e45de0eSOliver Tappe 			gDatalinkModule->put_route(fDomain, routeToDestination);
3744e45de0eSOliver Tappe 			if (status < B_OK)
3754e45de0eSOliver Tappe 				return status;
3764e45de0eSOliver Tappe 		}
377727ad0b0SHugo Santos 	}
378727ad0b0SHugo Santos 
379727ad0b0SHugo Santos 	// we need to activate no matter whether or not we have just disconnected,
380727ad0b0SHugo Santos 	// as calling connect() always triggers an implicit bind():
381727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, *endpoint->LocalAddress());
382727ad0b0SHugo Santos }
383727ad0b0SHugo Santos 
384727ad0b0SHugo Santos 
385727ad0b0SHugo Santos status_t
386727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
387727ad0b0SHugo Santos {
3882b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
389727ad0b0SHugo Santos 
390727ad0b0SHugo Santos 	if (endpoint->IsActive())
391727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
392727ad0b0SHugo Santos 
393727ad0b0SHugo Santos 	endpoint->SetActive(false);
394727ad0b0SHugo Santos 
395727ad0b0SHugo Santos 	return B_OK;
396727ad0b0SHugo Santos }
397727ad0b0SHugo Santos 
398727ad0b0SHugo Santos 
399cf5d9f4bSHugo Santos void
400cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
401cf5d9f4bSHugo Santos {
402cf5d9f4bSHugo Santos 	kprintf("-------- UDP Domain %p ---------\n", this);
403cf5d9f4bSHugo Santos 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
404cf5d9f4bSHugo Santos 
405cf5d9f4bSHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
406cf5d9f4bSHugo Santos 
407cb99c915SAxel Dörfler 	while (UdpEndpoint* endpoint = it.Next()) {
408cb99c915SAxel Dörfler 		endpoint->Dump();
409cf5d9f4bSHugo Santos 	}
410cf5d9f4bSHugo Santos }
411cf5d9f4bSHugo Santos 
412cf5d9f4bSHugo Santos 
413727ad0b0SHugo Santos status_t
414727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
415727ad0b0SHugo Santos 	const sockaddr *address)
416727ad0b0SHugo Santos {
417727ad0b0SHugo Santos 	if (AddressModule()->get_port(address) == 0)
418727ad0b0SHugo Santos 		return _BindToEphemeral(endpoint, address);
419727ad0b0SHugo Santos 
420727ad0b0SHugo Santos 	return _Bind(endpoint, address);
421727ad0b0SHugo Santos }
422727ad0b0SHugo Santos 
423727ad0b0SHugo Santos 
424727ad0b0SHugo Santos status_t
425727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
426727ad0b0SHugo Santos {
427727ad0b0SHugo Santos 	int socketOptions = endpoint->Socket()->options;
42840bbf860SHugo Santos 
42940bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
430bf48e753SHugo Santos 
431bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
432bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
433727ad0b0SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
434727ad0b0SHugo Santos 		address, true).Data());
435727ad0b0SHugo Santos 
43640bbf860SHugo Santos 	while (it.HasNext()) {
43740bbf860SHugo Santos 		UdpEndpoint *otherEndpoint = it.Next();
43825a2744fSHugo Santos 
439bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
4405084c839SHugo Santos 			ntohs(otherEndpoint->LocalAddress().Port()));
44125a2744fSHugo Santos 
44225a2744fSHugo Santos 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
443bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
44456f097ebSOliver Tappe 			if ((otherEndpoint->Socket()->options
44556f097ebSOliver Tappe 					& (SO_REUSEADDR | SO_REUSEPORT)) == 0
446d0eaec30SMichael Lotz 				|| (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
447727ad0b0SHugo Santos 				return EADDRINUSE;
44825a2744fSHugo Santos 
449bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
45025a2744fSHugo Santos 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
451d0eaec30SMichael Lotz 				&& ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
452d0eaec30SMichael Lotz 					|| (socketOptions & SO_REUSEPORT) == 0))
453727ad0b0SHugo Santos 				return EADDRINUSE;
454bf48e753SHugo Santos 		}
455bf48e753SHugo Santos 	}
456bf48e753SHugo Santos 
457727ad0b0SHugo Santos 	return _FinishBind(endpoint, address);
458bf48e753SHugo Santos }
459bf48e753SHugo Santos 
460bf48e753SHugo Santos 
461bf48e753SHugo Santos status_t
462727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
463727ad0b0SHugo Santos 	const sockaddr *address)
464727ad0b0SHugo Santos {
465727ad0b0SHugo Santos 	SocketAddressStorage newAddress(AddressModule());
466727ad0b0SHugo Santos 	status_t status = newAddress.SetTo(address);
467727ad0b0SHugo Santos 	if (status < B_OK)
468727ad0b0SHugo Santos 		return status;
469727ad0b0SHugo Santos 
470727ad0b0SHugo Santos 	uint16 allocedPort = _GetNextEphemeral();
471727ad0b0SHugo Santos 	if (allocedPort == 0)
472727ad0b0SHugo Santos 		return ENOBUFS;
473727ad0b0SHugo Santos 
4749e051839SOliver Tappe 	newAddress.SetPort(htons(allocedPort));
475727ad0b0SHugo Santos 
476727ad0b0SHugo Santos 	return _FinishBind(endpoint, *newAddress);
477727ad0b0SHugo Santos }
478727ad0b0SHugo Santos 
479727ad0b0SHugo Santos 
480727ad0b0SHugo Santos status_t
481727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
482727ad0b0SHugo Santos {
483727ad0b0SHugo Santos 	status_t status = endpoint->next->module->bind(endpoint->next, address);
484727ad0b0SHugo Santos 	if (status < B_OK)
485727ad0b0SHugo Santos 		return status;
48640bbf860SHugo Santos 
48740bbf860SHugo Santos 	fActiveEndpoints.Insert(endpoint);
488727ad0b0SHugo Santos 	endpoint->SetActive(true);
489727ad0b0SHugo Santos 
49040bbf860SHugo Santos 	return B_OK;
491bf48e753SHugo Santos }
492bf48e753SHugo Santos 
493bf48e753SHugo Santos 
494c22d69bfSAxel Dörfler UdpEndpoint *
49540bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
496bbbb5592SAxel Dörfler 	const sockaddr *peerAddress, uint32 index)
497c22d69bfSAxel Dörfler {
4982e1729d0SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
4992e1729d0SAxel Dörfler 
5009e051839SOliver Tappe 	TRACE_DOMAIN("finding Endpoint for %s <- %s",
501bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
502bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
503c3e054c8SHugo Santos 
504bbbb5592SAxel Dörfler 	UdpEndpoint* endpoint = fActiveEndpoints.Lookup(
505bbbb5592SAxel Dörfler 		std::make_pair(ourAddress, peerAddress));
506bbbb5592SAxel Dörfler 
507bbbb5592SAxel Dörfler 	// Make sure the bound_to_device constraint is fulfilled
508*da0d7409SAxel Dörfler 	while (endpoint != NULL && endpoint->socket->bound_to_device != 0
509*da0d7409SAxel Dörfler 		&& index != 0 && endpoint->socket->bound_to_device != index) {
510bbbb5592SAxel Dörfler 		endpoint = endpoint->HashTableLink();
511bbbb5592SAxel Dörfler 		if (endpoint != NULL
512bbbb5592SAxel Dörfler 			&& (!endpoint->LocalAddress().EqualTo(ourAddress, true)
513bbbb5592SAxel Dörfler 				|| !endpoint->PeerAddress().EqualTo(peerAddress, true)))
514bbbb5592SAxel Dörfler 			return NULL;
515bbbb5592SAxel Dörfler 	}
516bbbb5592SAxel Dörfler 
517bbbb5592SAxel Dörfler 	return endpoint;
518c22d69bfSAxel Dörfler }
519c22d69bfSAxel Dörfler 
520c22d69bfSAxel Dörfler 
521c22d69bfSAxel Dörfler status_t
522bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
523c22d69bfSAxel Dörfler {
52479a0d252SHugo Santos 	sockaddr* peerAddr = buffer->source;
52579a0d252SHugo Santos 	sockaddr* broadcastAddr = buffer->destination;
5269d433190SAxel Dörfler 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
5279d433190SAxel Dörfler 
528c22d69bfSAxel Dörfler 	sockaddr* mask = NULL;
52961729d93SAxel Dörfler 	if (buffer->interface_address != NULL)
53061729d93SAxel Dörfler 		mask = (sockaddr*)buffer->interface_address->mask;
531c22d69bfSAxel Dörfler 
5329d433190SAxel Dörfler 	TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
533c22d69bfSAxel Dörfler 
5349d433190SAxel Dörfler 	EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
535c22d69bfSAxel Dörfler 
5369d433190SAxel Dörfler 	while (UdpEndpoint* endpoint = iterator.Next()) {
53725a2744fSHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
53825a2744fSHugo Santos 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
53925a2744fSHugo Santos 
540bbbb5592SAxel Dörfler 		if (endpoint->socket->bound_to_device != 0
541bbbb5592SAxel Dörfler 			&& buffer->index != endpoint->socket->bound_to_device)
542bbbb5592SAxel Dörfler 			continue;
543bbbb5592SAxel Dörfler 
5445084c839SHugo Santos 		if (endpoint->LocalAddress().Port() != incomingPort) {
545c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
546c22d69bfSAxel Dörfler 			continue;
547c22d69bfSAxel Dörfler 		}
548c22d69bfSAxel Dörfler 
54925a2744fSHugo Santos 		if (!endpoint->PeerAddress().IsEmpty(true)) {
550c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
551c22d69bfSAxel Dörfler 			// this datagram is from there:
55225a2744fSHugo Santos 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
553c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
554c22d69bfSAxel Dörfler 				// this endpoint...
555c22d69bfSAxel Dörfler 				continue;
556c22d69bfSAxel Dörfler 			}
557c22d69bfSAxel Dörfler 		}
558c22d69bfSAxel Dörfler 
55925a2744fSHugo Santos 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
5609d433190SAxel Dörfler 			|| mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
561c22d69bfSAxel Dörfler 			// address matches, dispatch to this endpoint:
562c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
563c22d69bfSAxel Dörfler 		}
564c22d69bfSAxel Dörfler 	}
56540bbf860SHugo Santos 
566c22d69bfSAxel Dörfler 	return B_OK;
567c22d69bfSAxel Dörfler }
568c22d69bfSAxel Dörfler 
569c22d69bfSAxel Dörfler 
570c22d69bfSAxel Dörfler status_t
571bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
572c22d69bfSAxel Dörfler {
573bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
574c22d69bfSAxel Dörfler 
5752e1729d0SAxel Dörfler 	const sockaddr* localAddress = buffer->destination;
5762e1729d0SAxel Dörfler 	const sockaddr* peerAddress = buffer->source;
5772e1729d0SAxel Dörfler 
5782e1729d0SAxel Dörfler 	// look for full (most special) match:
579bbbb5592SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress,
580bbbb5592SAxel Dörfler 		buffer->index);
5812e1729d0SAxel Dörfler 	if (endpoint == NULL) {
5822e1729d0SAxel Dörfler 		// look for endpoint matching local address & port:
583bbbb5592SAxel Dörfler 		endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index);
5842e1729d0SAxel Dörfler 		if (endpoint == NULL) {
5852e1729d0SAxel Dörfler 			// look for endpoint matching peer address & port and local port:
5862e1729d0SAxel Dörfler 			SocketAddressStorage local(AddressModule());
5872e1729d0SAxel Dörfler 			local.SetToEmpty();
5882e1729d0SAxel Dörfler 			local.SetPort(AddressModule()->get_port(localAddress));
589bbbb5592SAxel Dörfler 			endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index);
5902e1729d0SAxel Dörfler 			if (endpoint == NULL) {
5912e1729d0SAxel Dörfler 				// last chance: look for endpoint matching local port only:
592bbbb5592SAxel Dörfler 				endpoint = _FindActiveEndpoint(*local, NULL, buffer->index);
5932e1729d0SAxel Dörfler 			}
5942e1729d0SAxel Dörfler 		}
5952e1729d0SAxel Dörfler 	}
5962e1729d0SAxel Dörfler 
5972bb43d82SAxel Dörfler 	if (endpoint == NULL) {
5982bb43d82SAxel Dörfler 		TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
599c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
6009e051839SOliver Tappe 	}
601c22d69bfSAxel Dörfler 
602c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
603c22d69bfSAxel Dörfler 	return B_OK;
604c22d69bfSAxel Dörfler }
605c22d69bfSAxel Dörfler 
606c22d69bfSAxel Dörfler 
607bf48e753SHugo Santos uint16
608bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
609c22d69bfSAxel Dörfler {
61040bbf860SHugo Santos 	uint16 stop, curr;
611bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
612bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
613bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
614bf48e753SHugo Santos 	} else {
615bf48e753SHugo Santos 		stop = kLast;
616bf48e753SHugo Santos 		curr = kFirst;
617bf48e753SHugo Santos 	}
618c22d69bfSAxel Dörfler 
619727ad0b0SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
620727ad0b0SHugo Santos 		fLastUsedEphemeral, curr, stop);
62140bbf860SHugo Santos 
6229e051839SOliver Tappe 	// TODO: a free list could be used to avoid the impact of these two
6239e051839SOliver Tappe 	//        nested loops most of the time... let's see how bad this really is
624727ad0b0SHugo Santos 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
625bf48e753SHugo Santos 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
62640bbf860SHugo Santos 
627727ad0b0SHugo Santos 		if (_EndpointWithPort(htons(curr)) == NULL) {
628bf48e753SHugo Santos 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
629bf48e753SHugo Santos 			fLastUsedEphemeral = curr;
630bf48e753SHugo Santos 			return curr;
631bf48e753SHugo Santos 		}
632727ad0b0SHugo Santos 	}
633727ad0b0SHugo Santos 
634727ad0b0SHugo Santos 	return 0;
635727ad0b0SHugo Santos }
636727ad0b0SHugo Santos 
637727ad0b0SHugo Santos 
638727ad0b0SHugo Santos UdpEndpoint *
639727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const
640727ad0b0SHugo Santos {
641727ad0b0SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
642727ad0b0SHugo Santos 
643727ad0b0SHugo Santos 	while (it.HasNext()) {
644727ad0b0SHugo Santos 		UdpEndpoint *endpoint = it.Next();
645727ad0b0SHugo Santos 		if (endpoint->LocalAddress().Port() == port)
646727ad0b0SHugo Santos 			return endpoint;
647727ad0b0SHugo Santos 	}
648727ad0b0SHugo Santos 
649727ad0b0SHugo Santos 	return NULL;
650727ad0b0SHugo Santos }
651c22d69bfSAxel Dörfler 
652bf48e753SHugo Santos 
653bf48e753SHugo Santos // #pragma mark -
654bf48e753SHugo Santos 
655bf48e753SHugo Santos 
656bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
657bf48e753SHugo Santos {
6582b07b8e0SIngo Weinhold 	mutex_init(&fLock, "UDP endpoints");
6592b07b8e0SIngo Weinhold 	fStatus = B_OK;
660bf48e753SHugo Santos }
661bf48e753SHugo Santos 
662bf48e753SHugo Santos 
663bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
664bf48e753SHugo Santos {
6652b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
666bf48e753SHugo Santos }
667bf48e753SHugo Santos 
668bf48e753SHugo Santos 
669bf48e753SHugo Santos status_t
670bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
671bf48e753SHugo Santos {
672bf48e753SHugo Santos 	return fStatus;
673bf48e753SHugo Santos }
674bf48e753SHugo Santos 
675bf48e753SHugo Santos 
676cf5d9f4bSHugo Santos int
677cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
678cf5d9f4bSHugo Santos {
679cf5d9f4bSHugo Santos 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
680cf5d9f4bSHugo Santos 
681cf5d9f4bSHugo Santos 	while (it.HasNext())
682cf5d9f4bSHugo Santos 		it.Next()->DumpEndpoints();
683cf5d9f4bSHugo Santos 
684cf5d9f4bSHugo Santos 	return 0;
685cf5d9f4bSHugo Santos }
686cf5d9f4bSHugo Santos 
687cf5d9f4bSHugo Santos 
688bf48e753SHugo Santos // #pragma mark - inbound
689bf48e753SHugo Santos 
690bf48e753SHugo Santos 
691bf48e753SHugo Santos status_t
692c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer)
693c22d69bfSAxel Dörfler {
6942bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
6952bb43d82SAxel Dörfler 
6969d433190SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
6972bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
6982bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
6992bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7002bb43d82SAxel Dörfler 		return B_ERROR;
7012bb43d82SAxel Dörfler 	}
7022bb43d82SAxel Dörfler 
7036a606180SHugo Santos 	status_t status = Deframe(buffer);
7042bb43d82SAxel Dörfler 	if (status != B_OK)
7056a606180SHugo Santos 		return status;
7066a606180SHugo Santos 
7072bb43d82SAxel Dörfler 	status = domainSupport->DemuxIncomingBuffer(buffer);
7082bb43d82SAxel Dörfler 	if (status != B_OK) {
7092bb43d82SAxel Dörfler 		TRACE_EPM("  ReceiveData(): no endpoint.");
7102bb43d82SAxel Dörfler 		// Send port unreachable error
7112bb43d82SAxel Dörfler 		domainSupport->Domain()->module->error_reply(NULL, buffer,
7122b415445SAxel Dörfler 			B_NET_ERROR_UNREACH_PORT, NULL);
7132bb43d82SAxel Dörfler 		return B_ERROR;
7142bb43d82SAxel Dörfler 	}
7152bb43d82SAxel Dörfler 
7162bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
7172bb43d82SAxel Dörfler 	return B_OK;
7182bb43d82SAxel Dörfler }
7192bb43d82SAxel Dörfler 
7202bb43d82SAxel Dörfler 
7212bb43d82SAxel Dörfler status_t
7222bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
7232bb43d82SAxel Dörfler {
7242bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
7252bb43d82SAxel Dörfler 		error, buffer, buffer->size);
7262bb43d82SAxel Dörfler 
7272bb43d82SAxel Dörfler 	// We only really need the port information
7282bb43d82SAxel Dörfler 	if (buffer->size < 4)
7292bb43d82SAxel Dörfler 		return B_BAD_VALUE;
7302bb43d82SAxel Dörfler 
7319d433190SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7322bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
7332bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
7342bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7352bb43d82SAxel Dörfler 		return B_ERROR;
7362bb43d82SAxel Dörfler 	}
7372bb43d82SAxel Dörfler 
7382bb43d82SAxel Dörfler 	// Deframe the buffer manually, as we usually only get 8 bytes from the
7392bb43d82SAxel Dörfler 	// original packet
7402bb43d82SAxel Dörfler 	udp_header header;
7412bb43d82SAxel Dörfler 	if (gBufferModule->read(buffer, 0, &header,
7422bb43d82SAxel Dörfler 			std::min(buffer->size, sizeof(udp_header))) != B_OK)
7432bb43d82SAxel Dörfler 		return B_BAD_VALUE;
744bf48e753SHugo Santos 
74561729d93SAxel Dörfler 	net_domain* domain = buffer->interface_address->domain;
7462bb43d82SAxel Dörfler 	net_address_module_info* addressModule = domain->address_module;
7476a606180SHugo Santos 
7482bb43d82SAxel Dörfler 	SocketAddress source(addressModule, buffer->source);
7492bb43d82SAxel Dörfler 	SocketAddress destination(addressModule, buffer->destination);
7506a606180SHugo Santos 
7512bb43d82SAxel Dörfler 	source.SetPort(header.source_port);
7522bb43d82SAxel Dörfler 	destination.SetPort(header.destination_port);
753727ad0b0SHugo Santos 
7543f2a18bdSAxel Dörfler 	return domainSupport->DeliverError(error, buffer);
7556a606180SHugo Santos }
7566a606180SHugo Santos 
7576a606180SHugo Santos 
7586a606180SHugo Santos status_t
7596a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer* buffer)
7606a606180SHugo Santos {
7616a606180SHugo Santos 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
7626a606180SHugo Santos 
76387001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
7649d433190SAxel Dörfler 	if (bufferHeader.Status() != B_OK)
765c22d69bfSAxel Dörfler 		return bufferHeader.Status();
766c22d69bfSAxel Dörfler 
767c22d69bfSAxel Dörfler 	udp_header& header = bufferHeader.Data();
768c22d69bfSAxel Dörfler 
7699d433190SAxel Dörfler 	net_domain* domain = _GetDomain(buffer);
7709d433190SAxel Dörfler 	if (domain == NULL) {
7716a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
77261729d93SAxel Dörfler 			"specified (interface address %p).", buffer->interface_address);
773c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
774c22d69bfSAxel Dörfler 	}
775bf48e753SHugo Santos 	net_address_module_info* addressModule = domain->address_module;
776bf48e753SHugo Santos 
77779a0d252SHugo Santos 	SocketAddress source(addressModule, buffer->source);
77879a0d252SHugo Santos 	SocketAddress destination(addressModule, buffer->destination);
779bf48e753SHugo Santos 
7804e8a1b33SHugo Santos 	source.SetPort(header.source_port);
7814e8a1b33SHugo Santos 	destination.SetPort(header.destination_port);
7824e8a1b33SHugo Santos 
7834e8a1b33SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
7844e8a1b33SHugo Santos 		destination.AsString(true).Data());
785c22d69bfSAxel Dörfler 
786c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
787c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
7886a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
789bf48e753SHugo Santos 			udpLength);
790c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
791c22d69bfSAxel Dörfler 	}
792bf48e753SHugo Santos 
793bf48e753SHugo Santos 	if (buffer->size > udpLength)
794c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
795c22d69bfSAxel Dörfler 
796c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
797c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
798d5b5a2c2SHugo Santos 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
799d5b5a2c2SHugo Santos 			buffer, IPPROTO_UDP);
800c22d69bfSAxel Dörfler 		if (sum != 0) {
8016a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
802c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
803c22d69bfSAxel Dörfler 		}
804c22d69bfSAxel Dörfler 	}
805c22d69bfSAxel Dörfler 
806c22d69bfSAxel Dörfler 	bufferHeader.Remove();
807c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
808c22d69bfSAxel Dörfler 
8096a606180SHugo Santos 	return B_OK;
810c22d69bfSAxel Dörfler }
811c22d69bfSAxel Dörfler 
812c22d69bfSAxel Dörfler 
813bf48e753SHugo Santos UdpDomainSupport *
814c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
815c22d69bfSAxel Dörfler {
8162b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
817bf48e753SHugo Santos 
8189d433190SAxel Dörfler 	UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
819bf48e753SHugo Santos 	if (domain)
820bf48e753SHugo Santos 		domain->Ref();
821bf48e753SHugo Santos 	return domain;
822bf48e753SHugo Santos }
823bf48e753SHugo Santos 
824bf48e753SHugo Santos 
825bf48e753SHugo Santos status_t
826bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
827bf48e753SHugo Santos {
8282b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
829bf48e753SHugo Santos 
830727ad0b0SHugo Santos 	if (domain->Put()) {
831bf48e753SHugo Santos 		fDomains.Remove(domain);
832bf48e753SHugo Santos 		delete domain;
833bf48e753SHugo Santos 	}
834bf48e753SHugo Santos 
835bf48e753SHugo Santos 	return B_OK;
836bf48e753SHugo Santos }
837bf48e753SHugo Santos 
838bf48e753SHugo Santos 
839bf48e753SHugo Santos // #pragma mark -
840bf48e753SHugo Santos 
841bf48e753SHugo Santos 
8429d433190SAxel Dörfler inline net_domain*
8439d433190SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer)
844bf48e753SHugo Santos {
8459d433190SAxel Dörfler 	if (buffer->interface_address != NULL)
8469d433190SAxel Dörfler 		return buffer->interface_address->domain;
8479d433190SAxel Dörfler 
8489d433190SAxel Dörfler 	return gStackModule->get_domain(buffer->destination->sa_family);
8499d433190SAxel Dörfler }
8509d433190SAxel Dörfler 
8519d433190SAxel Dörfler 
8529d433190SAxel Dörfler UdpDomainSupport*
8539d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create)
8549d433190SAxel Dörfler {
8559d433190SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
8569d433190SAxel Dörfler 
8579d433190SAxel Dörfler 	if (domain == NULL)
8589d433190SAxel Dörfler 		return NULL;
859bf48e753SHugo Santos 
860bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
861bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
862bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
863bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
864bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
865bf48e753SHugo Santos 	//      family.
8669d433190SAxel Dörfler 	UdpDomainList::Iterator iterator = fDomains.GetIterator();
8679d433190SAxel Dörfler 	while (UdpDomainSupport* domainSupport = iterator.Next()) {
868bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
869bf48e753SHugo Santos 			return domainSupport;
870bf48e753SHugo Santos 	}
871bf48e753SHugo Santos 
872bf48e753SHugo Santos 	if (!create)
873bf48e753SHugo Santos 		return NULL;
874bf48e753SHugo Santos 
8759d433190SAxel Dörfler 	UdpDomainSupport* domainSupport
8769d433190SAxel Dörfler 		= new (std::nothrow) UdpDomainSupport(domain);
877276aa463SIngo Weinhold 	if (domainSupport == NULL || domainSupport->Init() < B_OK) {
878bf48e753SHugo Santos 		delete domainSupport;
879bf48e753SHugo Santos 		return NULL;
880bf48e753SHugo Santos 	}
881bf48e753SHugo Santos 
882bf48e753SHugo Santos 	fDomains.Add(domainSupport);
883bf48e753SHugo Santos 	return domainSupport;
884c22d69bfSAxel Dörfler }
885c22d69bfSAxel Dörfler 
886c22d69bfSAxel Dörfler 
8879d433190SAxel Dörfler /*!	Retrieves the UdpDomainSupport object responsible for this buffer, if the
8889d433190SAxel Dörfler 	domain can be determined. This is only successful if the domain support is
8899d433190SAxel Dörfler 	already existing, ie. there must already be an endpoint for the domain.
8909d433190SAxel Dörfler */
8912bb43d82SAxel Dörfler UdpDomainSupport*
8929d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
8932bb43d82SAxel Dörfler {
8942bb43d82SAxel Dörfler 	MutexLocker _(fLock);
8959d433190SAxel Dörfler 
8969d433190SAxel Dörfler 	return _GetDomainSupport(_GetDomain(buffer), false);
8972bb43d82SAxel Dörfler 		// TODO: we don't want to hold to the manager's lock during the
8982bb43d82SAxel Dörfler 		// whole RX path, we may not hold an endpoint's lock with the
8992bb43d82SAxel Dörfler 		// manager lock held.
9002bb43d82SAxel Dörfler 		// But we should increase the domain's refcount here.
9012bb43d82SAxel Dörfler }
9022bb43d82SAxel Dörfler 
9032bb43d82SAxel Dörfler 
904c22d69bfSAxel Dörfler // #pragma mark -
905c22d69bfSAxel Dörfler 
906c22d69bfSAxel Dörfler 
907c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
908cb99c915SAxel Dörfler 	:
909cb99c915SAxel Dörfler 	DatagramSocket<>("udp endpoint", socket),
910cb99c915SAxel Dörfler 	fActive(false)
911cb99c915SAxel Dörfler {
912cb99c915SAxel Dörfler }
913bf48e753SHugo Santos 
914bf48e753SHugo Santos 
915c22d69bfSAxel Dörfler // #pragma mark - activation
916c22d69bfSAxel Dörfler 
917c22d69bfSAxel Dörfler 
918c22d69bfSAxel Dörfler status_t
91953f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
920c22d69bfSAxel Dörfler {
921bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
922727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
923c22d69bfSAxel Dörfler }
924c22d69bfSAxel Dörfler 
925c22d69bfSAxel Dörfler 
926c22d69bfSAxel Dörfler status_t
927c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
928c22d69bfSAxel Dörfler {
929bf48e753SHugo Santos 	TRACE_EP("Unbind()");
930727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
931c22d69bfSAxel Dörfler }
932c22d69bfSAxel Dörfler 
933c22d69bfSAxel Dörfler 
934c22d69bfSAxel Dörfler status_t
935c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
936c22d69bfSAxel Dörfler {
937bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
938727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
939c22d69bfSAxel Dörfler }
940c22d69bfSAxel Dörfler 
941c22d69bfSAxel Dörfler 
942c22d69bfSAxel Dörfler status_t
943c22d69bfSAxel Dörfler UdpEndpoint::Open()
944c22d69bfSAxel Dörfler {
945bf48e753SHugo Santos 	TRACE_EP("Open()");
946bf48e753SHugo Santos 
947119c6cddSIngo Weinhold 	AutoLocker _(fLock);
948727ad0b0SHugo Santos 
949c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
950c72ab92dSHugo Santos 	if (status < B_OK)
951c72ab92dSHugo Santos 		return status;
952bf48e753SHugo Santos 
953c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
954c72ab92dSHugo Santos 	if (fManager == NULL)
955bf48e753SHugo Santos 		return EAFNOSUPPORT;
956bf48e753SHugo Santos 
957bf48e753SHugo Santos 	return B_OK;
958c22d69bfSAxel Dörfler }
959c22d69bfSAxel Dörfler 
960c22d69bfSAxel Dörfler 
961c22d69bfSAxel Dörfler status_t
962c22d69bfSAxel Dörfler UdpEndpoint::Close()
963c22d69bfSAxel Dörfler {
964bf48e753SHugo Santos 	TRACE_EP("Close()");
965bf48e753SHugo Santos 	return B_OK;
966c22d69bfSAxel Dörfler }
967c22d69bfSAxel Dörfler 
968c22d69bfSAxel Dörfler 
969c22d69bfSAxel Dörfler status_t
970c22d69bfSAxel Dörfler UdpEndpoint::Free()
971c22d69bfSAxel Dörfler {
972bf48e753SHugo Santos 	TRACE_EP("Free()");
9730086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
974c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
975c22d69bfSAxel Dörfler }
976c22d69bfSAxel Dörfler 
977c22d69bfSAxel Dörfler 
978c22d69bfSAxel Dörfler // #pragma mark - outbound
979c22d69bfSAxel Dörfler 
980c22d69bfSAxel Dörfler 
981c22d69bfSAxel Dörfler status_t
982bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
983c22d69bfSAxel Dörfler {
984bf48e753SHugo Santos 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
985bf48e753SHugo Santos 
986d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
987c22d69bfSAxel Dörfler 		return EMSGSIZE;
988c22d69bfSAxel Dörfler 
989c22d69bfSAxel Dörfler 	buffer->protocol = IPPROTO_UDP;
990c22d69bfSAxel Dörfler 
991c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
9926c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
9936c353509SHugo Santos 	if (header.Status() < B_OK)
9946c353509SHugo Santos 		return header.Status();
995c22d69bfSAxel Dörfler 
99679a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
99779a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
9986c353509SHugo Santos 	header->udp_length = htons(buffer->size);
999c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
10006c353509SHugo Santos 	header->udp_checksum = 0;
10016c353509SHugo Santos 
10026c353509SHugo Santos 	header.Sync();
1003c22d69bfSAxel Dörfler 
1004d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1005d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
10066c353509SHugo Santos 	if (calculatedChecksum == 0)
10076c353509SHugo Santos 		calculatedChecksum = 0xffff;
10086c353509SHugo Santos 
10096c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
1010c22d69bfSAxel Dörfler 
1011c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
1012c22d69bfSAxel Dörfler }
1013c22d69bfSAxel Dörfler 
1014c22d69bfSAxel Dörfler 
1015bf48e753SHugo Santos status_t
1016bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
1017bf48e753SHugo Santos {
1018bf48e753SHugo Santos 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
1019bf48e753SHugo Santos 
10202651e51dSAxel Dörfler 	return gDatalinkModule->send_data(this, NULL, buffer);
1021bf48e753SHugo Santos }
1022bf48e753SHugo Santos 
1023bf48e753SHugo Santos 
1024c22d69bfSAxel Dörfler // #pragma mark - inbound
1025c22d69bfSAxel Dörfler 
1026c22d69bfSAxel Dörfler 
1027c22d69bfSAxel Dörfler ssize_t
1028c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
1029c22d69bfSAxel Dörfler {
1030bfb45f71SHugo Santos 	size_t bytes = AvailableData();
1031bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
1032bfb45f71SHugo Santos 	return bytes;
1033c22d69bfSAxel Dörfler }
1034c22d69bfSAxel Dörfler 
1035c22d69bfSAxel Dörfler 
1036c22d69bfSAxel Dörfler status_t
1037c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1038c22d69bfSAxel Dörfler {
1039bf48e753SHugo Santos 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
1040bf48e753SHugo Santos 
10412651e51dSAxel Dörfler 	status_t status = Dequeue(flags, _buffer);
1042cb99c915SAxel Dörfler 	TRACE_EP("  FetchData(): returned from fifo status: %s", strerror(status));
10432651e51dSAxel Dörfler 	if (status != B_OK)
1044c22d69bfSAxel Dörfler 		return status;
1045c22d69bfSAxel Dörfler 
1046bfb45f71SHugo Santos 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
1047c22d69bfSAxel Dörfler 	return B_OK;
1048c22d69bfSAxel Dörfler }
1049c22d69bfSAxel Dörfler 
1050c22d69bfSAxel Dörfler 
1051c22d69bfSAxel Dörfler status_t
1052bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
1053c22d69bfSAxel Dörfler {
1054bf48e753SHugo Santos 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
1055c22d69bfSAxel Dörfler 
10562651e51dSAxel Dörfler 	return EnqueueClone(buffer);
1057c22d69bfSAxel Dörfler }
1058c22d69bfSAxel Dörfler 
1059c22d69bfSAxel Dörfler 
10606a606180SHugo Santos status_t
10616a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
10626a606180SHugo Santos {
1063f6cfc5afSHugo Santos 	TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size);
1064f6cfc5afSHugo Santos 
10656a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
10666a606180SHugo Santos 	if (buffer == NULL)
10676a606180SHugo Santos 		return B_NO_MEMORY;
10686a606180SHugo Santos 
10696a606180SHugo Santos 	status_t status = sUdpEndpointManager->Deframe(buffer);
10706a606180SHugo Santos 	if (status < B_OK) {
10716a606180SHugo Santos 		gBufferModule->free(buffer);
10726a606180SHugo Santos 		return status;
10736a606180SHugo Santos 	}
10746a606180SHugo Santos 
10756a606180SHugo Santos 	return Enqueue(buffer);
10766a606180SHugo Santos }
10776a606180SHugo Santos 
10786a606180SHugo Santos 
1079cb99c915SAxel Dörfler void
1080cb99c915SAxel Dörfler UdpEndpoint::Dump() const
1081cb99c915SAxel Dörfler {
1082cb99c915SAxel Dörfler 	char local[64];
1083cb99c915SAxel Dörfler 	LocalAddress().AsString(local, sizeof(local), true);
1084cb99c915SAxel Dörfler 	char peer[64];
1085cb99c915SAxel Dörfler 	PeerAddress().AsString(peer, sizeof(peer), true);
1086cb99c915SAxel Dörfler 
1087cb99c915SAxel Dörfler 	kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1088cb99c915SAxel Dörfler }
1089cb99c915SAxel Dörfler 
1090cb99c915SAxel Dörfler 
1091c22d69bfSAxel Dörfler // #pragma mark - protocol interface
1092c22d69bfSAxel Dörfler 
1093c22d69bfSAxel Dörfler 
1094c22d69bfSAxel Dörfler net_protocol *
1095c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
1096c22d69bfSAxel Dörfler {
1097c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
1098c22d69bfSAxel Dörfler 
1099c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1100bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1101bf48e753SHugo Santos 		delete endpoint;
1102bf48e753SHugo Santos 		return NULL;
1103bf48e753SHugo Santos 	}
1104bf48e753SHugo Santos 
1105c22d69bfSAxel Dörfler 	return endpoint;
1106c22d69bfSAxel Dörfler }
1107c22d69bfSAxel Dörfler 
1108c22d69bfSAxel Dörfler 
1109c22d69bfSAxel Dörfler status_t
1110c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
1111c22d69bfSAxel Dörfler {
1112bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
1113c22d69bfSAxel Dörfler 	return B_OK;
1114c22d69bfSAxel Dörfler }
1115c22d69bfSAxel Dörfler 
1116c22d69bfSAxel Dörfler 
1117c22d69bfSAxel Dörfler status_t
1118c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1119c22d69bfSAxel Dörfler {
1120bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
1121c22d69bfSAxel Dörfler }
1122c22d69bfSAxel Dörfler 
1123c22d69bfSAxel Dörfler 
1124c22d69bfSAxel Dörfler status_t
1125c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1126c22d69bfSAxel Dörfler {
1127bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
1128c22d69bfSAxel Dörfler }
1129c22d69bfSAxel Dörfler 
1130c22d69bfSAxel Dörfler 
1131c22d69bfSAxel Dörfler status_t
1132c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1133c22d69bfSAxel Dörfler {
1134bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
1135c22d69bfSAxel Dörfler }
1136c22d69bfSAxel Dörfler 
1137c22d69bfSAxel Dörfler 
1138c22d69bfSAxel Dörfler status_t
1139c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1140c22d69bfSAxel Dörfler {
1141bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1142c22d69bfSAxel Dörfler }
1143c22d69bfSAxel Dörfler 
1144c22d69bfSAxel Dörfler 
1145c22d69bfSAxel Dörfler status_t
1146c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1147c22d69bfSAxel Dörfler {
1148ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1149c22d69bfSAxel Dörfler }
1150c22d69bfSAxel Dörfler 
1151c22d69bfSAxel Dörfler 
1152c22d69bfSAxel Dörfler status_t
1153c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1154c22d69bfSAxel Dörfler 	size_t *_length)
1155c22d69bfSAxel Dörfler {
1156c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1157c22d69bfSAxel Dörfler 		value, _length);
1158c22d69bfSAxel Dörfler }
1159c22d69bfSAxel Dörfler 
1160c22d69bfSAxel Dörfler 
1161c22d69bfSAxel Dörfler status_t
116245b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
116345b5203bSHugo Santos 	int *length)
116445b5203bSHugo Santos {
116545b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
116645b5203bSHugo Santos 		value, length);
116745b5203bSHugo Santos }
116845b5203bSHugo Santos 
116945b5203bSHugo Santos 
117045b5203bSHugo Santos status_t
117145b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
117245b5203bSHugo Santos 	const void *value, int length)
117345b5203bSHugo Santos {
117445b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
117545b5203bSHugo Santos 		value, length);
117645b5203bSHugo Santos }
117745b5203bSHugo Santos 
117845b5203bSHugo Santos 
117945b5203bSHugo Santos status_t
118053f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1181c22d69bfSAxel Dörfler {
1182bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1183c22d69bfSAxel Dörfler }
1184c22d69bfSAxel Dörfler 
1185c22d69bfSAxel Dörfler 
1186c22d69bfSAxel Dörfler status_t
1187c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1188c22d69bfSAxel Dörfler {
1189bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1190c22d69bfSAxel Dörfler }
1191c22d69bfSAxel Dörfler 
1192c22d69bfSAxel Dörfler 
1193c22d69bfSAxel Dörfler status_t
1194c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1195c22d69bfSAxel Dörfler {
1196ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1197c22d69bfSAxel Dörfler }
1198c22d69bfSAxel Dörfler 
1199c22d69bfSAxel Dörfler 
1200c22d69bfSAxel Dörfler status_t
1201c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1202c22d69bfSAxel Dörfler {
1203ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1204c22d69bfSAxel Dörfler }
1205c22d69bfSAxel Dörfler 
1206c22d69bfSAxel Dörfler 
1207c22d69bfSAxel Dörfler status_t
1208c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1209c22d69bfSAxel Dörfler 	net_buffer *buffer)
1210c22d69bfSAxel Dörfler {
1211bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1212c22d69bfSAxel Dörfler }
1213c22d69bfSAxel Dörfler 
1214c22d69bfSAxel Dörfler 
1215c22d69bfSAxel Dörfler status_t
1216c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1217c22d69bfSAxel Dörfler {
1218bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1219c22d69bfSAxel Dörfler }
1220c22d69bfSAxel Dörfler 
1221c22d69bfSAxel Dörfler 
1222c22d69bfSAxel Dörfler ssize_t
1223c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1224c22d69bfSAxel Dörfler {
1225bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1226c22d69bfSAxel Dörfler }
1227c22d69bfSAxel Dörfler 
1228c22d69bfSAxel Dörfler 
1229c22d69bfSAxel Dörfler status_t
1230c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1231c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1232c22d69bfSAxel Dörfler {
1233bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1234c22d69bfSAxel Dörfler }
1235c22d69bfSAxel Dörfler 
1236c22d69bfSAxel Dörfler 
1237c22d69bfSAxel Dörfler ssize_t
1238c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1239c22d69bfSAxel Dörfler {
1240bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1241c22d69bfSAxel Dörfler }
1242c22d69bfSAxel Dörfler 
1243c22d69bfSAxel Dörfler 
1244c22d69bfSAxel Dörfler struct net_domain *
1245c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1246c22d69bfSAxel Dörfler {
1247c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1248c22d69bfSAxel Dörfler }
1249c22d69bfSAxel Dörfler 
1250c22d69bfSAxel Dörfler 
1251c22d69bfSAxel Dörfler size_t
1252c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1253c22d69bfSAxel Dörfler {
1254c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1255c22d69bfSAxel Dörfler }
1256c22d69bfSAxel Dörfler 
1257c22d69bfSAxel Dörfler 
1258c22d69bfSAxel Dörfler status_t
1259c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1260c22d69bfSAxel Dörfler {
1261c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1262c22d69bfSAxel Dörfler }
1263c22d69bfSAxel Dörfler 
1264c22d69bfSAxel Dörfler 
1265c22d69bfSAxel Dörfler status_t
12666a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
12676a606180SHugo Santos {
12686a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
12696a606180SHugo Santos }
12706a606180SHugo Santos 
12716a606180SHugo Santos 
12726a606180SHugo Santos status_t
12732b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer)
1274c22d69bfSAxel Dörfler {
12752b415445SAxel Dörfler 	status_t notifyError = B_OK;
12762bb43d82SAxel Dörfler 
12772b415445SAxel Dörfler 	switch (error) {
12782b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_NET:
12792b415445SAxel Dörfler 			notifyError = ENETUNREACH;
12802bb43d82SAxel Dörfler 			break;
12812b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_HOST:
12822b415445SAxel Dörfler 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
12832b415445SAxel Dörfler 			notifyError = EHOSTUNREACH;
12842bb43d82SAxel Dörfler 			break;
12852b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PROTOCOL:
12862b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PORT:
12872b415445SAxel Dörfler 			notifyError = ECONNREFUSED;
12882bb43d82SAxel Dörfler 			break;
12892b415445SAxel Dörfler 		case B_NET_ERROR_MESSAGE_SIZE:
12902b415445SAxel Dörfler 			notifyError = EMSGSIZE;
12912b415445SAxel Dörfler 			break;
12922b415445SAxel Dörfler 		case B_NET_ERROR_PARAMETER_PROBLEM:
12932b415445SAxel Dörfler 			notifyError = ENOPROTOOPT;
12942b415445SAxel Dörfler 			break;
12952b415445SAxel Dörfler 
12962b415445SAxel Dörfler 		case B_NET_ERROR_QUENCH:
12972bb43d82SAxel Dörfler 		default:
12982bb43d82SAxel Dörfler 			// ignore them
12992bb43d82SAxel Dörfler 			gBufferModule->free(buffer);
13002bb43d82SAxel Dörfler 			return B_OK;
1301c22d69bfSAxel Dörfler 	}
1302c22d69bfSAxel Dörfler 
13037e046eabSAxel Dörfler 	ASSERT(notifyError != B_OK);
13047e046eabSAxel Dörfler 
13057e046eabSAxel Dörfler 	return sUdpEndpointManager->ReceiveError(notifyError, buffer);
13067e046eabSAxel Dörfler }
13077e046eabSAxel Dörfler 
1308c22d69bfSAxel Dörfler 
1309c22d69bfSAxel Dörfler status_t
13102b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
13112b415445SAxel Dörfler 	net_error_data *errorData)
1312c22d69bfSAxel Dörfler {
1313c22d69bfSAxel Dörfler 	return B_ERROR;
1314c22d69bfSAxel Dörfler }
1315c22d69bfSAxel Dörfler 
1316c22d69bfSAxel Dörfler 
131778888c44SAxel Dörfler ssize_t
131878888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol,
131978888c44SAxel Dörfler 	net_buffer* buffer, void *data, size_t dataSize)
132078888c44SAxel Dörfler {
132178888c44SAxel Dörfler 	return protocol->next->module->process_ancillary_data_no_container(
132278888c44SAxel Dörfler 		protocol, buffer, data, dataSize);
132378888c44SAxel Dörfler }
132478888c44SAxel Dörfler 
132578888c44SAxel Dörfler 
1326c22d69bfSAxel Dörfler //	#pragma mark - module interface
1327c22d69bfSAxel Dörfler 
1328c22d69bfSAxel Dörfler 
1329c22d69bfSAxel Dörfler static status_t
1330c22d69bfSAxel Dörfler init_udp()
1331c22d69bfSAxel Dörfler {
1332c22d69bfSAxel Dörfler 	status_t status;
1333bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1334c22d69bfSAxel Dörfler 
1335c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1336658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1337658a5506SHugo Santos 		return B_NO_MEMORY;
1338658a5506SHugo Santos 
1339c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1340c22d69bfSAxel Dörfler 	if (status != B_OK)
1341d438fa4cSHugo Santos 		goto err1;
1342c22d69bfSAxel Dörfler 
134361729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
134461729d93SAxel Dörfler 		IPPROTO_IP,
1345c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1346c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1347c22d69bfSAxel Dörfler 		NULL);
1348c22d69bfSAxel Dörfler 	if (status < B_OK)
1349658a5506SHugo Santos 		goto err1;
135061729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
135161729d93SAxel Dörfler 		IPPROTO_IP,
13528d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13538d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13548d1485faSAxel Dörfler 		NULL);
13558d1485faSAxel Dörfler 	if (status < B_OK)
13568d1485faSAxel Dörfler 		goto err1;
13578d1485faSAxel Dörfler 
135861729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
135961729d93SAxel Dörfler 		IPPROTO_UDP,
1360c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1361c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1362c22d69bfSAxel Dörfler 		NULL);
1363c22d69bfSAxel Dörfler 	if (status < B_OK)
1364658a5506SHugo Santos 		goto err1;
136561729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
136661729d93SAxel Dörfler 		IPPROTO_UDP,
13678d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13688d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13698d1485faSAxel Dörfler 		NULL);
13708d1485faSAxel Dörfler 	if (status < B_OK)
13718d1485faSAxel Dörfler 		goto err1;
1372c22d69bfSAxel Dörfler 
137361729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
137461729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
1375c22d69bfSAxel Dörfler 	if (status < B_OK)
1376658a5506SHugo Santos 		goto err1;
137761729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
137861729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
13798d1485faSAxel Dörfler 	if (status < B_OK)
13808d1485faSAxel Dörfler 		goto err1;
1381c22d69bfSAxel Dörfler 
1382cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1383cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1384cf5d9f4bSHugo Santos 
1385c22d69bfSAxel Dörfler 	return B_OK;
1386c22d69bfSAxel Dörfler 
1387c22d69bfSAxel Dörfler err1:
13888d1485faSAxel Dörfler 	// TODO: shouldn't unregister the protocols here?
1389658a5506SHugo Santos 	delete sUdpEndpointManager;
1390c22d69bfSAxel Dörfler 
1391bf48e753SHugo Santos 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1392c22d69bfSAxel Dörfler 	return status;
1393c22d69bfSAxel Dörfler }
1394c22d69bfSAxel Dörfler 
1395c22d69bfSAxel Dörfler 
1396c22d69bfSAxel Dörfler static status_t
1397c22d69bfSAxel Dörfler uninit_udp()
1398c22d69bfSAxel Dörfler {
1399bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1400cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1401cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1402c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1403c22d69bfSAxel Dörfler 	return B_OK;
1404c22d69bfSAxel Dörfler }
1405c22d69bfSAxel Dörfler 
1406c22d69bfSAxel Dörfler 
1407c22d69bfSAxel Dörfler static status_t
1408c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1409c22d69bfSAxel Dörfler {
1410c22d69bfSAxel Dörfler 	switch (op) {
1411c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1412c22d69bfSAxel Dörfler 			return init_udp();
1413c22d69bfSAxel Dörfler 
1414c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1415c22d69bfSAxel Dörfler 			return uninit_udp();
1416c22d69bfSAxel Dörfler 
1417c22d69bfSAxel Dörfler 		default:
1418c22d69bfSAxel Dörfler 			return B_ERROR;
1419c22d69bfSAxel Dörfler 	}
1420c22d69bfSAxel Dörfler }
1421c22d69bfSAxel Dörfler 
1422c22d69bfSAxel Dörfler 
1423c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1424c22d69bfSAxel Dörfler 	{
1425c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1426c22d69bfSAxel Dörfler 		0,
1427c22d69bfSAxel Dörfler 		udp_std_ops
1428c22d69bfSAxel Dörfler 	},
14296f58064fSAxel Dörfler 	NET_PROTOCOL_ATOMIC_MESSAGES,
14306f58064fSAxel Dörfler 
1431c22d69bfSAxel Dörfler 	udp_init_protocol,
1432c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1433c22d69bfSAxel Dörfler 	udp_open,
1434c22d69bfSAxel Dörfler 	udp_close,
1435c22d69bfSAxel Dörfler 	udp_free,
1436c22d69bfSAxel Dörfler 	udp_connect,
1437c22d69bfSAxel Dörfler 	udp_accept,
1438c22d69bfSAxel Dörfler 	udp_control,
143945b5203bSHugo Santos 	udp_getsockopt,
144045b5203bSHugo Santos 	udp_setsockopt,
1441c22d69bfSAxel Dörfler 	udp_bind,
1442c22d69bfSAxel Dörfler 	udp_unbind,
1443c22d69bfSAxel Dörfler 	udp_listen,
1444c22d69bfSAxel Dörfler 	udp_shutdown,
1445c22d69bfSAxel Dörfler 	udp_send_data,
1446c22d69bfSAxel Dörfler 	udp_send_routed_data,
1447c22d69bfSAxel Dörfler 	udp_send_avail,
1448c22d69bfSAxel Dörfler 	udp_read_data,
1449c22d69bfSAxel Dörfler 	udp_read_avail,
1450c22d69bfSAxel Dörfler 	udp_get_domain,
1451c22d69bfSAxel Dörfler 	udp_get_mtu,
1452c22d69bfSAxel Dörfler 	udp_receive_data,
14536a606180SHugo Santos 	udp_deliver_data,
14542bb43d82SAxel Dörfler 	udp_error_received,
1455c22d69bfSAxel Dörfler 	udp_error_reply,
14569871124eSAxel Dörfler 	NULL,		// add_ancillary_data()
14579871124eSAxel Dörfler 	NULL,		// process_ancillary_data()
145878888c44SAxel Dörfler 	udp_process_ancillary_data_no_container,
14599871124eSAxel Dörfler 	NULL,		// send_data_no_buffer()
14609871124eSAxel Dörfler 	NULL		// read_data_no_buffer()
1461c22d69bfSAxel Dörfler };
1462c22d69bfSAxel Dörfler 
1463658a5506SHugo Santos module_dependency module_dependencies[] = {
1464658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1465658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1466658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
14672bb43d82SAxel Dörfler 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1468658a5506SHugo Santos 	{}
1469658a5506SHugo Santos };
1470658a5506SHugo Santos 
1471c22d69bfSAxel Dörfler module_info *modules[] = {
1472c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1473c22d69bfSAxel Dörfler 	NULL
1474c22d69bfSAxel Dörfler };
1475