xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 9e05183977f2e7cd320b86ea1d4adf82588d69d6)
1c22d69bfSAxel Dörfler /*
26f58064fSAxel Dörfler  * Copyright 2006-2008, 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 
11884052230SAxel Dörfler 	UdpHashDefinition(net_address_module_info *_module)
11984052230SAxel Dörfler 		: module(_module) {}
12084052230SAxel Dörfler 	UdpHashDefinition(const UdpHashDefinition& definition)
12184052230SAxel Dörfler 		: module(definition.module) {}
12240bbf860SHugo Santos 
12340bbf860SHugo Santos 	size_t HashKey(const KeyType &key) const
12440bbf860SHugo Santos 	{
12540bbf860SHugo Santos 		return _Mix(module->hash_address_pair(key.first, key.second));
12640bbf860SHugo Santos 	}
12740bbf860SHugo Santos 
12840bbf860SHugo Santos 	size_t Hash(UdpEndpoint *endpoint) const
12940bbf860SHugo Santos 	{
13040bbf860SHugo Santos 		return _Mix(endpoint->LocalAddress().HashPair(*endpoint->PeerAddress()));
13140bbf860SHugo Santos 	}
13240bbf860SHugo Santos 
13340bbf860SHugo Santos 	static size_t _Mix(size_t hash)
13440bbf860SHugo Santos 	{
13540bbf860SHugo Santos 		// move the bits into the relevant range (as defined by kNumHashBuckets):
13640bbf860SHugo Santos 		return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
13740bbf860SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
13840bbf860SHugo Santos 	}
13940bbf860SHugo Santos 
14040bbf860SHugo Santos 	bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
14140bbf860SHugo Santos 	{
14240bbf860SHugo Santos 		return endpoint->LocalAddress().EqualTo(key.first, true)
14340bbf860SHugo Santos 			&& endpoint->PeerAddress().EqualTo(key.second, true);
14440bbf860SHugo Santos 	}
14540bbf860SHugo Santos 
14640bbf860SHugo Santos 	HashTableLink<UdpEndpoint> *GetLink(UdpEndpoint *endpoint) const
14740bbf860SHugo Santos 	{
14840bbf860SHugo Santos 		return endpoint->HashTableLink();
14940bbf860SHugo Santos 	}
15040bbf860SHugo Santos 
15140bbf860SHugo Santos 	net_address_module_info *module;
152c22d69bfSAxel Dörfler };
153c22d69bfSAxel Dörfler 
154c22d69bfSAxel Dörfler 
155bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
156c22d69bfSAxel Dörfler public:
157bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
158727ad0b0SHugo Santos 	~UdpDomainSupport();
159c22d69bfSAxel Dörfler 
160276aa463SIngo Weinhold 	status_t Init();
161bf48e753SHugo Santos 
162bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
163bf48e753SHugo Santos 
164bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
165727ad0b0SHugo Santos 	bool Put() { fEndpointCount--; return fEndpointCount == 0; }
166bf48e753SHugo Santos 
167bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer *buffer);
168727ad0b0SHugo Santos 
169727ad0b0SHugo Santos 	status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
170727ad0b0SHugo Santos 	status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
171727ad0b0SHugo Santos 	status_t UnbindEndpoint(UdpEndpoint *endpoint);
172727ad0b0SHugo Santos 
173cf5d9f4bSHugo Santos 	void DumpEndpoints() const;
174bf48e753SHugo Santos 
175c22d69bfSAxel Dörfler private:
176727ad0b0SHugo Santos 	status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
177727ad0b0SHugo Santos 	status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
178727ad0b0SHugo Santos 	status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
179727ad0b0SHugo Santos 	status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
180727ad0b0SHugo Santos 
18140bbf860SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
18240bbf860SHugo Santos 		const sockaddr *peerAddress);
183bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
184bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
185bf48e753SHugo Santos 
186bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
187727ad0b0SHugo Santos 	UdpEndpoint *_EndpointWithPort(uint16 port) const;
188bf48e753SHugo Santos 
189bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
190727ad0b0SHugo Santos 		{ return fDomain->address_module; }
191bf48e753SHugo Santos 
19240bbf860SHugo Santos 	typedef OpenHashTable<UdpHashDefinition, false> EndpointTable;
19340bbf860SHugo Santos 
1942b07b8e0SIngo Weinhold 	mutex			fLock;
195bf48e753SHugo Santos 	net_domain		*fDomain;
196bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
19740bbf860SHugo Santos 	EndpointTable	fActiveEndpoints;
198bf48e753SHugo Santos 	uint32			fEndpointCount;
199bf48e753SHugo Santos 
200bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
201bf48e753SHugo Santos 	static const uint16		kLast = 65535;
202bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
203bf48e753SHugo Santos 							// if you change this, adjust the shifting in
204bf48e753SHugo Santos 							// Hash() accordingly!
205bf48e753SHugo Santos };
206bf48e753SHugo Santos 
207bf48e753SHugo Santos 
208bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
209bf48e753SHugo Santos 
210bf48e753SHugo Santos 
211bf48e753SHugo Santos class UdpEndpointManager {
212c22d69bfSAxel Dörfler public:
213c22d69bfSAxel Dörfler 	UdpEndpointManager();
214c22d69bfSAxel Dörfler 	~UdpEndpointManager();
215c22d69bfSAxel Dörfler 
216c22d69bfSAxel Dörfler 	status_t		ReceiveData(net_buffer *buffer);
2176a606180SHugo Santos 	status_t		Deframe(net_buffer *buffer);
218c22d69bfSAxel Dörfler 
219bf48e753SHugo Santos 	UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
220bf48e753SHugo Santos 	status_t FreeEndpoint(UdpDomainSupport *domain);
221c22d69bfSAxel Dörfler 
222c22d69bfSAxel Dörfler 	status_t		InitCheck() const;
223bf48e753SHugo Santos 
224cf5d9f4bSHugo Santos 	static int DumpEndpoints(int argc, char *argv[]);
225cf5d9f4bSHugo Santos 
226c22d69bfSAxel Dörfler private:
227bf48e753SHugo Santos 	UdpDomainSupport *_GetDomain(net_domain *domain, bool create);
228bf48e753SHugo Santos 
2292b07b8e0SIngo Weinhold 	mutex			fLock;
230c22d69bfSAxel Dörfler 	status_t		fStatus;
231bf48e753SHugo Santos 	UdpDomainList	fDomains;
232c22d69bfSAxel Dörfler };
233c22d69bfSAxel Dörfler 
234c22d69bfSAxel Dörfler 
235c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
236c22d69bfSAxel Dörfler 
237c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
238658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
239658a5506SHugo Santos net_stack_module_info *gStackModule;
240c22d69bfSAxel Dörfler 
241c22d69bfSAxel Dörfler 
242c22d69bfSAxel Dörfler // #pragma mark -
243c22d69bfSAxel Dörfler 
244c22d69bfSAxel Dörfler 
245bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
246c22d69bfSAxel Dörfler 	:
247bf48e753SHugo Santos 	fDomain(domain),
248276aa463SIngo Weinhold 	fActiveEndpoints(domain->address_module),
249bf48e753SHugo Santos 	fEndpointCount(0)
250c22d69bfSAxel Dörfler {
2512b07b8e0SIngo Weinhold 	mutex_init(&fLock, "udp domain");
252727ad0b0SHugo Santos 
253727ad0b0SHugo Santos 	fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
254727ad0b0SHugo Santos }
255727ad0b0SHugo Santos 
256727ad0b0SHugo Santos 
257727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
258727ad0b0SHugo Santos {
2592b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
260bf48e753SHugo Santos }
261bf48e753SHugo Santos 
262bf48e753SHugo Santos 
263bf48e753SHugo Santos status_t
264276aa463SIngo Weinhold UdpDomainSupport::Init()
265bf48e753SHugo Santos {
266276aa463SIngo Weinhold 	return fActiveEndpoints.Init(kNumHashBuckets);
267bf48e753SHugo Santos }
268bf48e753SHugo Santos 
269bf48e753SHugo Santos 
270bf48e753SHugo Santos status_t
271bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
272bf48e753SHugo Santos {
273727ad0b0SHugo Santos 	// NOTE multicast is delivered directly to the endpoint
274727ad0b0SHugo Santos 
2752b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
276727ad0b0SHugo Santos 
277bf48e753SHugo Santos 	if (buffer->flags & MSG_BCAST)
278bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
279bf48e753SHugo Santos 	else if (buffer->flags & MSG_MCAST)
280727ad0b0SHugo Santos 		return B_ERROR;
281bf48e753SHugo Santos 
282bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
283bf48e753SHugo Santos }
284bf48e753SHugo Santos 
285bf48e753SHugo Santos 
286bf48e753SHugo Santos status_t
287727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
288727ad0b0SHugo Santos 	const sockaddr *address)
289727ad0b0SHugo Santos {
2902b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
291727ad0b0SHugo Santos 
292727ad0b0SHugo Santos 	if (endpoint->IsActive())
293727ad0b0SHugo Santos 		return EINVAL;
294727ad0b0SHugo Santos 
295727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, address);
296727ad0b0SHugo Santos }
297727ad0b0SHugo Santos 
298727ad0b0SHugo Santos 
299727ad0b0SHugo Santos status_t
300727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
301727ad0b0SHugo Santos 	const sockaddr *address)
302727ad0b0SHugo Santos {
3032b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
304727ad0b0SHugo Santos 
305727ad0b0SHugo Santos 	if (endpoint->IsActive()) {
306727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
307727ad0b0SHugo Santos 		endpoint->SetActive(false);
308727ad0b0SHugo Santos 	}
309727ad0b0SHugo Santos 
310727ad0b0SHugo Santos 	if (address->sa_family == AF_UNSPEC) {
311727ad0b0SHugo Santos 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
312727ad0b0SHugo Santos 		// so we reset the peer address:
313727ad0b0SHugo Santos 		endpoint->PeerAddress().SetToEmpty();
314727ad0b0SHugo Santos 	} else {
315727ad0b0SHugo Santos 		status_t status = endpoint->PeerAddress().SetTo(address);
316727ad0b0SHugo Santos 		if (status < B_OK)
317727ad0b0SHugo Santos 			return status;
318727ad0b0SHugo Santos 	}
319727ad0b0SHugo Santos 
320727ad0b0SHugo Santos 	// we need to activate no matter whether or not we have just disconnected,
321727ad0b0SHugo Santos 	// as calling connect() always triggers an implicit bind():
322727ad0b0SHugo Santos 	return _BindEndpoint(endpoint, *endpoint->LocalAddress());
323727ad0b0SHugo Santos }
324727ad0b0SHugo Santos 
325727ad0b0SHugo Santos 
326727ad0b0SHugo Santos status_t
327727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
328727ad0b0SHugo Santos {
3292b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
330727ad0b0SHugo Santos 
331727ad0b0SHugo Santos 	if (endpoint->IsActive())
332727ad0b0SHugo Santos 		fActiveEndpoints.Remove(endpoint);
333727ad0b0SHugo Santos 
334727ad0b0SHugo Santos 	endpoint->SetActive(false);
335727ad0b0SHugo Santos 
336727ad0b0SHugo Santos 	return B_OK;
337727ad0b0SHugo Santos }
338727ad0b0SHugo Santos 
339727ad0b0SHugo Santos 
340cf5d9f4bSHugo Santos void
341cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
342cf5d9f4bSHugo Santos {
343cf5d9f4bSHugo Santos 	kprintf("-------- UDP Domain %p ---------\n", this);
344cf5d9f4bSHugo Santos 	kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
345cf5d9f4bSHugo Santos 
346cf5d9f4bSHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
347cf5d9f4bSHugo Santos 
348cf5d9f4bSHugo Santos 	while (it.HasNext()) {
349cf5d9f4bSHugo Santos 		UdpEndpoint *endpoint = it.Next();
350cf5d9f4bSHugo Santos 
351cf5d9f4bSHugo Santos 		char localBuf[64], peerBuf[64];
352cf5d9f4bSHugo Santos 		endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true);
353cf5d9f4bSHugo Santos 		endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true);
354cf5d9f4bSHugo Santos 
355cf5d9f4bSHugo Santos 		kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf,
356cf5d9f4bSHugo Santos 			endpoint->AvailableData());
357cf5d9f4bSHugo Santos 	}
358cf5d9f4bSHugo Santos }
359cf5d9f4bSHugo Santos 
360cf5d9f4bSHugo Santos 
361727ad0b0SHugo Santos status_t
362727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
363727ad0b0SHugo Santos 	const sockaddr *address)
364727ad0b0SHugo Santos {
365727ad0b0SHugo Santos 	if (AddressModule()->get_port(address) == 0)
366727ad0b0SHugo Santos 		return _BindToEphemeral(endpoint, address);
367727ad0b0SHugo Santos 
368727ad0b0SHugo Santos 	return _Bind(endpoint, address);
369727ad0b0SHugo Santos }
370727ad0b0SHugo Santos 
371727ad0b0SHugo Santos 
372727ad0b0SHugo Santos status_t
373727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
374727ad0b0SHugo Santos {
375727ad0b0SHugo Santos 	int socketOptions = endpoint->Socket()->options;
37640bbf860SHugo Santos 
37740bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
378bf48e753SHugo Santos 
379bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
380bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
381727ad0b0SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
382727ad0b0SHugo Santos 		address, true).Data());
383727ad0b0SHugo Santos 
38440bbf860SHugo Santos 	while (it.HasNext()) {
38540bbf860SHugo Santos 		UdpEndpoint *otherEndpoint = it.Next();
38625a2744fSHugo Santos 
387bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
3885084c839SHugo Santos 			ntohs(otherEndpoint->LocalAddress().Port()));
38925a2744fSHugo Santos 
39025a2744fSHugo Santos 		if (otherEndpoint->LocalAddress().EqualPorts(address)) {
391bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
392727ad0b0SHugo Santos 			if (otherEndpoint->Socket()->options & (SO_REUSEADDR | SO_REUSEPORT) == 0
393727ad0b0SHugo Santos 				|| socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0)
394727ad0b0SHugo Santos 				return EADDRINUSE;
39525a2744fSHugo Santos 
396bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
39725a2744fSHugo Santos 			if (otherEndpoint->LocalAddress().EqualTo(address, false)
398727ad0b0SHugo Santos 				&& (otherEndpoint->Socket()->options & SO_REUSEPORT == 0
399727ad0b0SHugo Santos 					|| socketOptions & SO_REUSEPORT == 0))
400727ad0b0SHugo Santos 				return EADDRINUSE;
401bf48e753SHugo Santos 		}
402bf48e753SHugo Santos 	}
403bf48e753SHugo Santos 
404727ad0b0SHugo Santos 	return _FinishBind(endpoint, address);
405bf48e753SHugo Santos }
406bf48e753SHugo Santos 
407bf48e753SHugo Santos 
408bf48e753SHugo Santos status_t
409727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
410727ad0b0SHugo Santos 	const sockaddr *address)
411727ad0b0SHugo Santos {
412727ad0b0SHugo Santos 	SocketAddressStorage newAddress(AddressModule());
413727ad0b0SHugo Santos 	status_t status = newAddress.SetTo(address);
414727ad0b0SHugo Santos 	if (status < B_OK)
415727ad0b0SHugo Santos 		return status;
416727ad0b0SHugo Santos 
417727ad0b0SHugo Santos 	uint16 allocedPort = _GetNextEphemeral();
418727ad0b0SHugo Santos 	if (allocedPort == 0)
419727ad0b0SHugo Santos 		return ENOBUFS;
420727ad0b0SHugo Santos 
421*9e051839SOliver Tappe 	newAddress.SetPort(htons(allocedPort));
422727ad0b0SHugo Santos 
423727ad0b0SHugo Santos 	return _FinishBind(endpoint, *newAddress);
424727ad0b0SHugo Santos }
425727ad0b0SHugo Santos 
426727ad0b0SHugo Santos 
427727ad0b0SHugo Santos status_t
428727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
429727ad0b0SHugo Santos {
430727ad0b0SHugo Santos 	status_t status = endpoint->next->module->bind(endpoint->next, address);
431727ad0b0SHugo Santos 	if (status < B_OK)
432727ad0b0SHugo Santos 		return status;
43340bbf860SHugo Santos 
43440bbf860SHugo Santos 	fActiveEndpoints.Insert(endpoint);
435727ad0b0SHugo Santos 	endpoint->SetActive(true);
436727ad0b0SHugo Santos 
43740bbf860SHugo Santos 	return B_OK;
438bf48e753SHugo Santos }
439bf48e753SHugo Santos 
440bf48e753SHugo Santos 
441c22d69bfSAxel Dörfler UdpEndpoint *
44240bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
44340bbf860SHugo Santos 	const sockaddr *peerAddress)
444c22d69bfSAxel Dörfler {
445*9e051839SOliver Tappe 	TRACE_DOMAIN("finding Endpoint for %s <- %s",
446bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
447bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
448c3e054c8SHugo Santos 
44940bbf860SHugo Santos 	return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress));
450c22d69bfSAxel Dörfler }
451c22d69bfSAxel Dörfler 
452c22d69bfSAxel Dörfler 
453c22d69bfSAxel Dörfler status_t
454bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer)
455c22d69bfSAxel Dörfler {
45679a0d252SHugo Santos 	sockaddr *peerAddr = buffer->source;
45779a0d252SHugo Santos 	sockaddr *broadcastAddr = buffer->destination;
458c22d69bfSAxel Dörfler 	sockaddr *mask = NULL;
459c22d69bfSAxel Dörfler 	if (buffer->interface)
460c22d69bfSAxel Dörfler 		mask = (sockaddr *)buffer->interface->mask;
461c22d69bfSAxel Dörfler 
462bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer);
463c22d69bfSAxel Dörfler 
464bf48e753SHugo Santos 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
465c22d69bfSAxel Dörfler 
46640bbf860SHugo Santos 	EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
46740bbf860SHugo Santos 
46840bbf860SHugo Santos 	while (it.HasNext()) {
46940bbf860SHugo Santos 		UdpEndpoint *endpoint = it.Next();
470c22d69bfSAxel Dörfler 
47125a2744fSHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
47225a2744fSHugo Santos 			AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
47325a2744fSHugo Santos 
4745084c839SHugo Santos 		if (endpoint->LocalAddress().Port() != incomingPort) {
475c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
476c22d69bfSAxel Dörfler 			continue;
477c22d69bfSAxel Dörfler 		}
478c22d69bfSAxel Dörfler 
47925a2744fSHugo Santos 		if (!endpoint->PeerAddress().IsEmpty(true)) {
480c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
481c22d69bfSAxel Dörfler 			// this datagram is from there:
48225a2744fSHugo Santos 			if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
483c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
484c22d69bfSAxel Dörfler 				// this endpoint...
485c22d69bfSAxel Dörfler 				continue;
486c22d69bfSAxel Dörfler 			}
487c22d69bfSAxel Dörfler 		}
488c22d69bfSAxel Dörfler 
48925a2744fSHugo Santos 		if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
49025a2744fSHugo Santos 			|| endpoint->LocalAddress().IsEmpty(false)) {
491c22d69bfSAxel Dörfler 			// address matches, dispatch to this endpoint:
492c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
493c22d69bfSAxel Dörfler 		}
494c22d69bfSAxel Dörfler 	}
49540bbf860SHugo Santos 
496c22d69bfSAxel Dörfler 	return B_OK;
497c22d69bfSAxel Dörfler }
498c22d69bfSAxel Dörfler 
499c22d69bfSAxel Dörfler 
500c22d69bfSAxel Dörfler status_t
501bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer *buffer)
502c22d69bfSAxel Dörfler {
50379a0d252SHugo Santos 	struct sockaddr *peerAddr = buffer->source;
50479a0d252SHugo Santos 	struct sockaddr *localAddr = buffer->destination;
505c22d69bfSAxel Dörfler 
506bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
507c22d69bfSAxel Dörfler 
508c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint;
509c22d69bfSAxel Dörfler 	// look for full (most special) match:
510bf48e753SHugo Santos 	endpoint = _FindActiveEndpoint(localAddr, peerAddr);
511c22d69bfSAxel Dörfler 	if (!endpoint) {
512c22d69bfSAxel Dörfler 		// look for endpoint matching local address & port:
513bf48e753SHugo Santos 		endpoint = _FindActiveEndpoint(localAddr, NULL);
514c22d69bfSAxel Dörfler 		if (!endpoint) {
515c22d69bfSAxel Dörfler 			// look for endpoint matching peer address & port and local port:
51625a2744fSHugo Santos 			SocketAddressStorage local(AddressModule());
51725a2744fSHugo Santos 			local.SetToEmpty();
51825a2744fSHugo Santos 			local.SetPort(AddressModule()->get_port(localAddr));
51925a2744fSHugo Santos 			endpoint = _FindActiveEndpoint(*local, peerAddr);
520c22d69bfSAxel Dörfler 			if (!endpoint) {
521c22d69bfSAxel Dörfler 				// last chance: look for endpoint matching local port only:
52225a2744fSHugo Santos 				endpoint = _FindActiveEndpoint(*local, NULL);
523c22d69bfSAxel Dörfler 			}
524c22d69bfSAxel Dörfler 		}
525c22d69bfSAxel Dörfler 	}
526bf48e753SHugo Santos 
527*9e051839SOliver Tappe 	if (!endpoint) {
528*9e051839SOliver Tappe 		TRACE_DOMAIN("_DemuxBroadcast(%p) - no matching endpoint found!", buffer);
529c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
530*9e051839SOliver Tappe 	}
531c22d69bfSAxel Dörfler 
532c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
533c22d69bfSAxel Dörfler 	return B_OK;
534c22d69bfSAxel Dörfler }
535c22d69bfSAxel Dörfler 
536c22d69bfSAxel Dörfler 
537bf48e753SHugo Santos uint16
538bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
539c22d69bfSAxel Dörfler {
54040bbf860SHugo Santos 	uint16 stop, curr;
541bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
542bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
543bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
544bf48e753SHugo Santos 	} else {
545bf48e753SHugo Santos 		stop = kLast;
546bf48e753SHugo Santos 		curr = kFirst;
547bf48e753SHugo Santos 	}
548c22d69bfSAxel Dörfler 
549727ad0b0SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
550727ad0b0SHugo Santos 		fLastUsedEphemeral, curr, stop);
55140bbf860SHugo Santos 
552*9e051839SOliver Tappe 	// TODO: a free list could be used to avoid the impact of these two
553*9e051839SOliver Tappe 	//        nested loops most of the time... let's see how bad this really is
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 {
5882b07b8e0SIngo Weinhold 	mutex_init(&fLock, "UDP endpoints");
5892b07b8e0SIngo Weinhold 	fStatus = B_OK;
590bf48e753SHugo Santos }
591bf48e753SHugo Santos 
592bf48e753SHugo Santos 
593bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
594bf48e753SHugo Santos {
5952b07b8e0SIngo Weinhold 	mutex_destroy(&fLock);
596bf48e753SHugo Santos }
597bf48e753SHugo Santos 
598bf48e753SHugo Santos 
599bf48e753SHugo Santos status_t
600bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
601bf48e753SHugo Santos {
602bf48e753SHugo Santos 	return fStatus;
603bf48e753SHugo Santos }
604bf48e753SHugo Santos 
605bf48e753SHugo Santos 
606cf5d9f4bSHugo Santos int
607cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
608cf5d9f4bSHugo Santos {
609cf5d9f4bSHugo Santos 	UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
610cf5d9f4bSHugo Santos 
611cf5d9f4bSHugo Santos 	while (it.HasNext())
612cf5d9f4bSHugo Santos 		it.Next()->DumpEndpoints();
613cf5d9f4bSHugo Santos 
614cf5d9f4bSHugo Santos 	return 0;
615cf5d9f4bSHugo Santos }
616cf5d9f4bSHugo Santos 
617cf5d9f4bSHugo Santos 
618bf48e753SHugo Santos // #pragma mark - inbound
619bf48e753SHugo Santos 
620bf48e753SHugo Santos 
621bf48e753SHugo Santos status_t
622c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer)
623c22d69bfSAxel Dörfler {
6246a606180SHugo Santos 	status_t status = Deframe(buffer);
6256a606180SHugo Santos 	if (status < B_OK)
6266a606180SHugo Santos 		return status;
6276a606180SHugo Santos 
628bf48e753SHugo Santos 	TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
629bf48e753SHugo Santos 
6306a606180SHugo Santos 	net_domain *domain = buffer->interface->domain;
6316a606180SHugo Santos 
632727ad0b0SHugo Santos 	UdpDomainSupport *domainSupport = NULL;
6336a606180SHugo Santos 
634727ad0b0SHugo Santos 	{
6352b07b8e0SIngo Weinhold 		MutexLocker _(fLock);
636727ad0b0SHugo Santos 		domainSupport = _GetDomain(domain, false);
637727ad0b0SHugo Santos 		// TODO we don't want to hold to the manager's lock
638727ad0b0SHugo Santos 		//      during the whole RX path, we may not hold an
639727ad0b0SHugo Santos 		//      endpoint's lock with the manager lock held.
640727ad0b0SHugo Santos 		//      But we should increase the domain's refcount
641727ad0b0SHugo Santos 		//      here.
642727ad0b0SHugo Santos 	}
643727ad0b0SHugo Santos 
6446a606180SHugo Santos 	if (domainSupport == NULL) {
6456a606180SHugo Santos 		// we don't instantiate domain supports in the
6466a606180SHugo Santos 		// RX path as we are only interested in delivering
6476a606180SHugo Santos 		// data to existing sockets.
6486a606180SHugo Santos 		return B_ERROR;
6496a606180SHugo Santos 	}
6506a606180SHugo Santos 
6516a606180SHugo Santos 	status = domainSupport->DemuxIncomingBuffer(buffer);
6526a606180SHugo Santos 	if (status < B_OK) {
6536a606180SHugo Santos 		TRACE_EPM("  ReceiveData(): no endpoint.");
6546a606180SHugo Santos 		// TODO: send ICMP-error
6556a606180SHugo Santos 		return B_ERROR;
6566a606180SHugo Santos 	}
6576a606180SHugo Santos 
658a1deb55eSHugo Santos 	gBufferModule->free(buffer);
659a1deb55eSHugo Santos 	return B_OK;
6606a606180SHugo Santos }
6616a606180SHugo Santos 
6626a606180SHugo Santos 
6636a606180SHugo Santos status_t
6646a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer)
6656a606180SHugo Santos {
6666a606180SHugo Santos 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
6676a606180SHugo Santos 
66887001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
669c22d69bfSAxel Dörfler 	if (bufferHeader.Status() < B_OK)
670c22d69bfSAxel Dörfler 		return bufferHeader.Status();
671c22d69bfSAxel Dörfler 
672c22d69bfSAxel Dörfler 	udp_header &header = bufferHeader.Data();
673c22d69bfSAxel Dörfler 
674bf48e753SHugo Santos 	if (buffer->interface == NULL || buffer->interface->domain == NULL) {
6756a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
676bf48e753SHugo Santos 			"specified (interface %p).", buffer->interface);
677c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
678c22d69bfSAxel Dörfler 	}
679bf48e753SHugo Santos 
680bf48e753SHugo Santos 	net_domain *domain = buffer->interface->domain;
681bf48e753SHugo Santos 	net_address_module_info *addressModule = domain->address_module;
682bf48e753SHugo Santos 
68379a0d252SHugo Santos 	SocketAddress source(addressModule, buffer->source);
68479a0d252SHugo Santos 	SocketAddress destination(addressModule, buffer->destination);
685bf48e753SHugo Santos 
6864e8a1b33SHugo Santos 	source.SetPort(header.source_port);
6874e8a1b33SHugo Santos 	destination.SetPort(header.destination_port);
6884e8a1b33SHugo Santos 
6894e8a1b33SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s", source.AsString(true).Data(),
6904e8a1b33SHugo Santos 		destination.AsString(true).Data());
691c22d69bfSAxel Dörfler 
692c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
693c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
6946a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
695bf48e753SHugo Santos 			udpLength);
696c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
697c22d69bfSAxel Dörfler 	}
698bf48e753SHugo Santos 
699bf48e753SHugo Santos 	if (buffer->size > udpLength)
700c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
701c22d69bfSAxel Dörfler 
702c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
703c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
704d5b5a2c2SHugo Santos 		uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
705d5b5a2c2SHugo Santos 			buffer, IPPROTO_UDP);
706c22d69bfSAxel Dörfler 		if (sum != 0) {
7076a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
708c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
709c22d69bfSAxel Dörfler 		}
710c22d69bfSAxel Dörfler 	}
711c22d69bfSAxel Dörfler 
712c22d69bfSAxel Dörfler 	bufferHeader.Remove();
713c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
714c22d69bfSAxel Dörfler 
7156a606180SHugo Santos 	return B_OK;
716c22d69bfSAxel Dörfler }
717c22d69bfSAxel Dörfler 
718c22d69bfSAxel Dörfler 
719bf48e753SHugo Santos UdpDomainSupport *
720c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
721c22d69bfSAxel Dörfler {
7222b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
723bf48e753SHugo Santos 
724bf48e753SHugo Santos 	UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true);
725bf48e753SHugo Santos 	if (domain)
726bf48e753SHugo Santos 		domain->Ref();
727bf48e753SHugo Santos 	return domain;
728bf48e753SHugo Santos }
729bf48e753SHugo Santos 
730bf48e753SHugo Santos 
731bf48e753SHugo Santos status_t
732bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
733bf48e753SHugo Santos {
7342b07b8e0SIngo Weinhold 	MutexLocker _(fLock);
735bf48e753SHugo Santos 
736727ad0b0SHugo Santos 	if (domain->Put()) {
737bf48e753SHugo Santos 		fDomains.Remove(domain);
738bf48e753SHugo Santos 		delete domain;
739bf48e753SHugo Santos 	}
740bf48e753SHugo Santos 
741bf48e753SHugo Santos 	return B_OK;
742bf48e753SHugo Santos }
743bf48e753SHugo Santos 
744bf48e753SHugo Santos 
745bf48e753SHugo Santos // #pragma mark -
746bf48e753SHugo Santos 
747bf48e753SHugo Santos 
748bf48e753SHugo Santos UdpDomainSupport *
749bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
750bf48e753SHugo Santos {
751bf48e753SHugo Santos 	UdpDomainList::Iterator it = fDomains.GetIterator();
752bf48e753SHugo Santos 
753bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
754bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
755bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
756bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
757bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
758bf48e753SHugo Santos 	//      family.
759bf48e753SHugo Santos 	while (it.HasNext()) {
760bf48e753SHugo Santos 		UdpDomainSupport *domainSupport = it.Next();
761bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
762bf48e753SHugo Santos 			return domainSupport;
763bf48e753SHugo Santos 	}
764bf48e753SHugo Santos 
765bf48e753SHugo Santos 	if (!create)
766bf48e753SHugo Santos 		return NULL;
767bf48e753SHugo Santos 
768bf48e753SHugo Santos 	UdpDomainSupport *domainSupport =
769bf48e753SHugo Santos 		new (std::nothrow) UdpDomainSupport(domain);
770276aa463SIngo Weinhold 	if (domainSupport == NULL || domainSupport->Init() < B_OK) {
771bf48e753SHugo Santos 		delete domainSupport;
772bf48e753SHugo Santos 		return NULL;
773bf48e753SHugo Santos 	}
774bf48e753SHugo Santos 
775bf48e753SHugo Santos 	fDomains.Add(domainSupport);
776bf48e753SHugo Santos 	return domainSupport;
777c22d69bfSAxel Dörfler }
778c22d69bfSAxel Dörfler 
779c22d69bfSAxel Dörfler 
780c22d69bfSAxel Dörfler // #pragma mark -
781c22d69bfSAxel Dörfler 
782c22d69bfSAxel Dörfler 
783c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
784c72ab92dSHugo Santos 	: DatagramSocket<>("udp endpoint", socket), fActive(false) {}
785bf48e753SHugo Santos 
786bf48e753SHugo Santos 
787c22d69bfSAxel Dörfler // #pragma mark - activation
788c22d69bfSAxel Dörfler 
789c22d69bfSAxel Dörfler 
790c22d69bfSAxel Dörfler status_t
79153f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
792c22d69bfSAxel Dörfler {
793bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
794727ad0b0SHugo Santos 	return fManager->BindEndpoint(this, address);
795c22d69bfSAxel Dörfler }
796c22d69bfSAxel Dörfler 
797c22d69bfSAxel Dörfler 
798c22d69bfSAxel Dörfler status_t
799c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
800c22d69bfSAxel Dörfler {
801bf48e753SHugo Santos 	TRACE_EP("Unbind()");
802727ad0b0SHugo Santos 	return fManager->UnbindEndpoint(this);
803c22d69bfSAxel Dörfler }
804c22d69bfSAxel Dörfler 
805c22d69bfSAxel Dörfler 
806c22d69bfSAxel Dörfler status_t
807c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
808c22d69bfSAxel Dörfler {
809bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
810727ad0b0SHugo Santos 	return fManager->ConnectEndpoint(this, address);
811c22d69bfSAxel Dörfler }
812c22d69bfSAxel Dörfler 
813c22d69bfSAxel Dörfler 
814c22d69bfSAxel Dörfler status_t
815c22d69bfSAxel Dörfler UdpEndpoint::Open()
816c22d69bfSAxel Dörfler {
817bf48e753SHugo Santos 	TRACE_EP("Open()");
818bf48e753SHugo Santos 
819119c6cddSIngo Weinhold 	AutoLocker _(fLock);
820727ad0b0SHugo Santos 
821c72ab92dSHugo Santos 	status_t status = ProtocolSocket::Open();
822c72ab92dSHugo Santos 	if (status < B_OK)
823c72ab92dSHugo Santos 		return status;
824bf48e753SHugo Santos 
825c72ab92dSHugo Santos 	fManager = sUdpEndpointManager->OpenEndpoint(this);
826c72ab92dSHugo Santos 	if (fManager == NULL)
827bf48e753SHugo Santos 		return EAFNOSUPPORT;
828bf48e753SHugo Santos 
829bf48e753SHugo Santos 	return B_OK;
830c22d69bfSAxel Dörfler }
831c22d69bfSAxel Dörfler 
832c22d69bfSAxel Dörfler 
833c22d69bfSAxel Dörfler status_t
834c22d69bfSAxel Dörfler UdpEndpoint::Close()
835c22d69bfSAxel Dörfler {
836bf48e753SHugo Santos 	TRACE_EP("Close()");
837bf48e753SHugo Santos 	return B_OK;
838c22d69bfSAxel Dörfler }
839c22d69bfSAxel Dörfler 
840c22d69bfSAxel Dörfler 
841c22d69bfSAxel Dörfler status_t
842c22d69bfSAxel Dörfler UdpEndpoint::Free()
843c22d69bfSAxel Dörfler {
844bf48e753SHugo Santos 	TRACE_EP("Free()");
8450086fe20SHugo Santos 	fManager->UnbindEndpoint(this);
846c72ab92dSHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fManager);
847c22d69bfSAxel Dörfler }
848c22d69bfSAxel Dörfler 
849c22d69bfSAxel Dörfler 
850c22d69bfSAxel Dörfler // #pragma mark - outbound
851c22d69bfSAxel Dörfler 
852c22d69bfSAxel Dörfler 
853c22d69bfSAxel Dörfler status_t
854bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
855c22d69bfSAxel Dörfler {
856bf48e753SHugo Santos 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
857bf48e753SHugo Santos 
858d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
859c22d69bfSAxel Dörfler 		return EMSGSIZE;
860c22d69bfSAxel Dörfler 
861c22d69bfSAxel Dörfler 	buffer->protocol = IPPROTO_UDP;
862c22d69bfSAxel Dörfler 
863c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
8646c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
8656c353509SHugo Santos 	if (header.Status() < B_OK)
8666c353509SHugo Santos 		return header.Status();
867c22d69bfSAxel Dörfler 
86879a0d252SHugo Santos 	header->source_port = AddressModule()->get_port(buffer->source);
86979a0d252SHugo Santos 	header->destination_port = AddressModule()->get_port(buffer->destination);
8706c353509SHugo Santos 	header->udp_length = htons(buffer->size);
871c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
8726c353509SHugo Santos 	header->udp_checksum = 0;
8736c353509SHugo Santos 
8746c353509SHugo Santos 	header.Sync();
875c22d69bfSAxel Dörfler 
876d5b5a2c2SHugo Santos 	uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
877d5b5a2c2SHugo Santos 		gBufferModule, buffer, IPPROTO_UDP);
8786c353509SHugo Santos 	if (calculatedChecksum == 0)
8796c353509SHugo Santos 		calculatedChecksum = 0xffff;
8806c353509SHugo Santos 
8816c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
882c22d69bfSAxel Dörfler 
883c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
884c22d69bfSAxel Dörfler }
885c22d69bfSAxel Dörfler 
886c22d69bfSAxel Dörfler 
887bf48e753SHugo Santos status_t
888bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
889bf48e753SHugo Santos {
890bf48e753SHugo Santos 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
891bf48e753SHugo Santos 
8921408d1f0SHugo Santos 	return gDatalinkModule->send_datagram(this, NULL, buffer);
893bf48e753SHugo Santos }
894bf48e753SHugo Santos 
895bf48e753SHugo Santos 
896c22d69bfSAxel Dörfler // #pragma mark - inbound
897c22d69bfSAxel Dörfler 
898c22d69bfSAxel Dörfler 
899c22d69bfSAxel Dörfler ssize_t
900c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
901c22d69bfSAxel Dörfler {
902bfb45f71SHugo Santos 	size_t bytes = AvailableData();
903bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
904bfb45f71SHugo Santos 	return bytes;
905c22d69bfSAxel Dörfler }
906c22d69bfSAxel Dörfler 
907c22d69bfSAxel Dörfler 
908c22d69bfSAxel Dörfler status_t
909c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
910c22d69bfSAxel Dörfler {
911bf48e753SHugo Santos 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
912bf48e753SHugo Santos 
913bfb45f71SHugo Santos 	status_t status = SocketDequeue(flags, _buffer);
914bf48e753SHugo Santos 	TRACE_EP("  FetchData(): returned from fifo status=0x%lx", status);
915c22d69bfSAxel Dörfler 	if (status < B_OK)
916c22d69bfSAxel Dörfler 		return status;
917c22d69bfSAxel Dörfler 
918bfb45f71SHugo Santos 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
919c22d69bfSAxel Dörfler 	return B_OK;
920c22d69bfSAxel Dörfler }
921c22d69bfSAxel Dörfler 
922c22d69bfSAxel Dörfler 
923c22d69bfSAxel Dörfler status_t
924bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
925c22d69bfSAxel Dörfler {
926bf48e753SHugo Santos 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
927c22d69bfSAxel Dörfler 
92849f3c71eSHugo Santos 	return SocketEnqueue(buffer);
929c22d69bfSAxel Dörfler }
930c22d69bfSAxel Dörfler 
931c22d69bfSAxel Dörfler 
9326a606180SHugo Santos status_t
9336a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
9346a606180SHugo Santos {
935f6cfc5afSHugo Santos 	TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size);
936f6cfc5afSHugo Santos 
9376a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
9386a606180SHugo Santos 	if (buffer == NULL)
9396a606180SHugo Santos 		return B_NO_MEMORY;
9406a606180SHugo Santos 
9416a606180SHugo Santos 	status_t status = sUdpEndpointManager->Deframe(buffer);
9426a606180SHugo Santos 	if (status < B_OK) {
9436a606180SHugo Santos 		gBufferModule->free(buffer);
9446a606180SHugo Santos 		return status;
9456a606180SHugo Santos 	}
9466a606180SHugo Santos 
9476a606180SHugo Santos 	// we call Enqueue() instead of SocketEnqueue() as there is
9486a606180SHugo Santos 	// no need to clone the buffer again.
9496a606180SHugo Santos 	return Enqueue(buffer);
9506a606180SHugo Santos }
9516a606180SHugo Santos 
9526a606180SHugo Santos 
953c22d69bfSAxel Dörfler // #pragma mark - protocol interface
954c22d69bfSAxel Dörfler 
955c22d69bfSAxel Dörfler 
956c22d69bfSAxel Dörfler net_protocol *
957c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
958c22d69bfSAxel Dörfler {
959c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
960c22d69bfSAxel Dörfler 
961c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
962bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
963bf48e753SHugo Santos 		delete endpoint;
964bf48e753SHugo Santos 		return NULL;
965bf48e753SHugo Santos 	}
966bf48e753SHugo Santos 
967c22d69bfSAxel Dörfler 	return endpoint;
968c22d69bfSAxel Dörfler }
969c22d69bfSAxel Dörfler 
970c22d69bfSAxel Dörfler 
971c22d69bfSAxel Dörfler status_t
972c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
973c22d69bfSAxel Dörfler {
974bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
975c22d69bfSAxel Dörfler 	return B_OK;
976c22d69bfSAxel Dörfler }
977c22d69bfSAxel Dörfler 
978c22d69bfSAxel Dörfler 
979c22d69bfSAxel Dörfler status_t
980c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
981c22d69bfSAxel Dörfler {
982bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
983c22d69bfSAxel Dörfler }
984c22d69bfSAxel Dörfler 
985c22d69bfSAxel Dörfler 
986c22d69bfSAxel Dörfler status_t
987c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
988c22d69bfSAxel Dörfler {
989bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
990c22d69bfSAxel Dörfler }
991c22d69bfSAxel Dörfler 
992c22d69bfSAxel Dörfler 
993c22d69bfSAxel Dörfler status_t
994c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
995c22d69bfSAxel Dörfler {
996bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
997c22d69bfSAxel Dörfler }
998c22d69bfSAxel Dörfler 
999c22d69bfSAxel Dörfler 
1000c22d69bfSAxel Dörfler status_t
1001c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1002c22d69bfSAxel Dörfler {
1003bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1004c22d69bfSAxel Dörfler }
1005c22d69bfSAxel Dörfler 
1006c22d69bfSAxel Dörfler 
1007c22d69bfSAxel Dörfler status_t
1008c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1009c22d69bfSAxel Dörfler {
1010c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1011c22d69bfSAxel Dörfler }
1012c22d69bfSAxel Dörfler 
1013c22d69bfSAxel Dörfler 
1014c22d69bfSAxel Dörfler status_t
1015c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1016c22d69bfSAxel Dörfler 	size_t *_length)
1017c22d69bfSAxel Dörfler {
1018c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1019c22d69bfSAxel Dörfler 		value, _length);
1020c22d69bfSAxel Dörfler }
1021c22d69bfSAxel Dörfler 
1022c22d69bfSAxel Dörfler 
1023c22d69bfSAxel Dörfler status_t
102445b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
102545b5203bSHugo Santos 	int *length)
102645b5203bSHugo Santos {
102745b5203bSHugo Santos 	return protocol->next->module->getsockopt(protocol->next, level, option,
102845b5203bSHugo Santos 		value, length);
102945b5203bSHugo Santos }
103045b5203bSHugo Santos 
103145b5203bSHugo Santos 
103245b5203bSHugo Santos status_t
103345b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
103445b5203bSHugo Santos 	const void *value, int length)
103545b5203bSHugo Santos {
103645b5203bSHugo Santos 	return protocol->next->module->setsockopt(protocol->next, level, option,
103745b5203bSHugo Santos 		value, length);
103845b5203bSHugo Santos }
103945b5203bSHugo Santos 
104045b5203bSHugo Santos 
104145b5203bSHugo Santos status_t
104253f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1043c22d69bfSAxel Dörfler {
1044bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1045c22d69bfSAxel Dörfler }
1046c22d69bfSAxel Dörfler 
1047c22d69bfSAxel Dörfler 
1048c22d69bfSAxel Dörfler status_t
1049c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1050c22d69bfSAxel Dörfler {
1051bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1052c22d69bfSAxel Dörfler }
1053c22d69bfSAxel Dörfler 
1054c22d69bfSAxel Dörfler 
1055c22d69bfSAxel Dörfler status_t
1056c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1057c22d69bfSAxel Dörfler {
1058c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1059c22d69bfSAxel Dörfler }
1060c22d69bfSAxel Dörfler 
1061c22d69bfSAxel Dörfler 
1062c22d69bfSAxel Dörfler status_t
1063c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1064c22d69bfSAxel Dörfler {
1065c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1066c22d69bfSAxel Dörfler }
1067c22d69bfSAxel Dörfler 
1068c22d69bfSAxel Dörfler 
1069c22d69bfSAxel Dörfler status_t
1070c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1071c22d69bfSAxel Dörfler 	net_buffer *buffer)
1072c22d69bfSAxel Dörfler {
1073bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1074c22d69bfSAxel Dörfler }
1075c22d69bfSAxel Dörfler 
1076c22d69bfSAxel Dörfler 
1077c22d69bfSAxel Dörfler status_t
1078c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1079c22d69bfSAxel Dörfler {
1080bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1081c22d69bfSAxel Dörfler }
1082c22d69bfSAxel Dörfler 
1083c22d69bfSAxel Dörfler 
1084c22d69bfSAxel Dörfler ssize_t
1085c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1086c22d69bfSAxel Dörfler {
1087bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1088c22d69bfSAxel Dörfler }
1089c22d69bfSAxel Dörfler 
1090c22d69bfSAxel Dörfler 
1091c22d69bfSAxel Dörfler status_t
1092c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1093c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1094c22d69bfSAxel Dörfler {
1095bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1096c22d69bfSAxel Dörfler }
1097c22d69bfSAxel Dörfler 
1098c22d69bfSAxel Dörfler 
1099c22d69bfSAxel Dörfler ssize_t
1100c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1101c22d69bfSAxel Dörfler {
1102bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1103c22d69bfSAxel Dörfler }
1104c22d69bfSAxel Dörfler 
1105c22d69bfSAxel Dörfler 
1106c22d69bfSAxel Dörfler struct net_domain *
1107c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1108c22d69bfSAxel Dörfler {
1109c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1110c22d69bfSAxel Dörfler }
1111c22d69bfSAxel Dörfler 
1112c22d69bfSAxel Dörfler 
1113c22d69bfSAxel Dörfler size_t
1114c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1115c22d69bfSAxel Dörfler {
1116c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1117c22d69bfSAxel Dörfler }
1118c22d69bfSAxel Dörfler 
1119c22d69bfSAxel Dörfler 
1120c22d69bfSAxel Dörfler status_t
1121c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1122c22d69bfSAxel Dörfler {
1123c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1124c22d69bfSAxel Dörfler }
1125c22d69bfSAxel Dörfler 
1126c22d69bfSAxel Dörfler 
1127c22d69bfSAxel Dörfler status_t
11286a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
11296a606180SHugo Santos {
11306a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
11316a606180SHugo Santos }
11326a606180SHugo Santos 
11336a606180SHugo Santos 
11346a606180SHugo Santos status_t
1135c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data)
1136c22d69bfSAxel Dörfler {
1137c22d69bfSAxel Dörfler 	return B_ERROR;
1138c22d69bfSAxel Dörfler }
1139c22d69bfSAxel Dörfler 
1140c22d69bfSAxel Dörfler 
1141c22d69bfSAxel Dörfler status_t
1142c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
1143c22d69bfSAxel Dörfler 	void *errorData)
1144c22d69bfSAxel Dörfler {
1145c22d69bfSAxel Dörfler 	return B_ERROR;
1146c22d69bfSAxel Dörfler }
1147c22d69bfSAxel Dörfler 
1148c22d69bfSAxel Dörfler 
1149c22d69bfSAxel Dörfler //	#pragma mark - module interface
1150c22d69bfSAxel Dörfler 
1151c22d69bfSAxel Dörfler 
1152c22d69bfSAxel Dörfler static status_t
1153c22d69bfSAxel Dörfler init_udp()
1154c22d69bfSAxel Dörfler {
1155c22d69bfSAxel Dörfler 	status_t status;
1156bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1157c22d69bfSAxel Dörfler 
1158c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1159658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1160658a5506SHugo Santos 		return B_NO_MEMORY;
1161658a5506SHugo Santos 
1162c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1163c22d69bfSAxel Dörfler 	if (status != B_OK)
1164d438fa4cSHugo Santos 		goto err1;
1165c22d69bfSAxel Dörfler 
1166bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP,
1167c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1168c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1169c22d69bfSAxel Dörfler 		NULL);
1170c22d69bfSAxel Dörfler 	if (status < B_OK)
1171658a5506SHugo Santos 		goto err1;
1172bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
1173c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1174c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1175c22d69bfSAxel Dörfler 		NULL);
1176c22d69bfSAxel Dörfler 	if (status < B_OK)
1177658a5506SHugo Santos 		goto err1;
1178c22d69bfSAxel Dörfler 
1179bfb45f71SHugo Santos 	status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
1180c22d69bfSAxel Dörfler 		"network/protocols/udp/v1");
1181c22d69bfSAxel Dörfler 	if (status < B_OK)
1182658a5506SHugo Santos 		goto err1;
1183c22d69bfSAxel Dörfler 
1184cf5d9f4bSHugo Santos 	add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1185cf5d9f4bSHugo Santos 		"lists all open UDP endpoints");
1186cf5d9f4bSHugo Santos 
1187c22d69bfSAxel Dörfler 	return B_OK;
1188c22d69bfSAxel Dörfler 
1189c22d69bfSAxel Dörfler err1:
1190658a5506SHugo Santos 	delete sUdpEndpointManager;
1191c22d69bfSAxel Dörfler 
1192bf48e753SHugo Santos 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1193c22d69bfSAxel Dörfler 	return status;
1194c22d69bfSAxel Dörfler }
1195c22d69bfSAxel Dörfler 
1196c22d69bfSAxel Dörfler 
1197c22d69bfSAxel Dörfler static status_t
1198c22d69bfSAxel Dörfler uninit_udp()
1199c22d69bfSAxel Dörfler {
1200bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1201cf5d9f4bSHugo Santos 	remove_debugger_command("udp_endpoints",
1202cf5d9f4bSHugo Santos 		UdpEndpointManager::DumpEndpoints);
1203c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1204c22d69bfSAxel Dörfler 	return B_OK;
1205c22d69bfSAxel Dörfler }
1206c22d69bfSAxel Dörfler 
1207c22d69bfSAxel Dörfler 
1208c22d69bfSAxel Dörfler static status_t
1209c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1210c22d69bfSAxel Dörfler {
1211c22d69bfSAxel Dörfler 	switch (op) {
1212c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1213c22d69bfSAxel Dörfler 			return init_udp();
1214c22d69bfSAxel Dörfler 
1215c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1216c22d69bfSAxel Dörfler 			return uninit_udp();
1217c22d69bfSAxel Dörfler 
1218c22d69bfSAxel Dörfler 		default:
1219c22d69bfSAxel Dörfler 			return B_ERROR;
1220c22d69bfSAxel Dörfler 	}
1221c22d69bfSAxel Dörfler }
1222c22d69bfSAxel Dörfler 
1223c22d69bfSAxel Dörfler 
1224c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1225c22d69bfSAxel Dörfler 	{
1226c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1227c22d69bfSAxel Dörfler 		0,
1228c22d69bfSAxel Dörfler 		udp_std_ops
1229c22d69bfSAxel Dörfler 	},
12306f58064fSAxel Dörfler 	NET_PROTOCOL_ATOMIC_MESSAGES,
12316f58064fSAxel Dörfler 
1232c22d69bfSAxel Dörfler 	udp_init_protocol,
1233c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1234c22d69bfSAxel Dörfler 	udp_open,
1235c22d69bfSAxel Dörfler 	udp_close,
1236c22d69bfSAxel Dörfler 	udp_free,
1237c22d69bfSAxel Dörfler 	udp_connect,
1238c22d69bfSAxel Dörfler 	udp_accept,
1239c22d69bfSAxel Dörfler 	udp_control,
124045b5203bSHugo Santos 	udp_getsockopt,
124145b5203bSHugo Santos 	udp_setsockopt,
1242c22d69bfSAxel Dörfler 	udp_bind,
1243c22d69bfSAxel Dörfler 	udp_unbind,
1244c22d69bfSAxel Dörfler 	udp_listen,
1245c22d69bfSAxel Dörfler 	udp_shutdown,
1246c22d69bfSAxel Dörfler 	udp_send_data,
1247c22d69bfSAxel Dörfler 	udp_send_routed_data,
1248c22d69bfSAxel Dörfler 	udp_send_avail,
1249c22d69bfSAxel Dörfler 	udp_read_data,
1250c22d69bfSAxel Dörfler 	udp_read_avail,
1251c22d69bfSAxel Dörfler 	udp_get_domain,
1252c22d69bfSAxel Dörfler 	udp_get_mtu,
1253c22d69bfSAxel Dörfler 	udp_receive_data,
12546a606180SHugo Santos 	udp_deliver_data,
1255c22d69bfSAxel Dörfler 	udp_error,
1256c22d69bfSAxel Dörfler 	udp_error_reply,
1257c22d69bfSAxel Dörfler };
1258c22d69bfSAxel Dörfler 
1259658a5506SHugo Santos module_dependency module_dependencies[] = {
1260658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1261658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1262658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1263658a5506SHugo Santos 	{}
1264658a5506SHugo Santos };
1265658a5506SHugo Santos 
1266c22d69bfSAxel Dörfler module_info *modules[] = {
1267c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1268c22d69bfSAxel Dörfler 	NULL
1269c22d69bfSAxel Dörfler };
1270