xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 119c6cdd0b754bd48ee1bb7b945bb02ffaa43fd3)
1c22d69bfSAxel Dörfler /*
2c3e054c8SHugo Santos  * Copyright 2006-2007, 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 
27c22d69bfSAxel Dörfler #include <netinet/in.h>
28c22d69bfSAxel Dörfler #include <new>
29c22d69bfSAxel Dörfler #include <stdlib.h>
30c22d69bfSAxel Dörfler #include <string.h>
31c3e054c8SHugo Santos #include <utility>
32c22d69bfSAxel Dörfler 
33727ad0b0SHugo Santos 
34727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
35727ad0b0SHugo Santos //      lock before holding a child UdpEndpoint's lock. This restriction
36727ad0b0SHugo Santos //      is dictated by the receive path as blind access to the endpoint
37727ad0b0SHugo Santos //      hash is required when holding the DomainSuppport's lock.
38727ad0b0SHugo Santos 
39727ad0b0SHugo Santos 
40af3a31f7SAxel Dörfler //#define TRACE_UDP
41c22d69bfSAxel Dörfler #ifdef TRACE_UDP
42c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x) dump_block x
43bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this
44bf48e753SHugo Santos // to compile with gcc 2.95
45bf48e753SHugo Santos #	define TRACE_EP(format, args...)	dprintf("UDP [%llu] %p " format "\n", \
46bf48e753SHugo Santos 		system_time(), this , ##args)
47bf48e753SHugo Santos #	define TRACE_EPM(format, args...)	dprintf("UDP [%llu] " format "\n", \
48bf48e753SHugo Santos 		system_time() , ##args)
49bf48e753SHugo Santos #	define TRACE_DOMAIN(format, args...)	dprintf("UDP [%llu] (%d) " format \
50bf48e753SHugo Santos 		"\n", system_time(), Domain()->family , ##args)
51c22d69bfSAxel Dörfler #else
52c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x)
53bf48e753SHugo Santos #	define TRACE_EP(args...)	do { } while (0)
54bf48e753SHugo Santos #	define TRACE_EPM(args...)	do { } while (0)
55bf48e753SHugo Santos #	define TRACE_DOMAIN(args...)	do { } while (0)
56c22d69bfSAxel Dörfler #endif
57c22d69bfSAxel Dörfler 
58c22d69bfSAxel Dörfler 
59c22d69bfSAxel Dörfler struct udp_header {
60c22d69bfSAxel Dörfler 	uint16 source_port;
61c22d69bfSAxel Dörfler 	uint16 destination_port;
62c22d69bfSAxel Dörfler 	uint16 udp_length;
63c22d69bfSAxel Dörfler 	uint16 udp_checksum;
64c22d69bfSAxel Dörfler } _PACKED;
65c22d69bfSAxel Dörfler 
66c22d69bfSAxel Dörfler 
676c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
686c353509SHugo Santos 	UDPChecksumField;
696c353509SHugo Santos 
70bf48e753SHugo Santos class UdpDomainSupport;
716c353509SHugo Santos 
72bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> {
73c22d69bfSAxel Dörfler public:
74c22d69bfSAxel Dörfler 	UdpEndpoint(net_socket *socket);
75bf48e753SHugo Santos 
7653f23f85SHugo Santos 	status_t				Bind(const sockaddr *newAddr);
77c22d69bfSAxel Dörfler 	status_t				Unbind(sockaddr *newAddr);
78c22d69bfSAxel Dörfler 	status_t				Connect(const sockaddr *newAddr);
79c22d69bfSAxel Dörfler 
80c22d69bfSAxel Dörfler 	status_t				Open();
81c22d69bfSAxel Dörfler 	status_t				Close();
82c22d69bfSAxel Dörfler 	status_t				Free();
83c22d69bfSAxel Dörfler 
84bf48e753SHugo Santos 	status_t				SendRoutedData(net_buffer *buffer, net_route *route);
85bf48e753SHugo Santos 	status_t				SendData(net_buffer *buffer);
86c22d69bfSAxel Dörfler 
87c22d69bfSAxel Dörfler 	ssize_t					BytesAvailable();
88c22d69bfSAxel Dörfler 	status_t				FetchData(size_t numBytes, uint32 flags,
89c22d69bfSAxel Dörfler 								net_buffer **_buffer);
90c22d69bfSAxel Dörfler 
91c22d69bfSAxel Dörfler 	status_t				StoreData(net_buffer *buffer);
926a606180SHugo Santos 	status_t				DeliverData(net_buffer *buffer);
93c22d69bfSAxel Dörfler 
94727ad0b0SHugo Santos 	// only the domain support will change/check the Active flag so
95727ad0b0SHugo Santos 	// we don't really need to protect it with the socket lock.
96727ad0b0SHugo Santos 	bool					IsActive() const { return fActive; }
97727ad0b0SHugo Santos 	void					SetActive(bool newValue) { fActive = newValue; }
98bf48e753SHugo Santos 
9940bbf860SHugo Santos 	HashTableLink<UdpEndpoint> *HashTableLink() { return &fLink; }
10040bbf860SHugo Santos 
101c22d69bfSAxel Dörfler private:
102c72ab92dSHugo Santos 	UdpDomainSupport		*fManager;
103c22d69bfSAxel Dörfler 	bool					fActive;
104c22d69bfSAxel Dörfler 								// an active UdpEndpoint is part of the endpoint
105c22d69bfSAxel Dörfler 								// hash (and it is bound and optionally connected)
10640bbf860SHugo Santos 
10740bbf860SHugo Santos 	::HashTableLink<UdpEndpoint> fLink;
10840bbf860SHugo Santos };
10940bbf860SHugo Santos 
11040bbf860SHugo Santos 
11140bbf860SHugo Santos class UdpDomainSupport;
11240bbf860SHugo Santos 
11340bbf860SHugo Santos struct UdpHashDefinition {
11440bbf860SHugo Santos 	typedef net_address_module_info ParentType;
11540bbf860SHugo Santos 	typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
11640bbf860SHugo Santos 	typedef UdpEndpoint ValueType;
11740bbf860SHugo Santos 
11840bbf860SHugo Santos 	UdpHashDefinition(net_address_module_info *parent)
11940bbf860SHugo Santos 		: module(parent) {}
12040bbf860SHugo Santos 
12140bbf860SHugo Santos 	size_t HashKey(const KeyType &key) const
12240bbf860SHugo Santos 	{
12340bbf860SHugo Santos 		return _Mix(module->hash_address_pair(key.first, key.second));
12440bbf860SHugo Santos 	}
12540bbf860SHugo Santos 
12640bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
12740bbf860SHugo Santos 	{
12840bbf860SHugo Santos 		return _Mix(endpoint->LocalAddress().HashPair(*endpoint->PeerAddress()));
12940bbf860SHugo Santos 	}
13040bbf860SHugo Santos 
13140bbf860SHugo Santos 	static size_t _Mix(size_t hash)
13240bbf860SHugo Santos 	{
13340bbf860SHugo Santos 		// move the bits into the relevant range (as defined by kNumHashBuckets):
13440bbf860SHugo Santos 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
13540bbf860SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
13640bbf860SHugo Santos 	}
13740bbf860SHugo Santos 
13840bbf860SHugo Santos 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
13940bbf860SHugo Santos 	{
14040bbf860SHugo Santos 		return endpoint->LocalAddress().EqualTo(key.first, true)
14140bbf860SHugo Santos 			&& endpoint->PeerAddress().EqualTo(key.second, true);
14240bbf860SHugo Santos 	}
14340bbf860SHugo Santos 
14440bbf860SHugo Santos 	HashTableLink<UdpEndpoint> *GetLink(UdpEndpoint *endpoint) const
14540bbf860SHugo Santos 	{
14640bbf860SHugo Santos 		return endpoint->HashTableLink();
14740bbf860SHugo Santos 	}
14840bbf860SHugo Santos 
14940bbf860SHugo Santos 	net_address_module_info *module;
150c22d69bfSAxel Dörfler };
151c22d69bfSAxel Dörfler 
152c22d69bfSAxel Dörfler 
153bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
154c22d69bfSAxel Dörfler public:
155bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
156727ad0b0SHugo Santos 	~UdpDomainSupport();
157c22d69bfSAxel Dörfler 
158bf48e753SHugo Santos 	status_t InitCheck() const;
159bf48e753SHugo Santos 
160bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
161bf48e753SHugo Santos 
162bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
163727ad0b0SHugo Santos 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
164bf48e753SHugo Santos 
165bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer *buffer);
166727ad0b0SHugo Santos 
167727ad0b0SHugo Santos 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
168727ad0b0SHugo Santos 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
169727ad0b0SHugo Santos 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
170727ad0b0SHugo Santos 
171cf5d9f4bSHugo Santos 	void DumpEndpoints() const;
172bf48e753SHugo Santos 
173c22d69bfSAxel Dörfler private:
174727ad0b0SHugo Santos 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
175727ad0b0SHugo Santos 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
176727ad0b0SHugo Santos 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
177727ad0b0SHugo Santos 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
178727ad0b0SHugo Santos 
17940bbf860SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
18040bbf860SHugo Santos 		const sockaddr *peerAddress);
181bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
182bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
183bf48e753SHugo Santos 
184bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
185727ad0b0SHugo Santos 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
186bf48e753SHugo Santos 
187bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
188727ad0b0SHugo Santos 		{ return fDomain->address_module; }
189bf48e753SHugo Santos 
19040bbf860SHugo Santos 	typedef OpenHashTable<UdpHashDefinition, false> EndpointTable;
19140bbf860SHugo Santos 
192727ad0b0SHugo Santos 	benaphore		fLock;
193bf48e753SHugo Santos 	net_domain		*fDomain;
194bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
19540bbf860SHugo Santos 	EndpointTable	fActiveEndpoints;
196bf48e753SHugo Santos 	uint32			fEndpointCount;
197bf48e753SHugo Santos 
198bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
199bf48e753SHugo Santos 	static const uint16		kLast = 65535;
200bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
201bf48e753SHugo Santos 							// if you change this, adjust the shifting in
202bf48e753SHugo Santos 							// Hash() accordingly!
203bf48e753SHugo Santos };
204bf48e753SHugo Santos 
205bf48e753SHugo Santos 
206bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
207bf48e753SHugo Santos 
208bf48e753SHugo Santos 
209bf48e753SHugo Santos class UdpEndpointManager {
210c22d69bfSAxel Dörfler public:
211c22d69bfSAxel Dörfler 	UdpEndpointManager();
212c22d69bfSAxel Dörfler 	~UdpEndpointManager();
213c22d69bfSAxel Dörfler 
214c22d69bfSAxel Dörfler 	status_t		ReceiveData(net_buffer *buffer);
2156a606180SHugo Santos 	status_t		Deframe(net_buffer *buffer);
216c22d69bfSAxel Dörfler 
217bf48e753SHugo Santos 	UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
218bf48e753SHugo Santos 	status_t FreeEndpoint(UdpDomainSupport *domain);
219c22d69bfSAxel Dörfler 
220c22d69bfSAxel Dörfler 	status_t		InitCheck() const;
221bf48e753SHugo Santos 
222cf5d9f4bSHugo Santos 	static int DumpEndpoints(int argc, char *argv[]);
223cf5d9f4bSHugo Santos 
224c22d69bfSAxel Dörfler private:
225bf48e753SHugo Santos 	UdpDomainSupport *_GetDomain(net_domain *domain, bool create);
226bf48e753SHugo Santos 
227c22d69bfSAxel Dörfler 	benaphore		fLock;
228c22d69bfSAxel Dörfler 	status_t		fStatus;
229bf48e753SHugo Santos 	UdpDomainList	fDomains;
230c22d69bfSAxel Dörfler };
231c22d69bfSAxel Dörfler 
232c22d69bfSAxel Dörfler 
233c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
234c22d69bfSAxel Dörfler 
235c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
236658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
237658a5506SHugo Santos net_stack_module_info *gStackModule;
238c22d69bfSAxel Dörfler 
239c22d69bfSAxel Dörfler 
240c22d69bfSAxel Dörfler // #pragma mark -
241c22d69bfSAxel Dörfler 
242c22d69bfSAxel Dörfler 
243bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
244c22d69bfSAxel Dörfler 	:
245bf48e753SHugo Santos 	fDomain(domain),
24640bbf860SHugo Santos 	fActiveEndpoints(domain->address_module, kNumHashBuckets),
247bf48e753SHugo Santos 	fEndpointCount(0)
248c22d69bfSAxel Dörfler {
249727ad0b0SHugo Santos 	benaphore_init(&fLock, "udp domain");
250727ad0b0SHugo Santos 
251727ad0b0SHugo Santos 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
252727ad0b0SHugo Santos }
253727ad0b0SHugo Santos 
254727ad0b0SHugo Santos 
255727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
256727ad0b0SHugo Santos {
257727ad0b0SHugo Santos 	benaphore_destroy(&fLock);
258bf48e753SHugo Santos }
259bf48e753SHugo Santos 
260bf48e753SHugo Santos 
261bf48e753SHugo Santos status_t
262bf48e753SHugo Santos UdpDomainSupport::InitCheck() const
263bf48e753SHugo Santos {
264727ad0b0SHugo Santos 	if (fLock.sem < B_OK)
265727ad0b0SHugo Santos 		return fLock.sem;
266727ad0b0SHugo Santos 
26740bbf860SHugo Santos 	return fActiveEndpoints.InitCheck();
268bf48e753SHugo Santos }
269bf48e753SHugo Santos 
270bf48e753SHugo Santos 
271bf48e753SHugo Santos status_t
272bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
273bf48e753SHugo Santos {
274727ad0b0SHugo Santos 	// NOTE multicast is delivered directly to the endpoint
275727ad0b0SHugo Santos 
276727ad0b0SHugo Santos 	BenaphoreLocker _(fLock);
277727ad0b0SHugo Santos 
278bf48e753SHugo Santos 	if (buffer->flags & MSG_BCAST)
279bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
280bf48e753SHugo Santos 	else if (buffer->flags & MSG_MCAST)
281727ad0b0SHugo Santos 		return B_ERROR;
282bf48e753SHugo Santos 
283bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
284bf48e753SHugo Santos }
285bf48e753SHugo Santos 
286bf48e753SHugo Santos 
287bf48e753SHugo Santos status_t
288727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
289727ad0b0SHugo Santos 	const sockaddr *address)
290727ad0b0SHugo Santos {
291727ad0b0SHugo Santos 	BenaphoreLocker _(fLock);
292727ad0b0SHugo Santos 
293727ad0b0SHugo Santos 	if (endpoint->IsActive())
294727ad0b0SHugo Santos 		return EINVAL;
295727ad0b0SHugo Santos 
296727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, address);
297727ad0b0SHugo Santos }
298727ad0b0SHugo Santos 
299727ad0b0SHugo Santos 
300727ad0b0SHugo Santos status_t
301727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
302727ad0b0SHugo Santos 	const sockaddr *address)
303727ad0b0SHugo Santos {
304727ad0b0SHugo Santos 	BenaphoreLocker _(fLock);
305727ad0b0SHugo Santos 
306727ad0b0SHugo Santos 	if (endpoint->IsActive()) {
307727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
308727ad0b0SHugo Santos 		endpoint->SetActive(false);
309727ad0b0SHugo Santos 	}
310727ad0b0SHugo Santos 
311727ad0b0SHugo Santos 	if (address->sa_family == AF_UNSPEC) {
312727ad0b0SHugo Santos 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
313727ad0b0SHugo Santos 		// so we reset the peer address:
314727ad0b0SHugo Santos 		endpoint->PeerAddress().SetToEmpty();
315727ad0b0SHugo Santos 	} else {
316727ad0b0SHugo Santos 		status_t status = endpoint->PeerAddress().SetTo(address);
317727ad0b0SHugo Santos 		if (status < B_OK)
318727ad0b0SHugo Santos 			return status;
319727ad0b0SHugo Santos 	}
320727ad0b0SHugo Santos 
321727ad0b0SHugo Santos 	// we need to activate no matter whether or not we have just disconnected,
322727ad0b0SHugo Santos 	// as calling connect() always triggers an implicit bind():
323727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, *endpoint->LocalAddress());
324727ad0b0SHugo Santos }
325727ad0b0SHugo Santos 
326727ad0b0SHugo Santos 
327727ad0b0SHugo Santos status_t
328727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
329727ad0b0SHugo Santos {
330727ad0b0SHugo Santos 	BenaphoreLocker _(fLock);
331727ad0b0SHugo Santos 
332727ad0b0SHugo Santos 	if (endpoint->IsActive())
333727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
334727ad0b0SHugo Santos 
335727ad0b0SHugo Santos 	endpoint->SetActive(false);
336727ad0b0SHugo Santos 
337727ad0b0SHugo Santos 	return B_OK;
338727ad0b0SHugo Santos }
339727ad0b0SHugo Santos 
340727ad0b0SHugo Santos 
341cf5d9f4bSHugo Santos void
342cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
343cf5d9f4bSHugo Santos {
344cf5d9f4bSHugo Santos 	kprintf("-------- UDP Domain %p ---------\n", this);
345cf5d9f4bSHugo Santos 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
346cf5d9f4bSHugo Santos 
347cf5d9f4bSHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
348cf5d9f4bSHugo Santos 
349cf5d9f4bSHugo Santos 	while (it.HasNext()) {
350cf5d9f4bSHugo Santos 		UdpEndpoint *endpoint = it.Next();
351cf5d9f4bSHugo Santos 
352cf5d9f4bSHugo Santos 		char localBuf[64], peerBuf[64];
353cf5d9f4bSHugo Santos 		endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true);
354cf5d9f4bSHugo Santos 		endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true);
355cf5d9f4bSHugo Santos 
356cf5d9f4bSHugo Santos 		kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf,
357cf5d9f4bSHugo Santos 			endpoint->AvailableData());
358cf5d9f4bSHugo Santos 	}
359cf5d9f4bSHugo Santos }
360cf5d9f4bSHugo Santos 
361cf5d9f4bSHugo Santos 
362727ad0b0SHugo Santos status_t
363727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
364727ad0b0SHugo Santos 	const sockaddr *address)
365727ad0b0SHugo Santos {
366727ad0b0SHugo Santos 	if (AddressModule()->get_port(address) == 0)
367727ad0b0SHugo Santos 		return _BindToEphemeral(endpoint, address);
368727ad0b0SHugo Santos 
369727ad0b0SHugo Santos 	return _Bind(endpoint, address);
370727ad0b0SHugo Santos }
371727ad0b0SHugo Santos 
372727ad0b0SHugo Santos 
373727ad0b0SHugo Santos status_t
374727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
375727ad0b0SHugo Santos {
376727ad0b0SHugo Santos 	int socketOptions = endpoint->Socket()->options;
37740bbf860SHugo Santos 
37840bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
379bf48e753SHugo Santos 
380bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
381bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
382727ad0b0SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
383727ad0b0SHugo Santos 		address, true).Data());
384727ad0b0SHugo Santos 
38540bbf860SHugo Santos 	while (it.HasNext()) {
38640bbf860SHugo Santos 		UdpEndpoint *otherEndpoint = it.Next();
38725a2744fSHugo Santos 
388bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
3895084c839SHugo Santos 			ntohs(otherEndpoint->LocalAddress().Port()));
39025a2744fSHugo Santos 
39125a2744fSHugo Santos 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
392bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
393727ad0b0SHugo Santos 			if (otherEndpoint->Socket()->options & (SO_REUSEADDR | SO_REUSEPORT) == 0
394727ad0b0SHugo Santos 				|| socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0)
395727ad0b0SHugo Santos 				return EADDRINUSE;
39625a2744fSHugo Santos 
397bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
39825a2744fSHugo Santos 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
399727ad0b0SHugo Santos 				&& (otherEndpoint->Socket()->options & SO_REUSEPORT == 0
400727ad0b0SHugo Santos 					|| socketOptions & SO_REUSEPORT == 0))
401727ad0b0SHugo Santos 				return EADDRINUSE;
402bf48e753SHugo Santos 		}
403bf48e753SHugo Santos 	}
404bf48e753SHugo Santos 
405727ad0b0SHugo Santos 	return _FinishBind(endpoint, address);
406bf48e753SHugo Santos }
407bf48e753SHugo Santos 
408bf48e753SHugo Santos 
409bf48e753SHugo Santos status_t
410727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
411727ad0b0SHugo Santos 	const sockaddr *address)
412727ad0b0SHugo Santos {
413727ad0b0SHugo Santos 	SocketAddressStorage newAddress(AddressModule());
414727ad0b0SHugo Santos 	status_t status = newAddress.SetTo(address);
415727ad0b0SHugo Santos 	if (status < B_OK)
416727ad0b0SHugo Santos 		return status;
417727ad0b0SHugo Santos 
418727ad0b0SHugo Santos 	uint16 allocedPort = _GetNextEphemeral();
419727ad0b0SHugo Santos 	if (allocedPort == 0)
420727ad0b0SHugo Santos 		return ENOBUFS;
421727ad0b0SHugo Santos 
422727ad0b0SHugo Santos 	newAddress.SetPort(allocedPort);
423727ad0b0SHugo Santos 
424727ad0b0SHugo Santos 	return _FinishBind(endpoint, *newAddress);
425727ad0b0SHugo Santos }
426727ad0b0SHugo Santos 
427727ad0b0SHugo Santos 
428727ad0b0SHugo Santos status_t
429727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
430727ad0b0SHugo Santos {
431727ad0b0SHugo Santos 	status_t status = endpoint->next->module->bind(endpoint->next, address);
432727ad0b0SHugo Santos 	if (status < B_OK)
433727ad0b0SHugo Santos 		return status;
43440bbf860SHugo Santos 
43540bbf860SHugo Santos 	fActiveEndpoints.Insert(endpoint);
436727ad0b0SHugo Santos 	endpoint->SetActive(true);
437727ad0b0SHugo Santos 
43840bbf860SHugo Santos 	return B_OK;
439bf48e753SHugo Santos }
440bf48e753SHugo Santos 
441bf48e753SHugo Santos 
442c22d69bfSAxel Dörfler UdpEndpoint *
44340bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
44440bbf860SHugo Santos 	const sockaddr *peerAddress)
445c22d69bfSAxel Dörfler {
446bf48e753SHugo Santos 	TRACE_DOMAIN("finding Endpoint for %s -> %s",
447bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
448bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
449c3e054c8SHugo Santos 
45040bbf860SHugo Santos 	return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress));
451c22d69bfSAxel Dörfler }
452c22d69bfSAxel Dörfler 
453c22d69bfSAxel Dörfler 
454c22d69bfSAxel Dörfler status_t
455bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer)
456c22d69bfSAxel Dörfler {
45779a0d252SHugo Santos 	sockaddr *peerAddr = buffer->source;
45879a0d252SHugo Santos 	sockaddr *broadcastAddr = buffer->destination;
459c22d69bfSAxel Dörfler 	sockaddr *mask = NULL;
460c22d69bfSAxel Dörfler 	if (buffer->interface)
461c22d69bfSAxel Dörfler 		mask = (sockaddr *)buffer->interface->mask;
462c22d69bfSAxel Dörfler 
463bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer);
464c22d69bfSAxel Dörfler 
465bf48e753SHugo Santos 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
466c22d69bfSAxel Dörfler 
46740bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
46840bbf860SHugo Santos 
46940bbf860SHugo Santos 	while (it.HasNext()) {
47040bbf860SHugo Santos 		UdpEndpoint *endpoint = it.Next();
471c22d69bfSAxel Dörfler 
47225a2744fSHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
47325a2744fSHugo Santos 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
47425a2744fSHugo Santos 
4755084c839SHugo Santos 		if (endpoint->LocalAddress().Port() != incomingPort) {
476c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
477c22d69bfSAxel Dörfler 			continue;
478c22d69bfSAxel Dörfler 		}
479c22d69bfSAxel Dörfler 
48025a2744fSHugo Santos 		if (!endpoint->PeerAddress().IsEmpty(true)) {
481c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
482c22d69bfSAxel Dörfler 			// this datagram is from there:
48325a2744fSHugo Santos 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
484c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
485c22d69bfSAxel Dörfler 				// this endpoint...
486c22d69bfSAxel Dörfler 				continue;
487c22d69bfSAxel Dörfler 			}
488c22d69bfSAxel Dörfler 		}
489c22d69bfSAxel Dörfler 
49025a2744fSHugo Santos 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
49125a2744fSHugo Santos 			|| endpoint->LocalAddress().IsEmpty(false)) {
492c22d69bfSAxel Dörfler 			// address matches, dispatch to this endpoint:
493c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
494c22d69bfSAxel Dörfler 		}
495c22d69bfSAxel Dörfler 	}
49640bbf860SHugo Santos 
497c22d69bfSAxel Dörfler 	return B_OK;
498c22d69bfSAxel Dörfler }
499c22d69bfSAxel Dörfler 
500c22d69bfSAxel Dörfler 
501c22d69bfSAxel Dörfler status_t
502bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer *buffer)
503c22d69bfSAxel Dörfler {
50479a0d252SHugo Santos 	struct sockaddr *peerAddr = buffer->source;
50579a0d252SHugo Santos 	struct sockaddr *localAddr = buffer->destination;
506c22d69bfSAxel Dörfler 
507bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
508c22d69bfSAxel Dörfler 
509c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint;
510c22d69bfSAxel Dörfler 	// look for full (most special) match:
511bf48e753SHugo Santos 	endpoint = _FindActiveEndpoint(localAddr, peerAddr);
512c22d69bfSAxel Dörfler 	if (!endpoint) {
513c22d69bfSAxel Dörfler 		// look for endpoint matching local address & port:
514bf48e753SHugo Santos 		endpoint = _FindActiveEndpoint(localAddr, NULL);
515c22d69bfSAxel Dörfler 		if (!endpoint) {
516c22d69bfSAxel Dörfler 			// look for endpoint matching peer address & port and local port:
51725a2744fSHugo Santos 			SocketAddressStorage local(AddressModule());
51825a2744fSHugo Santos 			local.SetToEmpty();
51925a2744fSHugo Santos 			local.SetPort(AddressModule()->get_port(localAddr));
52025a2744fSHugo Santos 			endpoint = _FindActiveEndpoint(*local, peerAddr);
521c22d69bfSAxel Dörfler 			if (!endpoint) {
522c22d69bfSAxel Dörfler 				// last chance: look for endpoint matching local port only:
52325a2744fSHugo Santos 				endpoint = _FindActiveEndpoint(*local, NULL);
524c22d69bfSAxel Dörfler 			}
525c22d69bfSAxel Dörfler 		}
526c22d69bfSAxel Dörfler 	}
527bf48e753SHugo Santos 
528c22d69bfSAxel Dörfler 	if (!endpoint)
529c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
530c22d69bfSAxel Dörfler 
531c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
532c22d69bfSAxel Dörfler 	return B_OK;
533c22d69bfSAxel Dörfler }
534c22d69bfSAxel Dörfler 
535c22d69bfSAxel Dörfler 
536bf48e753SHugo Santos uint16
537bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
538c22d69bfSAxel Dörfler {
53940bbf860SHugo Santos 	uint16 stop, curr;
540bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
541bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
542bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
543bf48e753SHugo Santos 	} else {
544bf48e753SHugo Santos 		stop = kLast;
545bf48e753SHugo Santos 		curr = kFirst;
546bf48e753SHugo Santos 	}
547c22d69bfSAxel Dörfler 
548bf48e753SHugo Santos 	// TODO: a free list could be used to avoid the impact of these
549bf48e753SHugo Santos 	//       two nested loops most of the time... let's see how bad this really is
55040bbf860SHugo Santos 
551727ad0b0SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
552727ad0b0SHugo Santos 		fLastUsedEphemeral, curr, stop);
55340bbf860SHugo Santos 
554727ad0b0SHugo Santos 	for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
555bf48e753SHugo Santos 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
55640bbf860SHugo Santos 
557727ad0b0SHugo Santos 		if (_EndpointWithPort(htons(curr)) == NULL) {
558bf48e753SHugo Santos 			TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
559bf48e753SHugo Santos 			fLastUsedEphemeral = curr;
560bf48e753SHugo Santos 			return curr;
561bf48e753SHugo Santos 		}
562727ad0b0SHugo Santos 	}
563727ad0b0SHugo Santos 
564727ad0b0SHugo Santos 	return 0;
565727ad0b0SHugo Santos }
566727ad0b0SHugo Santos 
567727ad0b0SHugo Santos 
568727ad0b0SHugo Santos UdpEndpoint *
569727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const
570727ad0b0SHugo Santos {
571727ad0b0SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
572727ad0b0SHugo Santos 
573727ad0b0SHugo Santos 	while (it.HasNext()) {
574727ad0b0SHugo Santos 		UdpEndpoint *endpoint = it.Next();
575727ad0b0SHugo Santos 		if (endpoint->LocalAddress().Port() == port)
576727ad0b0SHugo Santos 			return endpoint;
577727ad0b0SHugo Santos 	}
578727ad0b0SHugo Santos 
579727ad0b0SHugo Santos 	return NULL;
580727ad0b0SHugo Santos }
581c22d69bfSAxel Dörfler 
582bf48e753SHugo Santos 
583bf48e753SHugo Santos // #pragma mark -
584bf48e753SHugo Santos 
585bf48e753SHugo Santos 
586bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
587bf48e753SHugo Santos {
588bf48e753SHugo Santos 	fStatus = benaphore_init(&fLock, "UDP endpoints");
589bf48e753SHugo Santos }
590bf48e753SHugo Santos 
591bf48e753SHugo Santos 
592bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
593bf48e753SHugo Santos {
594bf48e753SHugo Santos 	benaphore_destroy(&fLock);
595bf48e753SHugo Santos }
596bf48e753SHugo Santos 
597bf48e753SHugo Santos 
598bf48e753SHugo Santos status_t
599bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
600bf48e753SHugo Santos {
601bf48e753SHugo Santos 	return fStatus;
602bf48e753SHugo Santos }
603bf48e753SHugo Santos 
604bf48e753SHugo Santos 
605cf5d9f4bSHugo Santos int
606cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
607cf5d9f4bSHugo Santos {
608cf5d9f4bSHugo Santos 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
609cf5d9f4bSHugo Santos 
610cf5d9f4bSHugo Santos 	while (it.HasNext())
611cf5d9f4bSHugo Santos 		it.Next()->DumpEndpoints();
612cf5d9f4bSHugo Santos 
613cf5d9f4bSHugo Santos 	return 0;
614cf5d9f4bSHugo Santos }
615cf5d9f4bSHugo Santos 
616cf5d9f4bSHugo Santos 
617bf48e753SHugo Santos // #pragma mark - inbound
618bf48e753SHugo Santos 
619bf48e753SHugo Santos 
620bf48e753SHugo Santos status_t
621c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer)
622c22d69bfSAxel Dörfler {
6236a606180SHugo Santos 	status_t status = Deframe(buffer);
6246a606180SHugo Santos 	if (status < B_OK)
6256a606180SHugo Santos 		return status;
6266a606180SHugo Santos 
627bf48e753SHugo Santos 	TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
628bf48e753SHugo Santos 
6296a606180SHugo Santos 	net_domain *domain = buffer->interface->domain;
6306a606180SHugo Santos 
631727ad0b0SHugo Santos 	UdpDomainSupport *domainSupport = NULL;
6326a606180SHugo Santos 
633727ad0b0SHugo Santos 	{
634727ad0b0SHugo Santos 		BenaphoreLocker _(fLock);
635727ad0b0SHugo Santos 		domainSupport = _GetDomain(domain, false);
636727ad0b0SHugo Santos 		// TODO we don't want to hold to the manager's lock
637727ad0b0SHugo Santos 		//      during the whole RX path, we may not hold an
638727ad0b0SHugo Santos 		//      endpoint's lock with the manager lock held.
639727ad0b0SHugo Santos 		//      But we should increase the domain's refcount
640727ad0b0SHugo Santos 		//      here.
641727ad0b0SHugo Santos 	}
642727ad0b0SHugo Santos 
6436a606180SHugo Santos 	if (domainSupport == NULL) {
6446a606180SHugo Santos 		// we don't instantiate domain supports in the
6456a606180SHugo Santos 		// RX path as we are only interested in delivering
6466a606180SHugo Santos 		// data to existing sockets.
6476a606180SHugo Santos 		return B_ERROR;
6486a606180SHugo Santos 	}
6496a606180SHugo Santos 
6506a606180SHugo Santos 	status = domainSupport->DemuxIncomingBuffer(buffer);
6516a606180SHugo Santos 	if (status < B_OK) {
6526a606180SHugo Santos 		TRACE_EPM("  ReceiveData(): no endpoint.");
6536a606180SHugo Santos 		// TODO: send ICMP-error
6546a606180SHugo Santos 		return B_ERROR;
6556a606180SHugo Santos 	}
6566a606180SHugo Santos 
657a1deb55eSHugo Santos 	gBufferModule->free(buffer);
658a1deb55eSHugo Santos 	return B_OK;
6596a606180SHugo Santos }
6606a606180SHugo Santos 
6616a606180SHugo Santos 
6626a606180SHugo Santos status_t
6636a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer)
6646a606180SHugo Santos {
6656a606180SHugo Santos 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
6666a606180SHugo Santos 
66787001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
668c22d69bfSAxel Dörfler 	if (bufferHeader.Status() < B_OK)
669c22d69bfSAxel Dörfler 		return bufferHeader.Status();
670c22d69bfSAxel Dörfler 
671c22d69bfSAxel Dörfler 	udp_header &header = bufferHeader.Data();
672c22d69bfSAxel Dörfler 
673bf48e753SHugo Santos 	if (buffer->interface == NULL || buffer->interface->domain == NULL) {
6746a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
675bf48e753SHugo Santos 			"specified (interface %p).", buffer->interface);
676c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
677c22d69bfSAxel Dörfler 	}
678bf48e753SHugo Santos 
679bf48e753SHugo Santos 	net_domain *domain = buffer->interface->domain;
680bf48e753SHugo Santos 	net_address_module_info *addressModule = domain->address_module;
681bf48e753SHugo Santos 
68279a0d252SHugo Santos 	SocketAddress source(addressModule, buffer->source);
68379a0d252SHugo Santos 	SocketAddress destination(addressModule, buffer->destination);
684bf48e753SHugo Santos 
6854e8a1b33SHugo Santos 	source.SetPort(header.source_port);
6864e8a1b33SHugo Santos 	destination.SetPort(header.destination_port);
6874e8a1b33SHugo Santos 
6884e8a1b33SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
6894e8a1b33SHugo Santos 		destination.AsString(true).Data());
690c22d69bfSAxel Dörfler 
691c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
692c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
6936a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
694bf48e753SHugo Santos 			udpLength);
695c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
696c22d69bfSAxel Dörfler 	}
697bf48e753SHugo Santos 
698bf48e753SHugo Santos 	if (buffer->size > udpLength)
699c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
700c22d69bfSAxel Dörfler 
701c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
702c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
703d5b5a2c2SHugo Santos 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
704d5b5a2c2SHugo Santos 			buffer, IPPROTO_UDP);
705c22d69bfSAxel Dörfler 		if (sum != 0) {
7066a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
707c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
708c22d69bfSAxel Dörfler 		}
709c22d69bfSAxel Dörfler 	}
710c22d69bfSAxel Dörfler 
711c22d69bfSAxel Dörfler 	bufferHeader.Remove();
712c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
713c22d69bfSAxel Dörfler 
7146a606180SHugo Santos 	return B_OK;
715c22d69bfSAxel Dörfler }
716c22d69bfSAxel Dörfler 
717c22d69bfSAxel Dörfler 
718bf48e753SHugo Santos UdpDomainSupport *
719c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
720c22d69bfSAxel Dörfler {
721bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
722bf48e753SHugo Santos 
723bf48e753SHugo Santos 	UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true);
724bf48e753SHugo Santos 	if (domain)
725bf48e753SHugo Santos 		domain->Ref();
726bf48e753SHugo Santos 	return domain;
727bf48e753SHugo Santos }
728bf48e753SHugo Santos 
729bf48e753SHugo Santos 
730bf48e753SHugo Santos status_t
731bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
732bf48e753SHugo Santos {
733bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
734bf48e753SHugo Santos 
735727ad0b0SHugo Santos 	if (domain->Put()) {
736bf48e753SHugo Santos 		fDomains.Remove(domain);
737bf48e753SHugo Santos 		delete domain;
738bf48e753SHugo Santos 	}
739bf48e753SHugo Santos 
740bf48e753SHugo Santos 	return B_OK;
741bf48e753SHugo Santos }
742bf48e753SHugo Santos 
743bf48e753SHugo Santos 
744bf48e753SHugo Santos // #pragma mark -
745bf48e753SHugo Santos 
746bf48e753SHugo Santos 
747bf48e753SHugo Santos UdpDomainSupport *
748bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
749bf48e753SHugo Santos {
750bf48e753SHugo Santos 	UdpDomainList::Iterator it = fDomains.GetIterator();
751bf48e753SHugo Santos 
752bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
753bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
754bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
755bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
756bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
757bf48e753SHugo Santos 	//      family.
758bf48e753SHugo Santos 	while (it.HasNext()) {
759bf48e753SHugo Santos 		UdpDomainSupport *domainSupport = it.Next();
760bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
761bf48e753SHugo Santos 			return domainSupport;
762bf48e753SHugo Santos 	}
763bf48e753SHugo Santos 
764bf48e753SHugo Santos 	if (!create)
765bf48e753SHugo Santos 		return NULL;
766bf48e753SHugo Santos 
767bf48e753SHugo Santos 	UdpDomainSupport *domainSupport =
768bf48e753SHugo Santos 		new (std::nothrow) UdpDomainSupport(domain);
769bf48e753SHugo Santos 	if (domainSupport == NULL || domainSupport->InitCheck() < B_OK) {
770bf48e753SHugo Santos 		delete domainSupport;
771bf48e753SHugo Santos 		return NULL;
772bf48e753SHugo Santos 	}
773bf48e753SHugo Santos 
774bf48e753SHugo Santos 	fDomains.Add(domainSupport);
775bf48e753SHugo Santos 	return domainSupport;
776c22d69bfSAxel Dörfler }
777c22d69bfSAxel Dörfler 
778c22d69bfSAxel Dörfler 
779c22d69bfSAxel Dörfler // #pragma mark -
780c22d69bfSAxel Dörfler 
781c22d69bfSAxel Dörfler 
782c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
783c72ab92dSHugo Santos 	: DatagramSocket<>("udp endpoint", socket), fActive(false) {}
784bf48e753SHugo Santos 
785bf48e753SHugo Santos 
786c22d69bfSAxel Dörfler // #pragma mark - activation
787c22d69bfSAxel Dörfler 
788c22d69bfSAxel Dörfler 
789c22d69bfSAxel Dörfler status_t
79053f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
791c22d69bfSAxel Dörfler {
792bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
793727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
794c22d69bfSAxel Dörfler }
795c22d69bfSAxel Dörfler 
796c22d69bfSAxel Dörfler 
797c22d69bfSAxel Dörfler status_t
798c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
799c22d69bfSAxel Dörfler {
800bf48e753SHugo Santos 	TRACE_EP("Unbind()");
801727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
802c22d69bfSAxel Dörfler }
803c22d69bfSAxel Dörfler 
804c22d69bfSAxel Dörfler 
805c22d69bfSAxel Dörfler status_t
806c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
807c22d69bfSAxel Dörfler {
808bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
809727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
810c22d69bfSAxel Dörfler }
811c22d69bfSAxel Dörfler 
812c22d69bfSAxel Dörfler 
813c22d69bfSAxel Dörfler status_t
814c22d69bfSAxel Dörfler UdpEndpoint::Open()
815c22d69bfSAxel Dörfler {
816bf48e753SHugo Santos 	TRACE_EP("Open()");
817bf48e753SHugo Santos 
818*119c6cddSIngo Weinhold 	AutoLocker _(fLock);
819727ad0b0SHugo Santos 
820c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
821c72ab92dSHugo Santos 	if (status < B_OK)
822c72ab92dSHugo Santos 		return status;
823bf48e753SHugo Santos 
824c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
825c72ab92dSHugo Santos 	if (fManager == NULL)
826bf48e753SHugo Santos 		return EAFNOSUPPORT;
827bf48e753SHugo Santos 
828bf48e753SHugo Santos 	return B_OK;
829c22d69bfSAxel Dörfler }
830c22d69bfSAxel Dörfler 
831c22d69bfSAxel Dörfler 
832c22d69bfSAxel Dörfler status_t
833c22d69bfSAxel Dörfler UdpEndpoint::Close()
834c22d69bfSAxel Dörfler {
835bf48e753SHugo Santos 	TRACE_EP("Close()");
836bf48e753SHugo Santos 	return B_OK;
837c22d69bfSAxel Dörfler }
838c22d69bfSAxel Dörfler 
839c22d69bfSAxel Dörfler 
840c22d69bfSAxel Dörfler status_t
841c22d69bfSAxel Dörfler UdpEndpoint::Free()
842c22d69bfSAxel Dörfler {
843bf48e753SHugo Santos 	TRACE_EP("Free()");
8440086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
845c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
846c22d69bfSAxel Dörfler }
847c22d69bfSAxel Dörfler 
848c22d69bfSAxel Dörfler 
849c22d69bfSAxel Dörfler // #pragma mark - outbound
850c22d69bfSAxel Dörfler 
851c22d69bfSAxel Dörfler 
852c22d69bfSAxel Dörfler status_t
853bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
854c22d69bfSAxel Dörfler {
855bf48e753SHugo Santos 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
856bf48e753SHugo Santos 
857d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
858c22d69bfSAxel Dörfler 		return EMSGSIZE;
859c22d69bfSAxel Dörfler 
860c22d69bfSAxel Dörfler 	buffer->protocol = IPPROTO_UDP;
861c22d69bfSAxel Dörfler 
862c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
8636c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
8646c353509SHugo Santos 	if (header.Status() < B_OK)
8656c353509SHugo Santos 		return header.Status();
866c22d69bfSAxel Dörfler 
86779a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
86879a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
8696c353509SHugo Santos 	header->udp_length = htons(buffer->size);
870c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
8716c353509SHugo Santos 	header->udp_checksum = 0;
8726c353509SHugo Santos 
8736c353509SHugo Santos 	header.Sync();
874c22d69bfSAxel Dörfler 
875d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
876d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
8776c353509SHugo Santos 	if (calculatedChecksum == 0)
8786c353509SHugo Santos 		calculatedChecksum = 0xffff;
8796c353509SHugo Santos 
8806c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
881c22d69bfSAxel Dörfler 
882c22d69bfSAxel Dörfler 	TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: "));
8836c353509SHugo Santos 
884c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
885c22d69bfSAxel Dörfler }
886c22d69bfSAxel Dörfler 
887c22d69bfSAxel Dörfler 
888bf48e753SHugo Santos status_t
889bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
890bf48e753SHugo Santos {
891bf48e753SHugo Santos 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
892bf48e753SHugo Santos 
8931408d1f0SHugo Santos 	return gDatalinkModule->send_datagram(this, NULL, buffer);
894bf48e753SHugo Santos }
895bf48e753SHugo Santos 
896bf48e753SHugo Santos 
897c22d69bfSAxel Dörfler // #pragma mark - inbound
898c22d69bfSAxel Dörfler 
899c22d69bfSAxel Dörfler 
900c22d69bfSAxel Dörfler ssize_t
901c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
902c22d69bfSAxel Dörfler {
903bfb45f71SHugo Santos 	size_t bytes = AvailableData();
904bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
905bfb45f71SHugo Santos 	return bytes;
906c22d69bfSAxel Dörfler }
907c22d69bfSAxel Dörfler 
908c22d69bfSAxel Dörfler 
909c22d69bfSAxel Dörfler status_t
910c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
911c22d69bfSAxel Dörfler {
912bf48e753SHugo Santos 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
913bf48e753SHugo Santos 
914bfb45f71SHugo Santos 	status_t status = SocketDequeue(flags, _buffer);
915bf48e753SHugo Santos 	TRACE_EP("  FetchData(): returned from fifo status=0x%lx", status);
916c22d69bfSAxel Dörfler 	if (status < B_OK)
917c22d69bfSAxel Dörfler 		return status;
918c22d69bfSAxel Dörfler 
919bfb45f71SHugo Santos 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
920c22d69bfSAxel Dörfler 	return B_OK;
921c22d69bfSAxel Dörfler }
922c22d69bfSAxel Dörfler 
923c22d69bfSAxel Dörfler 
924c22d69bfSAxel Dörfler status_t
925bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
926c22d69bfSAxel Dörfler {
927bf48e753SHugo Santos 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
928c22d69bfSAxel Dörfler 
92949f3c71eSHugo Santos 	return SocketEnqueue(buffer);
930c22d69bfSAxel Dörfler }
931c22d69bfSAxel Dörfler 
932c22d69bfSAxel Dörfler 
9336a606180SHugo Santos status_t
9346a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
9356a606180SHugo Santos {
936f6cfc5afSHugo Santos 	TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size);
937f6cfc5afSHugo Santos 
9386a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
9396a606180SHugo Santos 	if (buffer == NULL)
9406a606180SHugo Santos 		return B_NO_MEMORY;
9416a606180SHugo Santos 
9426a606180SHugo Santos 	status_t status = sUdpEndpointManager->Deframe(buffer);
9436a606180SHugo Santos 	if (status < B_OK) {
9446a606180SHugo Santos 		gBufferModule->free(buffer);
9456a606180SHugo Santos 		return status;
9466a606180SHugo Santos 	}
9476a606180SHugo Santos 
9486a606180SHugo Santos 	// we call Enqueue() instead of SocketEnqueue() as there is
9496a606180SHugo Santos 	// no need to clone the buffer again.
9506a606180SHugo Santos 	return Enqueue(buffer);
9516a606180SHugo Santos }
9526a606180SHugo Santos 
9536a606180SHugo Santos 
954c22d69bfSAxel Dörfler // #pragma mark - protocol interface
955c22d69bfSAxel Dörfler 
956c22d69bfSAxel Dörfler 
957c22d69bfSAxel Dörfler net_protocol *
958c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
959c22d69bfSAxel Dörfler {
960c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
961c22d69bfSAxel Dörfler 
962c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
963bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
964bf48e753SHugo Santos 		delete endpoint;
965bf48e753SHugo Santos 		return NULL;
966bf48e753SHugo Santos 	}
967bf48e753SHugo Santos 
968c22d69bfSAxel Dörfler 	return endpoint;
969c22d69bfSAxel Dörfler }
970c22d69bfSAxel Dörfler 
971c22d69bfSAxel Dörfler 
972c22d69bfSAxel Dörfler status_t
973c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
974c22d69bfSAxel Dörfler {
975bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
976c22d69bfSAxel Dörfler 	return B_OK;
977c22d69bfSAxel Dörfler }
978c22d69bfSAxel Dörfler 
979c22d69bfSAxel Dörfler 
980c22d69bfSAxel Dörfler status_t
981c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
982c22d69bfSAxel Dörfler {
983bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
984c22d69bfSAxel Dörfler }
985c22d69bfSAxel Dörfler 
986c22d69bfSAxel Dörfler 
987c22d69bfSAxel Dörfler status_t
988c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
989c22d69bfSAxel Dörfler {
990bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
991c22d69bfSAxel Dörfler }
992c22d69bfSAxel Dörfler 
993c22d69bfSAxel Dörfler 
994c22d69bfSAxel Dörfler status_t
995c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
996c22d69bfSAxel Dörfler {
997bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
998c22d69bfSAxel Dörfler }
999c22d69bfSAxel Dörfler 
1000c22d69bfSAxel Dörfler 
1001c22d69bfSAxel Dörfler status_t
1002c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1003c22d69bfSAxel Dörfler {
1004bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1005c22d69bfSAxel Dörfler }
1006c22d69bfSAxel Dörfler 
1007c22d69bfSAxel Dörfler 
1008c22d69bfSAxel Dörfler status_t
1009c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1010c22d69bfSAxel Dörfler {
1011c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1012c22d69bfSAxel Dörfler }
1013c22d69bfSAxel Dörfler 
1014c22d69bfSAxel Dörfler 
1015c22d69bfSAxel Dörfler status_t
1016c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1017c22d69bfSAxel Dörfler 	size_t *_length)
1018c22d69bfSAxel Dörfler {
1019c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1020c22d69bfSAxel Dörfler 		value, _length);
1021c22d69bfSAxel Dörfler }
1022c22d69bfSAxel Dörfler 
1023c22d69bfSAxel Dörfler 
1024c22d69bfSAxel Dörfler status_t
102545b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
102645b5203bSHugo Santos 	int *length)
102745b5203bSHugo Santos {
102845b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
102945b5203bSHugo Santos 		value, length);
103045b5203bSHugo Santos }
103145b5203bSHugo Santos 
103245b5203bSHugo Santos 
103345b5203bSHugo Santos status_t
103445b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
103545b5203bSHugo Santos 	const void *value, int length)
103645b5203bSHugo Santos {
103745b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
103845b5203bSHugo Santos 		value, length);
103945b5203bSHugo Santos }
104045b5203bSHugo Santos 
104145b5203bSHugo Santos 
104245b5203bSHugo Santos status_t
104353f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1044c22d69bfSAxel Dörfler {
1045bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1046c22d69bfSAxel Dörfler }
1047c22d69bfSAxel Dörfler 
1048c22d69bfSAxel Dörfler 
1049c22d69bfSAxel Dörfler status_t
1050c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1051c22d69bfSAxel Dörfler {
1052bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1053c22d69bfSAxel Dörfler }
1054c22d69bfSAxel Dörfler 
1055c22d69bfSAxel Dörfler 
1056c22d69bfSAxel Dörfler status_t
1057c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1058c22d69bfSAxel Dörfler {
1059c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1060c22d69bfSAxel Dörfler }
1061c22d69bfSAxel Dörfler 
1062c22d69bfSAxel Dörfler 
1063c22d69bfSAxel Dörfler status_t
1064c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1065c22d69bfSAxel Dörfler {
1066c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1067c22d69bfSAxel Dörfler }
1068c22d69bfSAxel Dörfler 
1069c22d69bfSAxel Dörfler 
1070c22d69bfSAxel Dörfler status_t
1071c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1072c22d69bfSAxel Dörfler 	net_buffer *buffer)
1073c22d69bfSAxel Dörfler {
1074bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1075c22d69bfSAxel Dörfler }
1076c22d69bfSAxel Dörfler 
1077c22d69bfSAxel Dörfler 
1078c22d69bfSAxel Dörfler status_t
1079c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1080c22d69bfSAxel Dörfler {
1081bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1082c22d69bfSAxel Dörfler }
1083c22d69bfSAxel Dörfler 
1084c22d69bfSAxel Dörfler 
1085c22d69bfSAxel Dörfler ssize_t
1086c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1087c22d69bfSAxel Dörfler {
1088bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1089c22d69bfSAxel Dörfler }
1090c22d69bfSAxel Dörfler 
1091c22d69bfSAxel Dörfler 
1092c22d69bfSAxel Dörfler status_t
1093c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1094c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1095c22d69bfSAxel Dörfler {
1096bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1097c22d69bfSAxel Dörfler }
1098c22d69bfSAxel Dörfler 
1099c22d69bfSAxel Dörfler 
1100c22d69bfSAxel Dörfler ssize_t
1101c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1102c22d69bfSAxel Dörfler {
1103bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1104c22d69bfSAxel Dörfler }
1105c22d69bfSAxel Dörfler 
1106c22d69bfSAxel Dörfler 
1107c22d69bfSAxel Dörfler struct net_domain *
1108c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1109c22d69bfSAxel Dörfler {
1110c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1111c22d69bfSAxel Dörfler }
1112c22d69bfSAxel Dörfler 
1113c22d69bfSAxel Dörfler 
1114c22d69bfSAxel Dörfler size_t
1115c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1116c22d69bfSAxel Dörfler {
1117c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1118c22d69bfSAxel Dörfler }
1119c22d69bfSAxel Dörfler 
1120c22d69bfSAxel Dörfler 
1121c22d69bfSAxel Dörfler status_t
1122c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1123c22d69bfSAxel Dörfler {
1124c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1125c22d69bfSAxel Dörfler }
1126c22d69bfSAxel Dörfler 
1127c22d69bfSAxel Dörfler 
1128c22d69bfSAxel Dörfler status_t
11296a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
11306a606180SHugo Santos {
11316a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
11326a606180SHugo Santos }
11336a606180SHugo Santos 
11346a606180SHugo Santos 
11356a606180SHugo Santos status_t
1136c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data)
1137c22d69bfSAxel Dörfler {
1138c22d69bfSAxel Dörfler 	return B_ERROR;
1139c22d69bfSAxel Dörfler }
1140c22d69bfSAxel Dörfler 
1141c22d69bfSAxel Dörfler 
1142c22d69bfSAxel Dörfler status_t
1143c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
1144c22d69bfSAxel Dörfler 	void *errorData)
1145c22d69bfSAxel Dörfler {
1146c22d69bfSAxel Dörfler 	return B_ERROR;
1147c22d69bfSAxel Dörfler }
1148c22d69bfSAxel Dörfler 
1149c22d69bfSAxel Dörfler 
1150c22d69bfSAxel Dörfler //	#pragma mark - module interface
1151c22d69bfSAxel Dörfler 
1152c22d69bfSAxel Dörfler 
1153c22d69bfSAxel Dörfler static status_t
1154c22d69bfSAxel Dörfler init_udp()
1155c22d69bfSAxel Dörfler {
1156c22d69bfSAxel Dörfler 	status_t status;
1157bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1158c22d69bfSAxel Dörfler 
1159c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1160658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1161658a5506SHugo Santos 		return B_NO_MEMORY;
1162658a5506SHugo Santos 
1163c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1164c22d69bfSAxel Dörfler 	if (status != B_OK)
1165d438fa4cSHugo Santos 		goto err1;
1166c22d69bfSAxel Dörfler 
1167bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP,
1168c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1169c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1170c22d69bfSAxel Dörfler 		NULL);
1171c22d69bfSAxel Dörfler 	if (status < B_OK)
1172658a5506SHugo Santos 		goto err1;
1173bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
1174c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1175c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1176c22d69bfSAxel Dörfler 		NULL);
1177c22d69bfSAxel Dörfler 	if (status < B_OK)
1178658a5506SHugo Santos 		goto err1;
1179c22d69bfSAxel Dörfler 
1180bfb45f71SHugo Santos 	status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
1181c22d69bfSAxel Dörfler 		"network/protocols/udp/v1");
1182c22d69bfSAxel Dörfler 	if (status < B_OK)
1183658a5506SHugo Santos 		goto err1;
1184c22d69bfSAxel Dörfler 
1185cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1186cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1187cf5d9f4bSHugo Santos 
1188c22d69bfSAxel Dörfler 	return B_OK;
1189c22d69bfSAxel Dörfler 
1190c22d69bfSAxel Dörfler err1:
1191658a5506SHugo Santos 	delete sUdpEndpointManager;
1192c22d69bfSAxel Dörfler 
1193bf48e753SHugo Santos 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1194c22d69bfSAxel Dörfler 	return status;
1195c22d69bfSAxel Dörfler }
1196c22d69bfSAxel Dörfler 
1197c22d69bfSAxel Dörfler 
1198c22d69bfSAxel Dörfler static status_t
1199c22d69bfSAxel Dörfler uninit_udp()
1200c22d69bfSAxel Dörfler {
1201bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1202cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1203cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1204c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1205c22d69bfSAxel Dörfler 	return B_OK;
1206c22d69bfSAxel Dörfler }
1207c22d69bfSAxel Dörfler 
1208c22d69bfSAxel Dörfler 
1209c22d69bfSAxel Dörfler static status_t
1210c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1211c22d69bfSAxel Dörfler {
1212c22d69bfSAxel Dörfler 	switch (op) {
1213c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1214c22d69bfSAxel Dörfler 			return init_udp();
1215c22d69bfSAxel Dörfler 
1216c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1217c22d69bfSAxel Dörfler 			return uninit_udp();
1218c22d69bfSAxel Dörfler 
1219c22d69bfSAxel Dörfler 		default:
1220c22d69bfSAxel Dörfler 			return B_ERROR;
1221c22d69bfSAxel Dörfler 	}
1222c22d69bfSAxel Dörfler }
1223c22d69bfSAxel Dörfler 
1224c22d69bfSAxel Dörfler 
1225c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1226c22d69bfSAxel Dörfler 	{
1227c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1228c22d69bfSAxel Dörfler 		0,
1229c22d69bfSAxel Dörfler 		udp_std_ops
1230c22d69bfSAxel Dörfler 	},
1231c22d69bfSAxel Dörfler 	udp_init_protocol,
1232c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1233c22d69bfSAxel Dörfler 	udp_open,
1234c22d69bfSAxel Dörfler 	udp_close,
1235c22d69bfSAxel Dörfler 	udp_free,
1236c22d69bfSAxel Dörfler 	udp_connect,
1237c22d69bfSAxel Dörfler 	udp_accept,
1238c22d69bfSAxel Dörfler 	udp_control,
123945b5203bSHugo Santos 	udp_getsockopt,
124045b5203bSHugo Santos 	udp_setsockopt,
1241c22d69bfSAxel Dörfler 	udp_bind,
1242c22d69bfSAxel Dörfler 	udp_unbind,
1243c22d69bfSAxel Dörfler 	udp_listen,
1244c22d69bfSAxel Dörfler 	udp_shutdown,
1245c22d69bfSAxel Dörfler 	udp_send_data,
1246c22d69bfSAxel Dörfler 	udp_send_routed_data,
1247c22d69bfSAxel Dörfler 	udp_send_avail,
1248c22d69bfSAxel Dörfler 	udp_read_data,
1249c22d69bfSAxel Dörfler 	udp_read_avail,
1250c22d69bfSAxel Dörfler 	udp_get_domain,
1251c22d69bfSAxel Dörfler 	udp_get_mtu,
1252c22d69bfSAxel Dörfler 	udp_receive_data,
12536a606180SHugo Santos 	udp_deliver_data,
1254c22d69bfSAxel Dörfler 	udp_error,
1255c22d69bfSAxel Dörfler 	udp_error_reply,
1256c22d69bfSAxel Dörfler };
1257c22d69bfSAxel Dörfler 
1258658a5506SHugo Santos module_dependency module_dependencies[] = {
1259658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1260658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1261658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1262658a5506SHugo Santos 	{}
1263658a5506SHugo Santos };
1264658a5506SHugo Santos 
1265c22d69bfSAxel Dörfler module_info *modules[] = {
1266c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1267c22d69bfSAxel Dörfler 	NULL
1268c22d69bfSAxel Dörfler };
1269