xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision bfb45f717c648c5cd68e84c8ca1f805d099ba3c5)
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>
19c22d69bfSAxel Dörfler #include <util/khash.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>
25*bfb45f71SHugo 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 
33af3a31f7SAxel Dörfler //#define TRACE_UDP
34c22d69bfSAxel Dörfler #ifdef TRACE_UDP
35c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x) dump_block x
36bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this
37bf48e753SHugo Santos // to compile with gcc 2.95
38bf48e753SHugo Santos #	define TRACE_EP(format, args...)	dprintf("UDP [%llu] %p " format "\n", \
39bf48e753SHugo Santos 		system_time(), this , ##args)
40bf48e753SHugo Santos #	define TRACE_EPM(format, args...)	dprintf("UDP [%llu] " format "\n", \
41bf48e753SHugo Santos 		system_time() , ##args)
42bf48e753SHugo Santos #	define TRACE_DOMAIN(format, args...)	dprintf("UDP [%llu] (%d) " format \
43bf48e753SHugo Santos 		"\n", system_time(), Domain()->family , ##args)
44c22d69bfSAxel Dörfler #else
45c22d69bfSAxel Dörfler #	define TRACE_BLOCK(x)
46bf48e753SHugo Santos #	define TRACE_EP(args...)	do { } while (0)
47bf48e753SHugo Santos #	define TRACE_EPM(args...)	do { } while (0)
48bf48e753SHugo Santos #	define TRACE_DOMAIN(args...)	do { } while (0)
49c22d69bfSAxel Dörfler #endif
50c22d69bfSAxel Dörfler 
51c22d69bfSAxel Dörfler 
52c22d69bfSAxel Dörfler struct udp_header {
53c22d69bfSAxel Dörfler 	uint16 source_port;
54c22d69bfSAxel Dörfler 	uint16 destination_port;
55c22d69bfSAxel Dörfler 	uint16 udp_length;
56c22d69bfSAxel Dörfler 	uint16 udp_checksum;
57c22d69bfSAxel Dörfler } _PACKED;
58c22d69bfSAxel Dörfler 
59c22d69bfSAxel Dörfler 
606c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
616c353509SHugo Santos 	UDPChecksumField;
626c353509SHugo Santos 
63bf48e753SHugo Santos class UdpDomainSupport;
646c353509SHugo Santos 
65*bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> {
66c22d69bfSAxel Dörfler public:
67c22d69bfSAxel Dörfler 	UdpEndpoint(net_socket *socket);
68bf48e753SHugo Santos 
69c22d69bfSAxel Dörfler 	status_t				Bind(sockaddr *newAddr);
70c22d69bfSAxel Dörfler 	status_t				Unbind(sockaddr *newAddr);
71c22d69bfSAxel Dörfler 	status_t				Connect(const sockaddr *newAddr);
72c22d69bfSAxel Dörfler 
73c22d69bfSAxel Dörfler 	status_t				Open();
74c22d69bfSAxel Dörfler 	status_t				Close();
75c22d69bfSAxel Dörfler 	status_t				Free();
76c22d69bfSAxel Dörfler 
77bf48e753SHugo Santos 	status_t				SendRoutedData(net_buffer *buffer, net_route *route);
78bf48e753SHugo Santos 	status_t				SendData(net_buffer *buffer);
79c22d69bfSAxel Dörfler 
80c22d69bfSAxel Dörfler 	ssize_t					BytesAvailable();
81c22d69bfSAxel Dörfler 	status_t				FetchData(size_t numBytes, uint32 flags,
82c22d69bfSAxel Dörfler 								net_buffer **_buffer);
83c22d69bfSAxel Dörfler 
84c22d69bfSAxel Dörfler 	status_t				StoreData(net_buffer *buffer);
85c22d69bfSAxel Dörfler 
86bf48e753SHugo Santos 	net_domain *			Domain() const
87bf48e753SHugo Santos 	{
88bf48e753SHugo Santos 		return socket->first_protocol->module->get_domain(socket->first_protocol);
89bf48e753SHugo Santos 	}
90bf48e753SHugo Santos 
91bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
92bf48e753SHugo Santos 	{
93bf48e753SHugo Santos 		return Domain()->address_module;
94bf48e753SHugo Santos 	}
95bf48e753SHugo Santos 
96bf48e753SHugo Santos 	UdpDomainSupport		*DomainSupport() const { return fDomain; }
97bf48e753SHugo Santos 
98c22d69bfSAxel Dörfler 	UdpEndpoint				*hash_link;
99c22d69bfSAxel Dörfler 								// link required by hash_table (see khash.h)
100c22d69bfSAxel Dörfler private:
101c22d69bfSAxel Dörfler 	status_t				_Activate();
102c22d69bfSAxel Dörfler 	status_t				_Deactivate();
103c22d69bfSAxel Dörfler 
104bf48e753SHugo Santos 	UdpDomainSupport		*fDomain;
105c22d69bfSAxel Dörfler 	bool					fActive;
106c22d69bfSAxel Dörfler 								// an active UdpEndpoint is part of the endpoint
107c22d69bfSAxel Dörfler 								// hash (and it is bound and optionally connected)
108c22d69bfSAxel Dörfler };
109c22d69bfSAxel Dörfler 
110c22d69bfSAxel Dörfler 
111bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
112c22d69bfSAxel Dörfler public:
113bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
114bf48e753SHugo Santos 	~UdpDomainSupport();
115c22d69bfSAxel Dörfler 
116bf48e753SHugo Santos 	status_t InitCheck() const;
117bf48e753SHugo Santos 
118bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
119bf48e753SHugo Santos 
120bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
121bf48e753SHugo Santos 	void Put() { fEndpointCount--; }
122bf48e753SHugo Santos 
123bf48e753SHugo Santos 	bool IsEmpty() const { return fEndpointCount == 0; }
124bf48e753SHugo Santos 
125bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer *buffer);
126bf48e753SHugo Santos 	status_t CheckBindRequest(sockaddr *address, int socketOptions);
127bf48e753SHugo Santos 	status_t ActivateEndpoint(UdpEndpoint *endpoint);
128bf48e753SHugo Santos 	status_t DeactivateEndpoint(UdpEndpoint *endpoint);
129bf48e753SHugo Santos 
130bf48e753SHugo Santos 	uint16 GetEphemeralPort();
131bf48e753SHugo Santos 
132c22d69bfSAxel Dörfler private:
133bf48e753SHugo Santos 	struct HashKey {
134bf48e753SHugo Santos 		HashKey() {}
135bf48e753SHugo Santos 		HashKey(net_address_module_info *module, const sockaddr *_local,
136bf48e753SHugo Santos 			const sockaddr *_peer)
137bf48e753SHugo Santos 			: address_module(module), local(_local), peer(_peer) {}
138bf48e753SHugo Santos 
139bf48e753SHugo Santos 		net_address_module_info *address_module;
140bf48e753SHugo Santos 		const sockaddr *local;
141bf48e753SHugo Santos 		const sockaddr *peer;
142c22d69bfSAxel Dörfler 	};
143c22d69bfSAxel Dörfler 
144bf48e753SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(sockaddr *ourAddress,
145bf48e753SHugo Santos 		sockaddr *peerAddress);
146bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
147bf48e753SHugo Santos 	status_t _DemuxMulticast(net_buffer *buffer);
148bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
149bf48e753SHugo Santos 
150bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
151bf48e753SHugo Santos 
152bf48e753SHugo Santos 	static int _Compare(void *udpEndpoint, const void *_key);
153bf48e753SHugo Santos 	static uint32 _Hash(void *udpEndpoint, const void *key, uint32 range);
154bf48e753SHugo Santos 
155bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
156bf48e753SHugo Santos 	{
157bf48e753SHugo Santos 		return fDomain->address_module;
158bf48e753SHugo Santos 	}
159bf48e753SHugo Santos 
160bf48e753SHugo Santos 	net_domain		*fDomain;
161bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
162bf48e753SHugo Santos 	hash_table		*fActiveEndpoints;
163bf48e753SHugo Santos 	uint32			fEndpointCount;
164bf48e753SHugo Santos 
165bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
166bf48e753SHugo Santos 	static const uint16		kLast = 65535;
167bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
168bf48e753SHugo Santos 							// if you change this, adjust the shifting in
169bf48e753SHugo Santos 							// Hash() accordingly!
170bf48e753SHugo Santos };
171bf48e753SHugo Santos 
172bf48e753SHugo Santos 
173bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
174bf48e753SHugo Santos 
175bf48e753SHugo Santos 
176bf48e753SHugo Santos class UdpEndpointManager {
177c22d69bfSAxel Dörfler public:
178c22d69bfSAxel Dörfler 	UdpEndpointManager();
179c22d69bfSAxel Dörfler 	~UdpEndpointManager();
180c22d69bfSAxel Dörfler 
181bf48e753SHugo Santos 	status_t		DemuxIncomingBuffer(net_domain *domain,
182bf48e753SHugo Santos 		net_buffer *buffer);
183c22d69bfSAxel Dörfler 	status_t		ReceiveData(net_buffer *buffer);
184c22d69bfSAxel Dörfler 
185bf48e753SHugo Santos 	UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
186bf48e753SHugo Santos 	status_t FreeEndpoint(UdpDomainSupport *domain);
187c22d69bfSAxel Dörfler 
188c22d69bfSAxel Dörfler 	uint16			GetEphemeralPort();
189c22d69bfSAxel Dörfler 
190bf48e753SHugo Santos 	benaphore		*Locker() { return &fLock; }
191c22d69bfSAxel Dörfler 	status_t		InitCheck() const;
192bf48e753SHugo Santos 
193c22d69bfSAxel Dörfler private:
194bf48e753SHugo Santos 	UdpDomainSupport *_GetDomain(net_domain *domain, bool create);
195bf48e753SHugo Santos 
196c22d69bfSAxel Dörfler 	benaphore		fLock;
197c22d69bfSAxel Dörfler 	status_t		fStatus;
198bf48e753SHugo Santos 	UdpDomainList	fDomains;
199c22d69bfSAxel Dörfler };
200c22d69bfSAxel Dörfler 
201c22d69bfSAxel Dörfler 
202c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
203c22d69bfSAxel Dörfler 
204*bfb45f71SHugo Santos net_stack_module_info *gStackModule;
205c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
206c22d69bfSAxel Dörfler static net_datalink_module_info *sDatalinkModule;
207c22d69bfSAxel Dörfler 
208c22d69bfSAxel Dörfler 
209c22d69bfSAxel Dörfler // #pragma mark -
210c22d69bfSAxel Dörfler 
211c22d69bfSAxel Dörfler 
212bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
213c22d69bfSAxel Dörfler 	:
214bf48e753SHugo Santos 	fDomain(domain),
215bf48e753SHugo Santos 	fLastUsedEphemeral(kLast),
216bf48e753SHugo Santos 	fEndpointCount(0)
217c22d69bfSAxel Dörfler {
218bf48e753SHugo Santos 	fActiveEndpoints = hash_init(kNumHashBuckets, offsetof(UdpEndpoint, hash_link),
219bf48e753SHugo Santos 		&_Compare, &_Hash);
220c22d69bfSAxel Dörfler }
221c22d69bfSAxel Dörfler 
222c22d69bfSAxel Dörfler 
223bf48e753SHugo Santos UdpDomainSupport::~UdpDomainSupport()
224c22d69bfSAxel Dörfler {
225bf48e753SHugo Santos 	if (fActiveEndpoints)
226bf48e753SHugo Santos 		hash_uninit(fActiveEndpoints);
227bf48e753SHugo Santos }
228bf48e753SHugo Santos 
229bf48e753SHugo Santos 
230bf48e753SHugo Santos status_t
231bf48e753SHugo Santos UdpDomainSupport::InitCheck() const
232bf48e753SHugo Santos {
233bf48e753SHugo Santos 	return fActiveEndpoints ? B_OK : B_NO_MEMORY;
234bf48e753SHugo Santos }
235bf48e753SHugo Santos 
236bf48e753SHugo Santos 
237bf48e753SHugo Santos status_t
238bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
239bf48e753SHugo Santos {
240bf48e753SHugo Santos 	if (buffer->flags & MSG_BCAST)
241bf48e753SHugo Santos 		return _DemuxBroadcast(buffer);
242bf48e753SHugo Santos 	else if (buffer->flags & MSG_MCAST)
243bf48e753SHugo Santos 		return _DemuxMulticast(buffer);
244bf48e753SHugo Santos 
245bf48e753SHugo Santos 	return _DemuxUnicast(buffer);
246bf48e753SHugo Santos }
247bf48e753SHugo Santos 
248bf48e753SHugo Santos 
249bf48e753SHugo Santos status_t
250bf48e753SHugo Santos UdpDomainSupport::CheckBindRequest(sockaddr *address, int socketOptions)
251bf48e753SHugo Santos {		// sUdpEndpointManager->Locker() must be locked!
252bf48e753SHugo Santos 	status_t status = B_OK;
253bf48e753SHugo Santos 	UdpEndpoint *otherEndpoint;
254bf48e753SHugo Santos 	sockaddr *otherAddr;
255bf48e753SHugo Santos 	struct hash_iterator endpointIterator;
256bf48e753SHugo Santos 
257bf48e753SHugo Santos 	// Iterate over all active UDP-endpoints and check if the requested bind
258bf48e753SHugo Santos 	// is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
259bf48e753SHugo Santos 	hash_open(fActiveEndpoints, &endpointIterator);
260bf48e753SHugo Santos 	TRACE_DOMAIN("CheckBindRequest() for %s...",
261bf48e753SHugo Santos 		AddressString(fDomain, address, true).Data());
262bf48e753SHugo Santos 	while(1) {
263bf48e753SHugo Santos 		otherEndpoint = (UdpEndpoint *)hash_next(fActiveEndpoints, &endpointIterator);
264bf48e753SHugo Santos 		if (!otherEndpoint)
265bf48e753SHugo Santos 			break;
266bf48e753SHugo Santos 		otherAddr = (sockaddr *)&otherEndpoint->socket->address;
267bf48e753SHugo Santos 		TRACE_DOMAIN("  ...checking endpoint %p (port=%u)...", otherEndpoint,
268bf48e753SHugo Santos 			ntohs(AddressModule()->get_port(otherAddr)));
269bf48e753SHugo Santos 		if (AddressModule()->equal_ports(otherAddr, address)) {
270bf48e753SHugo Santos 			// port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
271bf48e753SHugo Santos 			if (otherEndpoint->socket->options & (SO_REUSEADDR | SO_REUSEPORT) == 0
272bf48e753SHugo Santos 				|| socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0) {
273bf48e753SHugo Santos 				status = EADDRINUSE;
274bf48e753SHugo Santos 				break;
275bf48e753SHugo Santos 			}
276bf48e753SHugo Santos 			// if both addresses are the same, SO_REUSEPORT is required:
277bf48e753SHugo Santos 			if (AddressModule()->equal_addresses(otherAddr, address)
278bf48e753SHugo Santos 				&& (otherEndpoint->socket->options & SO_REUSEPORT == 0
279bf48e753SHugo Santos 					|| socketOptions & SO_REUSEPORT == 0)) {
280bf48e753SHugo Santos 				status = EADDRINUSE;
281bf48e753SHugo Santos 				break;
282bf48e753SHugo Santos 			}
283bf48e753SHugo Santos 		}
284bf48e753SHugo Santos 	}
285bf48e753SHugo Santos 	hash_close(fActiveEndpoints, &endpointIterator, false);
286bf48e753SHugo Santos 
287bf48e753SHugo Santos 	TRACE_DOMAIN("  CheckBindRequest done (status=%lx)", status);
288bf48e753SHugo Santos 	return status;
289bf48e753SHugo Santos }
290bf48e753SHugo Santos 
291bf48e753SHugo Santos 
292bf48e753SHugo Santos status_t
293bf48e753SHugo Santos UdpDomainSupport::ActivateEndpoint(UdpEndpoint *endpoint)
294bf48e753SHugo Santos {		// sUdpEndpointManager->Locker() must be locked!
295bf48e753SHugo Santos 	TRACE_DOMAIN("Endpoint(%s) was activated",
296bf48e753SHugo Santos 		AddressString(fDomain, (sockaddr *)&endpoint->socket->address, true).Data());
297bf48e753SHugo Santos 	return hash_insert(fActiveEndpoints, endpoint);
298bf48e753SHugo Santos }
299bf48e753SHugo Santos 
300bf48e753SHugo Santos 
301bf48e753SHugo Santos status_t
302bf48e753SHugo Santos UdpDomainSupport::DeactivateEndpoint(UdpEndpoint *endpoint)
303bf48e753SHugo Santos {		// sUdpEndpointManager->Locker() must be locked!
304bf48e753SHugo Santos 	TRACE_DOMAIN("Endpoint(%s) was deactivated",
305bf48e753SHugo Santos 		AddressString(fDomain, (sockaddr *)&endpoint->socket->address, true).Data());
306bf48e753SHugo Santos 	return hash_remove(fActiveEndpoints, endpoint);
307c22d69bfSAxel Dörfler }
308c22d69bfSAxel Dörfler 
309c22d69bfSAxel Dörfler 
310c22d69bfSAxel Dörfler uint16
311bf48e753SHugo Santos UdpDomainSupport::GetEphemeralPort()
312c22d69bfSAxel Dörfler {
313bf48e753SHugo Santos 	return _GetNextEphemeral();
314c22d69bfSAxel Dörfler }
315c22d69bfSAxel Dörfler 
316c22d69bfSAxel Dörfler 
317c22d69bfSAxel Dörfler UdpEndpoint *
318bf48e753SHugo Santos UdpDomainSupport::_FindActiveEndpoint(sockaddr *ourAddress,
319c22d69bfSAxel Dörfler 	sockaddr *peerAddress)
320c22d69bfSAxel Dörfler {
321bf48e753SHugo Santos 	TRACE_DOMAIN("finding Endpoint for %s -> %s",
322bf48e753SHugo Santos 		AddressString(fDomain, ourAddress, true).Data(),
323bf48e753SHugo Santos 		AddressString(fDomain, peerAddress, true).Data());
324c3e054c8SHugo Santos 
325bf48e753SHugo Santos 	HashKey key(AddressModule(), ourAddress, peerAddress);
326c3e054c8SHugo Santos 	return (UdpEndpoint *)hash_lookup(fActiveEndpoints, &key);
327c22d69bfSAxel Dörfler }
328c22d69bfSAxel Dörfler 
329c22d69bfSAxel Dörfler 
330c22d69bfSAxel Dörfler status_t
331bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer)
332c22d69bfSAxel Dörfler {
333c22d69bfSAxel Dörfler 	sockaddr *peerAddr = (sockaddr *)&buffer->source;
334c22d69bfSAxel Dörfler 	sockaddr *broadcastAddr = (sockaddr *)&buffer->destination;
335c22d69bfSAxel Dörfler 	sockaddr *mask = NULL;
336c22d69bfSAxel Dörfler 	if (buffer->interface)
337c22d69bfSAxel Dörfler 		mask = (sockaddr *)buffer->interface->mask;
338c22d69bfSAxel Dörfler 
339bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer);
340c22d69bfSAxel Dörfler 
341bf48e753SHugo Santos 	uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
342c22d69bfSAxel Dörfler 
343c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint;
344bf48e753SHugo Santos 	hash_iterator endpointIterator;
345bf48e753SHugo Santos 	hash_open(fActiveEndpoints, &endpointIterator);
346bf48e753SHugo Santos 	while ((endpoint = (UdpEndpoint *)hash_next(fActiveEndpoints,
347bf48e753SHugo Santos 		&endpointIterator)) != NULL) {
348bf48e753SHugo Santos 		sockaddr *addr = (sockaddr *)&endpoint->socket->address;
349bf48e753SHugo Santos 		TRACE_DOMAIN("  _DemuxBroadcast(): checking endpoint %s...",
350bf48e753SHugo Santos 			AddressString(fDomain, addr, true).Data());
351c22d69bfSAxel Dörfler 
352bf48e753SHugo Santos 		if (incomingPort != AddressModule()->get_port(addr)) {
353c22d69bfSAxel Dörfler 			// ports don't match, so we do not dispatch to this endpoint...
354c22d69bfSAxel Dörfler 			continue;
355c22d69bfSAxel Dörfler 		}
356c22d69bfSAxel Dörfler 
357bf48e753SHugo Santos 		sockaddr *connectAddr = (sockaddr *)&endpoint->socket->peer;
358bf48e753SHugo Santos 		if (!AddressModule()->is_empty_address(connectAddr, true)) {
359c22d69bfSAxel Dörfler 			// endpoint is connected to a specific destination, we check if
360c22d69bfSAxel Dörfler 			// this datagram is from there:
361bf48e753SHugo Santos 			if (!AddressModule()->equal_addresses_and_ports(connectAddr, peerAddr)) {
362c22d69bfSAxel Dörfler 				// no, datagram is from another peer, so we do not dispatch to
363c22d69bfSAxel Dörfler 				// this endpoint...
364c22d69bfSAxel Dörfler 				continue;
365c22d69bfSAxel Dörfler 			}
366c22d69bfSAxel Dörfler 		}
367c22d69bfSAxel Dörfler 
368bf48e753SHugo Santos 		if (AddressModule()->equal_masked_addresses(addr, broadcastAddr, mask)
369bf48e753SHugo Santos 			|| AddressModule()->is_empty_address(addr, false)) {
370c22d69bfSAxel Dörfler 				// address matches, dispatch to this endpoint:
371c22d69bfSAxel Dörfler 			endpoint->StoreData(buffer);
372c22d69bfSAxel Dörfler 		}
373c22d69bfSAxel Dörfler 	}
374c22d69bfSAxel Dörfler 	hash_close(fActiveEndpoints, &endpointIterator, false);
375c22d69bfSAxel Dörfler 	return B_OK;
376c22d69bfSAxel Dörfler }
377c22d69bfSAxel Dörfler 
378c22d69bfSAxel Dörfler 
379c22d69bfSAxel Dörfler status_t
380bf48e753SHugo Santos UdpDomainSupport::_DemuxMulticast(net_buffer *buffer)
381c22d69bfSAxel Dörfler {	// TODO: implement!
382bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxMulticast(%p)", buffer);
383bf48e753SHugo Santos 
384c22d69bfSAxel Dörfler 	return B_ERROR;
385c22d69bfSAxel Dörfler }
386c22d69bfSAxel Dörfler 
387c22d69bfSAxel Dörfler 
388c22d69bfSAxel Dörfler status_t
389bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer *buffer)
390c22d69bfSAxel Dörfler {
391c22d69bfSAxel Dörfler 	struct sockaddr *peerAddr = (struct sockaddr *)&buffer->source;
392c22d69bfSAxel Dörfler 	struct sockaddr *localAddr = (struct sockaddr *)&buffer->destination;
393c22d69bfSAxel Dörfler 
394bf48e753SHugo Santos 	TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
395c22d69bfSAxel Dörfler 
396c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint;
397c22d69bfSAxel Dörfler 	// look for full (most special) match:
398bf48e753SHugo Santos 	endpoint = _FindActiveEndpoint(localAddr, peerAddr);
399c22d69bfSAxel Dörfler 	if (!endpoint) {
400c22d69bfSAxel Dörfler 		// look for endpoint matching local address & port:
401bf48e753SHugo Santos 		endpoint = _FindActiveEndpoint(localAddr, NULL);
402c22d69bfSAxel Dörfler 		if (!endpoint) {
403c22d69bfSAxel Dörfler 			// look for endpoint matching peer address & port and local port:
404c22d69bfSAxel Dörfler 			sockaddr localPortAddr;
405bf48e753SHugo Santos 			AddressModule()->set_to_empty_address(&localPortAddr);
406bf48e753SHugo Santos 			uint16 localPort = AddressModule()->get_port(localAddr);
407bf48e753SHugo Santos 			AddressModule()->set_port(&localPortAddr, localPort);
408bf48e753SHugo Santos 			endpoint = _FindActiveEndpoint(&localPortAddr, peerAddr);
409c22d69bfSAxel Dörfler 			if (!endpoint) {
410c22d69bfSAxel Dörfler 				// last chance: look for endpoint matching local port only:
411bf48e753SHugo Santos 				endpoint = _FindActiveEndpoint(&localPortAddr, NULL);
412c22d69bfSAxel Dörfler 			}
413c22d69bfSAxel Dörfler 		}
414c22d69bfSAxel Dörfler 	}
415bf48e753SHugo Santos 
416c22d69bfSAxel Dörfler 	if (!endpoint)
417c22d69bfSAxel Dörfler 		return B_NAME_NOT_FOUND;
418c22d69bfSAxel Dörfler 
419c22d69bfSAxel Dörfler 	endpoint->StoreData(buffer);
420c22d69bfSAxel Dörfler 	return B_OK;
421c22d69bfSAxel Dörfler }
422c22d69bfSAxel Dörfler 
423c22d69bfSAxel Dörfler 
424bf48e753SHugo Santos uint16
425bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
426c22d69bfSAxel Dörfler {
427bf48e753SHugo Santos 	uint16 stop, curr, ncurr;
428bf48e753SHugo Santos 	if (fLastUsedEphemeral < kLast) {
429bf48e753SHugo Santos 		stop = fLastUsedEphemeral;
430bf48e753SHugo Santos 		curr = fLastUsedEphemeral + 1;
431bf48e753SHugo Santos 	} else {
432bf48e753SHugo Santos 		stop = kLast;
433bf48e753SHugo Santos 		curr = kFirst;
434bf48e753SHugo Santos 	}
435c22d69bfSAxel Dörfler 
436bf48e753SHugo Santos 	TRACE_DOMAIN("_GetNextEphemeral()");
437bf48e753SHugo Santos 	// TODO: a free list could be used to avoid the impact of these
438bf48e753SHugo Santos 	//       two nested loops most of the time... let's see how bad this really is
439bf48e753SHugo Santos 	bool found = false;
440bf48e753SHugo Santos 	uint16 endpointPort;
441bf48e753SHugo Santos 	hash_iterator endpointIterator;
442bf48e753SHugo Santos 	hash_open(fActiveEndpoints, &endpointIterator);
443bf48e753SHugo Santos 	while(!found && curr != stop) {
444bf48e753SHugo Santos 		TRACE_DOMAIN("  _GetNextEphemeral(): trying port %hu...", curr);
445bf48e753SHugo Santos 		ncurr = htons(curr);
446bf48e753SHugo Santos 		hash_rewind(fActiveEndpoints, &endpointIterator);
447bf48e753SHugo Santos 		while (!found) {
448bf48e753SHugo Santos 			UdpEndpoint *endpoint = (UdpEndpoint *)hash_next(fActiveEndpoints,
449bf48e753SHugo Santos 				&endpointIterator);
450bf48e753SHugo Santos 			if (!endpoint) {
451bf48e753SHugo Santos 				found = true;
452bf48e753SHugo Santos 				break;
453bf48e753SHugo Santos 			}
454bf48e753SHugo Santos 			endpointPort = AddressModule()->get_port(
455bf48e753SHugo Santos 				(sockaddr *)&endpoint->socket->address);
456bf48e753SHugo Santos 			TRACE_DOMAIN("  _GetNextEphemeral(): checking endpoint %p (port %hu)...",
457bf48e753SHugo Santos 				endpoint, ntohs(endpointPort));
458bf48e753SHugo Santos 			if (endpointPort == ncurr)
459bf48e753SHugo Santos 				break;
460bf48e753SHugo Santos 		}
461bf48e753SHugo Santos 		if (!found) {
462bf48e753SHugo Santos 			if (curr < kLast)
463bf48e753SHugo Santos 				curr++;
464c22d69bfSAxel Dörfler 			else
465bf48e753SHugo Santos 				curr = kFirst;
466bf48e753SHugo Santos 		}
467bf48e753SHugo Santos 	}
468bf48e753SHugo Santos 	hash_close(fActiveEndpoints, &endpointIterator, false);
469bf48e753SHugo Santos 	if (!found)
470bf48e753SHugo Santos 		return 0;
471bf48e753SHugo Santos 	TRACE_DOMAIN("  _GetNextEphemeral(): ...using port %hu", curr);
472bf48e753SHugo Santos 	fLastUsedEphemeral = curr;
473bf48e753SHugo Santos 	return curr;
474bf48e753SHugo Santos }
475c22d69bfSAxel Dörfler 
476bf48e753SHugo Santos 
477bf48e753SHugo Santos int
478bf48e753SHugo Santos UdpDomainSupport::_Compare(void *_udpEndpoint, const void *_key)
479bf48e753SHugo Santos {
480bf48e753SHugo Santos 	struct UdpEndpoint *udpEndpoint = (UdpEndpoint*)_udpEndpoint;
481bf48e753SHugo Santos 	const HashKey *key = (const HashKey *)_key;
482bf48e753SHugo Santos 
483bf48e753SHugo Santos 	sockaddr *ourAddr = (sockaddr *)&udpEndpoint->socket->address;
484bf48e753SHugo Santos 	sockaddr *peerAddr = (sockaddr *)&udpEndpoint->socket->peer;
485bf48e753SHugo Santos 
486bf48e753SHugo Santos 	net_address_module_info *addressModule = key->address_module;
487bf48e753SHugo Santos 
488bf48e753SHugo Santos 	if (addressModule->equal_addresses_and_ports(ourAddr, key->local)
489bf48e753SHugo Santos 		&& addressModule->equal_addresses_and_ports(peerAddr, key->peer))
490bf48e753SHugo Santos 		return 0;
491bf48e753SHugo Santos 
492bf48e753SHugo Santos 	return 1;
493bf48e753SHugo Santos }
494bf48e753SHugo Santos 
495bf48e753SHugo Santos 
496bf48e753SHugo Santos uint32
497bf48e753SHugo Santos UdpDomainSupport::_Hash(void *_udpEndpoint, const void *_key, uint32 range)
498bf48e753SHugo Santos {
499bf48e753SHugo Santos 	const HashKey *key = (const HashKey *)_key;
500bf48e753SHugo Santos 	HashKey key_storage;
501bf48e753SHugo Santos 	uint32 hash;
502bf48e753SHugo Santos 
503bf48e753SHugo Santos 	if (_udpEndpoint) {
504bf48e753SHugo Santos 		const UdpEndpoint *udpEndpoint = (const UdpEndpoint *)_udpEndpoint;
505bf48e753SHugo Santos 		key_storage = HashKey(udpEndpoint->DomainSupport()->AddressModule(),
506bf48e753SHugo Santos 			(const sockaddr *)&udpEndpoint->socket->address,
507bf48e753SHugo Santos 			(const sockaddr *)&udpEndpoint->socket->peer);
508bf48e753SHugo Santos 		key = &key_storage;
509bf48e753SHugo Santos 	}
510bf48e753SHugo Santos 
511bf48e753SHugo Santos 	hash = key->address_module->hash_address_pair(key->local, key->peer);
512bf48e753SHugo Santos 
513bf48e753SHugo Santos 	// move the bits into the relevant range (as defined by kNumHashBuckets):
514bf48e753SHugo Santos 	hash = (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
515bf48e753SHugo Santos 			^ (hash & 0xFFC00000UL) >> 22;
516bf48e753SHugo Santos 
517bf48e753SHugo Santos 	return hash % range;
518bf48e753SHugo Santos }
519bf48e753SHugo Santos 
520bf48e753SHugo Santos 
521bf48e753SHugo Santos // #pragma mark -
522bf48e753SHugo Santos 
523bf48e753SHugo Santos 
524bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
525bf48e753SHugo Santos {
526bf48e753SHugo Santos 	fStatus = benaphore_init(&fLock, "UDP endpoints");
527bf48e753SHugo Santos }
528bf48e753SHugo Santos 
529bf48e753SHugo Santos 
530bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
531bf48e753SHugo Santos {
532bf48e753SHugo Santos 	benaphore_destroy(&fLock);
533bf48e753SHugo Santos }
534bf48e753SHugo Santos 
535bf48e753SHugo Santos 
536bf48e753SHugo Santos status_t
537bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
538bf48e753SHugo Santos {
539bf48e753SHugo Santos 	return fStatus;
540bf48e753SHugo Santos }
541bf48e753SHugo Santos 
542bf48e753SHugo Santos 
543bf48e753SHugo Santos // #pragma mark - inbound
544bf48e753SHugo Santos 
545bf48e753SHugo Santos 
546bf48e753SHugo Santos status_t
547bf48e753SHugo Santos UdpEndpointManager::DemuxIncomingBuffer(net_domain *domain, net_buffer *buffer)
548bf48e753SHugo Santos {
549bf48e753SHugo Santos 	UdpDomainSupport *domainSupport = _GetDomain(domain, false);
550bf48e753SHugo Santos 	if (domainSupport == NULL) {
551bf48e753SHugo Santos 		// we don't instantiate domain supports in the
552bf48e753SHugo Santos 		// RX path as we are only interested in delivering
553bf48e753SHugo Santos 		// data to existing sockets.
554bf48e753SHugo Santos 		return B_BAD_VALUE;
555bf48e753SHugo Santos 	}
556bf48e753SHugo Santos 
557bf48e753SHugo Santos 	return domainSupport->DemuxIncomingBuffer(buffer);
558c22d69bfSAxel Dörfler }
559c22d69bfSAxel Dörfler 
560c22d69bfSAxel Dörfler 
561c22d69bfSAxel Dörfler status_t
562c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer)
563c22d69bfSAxel Dörfler {
564bf48e753SHugo Santos 	TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
565bf48e753SHugo Santos 
56687001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
567c22d69bfSAxel Dörfler 	if (bufferHeader.Status() < B_OK)
568c22d69bfSAxel Dörfler 		return bufferHeader.Status();
569c22d69bfSAxel Dörfler 
570c22d69bfSAxel Dörfler 	udp_header &header = bufferHeader.Data();
571c22d69bfSAxel Dörfler 
572c22d69bfSAxel Dörfler 	struct sockaddr *source = (struct sockaddr *)&buffer->source;
573c22d69bfSAxel Dörfler 	struct sockaddr *destination = (struct sockaddr *)&buffer->destination;
574c22d69bfSAxel Dörfler 
575bf48e753SHugo Santos 	if (buffer->interface == NULL || buffer->interface->domain == NULL) {
576bf48e753SHugo Santos 		TRACE_EPM("  ReceiveData(): UDP packed dropped as there was no domain "
577bf48e753SHugo Santos 			"specified (interface %p).", buffer->interface);
578c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
579c22d69bfSAxel Dörfler 	}
580bf48e753SHugo Santos 
581bf48e753SHugo Santos 	net_domain *domain = buffer->interface->domain;
582bf48e753SHugo Santos 	net_address_module_info *addressModule = domain->address_module;
583bf48e753SHugo Santos 
584bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
585bf48e753SHugo Santos 
586bf48e753SHugo Santos 	addressModule->set_port(source, header.source_port);
587bf48e753SHugo Santos 	addressModule->set_port(destination, header.destination_port);
588bf48e753SHugo Santos 
589bf48e753SHugo Santos 	TRACE_EPM("  ReceiveData(): data from %s to %s",
590bf48e753SHugo Santos 		AddressString(domain, source, true).Data(),
591bf48e753SHugo Santos 		AddressString(domain, destination, true).Data());
592c22d69bfSAxel Dörfler 
593c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
594c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
595bf48e753SHugo Santos 		TRACE_EPM("  ReceiveData(): buffer is too short, expected %hu.",
596bf48e753SHugo Santos 			udpLength);
597c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
598c22d69bfSAxel Dörfler 	}
599bf48e753SHugo Santos 
600bf48e753SHugo Santos 	if (buffer->size > udpLength)
601c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
602c22d69bfSAxel Dörfler 
603c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
604c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
605c22d69bfSAxel Dörfler 		Checksum udpChecksum;
606bf48e753SHugo Santos 		addressModule->checksum_address(&udpChecksum, source);
607bf48e753SHugo Santos 		addressModule->checksum_address(&udpChecksum, destination);
608c22d69bfSAxel Dörfler 		udpChecksum
609c22d69bfSAxel Dörfler 			<< (uint16)htons(IPPROTO_UDP)
610c22d69bfSAxel Dörfler 			<< header.udp_length
611c22d69bfSAxel Dörfler 					// peculiar but correct: UDP-len is used twice for checksum
612c22d69bfSAxel Dörfler 					// (as it is already contained in udp_header)
613c35b04deSAxel Dörfler 			<< Checksum::BufferHelper(buffer, gBufferModule);
614c22d69bfSAxel Dörfler 		uint16 sum = udpChecksum;
615c22d69bfSAxel Dörfler 		if (sum != 0) {
616bf48e753SHugo Santos 			TRACE_EPM("  ReceiveData(): bad checksum 0x%hx.", sum);
617c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
618c22d69bfSAxel Dörfler 		}
619c22d69bfSAxel Dörfler 	}
620c22d69bfSAxel Dörfler 
621c22d69bfSAxel Dörfler 	bufferHeader.Remove();
622c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
623c22d69bfSAxel Dörfler 
624bf48e753SHugo Santos 	status_t status = DemuxIncomingBuffer(domain, buffer);
625c22d69bfSAxel Dörfler 	if (status < B_OK) {
626bf48e753SHugo Santos 		TRACE_EPM("  ReceiveData(): no endpoint.");
627c22d69bfSAxel Dörfler 		// TODO: send ICMP-error
628c22d69bfSAxel Dörfler 		return B_ERROR;
629c22d69bfSAxel Dörfler 	}
630c22d69bfSAxel Dörfler 
631c22d69bfSAxel Dörfler 	return B_ERROR;
632c22d69bfSAxel Dörfler }
633c22d69bfSAxel Dörfler 
634c22d69bfSAxel Dörfler 
635bf48e753SHugo Santos UdpDomainSupport *
636c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
637c22d69bfSAxel Dörfler {
638bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
639bf48e753SHugo Santos 
640bf48e753SHugo Santos 	UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true);
641bf48e753SHugo Santos 	if (domain)
642bf48e753SHugo Santos 		domain->Ref();
643bf48e753SHugo Santos 	return domain;
644bf48e753SHugo Santos }
645bf48e753SHugo Santos 
646bf48e753SHugo Santos 
647bf48e753SHugo Santos status_t
648bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
649bf48e753SHugo Santos {
650bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
651bf48e753SHugo Santos 
652bf48e753SHugo Santos 	domain->Put();
653bf48e753SHugo Santos 
654bf48e753SHugo Santos 	if (domain->IsEmpty()) {
655bf48e753SHugo Santos 		fDomains.Remove(domain);
656bf48e753SHugo Santos 		delete domain;
657bf48e753SHugo Santos 	}
658bf48e753SHugo Santos 
659bf48e753SHugo Santos 	return B_OK;
660bf48e753SHugo Santos }
661bf48e753SHugo Santos 
662bf48e753SHugo Santos 
663bf48e753SHugo Santos // #pragma mark -
664bf48e753SHugo Santos 
665bf48e753SHugo Santos 
666bf48e753SHugo Santos UdpDomainSupport *
667bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
668bf48e753SHugo Santos {
669bf48e753SHugo Santos 	UdpDomainList::Iterator it = fDomains.GetIterator();
670bf48e753SHugo Santos 
671bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
672bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
673bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
674bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
675bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
676bf48e753SHugo Santos 	//      family.
677bf48e753SHugo Santos 	while (it.HasNext()) {
678bf48e753SHugo Santos 		UdpDomainSupport *domainSupport = it.Next();
679bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
680bf48e753SHugo Santos 			return domainSupport;
681bf48e753SHugo Santos 	}
682bf48e753SHugo Santos 
683bf48e753SHugo Santos 	if (!create)
684bf48e753SHugo Santos 		return NULL;
685bf48e753SHugo Santos 
686bf48e753SHugo Santos 	UdpDomainSupport *domainSupport =
687bf48e753SHugo Santos 		new (std::nothrow) UdpDomainSupport(domain);
688bf48e753SHugo Santos 	if (domainSupport == NULL || domainSupport->InitCheck() < B_OK) {
689bf48e753SHugo Santos 		delete domainSupport;
690bf48e753SHugo Santos 		return NULL;
691bf48e753SHugo Santos 	}
692bf48e753SHugo Santos 
693bf48e753SHugo Santos 	fDomains.Add(domainSupport);
694bf48e753SHugo Santos 	return domainSupport;
695c22d69bfSAxel Dörfler }
696c22d69bfSAxel Dörfler 
697c22d69bfSAxel Dörfler 
698c22d69bfSAxel Dörfler // #pragma mark -
699c22d69bfSAxel Dörfler 
700c22d69bfSAxel Dörfler 
701c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
702c22d69bfSAxel Dörfler 	:
703*bfb45f71SHugo Santos 	DatagramSocket<>("udp endpoint", socket),
704bf48e753SHugo Santos 	fDomain(NULL),
705c22d69bfSAxel Dörfler 	fActive(false)
706c22d69bfSAxel Dörfler {
707bf48e753SHugo Santos }
708bf48e753SHugo Santos 
709bf48e753SHugo Santos 
710c22d69bfSAxel Dörfler // #pragma mark - activation
711c22d69bfSAxel Dörfler 
712c22d69bfSAxel Dörfler 
713c22d69bfSAxel Dörfler status_t
714c22d69bfSAxel Dörfler UdpEndpoint::Bind(sockaddr *address)
715c22d69bfSAxel Dörfler {
716bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
717c22d69bfSAxel Dörfler 
718bf48e753SHugo Santos 	// let the underlying protocol check whether there is an interface that
719bf48e753SHugo Santos 	// supports the given address
720c22d69bfSAxel Dörfler 	status_t status = next->module->bind(next, address);
721c22d69bfSAxel Dörfler 	if (status < B_OK)
722c22d69bfSAxel Dörfler 		return status;
723c22d69bfSAxel Dörfler 
724c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sUdpEndpointManager->Locker());
725c22d69bfSAxel Dörfler 
726c22d69bfSAxel Dörfler 	if (fActive) {
727c22d69bfSAxel Dörfler 		// socket module should have called unbind() before!
728c22d69bfSAxel Dörfler 		return EINVAL;
729c22d69bfSAxel Dörfler 	}
730c22d69bfSAxel Dörfler 
731bf48e753SHugo Santos 	if (AddressModule()->get_port(address) == 0) {
732bf48e753SHugo Santos 		uint16 port = htons(fDomain->GetEphemeralPort());
733c22d69bfSAxel Dörfler 		if (port == 0)
734c22d69bfSAxel Dörfler 			return ENOBUFS;
735c22d69bfSAxel Dörfler 				// whoa, no more ephemeral port available!?!
736bf48e753SHugo Santos 		AddressModule()->set_port((sockaddr *)&socket->address, port);
737c22d69bfSAxel Dörfler 	} else {
738bf48e753SHugo Santos 		status = fDomain->CheckBindRequest((sockaddr *)&socket->address,
739c22d69bfSAxel Dörfler 			socket->options);
740c22d69bfSAxel Dörfler 		if (status < B_OK)
741c22d69bfSAxel Dörfler 			return status;
742c22d69bfSAxel Dörfler 	}
743c22d69bfSAxel Dörfler 
744c22d69bfSAxel Dörfler 	return _Activate();
745c22d69bfSAxel Dörfler }
746c22d69bfSAxel Dörfler 
747c22d69bfSAxel Dörfler 
748c22d69bfSAxel Dörfler status_t
749c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
750c22d69bfSAxel Dörfler {
751bf48e753SHugo Santos 	TRACE_EP("Unbind()");
752c22d69bfSAxel Dörfler 
753c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sUdpEndpointManager->Locker());
754c22d69bfSAxel Dörfler 
755c22d69bfSAxel Dörfler 	return _Deactivate();
756c22d69bfSAxel Dörfler }
757c22d69bfSAxel Dörfler 
758c22d69bfSAxel Dörfler 
759c22d69bfSAxel Dörfler status_t
760c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
761c22d69bfSAxel Dörfler {
762bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
763c22d69bfSAxel Dörfler 
764c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sUdpEndpointManager->Locker());
765c22d69bfSAxel Dörfler 
766c22d69bfSAxel Dörfler 	if (fActive)
767c22d69bfSAxel Dörfler 		_Deactivate();
768c22d69bfSAxel Dörfler 
769c22d69bfSAxel Dörfler 	if (address->sa_family == AF_UNSPEC) {
770c22d69bfSAxel Dörfler 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
771c22d69bfSAxel Dörfler 		// so we reset the peer address:
772bf48e753SHugo Santos 		AddressModule()->set_to_empty_address((sockaddr *)&socket->peer);
773bf48e753SHugo Santos 	} else {
774bf48e753SHugo Santos 		// TODO check if `address' is compatible with AddressModule()
775bf48e753SHugo Santos 		AddressModule()->set_to((sockaddr *)&socket->peer, address);
776bf48e753SHugo Santos 	}
777c22d69bfSAxel Dörfler 
778c22d69bfSAxel Dörfler 	// we need to activate no matter whether or not we have just disconnected,
779c22d69bfSAxel Dörfler 	// as calling connect() always triggers an implicit bind():
780c22d69bfSAxel Dörfler 	return _Activate();
781c22d69bfSAxel Dörfler }
782c22d69bfSAxel Dörfler 
783c22d69bfSAxel Dörfler 
784c22d69bfSAxel Dörfler status_t
785c22d69bfSAxel Dörfler UdpEndpoint::Open()
786c22d69bfSAxel Dörfler {
787bf48e753SHugo Santos 	TRACE_EP("Open()");
788bf48e753SHugo Santos 
789bf48e753SHugo Santos 	// we can't be the first protocol, there must an underlying
790bf48e753SHugo Santos 	// network protocol that supplies us with an address module.
791bf48e753SHugo Santos 	if (socket->first_protocol == NULL)
792bf48e753SHugo Santos 		return EAFNOSUPPORT;
793bf48e753SHugo Santos 
794bf48e753SHugo Santos 	if (Domain() == NULL || Domain()->address_module == NULL)
795bf48e753SHugo Santos 		return EAFNOSUPPORT;
796bf48e753SHugo Santos 
797bf48e753SHugo Santos 	fDomain = sUdpEndpointManager->OpenEndpoint(this);
798bf48e753SHugo Santos 
799bf48e753SHugo Santos 	if (fDomain == NULL)
800bf48e753SHugo Santos 		return EAFNOSUPPORT;
801bf48e753SHugo Santos 
802bf48e753SHugo Santos 	return B_OK;
803c22d69bfSAxel Dörfler }
804c22d69bfSAxel Dörfler 
805c22d69bfSAxel Dörfler 
806c22d69bfSAxel Dörfler status_t
807c22d69bfSAxel Dörfler UdpEndpoint::Close()
808c22d69bfSAxel Dörfler {
809bf48e753SHugo Santos 	TRACE_EP("Close()");
810bf48e753SHugo Santos 
811bf48e753SHugo Santos 	BenaphoreLocker _(sUdpEndpointManager->Locker());
812c22d69bfSAxel Dörfler 	if (fActive)
813c22d69bfSAxel Dörfler 		_Deactivate();
814bf48e753SHugo Santos 
815bf48e753SHugo Santos 	return B_OK;
816c22d69bfSAxel Dörfler }
817c22d69bfSAxel Dörfler 
818c22d69bfSAxel Dörfler 
819c22d69bfSAxel Dörfler status_t
820c22d69bfSAxel Dörfler UdpEndpoint::Free()
821c22d69bfSAxel Dörfler {
822bf48e753SHugo Santos 	TRACE_EP("Free()");
823bf48e753SHugo Santos 
824bf48e753SHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fDomain);
825c22d69bfSAxel Dörfler }
826c22d69bfSAxel Dörfler 
827c22d69bfSAxel Dörfler 
828c22d69bfSAxel Dörfler status_t
829c22d69bfSAxel Dörfler UdpEndpoint::_Activate()
830c22d69bfSAxel Dörfler {
831c22d69bfSAxel Dörfler 	if (fActive)
832c22d69bfSAxel Dörfler 		return B_ERROR;
833bf48e753SHugo Santos 	status_t status = fDomain->ActivateEndpoint(this);
834c22d69bfSAxel Dörfler 	fActive = (status == B_OK);
835c22d69bfSAxel Dörfler 	return status;
836c22d69bfSAxel Dörfler }
837c22d69bfSAxel Dörfler 
838c22d69bfSAxel Dörfler 
839c22d69bfSAxel Dörfler status_t
840c22d69bfSAxel Dörfler UdpEndpoint::_Deactivate()
841c22d69bfSAxel Dörfler {
842c22d69bfSAxel Dörfler 	if (!fActive)
843c22d69bfSAxel Dörfler 		return B_ERROR;
844c22d69bfSAxel Dörfler 	fActive = false;
845bf48e753SHugo Santos 	return fDomain->DeactivateEndpoint(this);
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 
867bf48e753SHugo Santos 	header->source_port = AddressModule()->get_port((sockaddr *)&buffer->source);
868bf48e753SHugo Santos 	header->destination_port = AddressModule()->get_port(
869c22d69bfSAxel Dörfler 		(sockaddr *)&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 
876c22d69bfSAxel Dörfler 	// generate UDP-checksum (simulating a so-called "pseudo-header"):
877c22d69bfSAxel Dörfler 	Checksum udpChecksum;
878bf48e753SHugo Santos 	AddressModule()->checksum_address(&udpChecksum,
879c22d69bfSAxel Dörfler 		(sockaddr *)route->interface->address);
880bf48e753SHugo Santos 	AddressModule()->checksum_address(&udpChecksum,
881c22d69bfSAxel Dörfler 		(sockaddr *)&buffer->destination);
882c22d69bfSAxel Dörfler 	udpChecksum
883c22d69bfSAxel Dörfler 		<< (uint16)htons(IPPROTO_UDP)
884c22d69bfSAxel Dörfler 		<< (uint16)htons(buffer->size)
885c22d69bfSAxel Dörfler 				// peculiar but correct: UDP-len is used twice for checksum
886c22d69bfSAxel Dörfler 				// (as it is already contained in udp_header)
887c35b04deSAxel Dörfler 		<< Checksum::BufferHelper(buffer, gBufferModule);
8886c353509SHugo Santos 
8896c353509SHugo Santos 	uint16 calculatedChecksum = udpChecksum;
8906c353509SHugo Santos 	if (calculatedChecksum == 0)
8916c353509SHugo Santos 		calculatedChecksum = 0xffff;
8926c353509SHugo Santos 
8936c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
894c22d69bfSAxel Dörfler 
895c22d69bfSAxel Dörfler 	TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: "));
8966c353509SHugo Santos 
897c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
898c22d69bfSAxel Dörfler }
899c22d69bfSAxel Dörfler 
900c22d69bfSAxel Dörfler 
901bf48e753SHugo Santos status_t
902bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
903bf48e753SHugo Santos {
904bf48e753SHugo Santos 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
905bf48e753SHugo Santos 
906bf48e753SHugo Santos 	net_route *route = NULL;
907bf48e753SHugo Santos 	status_t status = sDatalinkModule->get_buffer_route(Domain(), buffer,
908bf48e753SHugo Santos 		&route);
909bf48e753SHugo Santos 	if (status >= B_OK) {
910bf48e753SHugo Santos 		status = SendRoutedData(buffer, route);
911bf48e753SHugo Santos 		sDatalinkModule->put_route(Domain(), route);
912bf48e753SHugo Santos 	}
913bf48e753SHugo Santos 
914bf48e753SHugo Santos 	return status;
915bf48e753SHugo Santos }
916bf48e753SHugo Santos 
917bf48e753SHugo Santos 
918c22d69bfSAxel Dörfler // #pragma mark - inbound
919c22d69bfSAxel Dörfler 
920c22d69bfSAxel Dörfler 
921c22d69bfSAxel Dörfler ssize_t
922c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
923c22d69bfSAxel Dörfler {
924*bfb45f71SHugo Santos 	size_t bytes = AvailableData();
925*bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
926*bfb45f71SHugo Santos 	return bytes;
927c22d69bfSAxel Dörfler }
928c22d69bfSAxel Dörfler 
929c22d69bfSAxel Dörfler 
930c22d69bfSAxel Dörfler status_t
931c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
932c22d69bfSAxel Dörfler {
933bf48e753SHugo Santos 	TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags);
934bf48e753SHugo Santos 
935*bfb45f71SHugo Santos 	status_t status = SocketDequeue(flags, _buffer);
936bf48e753SHugo Santos 	TRACE_EP("  FetchData(): returned from fifo status=0x%lx", status);
937c22d69bfSAxel Dörfler 	if (status < B_OK)
938c22d69bfSAxel Dörfler 		return status;
939c22d69bfSAxel Dörfler 
940*bfb45f71SHugo Santos 	TRACE_EP("  FetchData(): returns buffer with %ld bytes", (*_buffer)->size);
941c22d69bfSAxel Dörfler 	return B_OK;
942c22d69bfSAxel Dörfler }
943c22d69bfSAxel Dörfler 
944c22d69bfSAxel Dörfler 
945c22d69bfSAxel Dörfler status_t
946bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
947c22d69bfSAxel Dörfler {
948bf48e753SHugo Santos 	TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size);
949c22d69bfSAxel Dörfler 
950*bfb45f71SHugo Santos 	return EnqueueClone(buffer);
951c22d69bfSAxel Dörfler }
952c22d69bfSAxel Dörfler 
953c22d69bfSAxel Dörfler 
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
1025c22d69bfSAxel Dörfler udp_bind(net_protocol *protocol, struct sockaddr *address)
1026c22d69bfSAxel Dörfler {
1027bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1028c22d69bfSAxel Dörfler }
1029c22d69bfSAxel Dörfler 
1030c22d69bfSAxel Dörfler 
1031c22d69bfSAxel Dörfler status_t
1032c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1033c22d69bfSAxel Dörfler {
1034bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1035c22d69bfSAxel Dörfler }
1036c22d69bfSAxel Dörfler 
1037c22d69bfSAxel Dörfler 
1038c22d69bfSAxel Dörfler status_t
1039c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1040c22d69bfSAxel Dörfler {
1041c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1042c22d69bfSAxel Dörfler }
1043c22d69bfSAxel Dörfler 
1044c22d69bfSAxel Dörfler 
1045c22d69bfSAxel Dörfler status_t
1046c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1047c22d69bfSAxel Dörfler {
1048c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1049c22d69bfSAxel Dörfler }
1050c22d69bfSAxel Dörfler 
1051c22d69bfSAxel Dörfler 
1052c22d69bfSAxel Dörfler status_t
1053c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1054c22d69bfSAxel Dörfler 	net_buffer *buffer)
1055c22d69bfSAxel Dörfler {
1056bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1057c22d69bfSAxel Dörfler }
1058c22d69bfSAxel Dörfler 
1059c22d69bfSAxel Dörfler 
1060c22d69bfSAxel Dörfler status_t
1061c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1062c22d69bfSAxel Dörfler {
1063bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1064c22d69bfSAxel Dörfler }
1065c22d69bfSAxel Dörfler 
1066c22d69bfSAxel Dörfler 
1067c22d69bfSAxel Dörfler ssize_t
1068c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1069c22d69bfSAxel Dörfler {
1070bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1071c22d69bfSAxel Dörfler }
1072c22d69bfSAxel Dörfler 
1073c22d69bfSAxel Dörfler 
1074c22d69bfSAxel Dörfler status_t
1075c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1076c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1077c22d69bfSAxel Dörfler {
1078bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1079c22d69bfSAxel Dörfler }
1080c22d69bfSAxel Dörfler 
1081c22d69bfSAxel Dörfler 
1082c22d69bfSAxel Dörfler ssize_t
1083c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1084c22d69bfSAxel Dörfler {
1085bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1086c22d69bfSAxel Dörfler }
1087c22d69bfSAxel Dörfler 
1088c22d69bfSAxel Dörfler 
1089c22d69bfSAxel Dörfler struct net_domain *
1090c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1091c22d69bfSAxel Dörfler {
1092c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1093c22d69bfSAxel Dörfler }
1094c22d69bfSAxel Dörfler 
1095c22d69bfSAxel Dörfler 
1096c22d69bfSAxel Dörfler size_t
1097c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1098c22d69bfSAxel Dörfler {
1099c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1100c22d69bfSAxel Dörfler }
1101c22d69bfSAxel Dörfler 
1102c22d69bfSAxel Dörfler 
1103c22d69bfSAxel Dörfler status_t
1104c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1105c22d69bfSAxel Dörfler {
1106c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1107c22d69bfSAxel Dörfler }
1108c22d69bfSAxel Dörfler 
1109c22d69bfSAxel Dörfler 
1110c22d69bfSAxel Dörfler status_t
1111c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data)
1112c22d69bfSAxel Dörfler {
1113c22d69bfSAxel Dörfler 	return B_ERROR;
1114c22d69bfSAxel Dörfler }
1115c22d69bfSAxel Dörfler 
1116c22d69bfSAxel Dörfler 
1117c22d69bfSAxel Dörfler status_t
1118c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
1119c22d69bfSAxel Dörfler 	void *errorData)
1120c22d69bfSAxel Dörfler {
1121c22d69bfSAxel Dörfler 	return B_ERROR;
1122c22d69bfSAxel Dörfler }
1123c22d69bfSAxel Dörfler 
1124c22d69bfSAxel Dörfler 
1125c22d69bfSAxel Dörfler //	#pragma mark - module interface
1126c22d69bfSAxel Dörfler 
1127c22d69bfSAxel Dörfler 
1128c22d69bfSAxel Dörfler static status_t
1129c22d69bfSAxel Dörfler init_udp()
1130c22d69bfSAxel Dörfler {
1131c22d69bfSAxel Dörfler 	status_t status;
1132bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1133c22d69bfSAxel Dörfler 
1134*bfb45f71SHugo Santos 	status = get_module(NET_STACK_MODULE_NAME, (module_info **)&gStackModule);
1135c22d69bfSAxel Dörfler 	if (status < B_OK)
1136c22d69bfSAxel Dörfler 		return status;
1137c35b04deSAxel Dörfler 	status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
1138c22d69bfSAxel Dörfler 	if (status < B_OK)
1139c22d69bfSAxel Dörfler 		goto err1;
1140c22d69bfSAxel Dörfler 	status = get_module(NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule);
1141c22d69bfSAxel Dörfler 	if (status < B_OK)
1142c22d69bfSAxel Dörfler 		goto err2;
1143c22d69bfSAxel Dörfler 
1144c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1145c22d69bfSAxel Dörfler 	if (sUdpEndpointManager == NULL) {
1146c22d69bfSAxel Dörfler 		status = ENOBUFS;
1147c22d69bfSAxel Dörfler 		goto err3;
1148c22d69bfSAxel Dörfler 	}
1149c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1150c22d69bfSAxel Dörfler 	if (status != B_OK)
1151c22d69bfSAxel Dörfler 		goto err3;
1152c22d69bfSAxel Dörfler 
1153*bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP,
1154c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1155c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1156c22d69bfSAxel Dörfler 		NULL);
1157c22d69bfSAxel Dörfler 	if (status < B_OK)
1158c22d69bfSAxel Dörfler 		goto err4;
1159*bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
1160c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1161c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1162c22d69bfSAxel Dörfler 		NULL);
1163c22d69bfSAxel Dörfler 	if (status < B_OK)
1164c22d69bfSAxel Dörfler 		goto err4;
1165c22d69bfSAxel Dörfler 
1166*bfb45f71SHugo Santos 	status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
1167c22d69bfSAxel Dörfler 		"network/protocols/udp/v1");
1168c22d69bfSAxel Dörfler 	if (status < B_OK)
1169c22d69bfSAxel Dörfler 		goto err4;
1170c22d69bfSAxel Dörfler 
1171c22d69bfSAxel Dörfler 	return B_OK;
1172c22d69bfSAxel Dörfler 
1173c22d69bfSAxel Dörfler err4:
1174c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1175c22d69bfSAxel Dörfler err3:
1176c22d69bfSAxel Dörfler 	put_module(NET_DATALINK_MODULE_NAME);
1177c22d69bfSAxel Dörfler err2:
1178c22d69bfSAxel Dörfler 	put_module(NET_BUFFER_MODULE_NAME);
1179c22d69bfSAxel Dörfler err1:
1180c22d69bfSAxel Dörfler 	put_module(NET_STACK_MODULE_NAME);
1181c22d69bfSAxel Dörfler 
1182bf48e753SHugo Santos 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1183c22d69bfSAxel Dörfler 	return status;
1184c22d69bfSAxel Dörfler }
1185c22d69bfSAxel Dörfler 
1186c22d69bfSAxel Dörfler 
1187c22d69bfSAxel Dörfler static status_t
1188c22d69bfSAxel Dörfler uninit_udp()
1189c22d69bfSAxel Dörfler {
1190bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1191c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1192c22d69bfSAxel Dörfler 	put_module(NET_DATALINK_MODULE_NAME);
1193c22d69bfSAxel Dörfler 	put_module(NET_BUFFER_MODULE_NAME);
1194c22d69bfSAxel Dörfler 	put_module(NET_STACK_MODULE_NAME);
1195c22d69bfSAxel Dörfler 	return B_OK;
1196c22d69bfSAxel Dörfler }
1197c22d69bfSAxel Dörfler 
1198c22d69bfSAxel Dörfler 
1199c22d69bfSAxel Dörfler static status_t
1200c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1201c22d69bfSAxel Dörfler {
1202c22d69bfSAxel Dörfler 	switch (op) {
1203c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1204c22d69bfSAxel Dörfler 			return init_udp();
1205c22d69bfSAxel Dörfler 
1206c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1207c22d69bfSAxel Dörfler 			return uninit_udp();
1208c22d69bfSAxel Dörfler 
1209c22d69bfSAxel Dörfler 		default:
1210c22d69bfSAxel Dörfler 			return B_ERROR;
1211c22d69bfSAxel Dörfler 	}
1212c22d69bfSAxel Dörfler }
1213c22d69bfSAxel Dörfler 
1214c22d69bfSAxel Dörfler 
1215c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1216c22d69bfSAxel Dörfler 	{
1217c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1218c22d69bfSAxel Dörfler 		0,
1219c22d69bfSAxel Dörfler 		udp_std_ops
1220c22d69bfSAxel Dörfler 	},
1221c22d69bfSAxel Dörfler 	udp_init_protocol,
1222c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1223c22d69bfSAxel Dörfler 	udp_open,
1224c22d69bfSAxel Dörfler 	udp_close,
1225c22d69bfSAxel Dörfler 	udp_free,
1226c22d69bfSAxel Dörfler 	udp_connect,
1227c22d69bfSAxel Dörfler 	udp_accept,
1228c22d69bfSAxel Dörfler 	udp_control,
1229c22d69bfSAxel Dörfler 	udp_bind,
1230c22d69bfSAxel Dörfler 	udp_unbind,
1231c22d69bfSAxel Dörfler 	udp_listen,
1232c22d69bfSAxel Dörfler 	udp_shutdown,
1233c22d69bfSAxel Dörfler 	udp_send_data,
1234c22d69bfSAxel Dörfler 	udp_send_routed_data,
1235c22d69bfSAxel Dörfler 	udp_send_avail,
1236c22d69bfSAxel Dörfler 	udp_read_data,
1237c22d69bfSAxel Dörfler 	udp_read_avail,
1238c22d69bfSAxel Dörfler 	udp_get_domain,
1239c22d69bfSAxel Dörfler 	udp_get_mtu,
1240c22d69bfSAxel Dörfler 	udp_receive_data,
1241c22d69bfSAxel Dörfler 	udp_error,
1242c22d69bfSAxel Dörfler 	udp_error_reply,
1243c22d69bfSAxel Dörfler };
1244c22d69bfSAxel Dörfler 
1245c22d69bfSAxel Dörfler module_info *modules[] = {
1246c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1247c22d69bfSAxel Dörfler 	NULL
1248c22d69bfSAxel Dörfler };
1249