xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 2b4154458a820aa0b55b2800de9f0a13ea6ec1e2)
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 
104c22d69bfSAxel Dörfler private:
105c72ab92dSHugo Santos 	UdpDomainSupport		*fManager;
106c22d69bfSAxel Dörfler 	bool					fActive;
10756f097ebSOliver Tappe 								// an active UdpEndpoint is part of the
10856f097ebSOliver Tappe 								// endpoint hash (and it is bound and optionally
10956f097ebSOliver Tappe 								// connected)
11040bbf860SHugo Santos 
1115147963dSStephan Aßmus 	UdpEndpoint				*fLink;
11240bbf860SHugo Santos };
11340bbf860SHugo Santos 
11440bbf860SHugo Santos 
11540bbf860SHugo Santos class UdpDomainSupport;
11640bbf860SHugo Santos 
11740bbf860SHugo Santos struct UdpHashDefinition {
11840bbf860SHugo Santos 	typedef net_address_module_info ParentType;
11940bbf860SHugo Santos 	typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
12040bbf860SHugo Santos 	typedef UdpEndpoint ValueType;
12140bbf860SHugo Santos 
12284052230SAxel Dörfler 	UdpHashDefinition(net_address_module_info *_module)
12384052230SAxel Dörfler 		: module(_module) {}
12484052230SAxel Dörfler 	UdpHashDefinition(const UdpHashDefinition& definition)
12584052230SAxel Dörfler 		: module(definition.module) {}
12640bbf860SHugo Santos 
12740bbf860SHugo Santos 	size_t HashKey(const KeyType &key) const
12840bbf860SHugo Santos 	{
12940bbf860SHugo Santos 		return _Mix(module->hash_address_pair(key.first, key.second));
13040bbf860SHugo Santos 	}
13140bbf860SHugo Santos 
13240bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
13340bbf860SHugo Santos 	{
13456f097ebSOliver Tappe 		return _Mix(endpoint->LocalAddress().HashPair(
13556f097ebSOliver Tappe 			*endpoint->PeerAddress()));
13640bbf860SHugo Santos 	}
13740bbf860SHugo Santos 
13840bbf860SHugo Santos 	static size_t _Mix(size_t hash)
13940bbf860SHugo Santos 	{
14056f097ebSOliver Tappe 		// move the bits into the relevant range (as defined by kNumHashBuckets)
14140bbf860SHugo Santos 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
14240bbf860SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
14340bbf860SHugo Santos 	}
14440bbf860SHugo Santos 
14540bbf860SHugo Santos 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
14640bbf860SHugo Santos 	{
14740bbf860SHugo Santos 		return endpoint->LocalAddress().EqualTo(key.first, true)
14840bbf860SHugo Santos 			&& endpoint->PeerAddress().EqualTo(key.second, true);
14940bbf860SHugo Santos 	}
15040bbf860SHugo Santos 
1515147963dSStephan Aßmus 	UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const
15240bbf860SHugo Santos 	{
15340bbf860SHugo Santos 		return endpoint->HashTableLink();
15440bbf860SHugo Santos 	}
15540bbf860SHugo Santos 
15640bbf860SHugo Santos 	net_address_module_info *module;
157c22d69bfSAxel Dörfler };
158c22d69bfSAxel Dörfler 
159c22d69bfSAxel Dörfler 
160bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
161c22d69bfSAxel Dörfler public:
162bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
163727ad0b0SHugo Santos 	~UdpDomainSupport();
164c22d69bfSAxel Dörfler 
165276aa463SIngo Weinhold 	status_t Init();
166bf48e753SHugo Santos 
167bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
168bf48e753SHugo Santos 
169bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
170727ad0b0SHugo Santos 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
171bf48e753SHugo Santos 
172bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer* buffer);
1732bb43d82SAxel Dörfler 	status_t DeliverError(status_t error, net_buffer* buffer);
174727ad0b0SHugo Santos 
175727ad0b0SHugo Santos 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
176727ad0b0SHugo Santos 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
177727ad0b0SHugo Santos 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
178727ad0b0SHugo Santos 
179cf5d9f4bSHugo Santos 	void DumpEndpoints() const;
180bf48e753SHugo Santos 
181c22d69bfSAxel Dörfler private:
182727ad0b0SHugo Santos 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
183727ad0b0SHugo Santos 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
184727ad0b0SHugo Santos 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
185727ad0b0SHugo Santos 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
186727ad0b0SHugo Santos 
18740bbf860SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
18840bbf860SHugo Santos 		const sockaddr *peerAddress);
189bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
190bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
191bf48e753SHugo Santos 
192bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
193727ad0b0SHugo Santos 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
194bf48e753SHugo Santos 
195bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
196727ad0b0SHugo Santos 		{ return fDomain->address_module; }
197bf48e753SHugo Santos 
1985147963dSStephan Aßmus 	typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable;
19940bbf860SHugo Santos 
2002b07b8e0SIngo Weinhold 	mutex			fLock;
201bf48e753SHugo Santos 	net_domain		*fDomain;
202bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
20340bbf860SHugo Santos 	EndpointTable	fActiveEndpoints;
204bf48e753SHugo Santos 	uint32			fEndpointCount;
205bf48e753SHugo Santos 
206bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
207bf48e753SHugo Santos 	static const uint16		kLast = 65535;
208bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
209bf48e753SHugo Santos 							// if you change this, adjust the shifting in
210bf48e753SHugo Santos 							// Hash() accordingly!
211bf48e753SHugo Santos };
212bf48e753SHugo Santos 
213bf48e753SHugo Santos 
214bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
215bf48e753SHugo Santos 
216bf48e753SHugo Santos 
217bf48e753SHugo Santos class UdpEndpointManager {
218c22d69bfSAxel Dörfler public:
219c22d69bfSAxel Dörfler 								UdpEndpointManager();
220c22d69bfSAxel Dörfler 								~UdpEndpointManager();
221c22d69bfSAxel Dörfler 
2222bb43d82SAxel Dörfler 			status_t			InitCheck() const;
2232bb43d82SAxel Dörfler 
224c22d69bfSAxel Dörfler 			status_t			ReceiveData(net_buffer* buffer);
2252bb43d82SAxel Dörfler 			status_t			ReceiveError(status_t error,
2262bb43d82SAxel Dörfler 									net_buffer* buffer);
2276a606180SHugo Santos 			status_t			Deframe(net_buffer* buffer);
228c22d69bfSAxel Dörfler 
229bf48e753SHugo Santos 			UdpDomainSupport*	OpenEndpoint(UdpEndpoint* endpoint);
230bf48e753SHugo Santos 			status_t			FreeEndpoint(UdpDomainSupport* domain);
231c22d69bfSAxel Dörfler 
232cf5d9f4bSHugo Santos 	static	int					DumpEndpoints(int argc, char *argv[]);
233cf5d9f4bSHugo Santos 
234c22d69bfSAxel Dörfler private:
235bf48e753SHugo Santos 			UdpDomainSupport*	_GetDomain(net_domain *domain, bool create);
2362bb43d82SAxel Dörfler 			UdpDomainSupport*	_GetDomain(net_buffer* buffer);
237bf48e753SHugo Santos 
2382b07b8e0SIngo Weinhold 			mutex				fLock;
239c22d69bfSAxel Dörfler 			status_t			fStatus;
240bf48e753SHugo Santos 			UdpDomainList		fDomains;
241c22d69bfSAxel Dörfler };
242c22d69bfSAxel Dörfler 
243c22d69bfSAxel Dörfler 
244c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
245c22d69bfSAxel Dörfler 
246c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
247658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
248658a5506SHugo Santos net_stack_module_info *gStackModule;
2492bb43d82SAxel Dörfler net_socket_module_info *gSocketModule;
250c22d69bfSAxel Dörfler 
251c22d69bfSAxel Dörfler 
252c22d69bfSAxel Dörfler // #pragma mark -
253c22d69bfSAxel Dörfler 
254c22d69bfSAxel Dörfler 
255bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
256c22d69bfSAxel Dörfler 	:
257bf48e753SHugo Santos 	fDomain(domain),
258276aa463SIngo Weinhold 	fActiveEndpoints(domain->address_module),
259bf48e753SHugo Santos 	fEndpointCount(0)
260c22d69bfSAxel Dörfler {
2612b07b8e0SIngo Weinhold 	mutex_init(&fLock, "udp domain");
262727ad0b0SHugo Santos 
263727ad0b0SHugo Santos 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
264727ad0b0SHugo Santos }
265727ad0b0SHugo Santos 
266727ad0b0SHugo Santos 
267727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
268727ad0b0SHugo Santos {
2692b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
270bf48e753SHugo Santos }
271bf48e753SHugo Santos 
272bf48e753SHugo Santos 
273bf48e753SHugo Santos status_t
274276aa463SIngo Weinhold UdpDomainSupport::Init()
275bf48e753SHugo Santos {
276276aa463SIngo Weinhold 	return fActiveEndpoints.Init(kNumHashBuckets);
277bf48e753SHugo Santos }
278bf48e753SHugo Santos 
279bf48e753SHugo Santos 
280bf48e753SHugo Santos status_t
281bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
282bf48e753SHugo Santos {
2832bb43d82SAxel Dörfler 	// NOTE: multicast is delivered directly to the endpoint
2842b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
285727ad0b0SHugo Santos 
2862bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_BCAST) != 0)
287bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
2882bb43d82SAxel Dörfler 	if ((buffer->flags & MSG_MCAST) != 0)
289727ad0b0SHugo Santos 		return B_ERROR;
290bf48e753SHugo Santos 
291bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
292bf48e753SHugo Santos }
293bf48e753SHugo Santos 
294bf48e753SHugo Santos 
295bf48e753SHugo Santos status_t
2962bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
2972bb43d82SAxel Dörfler {
2982bb43d82SAxel Dörfler 	if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0)
2992bb43d82SAxel Dörfler 		return B_ERROR;
3002bb43d82SAxel Dörfler 
3012bb43d82SAxel Dörfler 	MutexLocker _(fLock);
3022bb43d82SAxel Dörfler 
3032e1729d0SAxel Dörfler 	// Forward the error to the socket
3042e1729d0SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source,
3052e1729d0SAxel Dörfler 		buffer->destination);
3062e1729d0SAxel Dörfler 	if (endpoint != NULL) {
3072bb43d82SAxel Dörfler 		gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error);
3082e1729d0SAxel Dörfler 		endpoint->NotifyOne();
3092e1729d0SAxel Dörfler 	}
3102bb43d82SAxel Dörfler 
3112bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
3122bb43d82SAxel Dörfler 	return B_OK;
3132bb43d82SAxel Dörfler }
3142bb43d82SAxel Dörfler 
3152bb43d82SAxel Dörfler 
3162bb43d82SAxel Dörfler status_t
317727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
318727ad0b0SHugo Santos 	const sockaddr *address)
319727ad0b0SHugo Santos {
32056f097ebSOliver Tappe 	if (!AddressModule()->is_same_family(address))
32156f097ebSOliver Tappe 		return EAFNOSUPPORT;
32256f097ebSOliver Tappe 
3232b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
324727ad0b0SHugo Santos 
325727ad0b0SHugo Santos 	if (endpoint->IsActive())
326727ad0b0SHugo Santos 		return EINVAL;
327727ad0b0SHugo Santos 
328727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, address);
329727ad0b0SHugo Santos }
330727ad0b0SHugo Santos 
331727ad0b0SHugo Santos 
332727ad0b0SHugo Santos status_t
333727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
334727ad0b0SHugo Santos 	const sockaddr *address)
335727ad0b0SHugo Santos {
3362b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
337727ad0b0SHugo Santos 
338727ad0b0SHugo Santos 	if (endpoint->IsActive()) {
339727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
340727ad0b0SHugo Santos 		endpoint->SetActive(false);
341727ad0b0SHugo Santos 	}
342727ad0b0SHugo Santos 
343727ad0b0SHugo Santos 	if (address->sa_family == AF_UNSPEC) {
344727ad0b0SHugo Santos 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
345727ad0b0SHugo Santos 		// so we reset the peer address:
346727ad0b0SHugo Santos 		endpoint->PeerAddress().SetToEmpty();
347727ad0b0SHugo Santos 	} else {
34856f097ebSOliver Tappe 		if (!AddressModule()->is_same_family(address))
34956f097ebSOliver Tappe 			return EAFNOSUPPORT;
35056f097ebSOliver Tappe 
35156f097ebSOliver Tappe 		// consider destination address INADDR_ANY as INADDR_LOOPBACK
35256f097ebSOliver Tappe 		sockaddr_storage _address;
35356f097ebSOliver Tappe 		if (AddressModule()->is_empty_address(address, false)) {
35456f097ebSOliver Tappe 			AddressModule()->get_loopback_address((sockaddr *)&_address);
35556f097ebSOliver Tappe 			// for IPv4 and IPv6 the port is at the same offset
35656f097ebSOliver Tappe 			((sockaddr_in&)_address).sin_port
35756f097ebSOliver Tappe 				= ((sockaddr_in *)address)->sin_port;
35856f097ebSOliver Tappe 			address = (sockaddr *)&_address;
35956f097ebSOliver Tappe 		}
36056f097ebSOliver Tappe 
361727ad0b0SHugo Santos 		status_t status = endpoint->PeerAddress().SetTo(address);
362727ad0b0SHugo Santos 		if (status < B_OK)
363727ad0b0SHugo Santos 			return status;
3644e45de0eSOliver Tappe 		struct net_route *routeToDestination
3654e45de0eSOliver Tappe 			= gDatalinkModule->get_route(fDomain, address);
3664e45de0eSOliver Tappe 		if (routeToDestination) {
3674e45de0eSOliver Tappe 			status = endpoint->LocalAddress().SetTo(
36861729d93SAxel Dörfler 				routeToDestination->interface_address->local);
3694e45de0eSOliver Tappe 			gDatalinkModule->put_route(fDomain, routeToDestination);
3704e45de0eSOliver Tappe 			if (status < B_OK)
3714e45de0eSOliver Tappe 				return status;
3724e45de0eSOliver Tappe 		}
373727ad0b0SHugo Santos 	}
374727ad0b0SHugo Santos 
375727ad0b0SHugo Santos 	// we need to activate no matter whether or not we have just disconnected,
376727ad0b0SHugo Santos 	// as calling connect() always triggers an implicit bind():
377727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, *endpoint->LocalAddress());
378727ad0b0SHugo Santos }
379727ad0b0SHugo Santos 
380727ad0b0SHugo Santos 
381727ad0b0SHugo Santos status_t
382727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
383727ad0b0SHugo Santos {
3842b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
385727ad0b0SHugo Santos 
386727ad0b0SHugo Santos 	if (endpoint->IsActive())
387727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
388727ad0b0SHugo Santos 
389727ad0b0SHugo Santos 	endpoint->SetActive(false);
390727ad0b0SHugo Santos 
391727ad0b0SHugo Santos 	return B_OK;
392727ad0b0SHugo Santos }
393727ad0b0SHugo Santos 
394727ad0b0SHugo Santos 
395cf5d9f4bSHugo Santos void
396cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
397cf5d9f4bSHugo Santos {
398cf5d9f4bSHugo Santos 	kprintf("-------- UDP Domain %p ---------\n", this);
399cf5d9f4bSHugo Santos 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
400cf5d9f4bSHugo Santos 
401cf5d9f4bSHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
402cf5d9f4bSHugo Santos 
403cf5d9f4bSHugo Santos 	while (it.HasNext()) {
404cf5d9f4bSHugo Santos 		UdpEndpoint *endpoint = it.Next();
405cf5d9f4bSHugo Santos 
406cf5d9f4bSHugo Santos 		char localBuf[64], peerBuf[64];
407cf5d9f4bSHugo Santos 		endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true);
408cf5d9f4bSHugo Santos 		endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true);
409cf5d9f4bSHugo Santos 
410cf5d9f4bSHugo Santos 		kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf,
411cf5d9f4bSHugo Santos 			endpoint->AvailableData());
412cf5d9f4bSHugo Santos 	}
413cf5d9f4bSHugo Santos }
414cf5d9f4bSHugo Santos 
415cf5d9f4bSHugo Santos 
416727ad0b0SHugo Santos status_t
417727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
418727ad0b0SHugo Santos 	const sockaddr *address)
419727ad0b0SHugo Santos {
420727ad0b0SHugo Santos 	if (AddressModule()->get_port(address) == 0)
421727ad0b0SHugo Santos 		return _BindToEphemeral(endpoint, address);
422727ad0b0SHugo Santos 
423727ad0b0SHugo Santos 	return _Bind(endpoint, address);
424727ad0b0SHugo Santos }
425727ad0b0SHugo Santos 
426727ad0b0SHugo Santos 
427727ad0b0SHugo Santos status_t
428727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
429727ad0b0SHugo Santos {
430727ad0b0SHugo Santos 	int socketOptions = endpoint->Socket()->options;
43140bbf860SHugo Santos 
43240bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
433bf48e753SHugo Santos 
434bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
435bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
436727ad0b0SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
437727ad0b0SHugo Santos 		address, true).Data());
438727ad0b0SHugo Santos 
43940bbf860SHugo Santos 	while (it.HasNext()) {
44040bbf860SHugo Santos 		UdpEndpoint *otherEndpoint = it.Next();
44125a2744fSHugo Santos 
442bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
4435084c839SHugo Santos 			ntohs(otherEndpoint->LocalAddress().Port()));
44425a2744fSHugo Santos 
44525a2744fSHugo Santos 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
446bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
44756f097ebSOliver Tappe 			if ((otherEndpoint->Socket()->options
44856f097ebSOliver Tappe 					& (SO_REUSEADDR | SO_REUSEPORT)) == 0
449d0eaec30SMichael Lotz 				|| (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
450727ad0b0SHugo Santos 				return EADDRINUSE;
45125a2744fSHugo Santos 
452bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
45325a2744fSHugo Santos 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
454d0eaec30SMichael Lotz 				&& ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
455d0eaec30SMichael Lotz 					|| (socketOptions & SO_REUSEPORT) == 0))
456727ad0b0SHugo Santos 				return EADDRINUSE;
457bf48e753SHugo Santos 		}
458bf48e753SHugo Santos 	}
459bf48e753SHugo Santos 
460727ad0b0SHugo Santos 	return _FinishBind(endpoint, address);
461bf48e753SHugo Santos }
462bf48e753SHugo Santos 
463bf48e753SHugo Santos 
464bf48e753SHugo Santos status_t
465727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
466727ad0b0SHugo Santos 	const sockaddr *address)
467727ad0b0SHugo Santos {
468727ad0b0SHugo Santos 	SocketAddressStorage newAddress(AddressModule());
469727ad0b0SHugo Santos 	status_t status = newAddress.SetTo(address);
470727ad0b0SHugo Santos 	if (status < B_OK)
471727ad0b0SHugo Santos 		return status;
472727ad0b0SHugo Santos 
473727ad0b0SHugo Santos 	uint16 allocedPort = _GetNextEphemeral();
474727ad0b0SHugo Santos 	if (allocedPort == 0)
475727ad0b0SHugo Santos 		return ENOBUFS;
476727ad0b0SHugo Santos 
4779e051839SOliver Tappe 	newAddress.SetPort(htons(allocedPort));
478727ad0b0SHugo Santos 
479727ad0b0SHugo Santos 	return _FinishBind(endpoint, *newAddress);
480727ad0b0SHugo Santos }
481727ad0b0SHugo Santos 
482727ad0b0SHugo Santos 
483727ad0b0SHugo Santos status_t
484727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
485727ad0b0SHugo Santos {
486727ad0b0SHugo Santos 	status_t status = endpoint->next->module->bind(endpoint->next, address);
487727ad0b0SHugo Santos 	if (status < B_OK)
488727ad0b0SHugo Santos 		return status;
48940bbf860SHugo Santos 
49040bbf860SHugo Santos 	fActiveEndpoints.Insert(endpoint);
491727ad0b0SHugo Santos 	endpoint->SetActive(true);
492727ad0b0SHugo Santos 
49340bbf860SHugo Santos 	return B_OK;
494bf48e753SHugo Santos }
495bf48e753SHugo Santos 
496bf48e753SHugo Santos 
497c22d69bfSAxel Dörfler UdpEndpoint *
49840bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
49940bbf860SHugo Santos 	const sockaddr *peerAddress)
500c22d69bfSAxel Dörfler {
5012e1729d0SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&fLock);
5022e1729d0SAxel Dörfler 
5039e051839SOliver Tappe 	TRACE_DOMAIN("finding Endpoint for %s <- %s",
504bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
505bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
506c3e054c8SHugo Santos 
50740bbf860SHugo Santos 	return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress));
508c22d69bfSAxel Dörfler }
509c22d69bfSAxel Dörfler 
510c22d69bfSAxel Dörfler 
511c22d69bfSAxel Dörfler status_t
512bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer)
513c22d69bfSAxel Dörfler {
51479a0d252SHugo Santos 	sockaddr *peerAddr = buffer->source;
51579a0d252SHugo Santos 	sockaddr *broadcastAddr = buffer->destination;
516c22d69bfSAxel Dörfler 	sockaddr *mask = NULL;
51761729d93SAxel Dörfler 	if (buffer->interface_address != NULL)
51861729d93SAxel Dörfler 		mask = (sockaddr *)buffer->interface_address->mask;
519c22d69bfSAxel Dörfler 
520bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer);
521c22d69bfSAxel Dörfler 
522bf48e753SHugo Santos 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
523c22d69bfSAxel Dörfler 
52440bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
52540bbf860SHugo Santos 
52640bbf860SHugo Santos 	while (it.HasNext()) {
52740bbf860SHugo Santos 		UdpEndpoint *endpoint = it.Next();
528c22d69bfSAxel Dörfler 
52925a2744fSHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
53025a2744fSHugo Santos 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
53125a2744fSHugo Santos 
5325084c839SHugo Santos 		if (endpoint->LocalAddress().Port() != incomingPort) {
533c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
534c22d69bfSAxel Dörfler 			continue;
535c22d69bfSAxel Dörfler 		}
536c22d69bfSAxel Dörfler 
53725a2744fSHugo Santos 		if (!endpoint->PeerAddress().IsEmpty(true)) {
538c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
539c22d69bfSAxel Dörfler 			// this datagram is from there:
54025a2744fSHugo Santos 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
541c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
542c22d69bfSAxel Dörfler 				// this endpoint...
543c22d69bfSAxel Dörfler 				continue;
544c22d69bfSAxel Dörfler 			}
545c22d69bfSAxel Dörfler 		}
546c22d69bfSAxel Dörfler 
54725a2744fSHugo Santos 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
54825a2744fSHugo Santos 			|| endpoint->LocalAddress().IsEmpty(false)) {
549c22d69bfSAxel Dörfler 			// address matches, dispatch to this endpoint:
550c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
551c22d69bfSAxel Dörfler 		}
552c22d69bfSAxel Dörfler 	}
55340bbf860SHugo Santos 
554c22d69bfSAxel Dörfler 	return B_OK;
555c22d69bfSAxel Dörfler }
556c22d69bfSAxel Dörfler 
557c22d69bfSAxel Dörfler 
558c22d69bfSAxel Dörfler status_t
559bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
560c22d69bfSAxel Dörfler {
561bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
562c22d69bfSAxel Dörfler 
5632e1729d0SAxel Dörfler 	const sockaddr* localAddress = buffer->destination;
5642e1729d0SAxel Dörfler 	const sockaddr* peerAddress = buffer->source;
5652e1729d0SAxel Dörfler 
5662e1729d0SAxel Dörfler 	// look for full (most special) match:
5672e1729d0SAxel Dörfler 	UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress);
5682e1729d0SAxel Dörfler 	if (endpoint == NULL) {
5692e1729d0SAxel Dörfler 		// look for endpoint matching local address & port:
5702e1729d0SAxel Dörfler 		endpoint = _FindActiveEndpoint(localAddress, NULL);
5712e1729d0SAxel Dörfler 		if (endpoint == NULL) {
5722e1729d0SAxel Dörfler 			// look for endpoint matching peer address & port and local port:
5732e1729d0SAxel Dörfler 			SocketAddressStorage local(AddressModule());
5742e1729d0SAxel Dörfler 			local.SetToEmpty();
5752e1729d0SAxel Dörfler 			local.SetPort(AddressModule()->get_port(localAddress));
5762e1729d0SAxel Dörfler 			endpoint = _FindActiveEndpoint(*local, peerAddress);
5772e1729d0SAxel Dörfler 			if (endpoint == NULL) {
5782e1729d0SAxel Dörfler 				// last chance: look for endpoint matching local port only:
5792e1729d0SAxel Dörfler 				endpoint = _FindActiveEndpoint(*local, NULL);
5802e1729d0SAxel Dörfler 			}
5812e1729d0SAxel Dörfler 		}
5822e1729d0SAxel Dörfler 	}
5832e1729d0SAxel Dörfler 
5842bb43d82SAxel Dörfler 	if (endpoint == NULL) {
5852bb43d82SAxel Dörfler 		TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
586c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
5879e051839SOliver Tappe 	}
588c22d69bfSAxel Dörfler 
589c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
590c22d69bfSAxel Dörfler 	return B_OK;
591c22d69bfSAxel Dörfler }
592c22d69bfSAxel Dörfler 
593c22d69bfSAxel Dörfler 
594bf48e753SHugo Santos uint16
595bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
596c22d69bfSAxel Dörfler {
59740bbf860SHugo Santos 	uint16 stop, curr;
598bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
599bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
600bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
601bf48e753SHugo Santos 	} else {
602bf48e753SHugo Santos 		stop = kLast;
603bf48e753SHugo Santos 		curr = kFirst;
604bf48e753SHugo Santos 	}
605c22d69bfSAxel Dörfler 
606727ad0b0SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
607727ad0b0SHugo Santos 		fLastUsedEphemeral, curr, stop);
60840bbf860SHugo Santos 
6099e051839SOliver Tappe 	// TODO: a free list could be used to avoid the impact of these two
6109e051839SOliver Tappe 	//        nested loops most of the time... let's see how bad this really is
611727ad0b0SHugo Santos 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
612bf48e753SHugo Santos 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
61340bbf860SHugo Santos 
614727ad0b0SHugo Santos 		if (_EndpointWithPort(htons(curr)) == NULL) {
615bf48e753SHugo Santos 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
616bf48e753SHugo Santos 			fLastUsedEphemeral = curr;
617bf48e753SHugo Santos 			return curr;
618bf48e753SHugo Santos 		}
619727ad0b0SHugo Santos 	}
620727ad0b0SHugo Santos 
621727ad0b0SHugo Santos 	return 0;
622727ad0b0SHugo Santos }
623727ad0b0SHugo Santos 
624727ad0b0SHugo Santos 
625727ad0b0SHugo Santos UdpEndpoint *
626727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const
627727ad0b0SHugo Santos {
628727ad0b0SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
629727ad0b0SHugo Santos 
630727ad0b0SHugo Santos 	while (it.HasNext()) {
631727ad0b0SHugo Santos 		UdpEndpoint *endpoint = it.Next();
632727ad0b0SHugo Santos 		if (endpoint->LocalAddress().Port() == port)
633727ad0b0SHugo Santos 			return endpoint;
634727ad0b0SHugo Santos 	}
635727ad0b0SHugo Santos 
636727ad0b0SHugo Santos 	return NULL;
637727ad0b0SHugo Santos }
638c22d69bfSAxel Dörfler 
639bf48e753SHugo Santos 
640bf48e753SHugo Santos // #pragma mark -
641bf48e753SHugo Santos 
642bf48e753SHugo Santos 
643bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
644bf48e753SHugo Santos {
6452b07b8e0SIngo Weinhold 	mutex_init(&fLock, "UDP endpoints");
6462b07b8e0SIngo Weinhold 	fStatus = B_OK;
647bf48e753SHugo Santos }
648bf48e753SHugo Santos 
649bf48e753SHugo Santos 
650bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
651bf48e753SHugo Santos {
6522b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
653bf48e753SHugo Santos }
654bf48e753SHugo Santos 
655bf48e753SHugo Santos 
656bf48e753SHugo Santos status_t
657bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
658bf48e753SHugo Santos {
659bf48e753SHugo Santos 	return fStatus;
660bf48e753SHugo Santos }
661bf48e753SHugo Santos 
662bf48e753SHugo Santos 
663cf5d9f4bSHugo Santos int
664cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
665cf5d9f4bSHugo Santos {
666cf5d9f4bSHugo Santos 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
667cf5d9f4bSHugo Santos 
668cf5d9f4bSHugo Santos 	while (it.HasNext())
669cf5d9f4bSHugo Santos 		it.Next()->DumpEndpoints();
670cf5d9f4bSHugo Santos 
671cf5d9f4bSHugo Santos 	return 0;
672cf5d9f4bSHugo Santos }
673cf5d9f4bSHugo Santos 
674cf5d9f4bSHugo Santos 
675bf48e753SHugo Santos // #pragma mark - inbound
676bf48e753SHugo Santos 
677bf48e753SHugo Santos 
678bf48e753SHugo Santos status_t
679c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer)
680c22d69bfSAxel Dörfler {
6812bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
6822bb43d82SAxel Dörfler 
6832bb43d82SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomain(buffer);
6842bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
6852bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
6862bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
6872bb43d82SAxel Dörfler 		return B_ERROR;
6882bb43d82SAxel Dörfler 	}
6892bb43d82SAxel Dörfler 
6906a606180SHugo Santos 	status_t status = Deframe(buffer);
6912bb43d82SAxel Dörfler 	if (status != B_OK)
6926a606180SHugo Santos 		return status;
6936a606180SHugo Santos 
6942bb43d82SAxel Dörfler 	status = domainSupport->DemuxIncomingBuffer(buffer);
6952bb43d82SAxel Dörfler 	if (status != B_OK) {
6962bb43d82SAxel Dörfler 		TRACE_EPM("  ReceiveData(): no endpoint.");
6972bb43d82SAxel Dörfler 		// Send port unreachable error
6982bb43d82SAxel Dörfler 		domainSupport->Domain()->module->error_reply(NULL, buffer,
699*2b415445SAxel Dörfler 			B_NET_ERROR_UNREACH_PORT, NULL);
7002bb43d82SAxel Dörfler 		return B_ERROR;
7012bb43d82SAxel Dörfler 	}
7022bb43d82SAxel Dörfler 
7032bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
7042bb43d82SAxel Dörfler 	return B_OK;
7052bb43d82SAxel Dörfler }
7062bb43d82SAxel Dörfler 
7072bb43d82SAxel Dörfler 
7082bb43d82SAxel Dörfler status_t
7092bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
7102bb43d82SAxel Dörfler {
7112bb43d82SAxel Dörfler 	TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
7122bb43d82SAxel Dörfler 		error, buffer, buffer->size);
7132bb43d82SAxel Dörfler 
7142bb43d82SAxel Dörfler 	// We only really need the port information
7152bb43d82SAxel Dörfler 	if (buffer->size < 4)
7162bb43d82SAxel Dörfler 		return B_BAD_VALUE;
7172bb43d82SAxel Dörfler 
7182bb43d82SAxel Dörfler 	UdpDomainSupport* domainSupport = _GetDomain(buffer);
7192bb43d82SAxel Dörfler 	if (domainSupport == NULL) {
7202bb43d82SAxel Dörfler 		// we don't instantiate domain supports in the receiving path, as
7212bb43d82SAxel Dörfler 		// we are only interested in delivering data to existing sockets.
7222bb43d82SAxel Dörfler 		return B_ERROR;
7232bb43d82SAxel Dörfler 	}
7242bb43d82SAxel Dörfler 
7252bb43d82SAxel Dörfler 	// Deframe the buffer manually, as we usually only get 8 bytes from the
7262bb43d82SAxel Dörfler 	// original packet
7272bb43d82SAxel Dörfler 	udp_header header;
7282bb43d82SAxel Dörfler 	if (gBufferModule->read(buffer, 0, &header,
7292bb43d82SAxel Dörfler 			std::min(buffer->size, sizeof(udp_header))) != B_OK)
7302bb43d82SAxel Dörfler 		return B_BAD_VALUE;
731bf48e753SHugo Santos 
73261729d93SAxel Dörfler 	net_domain* domain = buffer->interface_address->domain;
7332bb43d82SAxel Dörfler 	net_address_module_info* addressModule = domain->address_module;
7346a606180SHugo Santos 
7352bb43d82SAxel Dörfler 	SocketAddress source(addressModule, buffer->source);
7362bb43d82SAxel Dörfler 	SocketAddress destination(addressModule, buffer->destination);
7376a606180SHugo Santos 
7382bb43d82SAxel Dörfler 	source.SetPort(header.source_port);
7392bb43d82SAxel Dörfler 	destination.SetPort(header.destination_port);
740727ad0b0SHugo Santos 
7412bb43d82SAxel Dörfler 	status_t status = domainSupport->DeliverError(error, buffer);
7422bb43d82SAxel Dörfler 	if (status != B_OK)
7432bb43d82SAxel Dörfler 		return status;
7446a606180SHugo Santos 
745a1deb55eSHugo Santos 	gBufferModule->free(buffer);
746a1deb55eSHugo Santos 	return B_OK;
7476a606180SHugo Santos }
7486a606180SHugo Santos 
7496a606180SHugo Santos 
7506a606180SHugo Santos status_t
7516a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer)
7526a606180SHugo Santos {
7536a606180SHugo Santos 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
7546a606180SHugo Santos 
75587001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
756c22d69bfSAxel Dörfler 	if (bufferHeader.Status() < B_OK)
757c22d69bfSAxel Dörfler 		return bufferHeader.Status();
758c22d69bfSAxel Dörfler 
759c22d69bfSAxel Dörfler 	udp_header &header = bufferHeader.Data();
760c22d69bfSAxel Dörfler 
76161729d93SAxel Dörfler 	if (buffer->interface_address == NULL
76261729d93SAxel Dörfler 		|| buffer->interface_address->domain == NULL) {
7636a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
76461729d93SAxel Dörfler 			"specified (interface address %p).", buffer->interface_address);
765c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
766c22d69bfSAxel Dörfler 	}
767bf48e753SHugo Santos 
76861729d93SAxel Dörfler 	net_domain *domain = buffer->interface_address->domain;
769bf48e753SHugo Santos 	net_address_module_info *addressModule = domain->address_module;
770bf48e753SHugo Santos 
77179a0d252SHugo Santos 	SocketAddress source(addressModule, buffer->source);
77279a0d252SHugo Santos 	SocketAddress destination(addressModule, buffer->destination);
773bf48e753SHugo Santos 
7744e8a1b33SHugo Santos 	source.SetPort(header.source_port);
7754e8a1b33SHugo Santos 	destination.SetPort(header.destination_port);
7764e8a1b33SHugo Santos 
7774e8a1b33SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
7784e8a1b33SHugo Santos 		destination.AsString(true).Data());
779c22d69bfSAxel Dörfler 
780c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
781c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
7826a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
783bf48e753SHugo Santos 			udpLength);
784c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
785c22d69bfSAxel Dörfler 	}
786bf48e753SHugo Santos 
787bf48e753SHugo Santos 	if (buffer->size > udpLength)
788c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
789c22d69bfSAxel Dörfler 
790c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
791c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
792d5b5a2c2SHugo Santos 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
793d5b5a2c2SHugo Santos 			buffer, IPPROTO_UDP);
794c22d69bfSAxel Dörfler 		if (sum != 0) {
7956a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
796c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
797c22d69bfSAxel Dörfler 		}
798c22d69bfSAxel Dörfler 	}
799c22d69bfSAxel Dörfler 
800c22d69bfSAxel Dörfler 	bufferHeader.Remove();
801c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
802c22d69bfSAxel Dörfler 
8036a606180SHugo Santos 	return B_OK;
804c22d69bfSAxel Dörfler }
805c22d69bfSAxel Dörfler 
806c22d69bfSAxel Dörfler 
807bf48e753SHugo Santos UdpDomainSupport *
808c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
809c22d69bfSAxel Dörfler {
8102b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
811bf48e753SHugo Santos 
812bf48e753SHugo Santos 	UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true);
813bf48e753SHugo Santos 	if (domain)
814bf48e753SHugo Santos 		domain->Ref();
815bf48e753SHugo Santos 	return domain;
816bf48e753SHugo Santos }
817bf48e753SHugo Santos 
818bf48e753SHugo Santos 
819bf48e753SHugo Santos status_t
820bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
821bf48e753SHugo Santos {
8222b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
823bf48e753SHugo Santos 
824727ad0b0SHugo Santos 	if (domain->Put()) {
825bf48e753SHugo Santos 		fDomains.Remove(domain);
826bf48e753SHugo Santos 		delete domain;
827bf48e753SHugo Santos 	}
828bf48e753SHugo Santos 
829bf48e753SHugo Santos 	return B_OK;
830bf48e753SHugo Santos }
831bf48e753SHugo Santos 
832bf48e753SHugo Santos 
833bf48e753SHugo Santos // #pragma mark -
834bf48e753SHugo Santos 
835bf48e753SHugo Santos 
836bf48e753SHugo Santos UdpDomainSupport *
837bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
838bf48e753SHugo Santos {
839bf48e753SHugo Santos 	UdpDomainList::Iterator it = fDomains.GetIterator();
840bf48e753SHugo Santos 
841bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
842bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
843bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
844bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
845bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
846bf48e753SHugo Santos 	//      family.
847bf48e753SHugo Santos 	while (it.HasNext()) {
848bf48e753SHugo Santos 		UdpDomainSupport *domainSupport = it.Next();
849bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
850bf48e753SHugo Santos 			return domainSupport;
851bf48e753SHugo Santos 	}
852bf48e753SHugo Santos 
853bf48e753SHugo Santos 	if (!create)
854bf48e753SHugo Santos 		return NULL;
855bf48e753SHugo Santos 
856bf48e753SHugo Santos 	UdpDomainSupport *domainSupport =
857bf48e753SHugo Santos 		new (std::nothrow) UdpDomainSupport(domain);
858276aa463SIngo Weinhold 	if (domainSupport == NULL || domainSupport->Init() < B_OK) {
859bf48e753SHugo Santos 		delete domainSupport;
860bf48e753SHugo Santos 		return NULL;
861bf48e753SHugo Santos 	}
862bf48e753SHugo Santos 
863bf48e753SHugo Santos 	fDomains.Add(domainSupport);
864bf48e753SHugo Santos 	return domainSupport;
865c22d69bfSAxel Dörfler }
866c22d69bfSAxel Dörfler 
867c22d69bfSAxel Dörfler 
8682bb43d82SAxel Dörfler UdpDomainSupport*
8692bb43d82SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer)
8702bb43d82SAxel Dörfler {
87161729d93SAxel Dörfler 	if (buffer->interface_address == NULL)
8722bb43d82SAxel Dörfler 		return NULL;
8732bb43d82SAxel Dörfler 
8742bb43d82SAxel Dörfler 	MutexLocker _(fLock);
87561729d93SAxel Dörfler 	return _GetDomain(buffer->interface_address->domain, false);
8762bb43d82SAxel Dörfler 		// TODO: we don't want to hold to the manager's lock during the
8772bb43d82SAxel Dörfler 		// whole RX path, we may not hold an endpoint's lock with the
8782bb43d82SAxel Dörfler 		// manager lock held.
8792bb43d82SAxel Dörfler 		// But we should increase the domain's refcount here.
8802bb43d82SAxel Dörfler }
8812bb43d82SAxel Dörfler 
8822bb43d82SAxel Dörfler 
883c22d69bfSAxel Dörfler // #pragma mark -
884c22d69bfSAxel Dörfler 
885c22d69bfSAxel Dörfler 
886c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
887c72ab92dSHugo Santos 	: DatagramSocket<>("udp endpoint", socket), fActive(false) {}
888bf48e753SHugo Santos 
889bf48e753SHugo Santos 
890c22d69bfSAxel Dörfler // #pragma mark - activation
891c22d69bfSAxel Dörfler 
892c22d69bfSAxel Dörfler 
893c22d69bfSAxel Dörfler status_t
89453f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
895c22d69bfSAxel Dörfler {
896bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
897727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
898c22d69bfSAxel Dörfler }
899c22d69bfSAxel Dörfler 
900c22d69bfSAxel Dörfler 
901c22d69bfSAxel Dörfler status_t
902c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
903c22d69bfSAxel Dörfler {
904bf48e753SHugo Santos 	TRACE_EP("Unbind()");
905727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
906c22d69bfSAxel Dörfler }
907c22d69bfSAxel Dörfler 
908c22d69bfSAxel Dörfler 
909c22d69bfSAxel Dörfler status_t
910c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
911c22d69bfSAxel Dörfler {
912bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
913727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
914c22d69bfSAxel Dörfler }
915c22d69bfSAxel Dörfler 
916c22d69bfSAxel Dörfler 
917c22d69bfSAxel Dörfler status_t
918c22d69bfSAxel Dörfler UdpEndpoint::Open()
919c22d69bfSAxel Dörfler {
920bf48e753SHugo Santos 	TRACE_EP("Open()");
921bf48e753SHugo Santos 
922119c6cddSIngo Weinhold 	AutoLocker _(fLock);
923727ad0b0SHugo Santos 
924c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
925c72ab92dSHugo Santos 	if (status < B_OK)
926c72ab92dSHugo Santos 		return status;
927bf48e753SHugo Santos 
928c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
929c72ab92dSHugo Santos 	if (fManager == NULL)
930bf48e753SHugo Santos 		return EAFNOSUPPORT;
931bf48e753SHugo Santos 
932bf48e753SHugo Santos 	return B_OK;
933c22d69bfSAxel Dörfler }
934c22d69bfSAxel Dörfler 
935c22d69bfSAxel Dörfler 
936c22d69bfSAxel Dörfler status_t
937c22d69bfSAxel Dörfler UdpEndpoint::Close()
938c22d69bfSAxel Dörfler {
939bf48e753SHugo Santos 	TRACE_EP("Close()");
940bf48e753SHugo Santos 	return B_OK;
941c22d69bfSAxel Dörfler }
942c22d69bfSAxel Dörfler 
943c22d69bfSAxel Dörfler 
944c22d69bfSAxel Dörfler status_t
945c22d69bfSAxel Dörfler UdpEndpoint::Free()
946c22d69bfSAxel Dörfler {
947bf48e753SHugo Santos 	TRACE_EP("Free()");
9480086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
949c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
950c22d69bfSAxel Dörfler }
951c22d69bfSAxel Dörfler 
952c22d69bfSAxel Dörfler 
953c22d69bfSAxel Dörfler // #pragma mark - outbound
954c22d69bfSAxel Dörfler 
955c22d69bfSAxel Dörfler 
956c22d69bfSAxel Dörfler status_t
957bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
958c22d69bfSAxel Dörfler {
959bf48e753SHugo Santos 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
960bf48e753SHugo Santos 
961d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
962c22d69bfSAxel Dörfler 		return EMSGSIZE;
963c22d69bfSAxel Dörfler 
964c22d69bfSAxel Dörfler 	buffer->protocol = IPPROTO_UDP;
965c22d69bfSAxel Dörfler 
966c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
9676c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
9686c353509SHugo Santos 	if (header.Status() < B_OK)
9696c353509SHugo Santos 		return header.Status();
970c22d69bfSAxel Dörfler 
97179a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
97279a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
9736c353509SHugo Santos 	header->udp_length = htons(buffer->size);
974c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
9756c353509SHugo Santos 	header->udp_checksum = 0;
9766c353509SHugo Santos 
9776c353509SHugo Santos 	header.Sync();
978c22d69bfSAxel Dörfler 
979d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
980d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
9816c353509SHugo Santos 	if (calculatedChecksum == 0)
9826c353509SHugo Santos 		calculatedChecksum = 0xffff;
9836c353509SHugo Santos 
9846c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
985c22d69bfSAxel Dörfler 
986c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
987c22d69bfSAxel Dörfler }
988c22d69bfSAxel Dörfler 
989c22d69bfSAxel Dörfler 
990bf48e753SHugo Santos status_t
991bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
992bf48e753SHugo Santos {
993bf48e753SHugo Santos 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
994bf48e753SHugo Santos 
9952651e51dSAxel Dörfler 	return gDatalinkModule->send_data(this, NULL, buffer);
996bf48e753SHugo Santos }
997bf48e753SHugo Santos 
998bf48e753SHugo Santos 
999c22d69bfSAxel Dörfler // #pragma mark - inbound
1000c22d69bfSAxel Dörfler 
1001c22d69bfSAxel Dörfler 
1002c22d69bfSAxel Dörfler ssize_t
1003c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
1004c22d69bfSAxel Dörfler {
1005bfb45f71SHugo Santos 	size_t bytes = AvailableData();
1006bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
1007bfb45f71SHugo Santos 	return bytes;
1008c22d69bfSAxel Dörfler }
1009c22d69bfSAxel Dörfler 
1010c22d69bfSAxel Dörfler 
1011c22d69bfSAxel Dörfler status_t
1012c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1013c22d69bfSAxel Dörfler {
1014bf48e753SHugo Santos 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
1015bf48e753SHugo Santos 
10162651e51dSAxel Dörfler 	status_t status = Dequeue(flags, _buffer);
1017bf48e753SHugo Santos 	TRACE_EP("  FetchData(): returned from fifo status=0x%lx", status);
10182651e51dSAxel Dörfler 	if (status != B_OK)
1019c22d69bfSAxel Dörfler 		return status;
1020c22d69bfSAxel Dörfler 
1021bfb45f71SHugo Santos 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
1022c22d69bfSAxel Dörfler 	return B_OK;
1023c22d69bfSAxel Dörfler }
1024c22d69bfSAxel Dörfler 
1025c22d69bfSAxel Dörfler 
1026c22d69bfSAxel Dörfler status_t
1027bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
1028c22d69bfSAxel Dörfler {
1029bf48e753SHugo Santos 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
1030c22d69bfSAxel Dörfler 
10312651e51dSAxel Dörfler 	return EnqueueClone(buffer);
1032c22d69bfSAxel Dörfler }
1033c22d69bfSAxel Dörfler 
1034c22d69bfSAxel Dörfler 
10356a606180SHugo Santos status_t
10366a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
10376a606180SHugo Santos {
1038f6cfc5afSHugo Santos 	TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size);
1039f6cfc5afSHugo Santos 
10406a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
10416a606180SHugo Santos 	if (buffer == NULL)
10426a606180SHugo Santos 		return B_NO_MEMORY;
10436a606180SHugo Santos 
10446a606180SHugo Santos 	status_t status = sUdpEndpointManager->Deframe(buffer);
10456a606180SHugo Santos 	if (status < B_OK) {
10466a606180SHugo Santos 		gBufferModule->free(buffer);
10476a606180SHugo Santos 		return status;
10486a606180SHugo Santos 	}
10496a606180SHugo Santos 
10506a606180SHugo Santos 	return Enqueue(buffer);
10516a606180SHugo Santos }
10526a606180SHugo Santos 
10536a606180SHugo Santos 
1054c22d69bfSAxel Dörfler // #pragma mark - protocol interface
1055c22d69bfSAxel Dörfler 
1056c22d69bfSAxel Dörfler 
1057c22d69bfSAxel Dörfler net_protocol *
1058c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
1059c22d69bfSAxel Dörfler {
1060c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
1061c22d69bfSAxel Dörfler 
1062c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1063bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1064bf48e753SHugo Santos 		delete endpoint;
1065bf48e753SHugo Santos 		return NULL;
1066bf48e753SHugo Santos 	}
1067bf48e753SHugo Santos 
1068c22d69bfSAxel Dörfler 	return endpoint;
1069c22d69bfSAxel Dörfler }
1070c22d69bfSAxel Dörfler 
1071c22d69bfSAxel Dörfler 
1072c22d69bfSAxel Dörfler status_t
1073c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
1074c22d69bfSAxel Dörfler {
1075bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
1076c22d69bfSAxel Dörfler 	return B_OK;
1077c22d69bfSAxel Dörfler }
1078c22d69bfSAxel Dörfler 
1079c22d69bfSAxel Dörfler 
1080c22d69bfSAxel Dörfler status_t
1081c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1082c22d69bfSAxel Dörfler {
1083bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
1084c22d69bfSAxel Dörfler }
1085c22d69bfSAxel Dörfler 
1086c22d69bfSAxel Dörfler 
1087c22d69bfSAxel Dörfler status_t
1088c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1089c22d69bfSAxel Dörfler {
1090bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
1091c22d69bfSAxel Dörfler }
1092c22d69bfSAxel Dörfler 
1093c22d69bfSAxel Dörfler 
1094c22d69bfSAxel Dörfler status_t
1095c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1096c22d69bfSAxel Dörfler {
1097bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
1098c22d69bfSAxel Dörfler }
1099c22d69bfSAxel Dörfler 
1100c22d69bfSAxel Dörfler 
1101c22d69bfSAxel Dörfler status_t
1102c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1103c22d69bfSAxel Dörfler {
1104bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1105c22d69bfSAxel Dörfler }
1106c22d69bfSAxel Dörfler 
1107c22d69bfSAxel Dörfler 
1108c22d69bfSAxel Dörfler status_t
1109c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1110c22d69bfSAxel Dörfler {
1111ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1112c22d69bfSAxel Dörfler }
1113c22d69bfSAxel Dörfler 
1114c22d69bfSAxel Dörfler 
1115c22d69bfSAxel Dörfler status_t
1116c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1117c22d69bfSAxel Dörfler 	size_t *_length)
1118c22d69bfSAxel Dörfler {
1119c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1120c22d69bfSAxel Dörfler 		value, _length);
1121c22d69bfSAxel Dörfler }
1122c22d69bfSAxel Dörfler 
1123c22d69bfSAxel Dörfler 
1124c22d69bfSAxel Dörfler status_t
112545b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
112645b5203bSHugo Santos 	int *length)
112745b5203bSHugo Santos {
112845b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
112945b5203bSHugo Santos 		value, length);
113045b5203bSHugo Santos }
113145b5203bSHugo Santos 
113245b5203bSHugo Santos 
113345b5203bSHugo Santos status_t
113445b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
113545b5203bSHugo Santos 	const void *value, int length)
113645b5203bSHugo Santos {
113745b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
113845b5203bSHugo Santos 		value, length);
113945b5203bSHugo Santos }
114045b5203bSHugo Santos 
114145b5203bSHugo Santos 
114245b5203bSHugo Santos status_t
114353f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1144c22d69bfSAxel Dörfler {
1145bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1146c22d69bfSAxel Dörfler }
1147c22d69bfSAxel Dörfler 
1148c22d69bfSAxel Dörfler 
1149c22d69bfSAxel Dörfler status_t
1150c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1151c22d69bfSAxel Dörfler {
1152bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1153c22d69bfSAxel Dörfler }
1154c22d69bfSAxel Dörfler 
1155c22d69bfSAxel Dörfler 
1156c22d69bfSAxel Dörfler status_t
1157c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1158c22d69bfSAxel Dörfler {
1159ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1160c22d69bfSAxel Dörfler }
1161c22d69bfSAxel Dörfler 
1162c22d69bfSAxel Dörfler 
1163c22d69bfSAxel Dörfler status_t
1164c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1165c22d69bfSAxel Dörfler {
1166ca215dfeSAxel Dörfler 	return B_NOT_SUPPORTED;
1167c22d69bfSAxel Dörfler }
1168c22d69bfSAxel Dörfler 
1169c22d69bfSAxel Dörfler 
1170c22d69bfSAxel Dörfler status_t
1171c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1172c22d69bfSAxel Dörfler 	net_buffer *buffer)
1173c22d69bfSAxel Dörfler {
1174bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1175c22d69bfSAxel Dörfler }
1176c22d69bfSAxel Dörfler 
1177c22d69bfSAxel Dörfler 
1178c22d69bfSAxel Dörfler status_t
1179c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1180c22d69bfSAxel Dörfler {
1181bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1182c22d69bfSAxel Dörfler }
1183c22d69bfSAxel Dörfler 
1184c22d69bfSAxel Dörfler 
1185c22d69bfSAxel Dörfler ssize_t
1186c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1187c22d69bfSAxel Dörfler {
1188bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1189c22d69bfSAxel Dörfler }
1190c22d69bfSAxel Dörfler 
1191c22d69bfSAxel Dörfler 
1192c22d69bfSAxel Dörfler status_t
1193c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1194c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1195c22d69bfSAxel Dörfler {
1196bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1197c22d69bfSAxel Dörfler }
1198c22d69bfSAxel Dörfler 
1199c22d69bfSAxel Dörfler 
1200c22d69bfSAxel Dörfler ssize_t
1201c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1202c22d69bfSAxel Dörfler {
1203bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1204c22d69bfSAxel Dörfler }
1205c22d69bfSAxel Dörfler 
1206c22d69bfSAxel Dörfler 
1207c22d69bfSAxel Dörfler struct net_domain *
1208c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1209c22d69bfSAxel Dörfler {
1210c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1211c22d69bfSAxel Dörfler }
1212c22d69bfSAxel Dörfler 
1213c22d69bfSAxel Dörfler 
1214c22d69bfSAxel Dörfler size_t
1215c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1216c22d69bfSAxel Dörfler {
1217c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1218c22d69bfSAxel Dörfler }
1219c22d69bfSAxel Dörfler 
1220c22d69bfSAxel Dörfler 
1221c22d69bfSAxel Dörfler status_t
1222c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1223c22d69bfSAxel Dörfler {
1224c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1225c22d69bfSAxel Dörfler }
1226c22d69bfSAxel Dörfler 
1227c22d69bfSAxel Dörfler 
1228c22d69bfSAxel Dörfler status_t
12296a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
12306a606180SHugo Santos {
12316a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
12326a606180SHugo Santos }
12336a606180SHugo Santos 
12346a606180SHugo Santos 
12356a606180SHugo Santos status_t
1236*2b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer)
1237c22d69bfSAxel Dörfler {
1238*2b415445SAxel Dörfler 	status_t notifyError = B_OK;
12392bb43d82SAxel Dörfler 
1240*2b415445SAxel Dörfler 	switch (error) {
1241*2b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_NET:
1242*2b415445SAxel Dörfler 			notifyError = ENETUNREACH;
12432bb43d82SAxel Dörfler 			break;
1244*2b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_HOST:
1245*2b415445SAxel Dörfler 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
1246*2b415445SAxel Dörfler 			notifyError = EHOSTUNREACH;
12472bb43d82SAxel Dörfler 			break;
1248*2b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PROTOCOL:
1249*2b415445SAxel Dörfler 		case B_NET_ERROR_UNREACH_PORT:
1250*2b415445SAxel Dörfler 			notifyError = ECONNREFUSED;
12512bb43d82SAxel Dörfler 			break;
1252*2b415445SAxel Dörfler 		case B_NET_ERROR_MESSAGE_SIZE:
1253*2b415445SAxel Dörfler 			notifyError = EMSGSIZE;
1254*2b415445SAxel Dörfler 			break;
1255*2b415445SAxel Dörfler 		case B_NET_ERROR_PARAMETER_PROBLEM:
1256*2b415445SAxel Dörfler 			notifyError = ENOPROTOOPT;
1257*2b415445SAxel Dörfler 			break;
1258*2b415445SAxel Dörfler 
1259*2b415445SAxel Dörfler 		case B_NET_ERROR_QUENCH:
12602bb43d82SAxel Dörfler 		default:
12612bb43d82SAxel Dörfler 			// ignore them
12622bb43d82SAxel Dörfler 			break;
12632bb43d82SAxel Dörfler 	}
12642bb43d82SAxel Dörfler 
1265*2b415445SAxel Dörfler 	if (notifyError != B_OK)
1266*2b415445SAxel Dörfler 		sUdpEndpointManager->ReceiveError(notifyError, buffer);
12672bb43d82SAxel Dörfler 
12682bb43d82SAxel Dörfler 	gBufferModule->free(buffer);
12692bb43d82SAxel Dörfler 	return B_OK;
1270c22d69bfSAxel Dörfler }
1271c22d69bfSAxel Dörfler 
1272c22d69bfSAxel Dörfler 
1273c22d69bfSAxel Dörfler status_t
1274*2b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
1275*2b415445SAxel Dörfler 	net_error_data *errorData)
1276c22d69bfSAxel Dörfler {
1277c22d69bfSAxel Dörfler 	return B_ERROR;
1278c22d69bfSAxel Dörfler }
1279c22d69bfSAxel Dörfler 
1280c22d69bfSAxel Dörfler 
128178888c44SAxel Dörfler ssize_t
128278888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol,
128378888c44SAxel Dörfler 	net_buffer* buffer, void *data, size_t dataSize)
128478888c44SAxel Dörfler {
128578888c44SAxel Dörfler 	return protocol->next->module->process_ancillary_data_no_container(
128678888c44SAxel Dörfler 		protocol, buffer, data, dataSize);
128778888c44SAxel Dörfler }
128878888c44SAxel Dörfler 
128978888c44SAxel Dörfler 
1290c22d69bfSAxel Dörfler //	#pragma mark - module interface
1291c22d69bfSAxel Dörfler 
1292c22d69bfSAxel Dörfler 
1293c22d69bfSAxel Dörfler static status_t
1294c22d69bfSAxel Dörfler init_udp()
1295c22d69bfSAxel Dörfler {
1296c22d69bfSAxel Dörfler 	status_t status;
1297bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1298c22d69bfSAxel Dörfler 
1299c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1300658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1301658a5506SHugo Santos 		return B_NO_MEMORY;
1302658a5506SHugo Santos 
1303c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1304c22d69bfSAxel Dörfler 	if (status != B_OK)
1305d438fa4cSHugo Santos 		goto err1;
1306c22d69bfSAxel Dörfler 
130761729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
130861729d93SAxel Dörfler 		IPPROTO_IP,
1309c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1310c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1311c22d69bfSAxel Dörfler 		NULL);
1312c22d69bfSAxel Dörfler 	if (status < B_OK)
1313658a5506SHugo Santos 		goto err1;
131461729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
131561729d93SAxel Dörfler 		IPPROTO_IP,
13168d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13178d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13188d1485faSAxel Dörfler 		NULL);
13198d1485faSAxel Dörfler 	if (status < B_OK)
13208d1485faSAxel Dörfler 		goto err1;
13218d1485faSAxel Dörfler 
132261729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
132361729d93SAxel Dörfler 		IPPROTO_UDP,
1324c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1325c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1326c22d69bfSAxel Dörfler 		NULL);
1327c22d69bfSAxel Dörfler 	if (status < B_OK)
1328658a5506SHugo Santos 		goto err1;
132961729d93SAxel Dörfler 	status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
133061729d93SAxel Dörfler 		IPPROTO_UDP,
13318d1485faSAxel Dörfler 		"network/protocols/udp/v1",
13328d1485faSAxel Dörfler 		"network/protocols/ipv6/v1",
13338d1485faSAxel Dörfler 		NULL);
13348d1485faSAxel Dörfler 	if (status < B_OK)
13358d1485faSAxel Dörfler 		goto err1;
1336c22d69bfSAxel Dörfler 
133761729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET,
133861729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
1339c22d69bfSAxel Dörfler 	if (status < B_OK)
1340658a5506SHugo Santos 		goto err1;
134161729d93SAxel Dörfler 	status = gStackModule->register_domain_receiving_protocol(AF_INET6,
134261729d93SAxel Dörfler 		IPPROTO_UDP, "network/protocols/udp/v1");
13438d1485faSAxel Dörfler 	if (status < B_OK)
13448d1485faSAxel Dörfler 		goto err1;
1345c22d69bfSAxel Dörfler 
1346cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1347cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1348cf5d9f4bSHugo Santos 
1349c22d69bfSAxel Dörfler 	return B_OK;
1350c22d69bfSAxel Dörfler 
1351c22d69bfSAxel Dörfler err1:
13528d1485faSAxel Dörfler 	// TODO: shouldn't unregister the protocols here?
1353658a5506SHugo Santos 	delete sUdpEndpointManager;
1354c22d69bfSAxel Dörfler 
1355bf48e753SHugo Santos 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1356c22d69bfSAxel Dörfler 	return status;
1357c22d69bfSAxel Dörfler }
1358c22d69bfSAxel Dörfler 
1359c22d69bfSAxel Dörfler 
1360c22d69bfSAxel Dörfler static status_t
1361c22d69bfSAxel Dörfler uninit_udp()
1362c22d69bfSAxel Dörfler {
1363bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1364cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1365cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1366c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1367c22d69bfSAxel Dörfler 	return B_OK;
1368c22d69bfSAxel Dörfler }
1369c22d69bfSAxel Dörfler 
1370c22d69bfSAxel Dörfler 
1371c22d69bfSAxel Dörfler static status_t
1372c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1373c22d69bfSAxel Dörfler {
1374c22d69bfSAxel Dörfler 	switch (op) {
1375c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1376c22d69bfSAxel Dörfler 			return init_udp();
1377c22d69bfSAxel Dörfler 
1378c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1379c22d69bfSAxel Dörfler 			return uninit_udp();
1380c22d69bfSAxel Dörfler 
1381c22d69bfSAxel Dörfler 		default:
1382c22d69bfSAxel Dörfler 			return B_ERROR;
1383c22d69bfSAxel Dörfler 	}
1384c22d69bfSAxel Dörfler }
1385c22d69bfSAxel Dörfler 
1386c22d69bfSAxel Dörfler 
1387c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1388c22d69bfSAxel Dörfler 	{
1389c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1390c22d69bfSAxel Dörfler 		0,
1391c22d69bfSAxel Dörfler 		udp_std_ops
1392c22d69bfSAxel Dörfler 	},
13936f58064fSAxel Dörfler 	NET_PROTOCOL_ATOMIC_MESSAGES,
13946f58064fSAxel Dörfler 
1395c22d69bfSAxel Dörfler 	udp_init_protocol,
1396c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1397c22d69bfSAxel Dörfler 	udp_open,
1398c22d69bfSAxel Dörfler 	udp_close,
1399c22d69bfSAxel Dörfler 	udp_free,
1400c22d69bfSAxel Dörfler 	udp_connect,
1401c22d69bfSAxel Dörfler 	udp_accept,
1402c22d69bfSAxel Dörfler 	udp_control,
140345b5203bSHugo Santos 	udp_getsockopt,
140445b5203bSHugo Santos 	udp_setsockopt,
1405c22d69bfSAxel Dörfler 	udp_bind,
1406c22d69bfSAxel Dörfler 	udp_unbind,
1407c22d69bfSAxel Dörfler 	udp_listen,
1408c22d69bfSAxel Dörfler 	udp_shutdown,
1409c22d69bfSAxel Dörfler 	udp_send_data,
1410c22d69bfSAxel Dörfler 	udp_send_routed_data,
1411c22d69bfSAxel Dörfler 	udp_send_avail,
1412c22d69bfSAxel Dörfler 	udp_read_data,
1413c22d69bfSAxel Dörfler 	udp_read_avail,
1414c22d69bfSAxel Dörfler 	udp_get_domain,
1415c22d69bfSAxel Dörfler 	udp_get_mtu,
1416c22d69bfSAxel Dörfler 	udp_receive_data,
14176a606180SHugo Santos 	udp_deliver_data,
14182bb43d82SAxel Dörfler 	udp_error_received,
1419c22d69bfSAxel Dörfler 	udp_error_reply,
14209871124eSAxel Dörfler 	NULL,		// add_ancillary_data()
14219871124eSAxel Dörfler 	NULL,		// process_ancillary_data()
142278888c44SAxel Dörfler 	udp_process_ancillary_data_no_container,
14239871124eSAxel Dörfler 	NULL,		// send_data_no_buffer()
14249871124eSAxel Dörfler 	NULL		// read_data_no_buffer()
1425c22d69bfSAxel Dörfler };
1426c22d69bfSAxel Dörfler 
1427658a5506SHugo Santos module_dependency module_dependencies[] = {
1428658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1429658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1430658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
14312bb43d82SAxel Dörfler 	{NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1432658a5506SHugo Santos 	{}
1433658a5506SHugo Santos };
1434658a5506SHugo Santos 
1435c22d69bfSAxel Dörfler module_info *modules[] = {
1436c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1437c22d69bfSAxel Dörfler 	NULL
1438c22d69bfSAxel Dörfler };
1439