xref: /haiku/src/add-ons/kernel/network/protocols/udp/udp.cpp (revision 1408d1f0ce8555b9b94037e6f1c9c530afe753b6)
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>
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 
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 
65bfb45f71SHugo 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);
856a606180SHugo Santos 	status_t				DeliverData(net_buffer *buffer);
86c22d69bfSAxel Dörfler 
87bf48e753SHugo Santos 	net_domain *			Domain() const
88bf48e753SHugo Santos 	{
89bf48e753SHugo Santos 		return socket->first_protocol->module->get_domain(socket->first_protocol);
90bf48e753SHugo Santos 	}
91bf48e753SHugo Santos 
92bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
93bf48e753SHugo Santos 	{
94bf48e753SHugo Santos 		return Domain()->address_module;
95bf48e753SHugo Santos 	}
96bf48e753SHugo Santos 
97bf48e753SHugo Santos 	UdpDomainSupport		*DomainSupport() const { return fDomain; }
98bf48e753SHugo Santos 
99c22d69bfSAxel Dörfler 	UdpEndpoint				*hash_link;
100c22d69bfSAxel Dörfler 								// link required by hash_table (see khash.h)
101c22d69bfSAxel Dörfler private:
102c22d69bfSAxel Dörfler 	status_t				_Activate();
103c22d69bfSAxel Dörfler 	status_t				_Deactivate();
104c22d69bfSAxel Dörfler 
105bf48e753SHugo Santos 	UdpDomainSupport		*fDomain;
106c22d69bfSAxel Dörfler 	bool					fActive;
107c22d69bfSAxel Dörfler 								// an active UdpEndpoint is part of the endpoint
108c22d69bfSAxel Dörfler 								// hash (and it is bound and optionally connected)
109c22d69bfSAxel Dörfler };
110c22d69bfSAxel Dörfler 
111c22d69bfSAxel Dörfler 
112bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
113c22d69bfSAxel Dörfler public:
114bf48e753SHugo Santos 	UdpDomainSupport(net_domain *domain);
115bf48e753SHugo Santos 	~UdpDomainSupport();
116c22d69bfSAxel Dörfler 
117bf48e753SHugo Santos 	status_t InitCheck() const;
118bf48e753SHugo Santos 
119bf48e753SHugo Santos 	net_domain *Domain() const { return fDomain; }
120bf48e753SHugo Santos 
121bf48e753SHugo Santos 	void Ref() { fEndpointCount++; }
122bf48e753SHugo Santos 	void Put() { fEndpointCount--; }
123bf48e753SHugo Santos 
124bf48e753SHugo Santos 	bool IsEmpty() const { return fEndpointCount == 0; }
125bf48e753SHugo Santos 
126bf48e753SHugo Santos 	status_t DemuxIncomingBuffer(net_buffer *buffer);
127bf48e753SHugo Santos 	status_t CheckBindRequest(sockaddr *address, int socketOptions);
128bf48e753SHugo Santos 	status_t ActivateEndpoint(UdpEndpoint *endpoint);
129bf48e753SHugo Santos 	status_t DeactivateEndpoint(UdpEndpoint *endpoint);
130bf48e753SHugo Santos 
131bf48e753SHugo Santos 	uint16 GetEphemeralPort();
132bf48e753SHugo Santos 
133c22d69bfSAxel Dörfler private:
134bf48e753SHugo Santos 	struct HashKey {
135bf48e753SHugo Santos 		HashKey() {}
136bf48e753SHugo Santos 		HashKey(net_address_module_info *module, const sockaddr *_local,
137bf48e753SHugo Santos 			const sockaddr *_peer)
138bf48e753SHugo Santos 			: address_module(module), local(_local), peer(_peer) {}
139bf48e753SHugo Santos 
140bf48e753SHugo Santos 		net_address_module_info *address_module;
141bf48e753SHugo Santos 		const sockaddr *local;
142bf48e753SHugo Santos 		const sockaddr *peer;
143c22d69bfSAxel Dörfler 	};
144c22d69bfSAxel Dörfler 
145bf48e753SHugo Santos 	UdpEndpoint *_FindActiveEndpoint(sockaddr *ourAddress,
146bf48e753SHugo Santos 		sockaddr *peerAddress);
147bf48e753SHugo Santos 	status_t _DemuxBroadcast(net_buffer *buffer);
148bf48e753SHugo Santos 	status_t _DemuxMulticast(net_buffer *buffer);
149bf48e753SHugo Santos 	status_t _DemuxUnicast(net_buffer *buffer);
150bf48e753SHugo Santos 
151bf48e753SHugo Santos 	uint16 _GetNextEphemeral();
152bf48e753SHugo Santos 
153bf48e753SHugo Santos 	static int _Compare(void *udpEndpoint, const void *_key);
154bf48e753SHugo Santos 	static uint32 _Hash(void *udpEndpoint, const void *key, uint32 range);
155bf48e753SHugo Santos 
156bf48e753SHugo Santos 	net_address_module_info *AddressModule() const
157bf48e753SHugo Santos 	{
158bf48e753SHugo Santos 		return fDomain->address_module;
159bf48e753SHugo Santos 	}
160bf48e753SHugo Santos 
161bf48e753SHugo Santos 	net_domain		*fDomain;
162bf48e753SHugo Santos 	uint16			fLastUsedEphemeral;
163bf48e753SHugo Santos 	hash_table		*fActiveEndpoints;
164bf48e753SHugo Santos 	uint32			fEndpointCount;
165bf48e753SHugo Santos 
166bf48e753SHugo Santos 	static const uint16		kFirst = 49152;
167bf48e753SHugo Santos 	static const uint16		kLast = 65535;
168bf48e753SHugo Santos 	static const uint32		kNumHashBuckets = 0x800;
169bf48e753SHugo Santos 							// if you change this, adjust the shifting in
170bf48e753SHugo Santos 							// Hash() accordingly!
171bf48e753SHugo Santos };
172bf48e753SHugo Santos 
173bf48e753SHugo Santos 
174bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
175bf48e753SHugo Santos 
176bf48e753SHugo Santos 
177bf48e753SHugo Santos class UdpEndpointManager {
178c22d69bfSAxel Dörfler public:
179c22d69bfSAxel Dörfler 	UdpEndpointManager();
180c22d69bfSAxel Dörfler 	~UdpEndpointManager();
181c22d69bfSAxel Dörfler 
182c22d69bfSAxel Dörfler 	status_t		ReceiveData(net_buffer *buffer);
1836a606180SHugo Santos 	status_t		Deframe(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 
204c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
205658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
206658a5506SHugo Santos net_stack_module_info *gStackModule;
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
547c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer)
548c22d69bfSAxel Dörfler {
5496a606180SHugo Santos 	status_t status = Deframe(buffer);
5506a606180SHugo Santos 	if (status < B_OK)
5516a606180SHugo Santos 		return status;
5526a606180SHugo Santos 
553bf48e753SHugo Santos 	TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
554bf48e753SHugo Santos 
5556a606180SHugo Santos 	net_domain *domain = buffer->interface->domain;
5566a606180SHugo Santos 
5576a606180SHugo Santos 	BenaphoreLocker _(fLock);
5586a606180SHugo Santos 
5596a606180SHugo Santos 	UdpDomainSupport *domainSupport = _GetDomain(domain, false);
5606a606180SHugo Santos 	if (domainSupport == NULL) {
5616a606180SHugo Santos 		// we don't instantiate domain supports in the
5626a606180SHugo Santos 		// RX path as we are only interested in delivering
5636a606180SHugo Santos 		// data to existing sockets.
5646a606180SHugo Santos 		return B_ERROR;
5656a606180SHugo Santos 	}
5666a606180SHugo Santos 
5676a606180SHugo Santos 	status = domainSupport->DemuxIncomingBuffer(buffer);
5686a606180SHugo Santos 	if (status < B_OK) {
5696a606180SHugo Santos 		TRACE_EPM("  ReceiveData(): no endpoint.");
5706a606180SHugo Santos 		// TODO: send ICMP-error
5716a606180SHugo Santos 		return B_ERROR;
5726a606180SHugo Santos 	}
5736a606180SHugo Santos 
5746a606180SHugo Santos 	return B_ERROR;
5756a606180SHugo Santos }
5766a606180SHugo Santos 
5776a606180SHugo Santos 
5786a606180SHugo Santos status_t
5796a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer)
5806a606180SHugo Santos {
5816a606180SHugo Santos 	TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
5826a606180SHugo Santos 
58387001e05SHugo Santos 	NetBufferHeaderReader<udp_header> bufferHeader(buffer);
584c22d69bfSAxel Dörfler 	if (bufferHeader.Status() < B_OK)
585c22d69bfSAxel Dörfler 		return bufferHeader.Status();
586c22d69bfSAxel Dörfler 
587c22d69bfSAxel Dörfler 	udp_header &header = bufferHeader.Data();
588c22d69bfSAxel Dörfler 
589c22d69bfSAxel Dörfler 	struct sockaddr *source = (struct sockaddr *)&buffer->source;
590c22d69bfSAxel Dörfler 	struct sockaddr *destination = (struct sockaddr *)&buffer->destination;
591c22d69bfSAxel Dörfler 
592bf48e753SHugo Santos 	if (buffer->interface == NULL || buffer->interface->domain == NULL) {
5936a606180SHugo Santos 		TRACE_EPM("  Deframe(): UDP packed dropped as there was no domain "
594bf48e753SHugo Santos 			"specified (interface %p).", buffer->interface);
595c22d69bfSAxel Dörfler 		return B_BAD_VALUE;
596c22d69bfSAxel Dörfler 	}
597bf48e753SHugo Santos 
598bf48e753SHugo Santos 	net_domain *domain = buffer->interface->domain;
599bf48e753SHugo Santos 	net_address_module_info *addressModule = domain->address_module;
600bf48e753SHugo Santos 
601bf48e753SHugo Santos 	addressModule->set_port(source, header.source_port);
602bf48e753SHugo Santos 	addressModule->set_port(destination, header.destination_port);
603bf48e753SHugo Santos 
6046a606180SHugo Santos 	TRACE_EPM("  Deframe(): data from %s to %s",
605bf48e753SHugo Santos 		AddressString(domain, source, true).Data(),
606bf48e753SHugo Santos 		AddressString(domain, destination, true).Data());
607c22d69bfSAxel Dörfler 
608c22d69bfSAxel Dörfler 	uint16 udpLength = ntohs(header.udp_length);
609c22d69bfSAxel Dörfler 	if (udpLength > buffer->size) {
6106a606180SHugo Santos 		TRACE_EPM("  Deframe(): buffer is too short, expected %hu.",
611bf48e753SHugo Santos 			udpLength);
612c22d69bfSAxel Dörfler 		return B_MISMATCHED_VALUES;
613c22d69bfSAxel Dörfler 	}
614bf48e753SHugo Santos 
615bf48e753SHugo Santos 	if (buffer->size > udpLength)
616c35b04deSAxel Dörfler 		gBufferModule->trim(buffer, udpLength);
617c22d69bfSAxel Dörfler 
618c22d69bfSAxel Dörfler 	if (header.udp_checksum != 0) {
619c22d69bfSAxel Dörfler 		// check UDP-checksum (simulating a so-called "pseudo-header"):
620c22d69bfSAxel Dörfler 		Checksum udpChecksum;
621bf48e753SHugo Santos 		addressModule->checksum_address(&udpChecksum, source);
622bf48e753SHugo Santos 		addressModule->checksum_address(&udpChecksum, destination);
623c22d69bfSAxel Dörfler 		udpChecksum
624c22d69bfSAxel Dörfler 			<< (uint16)htons(IPPROTO_UDP)
625c22d69bfSAxel Dörfler 			<< header.udp_length
626c22d69bfSAxel Dörfler 					// peculiar but correct: UDP-len is used twice for checksum
627c22d69bfSAxel Dörfler 					// (as it is already contained in udp_header)
628c35b04deSAxel Dörfler 			<< Checksum::BufferHelper(buffer, gBufferModule);
629c22d69bfSAxel Dörfler 		uint16 sum = udpChecksum;
630c22d69bfSAxel Dörfler 		if (sum != 0) {
6316a606180SHugo Santos 			TRACE_EPM("  Deframe(): bad checksum 0x%hx.", sum);
632c22d69bfSAxel Dörfler 			return B_BAD_VALUE;
633c22d69bfSAxel Dörfler 		}
634c22d69bfSAxel Dörfler 	}
635c22d69bfSAxel Dörfler 
636c22d69bfSAxel Dörfler 	bufferHeader.Remove();
637c22d69bfSAxel Dörfler 		// remove UDP-header from buffer before passing it on
638c22d69bfSAxel Dörfler 
6396a606180SHugo Santos 	return B_OK;
640c22d69bfSAxel Dörfler }
641c22d69bfSAxel Dörfler 
642c22d69bfSAxel Dörfler 
643bf48e753SHugo Santos UdpDomainSupport *
644c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
645c22d69bfSAxel Dörfler {
646bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
647bf48e753SHugo Santos 
648bf48e753SHugo Santos 	UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true);
649bf48e753SHugo Santos 	if (domain)
650bf48e753SHugo Santos 		domain->Ref();
651bf48e753SHugo Santos 	return domain;
652bf48e753SHugo Santos }
653bf48e753SHugo Santos 
654bf48e753SHugo Santos 
655bf48e753SHugo Santos status_t
656bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
657bf48e753SHugo Santos {
658bf48e753SHugo Santos 	BenaphoreLocker _(fLock);
659bf48e753SHugo Santos 
660bf48e753SHugo Santos 	domain->Put();
661bf48e753SHugo Santos 
662bf48e753SHugo Santos 	if (domain->IsEmpty()) {
663bf48e753SHugo Santos 		fDomains.Remove(domain);
664bf48e753SHugo Santos 		delete domain;
665bf48e753SHugo Santos 	}
666bf48e753SHugo Santos 
667bf48e753SHugo Santos 	return B_OK;
668bf48e753SHugo Santos }
669bf48e753SHugo Santos 
670bf48e753SHugo Santos 
671bf48e753SHugo Santos // #pragma mark -
672bf48e753SHugo Santos 
673bf48e753SHugo Santos 
674bf48e753SHugo Santos UdpDomainSupport *
675bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
676bf48e753SHugo Santos {
677bf48e753SHugo Santos 	UdpDomainList::Iterator it = fDomains.GetIterator();
678bf48e753SHugo Santos 
679bf48e753SHugo Santos 	// TODO convert this into a Hashtable or install per-domain
680bf48e753SHugo Santos 	//      receiver handlers that forward the requests to the
681bf48e753SHugo Santos 	//      appropriate DemuxIncomingBuffer(). For instance, while
682bf48e753SHugo Santos 	//      being constructed UdpDomainSupport could call
683bf48e753SHugo Santos 	//      register_domain_receiving_protocol() with the right
684bf48e753SHugo Santos 	//      family.
685bf48e753SHugo Santos 	while (it.HasNext()) {
686bf48e753SHugo Santos 		UdpDomainSupport *domainSupport = it.Next();
687bf48e753SHugo Santos 		if (domainSupport->Domain() == domain)
688bf48e753SHugo Santos 			return domainSupport;
689bf48e753SHugo Santos 	}
690bf48e753SHugo Santos 
691bf48e753SHugo Santos 	if (!create)
692bf48e753SHugo Santos 		return NULL;
693bf48e753SHugo Santos 
694bf48e753SHugo Santos 	UdpDomainSupport *domainSupport =
695bf48e753SHugo Santos 		new (std::nothrow) UdpDomainSupport(domain);
696bf48e753SHugo Santos 	if (domainSupport == NULL || domainSupport->InitCheck() < B_OK) {
697bf48e753SHugo Santos 		delete domainSupport;
698bf48e753SHugo Santos 		return NULL;
699bf48e753SHugo Santos 	}
700bf48e753SHugo Santos 
701bf48e753SHugo Santos 	fDomains.Add(domainSupport);
702bf48e753SHugo Santos 	return domainSupport;
703c22d69bfSAxel Dörfler }
704c22d69bfSAxel Dörfler 
705c22d69bfSAxel Dörfler 
706c22d69bfSAxel Dörfler // #pragma mark -
707c22d69bfSAxel Dörfler 
708c22d69bfSAxel Dörfler 
709c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
710c22d69bfSAxel Dörfler 	:
711bfb45f71SHugo Santos 	DatagramSocket<>("udp endpoint", socket),
712bf48e753SHugo Santos 	fDomain(NULL),
713c22d69bfSAxel Dörfler 	fActive(false)
714c22d69bfSAxel Dörfler {
715bf48e753SHugo Santos }
716bf48e753SHugo Santos 
717bf48e753SHugo Santos 
718c22d69bfSAxel Dörfler // #pragma mark - activation
719c22d69bfSAxel Dörfler 
720c22d69bfSAxel Dörfler 
721c22d69bfSAxel Dörfler status_t
722c22d69bfSAxel Dörfler UdpEndpoint::Bind(sockaddr *address)
723c22d69bfSAxel Dörfler {
724bf48e753SHugo Santos 	TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
725c22d69bfSAxel Dörfler 
726bf48e753SHugo Santos 	// let the underlying protocol check whether there is an interface that
727bf48e753SHugo Santos 	// supports the given address
728c22d69bfSAxel Dörfler 	status_t status = next->module->bind(next, address);
729c22d69bfSAxel Dörfler 	if (status < B_OK)
730c22d69bfSAxel Dörfler 		return status;
731c22d69bfSAxel Dörfler 
732c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sUdpEndpointManager->Locker());
733c22d69bfSAxel Dörfler 
734c22d69bfSAxel Dörfler 	if (fActive) {
735c22d69bfSAxel Dörfler 		// socket module should have called unbind() before!
736c22d69bfSAxel Dörfler 		return EINVAL;
737c22d69bfSAxel Dörfler 	}
738c22d69bfSAxel Dörfler 
739bf48e753SHugo Santos 	if (AddressModule()->get_port(address) == 0) {
740bf48e753SHugo Santos 		uint16 port = htons(fDomain->GetEphemeralPort());
741c22d69bfSAxel Dörfler 		if (port == 0)
742c22d69bfSAxel Dörfler 			return ENOBUFS;
743c22d69bfSAxel Dörfler 				// whoa, no more ephemeral port available!?!
744bf48e753SHugo Santos 		AddressModule()->set_port((sockaddr *)&socket->address, port);
745c22d69bfSAxel Dörfler 	} else {
746bf48e753SHugo Santos 		status = fDomain->CheckBindRequest((sockaddr *)&socket->address,
747c22d69bfSAxel Dörfler 			socket->options);
748c22d69bfSAxel Dörfler 		if (status < B_OK)
749c22d69bfSAxel Dörfler 			return status;
750c22d69bfSAxel Dörfler 	}
751c22d69bfSAxel Dörfler 
752c22d69bfSAxel Dörfler 	return _Activate();
753c22d69bfSAxel Dörfler }
754c22d69bfSAxel Dörfler 
755c22d69bfSAxel Dörfler 
756c22d69bfSAxel Dörfler status_t
757c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
758c22d69bfSAxel Dörfler {
759bf48e753SHugo Santos 	TRACE_EP("Unbind()");
760c22d69bfSAxel Dörfler 
761c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sUdpEndpointManager->Locker());
762c22d69bfSAxel Dörfler 
763c22d69bfSAxel Dörfler 	return _Deactivate();
764c22d69bfSAxel Dörfler }
765c22d69bfSAxel Dörfler 
766c22d69bfSAxel Dörfler 
767c22d69bfSAxel Dörfler status_t
768c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
769c22d69bfSAxel Dörfler {
770bf48e753SHugo Santos 	TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
771c22d69bfSAxel Dörfler 
772c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sUdpEndpointManager->Locker());
773c22d69bfSAxel Dörfler 
774c22d69bfSAxel Dörfler 	if (fActive)
775c22d69bfSAxel Dörfler 		_Deactivate();
776c22d69bfSAxel Dörfler 
777c22d69bfSAxel Dörfler 	if (address->sa_family == AF_UNSPEC) {
778c22d69bfSAxel Dörfler 		// [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
779c22d69bfSAxel Dörfler 		// so we reset the peer address:
780bf48e753SHugo Santos 		AddressModule()->set_to_empty_address((sockaddr *)&socket->peer);
781bf48e753SHugo Santos 	} else {
782bf48e753SHugo Santos 		// TODO check if `address' is compatible with AddressModule()
783bf48e753SHugo Santos 		AddressModule()->set_to((sockaddr *)&socket->peer, address);
784bf48e753SHugo Santos 	}
785c22d69bfSAxel Dörfler 
786c22d69bfSAxel Dörfler 	// we need to activate no matter whether or not we have just disconnected,
787c22d69bfSAxel Dörfler 	// as calling connect() always triggers an implicit bind():
788c22d69bfSAxel Dörfler 	return _Activate();
789c22d69bfSAxel Dörfler }
790c22d69bfSAxel Dörfler 
791c22d69bfSAxel Dörfler 
792c22d69bfSAxel Dörfler status_t
793c22d69bfSAxel Dörfler UdpEndpoint::Open()
794c22d69bfSAxel Dörfler {
795bf48e753SHugo Santos 	TRACE_EP("Open()");
796bf48e753SHugo Santos 
797bf48e753SHugo Santos 	// we can't be the first protocol, there must an underlying
798bf48e753SHugo Santos 	// network protocol that supplies us with an address module.
799bf48e753SHugo Santos 	if (socket->first_protocol == NULL)
800bf48e753SHugo Santos 		return EAFNOSUPPORT;
801bf48e753SHugo Santos 
802bf48e753SHugo Santos 	if (Domain() == NULL || Domain()->address_module == NULL)
803bf48e753SHugo Santos 		return EAFNOSUPPORT;
804bf48e753SHugo Santos 
805bf48e753SHugo Santos 	fDomain = sUdpEndpointManager->OpenEndpoint(this);
806bf48e753SHugo Santos 
807bf48e753SHugo Santos 	if (fDomain == NULL)
808bf48e753SHugo Santos 		return EAFNOSUPPORT;
809bf48e753SHugo Santos 
810bf48e753SHugo Santos 	return B_OK;
811c22d69bfSAxel Dörfler }
812c22d69bfSAxel Dörfler 
813c22d69bfSAxel Dörfler 
814c22d69bfSAxel Dörfler status_t
815c22d69bfSAxel Dörfler UdpEndpoint::Close()
816c22d69bfSAxel Dörfler {
817bf48e753SHugo Santos 	TRACE_EP("Close()");
818bf48e753SHugo Santos 
819bf48e753SHugo Santos 	BenaphoreLocker _(sUdpEndpointManager->Locker());
820c22d69bfSAxel Dörfler 	if (fActive)
821c22d69bfSAxel Dörfler 		_Deactivate();
822bf48e753SHugo Santos 
823bf48e753SHugo Santos 	return B_OK;
824c22d69bfSAxel Dörfler }
825c22d69bfSAxel Dörfler 
826c22d69bfSAxel Dörfler 
827c22d69bfSAxel Dörfler status_t
828c22d69bfSAxel Dörfler UdpEndpoint::Free()
829c22d69bfSAxel Dörfler {
830bf48e753SHugo Santos 	TRACE_EP("Free()");
831bf48e753SHugo Santos 
832bf48e753SHugo Santos 	return sUdpEndpointManager->FreeEndpoint(fDomain);
833c22d69bfSAxel Dörfler }
834c22d69bfSAxel Dörfler 
835c22d69bfSAxel Dörfler 
836c22d69bfSAxel Dörfler status_t
837c22d69bfSAxel Dörfler UdpEndpoint::_Activate()
838c22d69bfSAxel Dörfler {
839c22d69bfSAxel Dörfler 	if (fActive)
840c22d69bfSAxel Dörfler 		return B_ERROR;
841bf48e753SHugo Santos 	status_t status = fDomain->ActivateEndpoint(this);
842c22d69bfSAxel Dörfler 	fActive = (status == B_OK);
843c22d69bfSAxel Dörfler 	return status;
844c22d69bfSAxel Dörfler }
845c22d69bfSAxel Dörfler 
846c22d69bfSAxel Dörfler 
847c22d69bfSAxel Dörfler status_t
848c22d69bfSAxel Dörfler UdpEndpoint::_Deactivate()
849c22d69bfSAxel Dörfler {
850c22d69bfSAxel Dörfler 	if (!fActive)
851c22d69bfSAxel Dörfler 		return B_ERROR;
852c22d69bfSAxel Dörfler 	fActive = false;
853bf48e753SHugo Santos 	return fDomain->DeactivateEndpoint(this);
854c22d69bfSAxel Dörfler }
855c22d69bfSAxel Dörfler 
856c22d69bfSAxel Dörfler 
857c22d69bfSAxel Dörfler // #pragma mark - outbound
858c22d69bfSAxel Dörfler 
859c22d69bfSAxel Dörfler 
860c22d69bfSAxel Dörfler status_t
861bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
862c22d69bfSAxel Dörfler {
863bf48e753SHugo Santos 	TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route);
864bf48e753SHugo Santos 
865d86f48f3SHugo Santos 	if (buffer->size > (0xffff - sizeof(udp_header)))
866c22d69bfSAxel Dörfler 		return EMSGSIZE;
867c22d69bfSAxel Dörfler 
868c22d69bfSAxel Dörfler 	buffer->protocol = IPPROTO_UDP;
869c22d69bfSAxel Dörfler 
870c22d69bfSAxel Dörfler 	// add and fill UDP-specific header:
8716c353509SHugo Santos 	NetBufferPrepend<udp_header> header(buffer);
8726c353509SHugo Santos 	if (header.Status() < B_OK)
8736c353509SHugo Santos 		return header.Status();
874c22d69bfSAxel Dörfler 
875bf48e753SHugo Santos 	header->source_port = AddressModule()->get_port((sockaddr *)&buffer->source);
876bf48e753SHugo Santos 	header->destination_port = AddressModule()->get_port(
877c22d69bfSAxel Dörfler 		(sockaddr *)&buffer->destination);
8786c353509SHugo Santos 	header->udp_length = htons(buffer->size);
879c22d69bfSAxel Dörfler 		// the udp-header is already included in the buffer-size
8806c353509SHugo Santos 	header->udp_checksum = 0;
8816c353509SHugo Santos 
8826c353509SHugo Santos 	header.Sync();
883c22d69bfSAxel Dörfler 
884c22d69bfSAxel Dörfler 	// generate UDP-checksum (simulating a so-called "pseudo-header"):
885c22d69bfSAxel Dörfler 	Checksum udpChecksum;
886bf48e753SHugo Santos 	AddressModule()->checksum_address(&udpChecksum,
887c22d69bfSAxel Dörfler 		(sockaddr *)route->interface->address);
888bf48e753SHugo Santos 	AddressModule()->checksum_address(&udpChecksum,
889c22d69bfSAxel Dörfler 		(sockaddr *)&buffer->destination);
890c22d69bfSAxel Dörfler 	udpChecksum
891c22d69bfSAxel Dörfler 		<< (uint16)htons(IPPROTO_UDP)
892c22d69bfSAxel Dörfler 		<< (uint16)htons(buffer->size)
893c22d69bfSAxel Dörfler 				// peculiar but correct: UDP-len is used twice for checksum
894c22d69bfSAxel Dörfler 				// (as it is already contained in udp_header)
895c35b04deSAxel Dörfler 		<< Checksum::BufferHelper(buffer, gBufferModule);
8966c353509SHugo Santos 
8976c353509SHugo Santos 	uint16 calculatedChecksum = udpChecksum;
8986c353509SHugo Santos 	if (calculatedChecksum == 0)
8996c353509SHugo Santos 		calculatedChecksum = 0xffff;
9006c353509SHugo Santos 
9016c353509SHugo Santos 	*UDPChecksumField(buffer) = calculatedChecksum;
902c22d69bfSAxel Dörfler 
903c22d69bfSAxel Dörfler 	TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: "));
9046c353509SHugo Santos 
905c22d69bfSAxel Dörfler 	return next->module->send_routed_data(next, route, buffer);
906c22d69bfSAxel Dörfler }
907c22d69bfSAxel Dörfler 
908c22d69bfSAxel Dörfler 
909bf48e753SHugo Santos status_t
910bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
911bf48e753SHugo Santos {
912bf48e753SHugo Santos 	TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size);
913bf48e753SHugo Santos 
914*1408d1f0SHugo Santos 	return gDatalinkModule->send_datagram(this, NULL, buffer);
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 {
924bfb45f71SHugo Santos 	size_t bytes = AvailableData();
925bfb45f71SHugo Santos 	TRACE_EP("BytesAvailable(): %lu", bytes);
926bfb45f71SHugo 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 
935bfb45f71SHugo 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 
940bfb45f71SHugo 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 
95049f3c71eSHugo Santos 	return SocketEnqueue(buffer);
951c22d69bfSAxel Dörfler }
952c22d69bfSAxel Dörfler 
953c22d69bfSAxel Dörfler 
9546a606180SHugo Santos status_t
9556a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
9566a606180SHugo Santos {
9576a606180SHugo Santos 	net_buffer *buffer = gBufferModule->clone(_buffer, false);
9586a606180SHugo Santos 	if (buffer == NULL)
9596a606180SHugo Santos 		return B_NO_MEMORY;
9606a606180SHugo Santos 
9616a606180SHugo Santos 	status_t status = sUdpEndpointManager->Deframe(buffer);
9626a606180SHugo Santos 	if (status < B_OK) {
9636a606180SHugo Santos 		gBufferModule->free(buffer);
9646a606180SHugo Santos 		return status;
9656a606180SHugo Santos 	}
9666a606180SHugo Santos 
9676a606180SHugo Santos 	// we call Enqueue() instead of SocketEnqueue() as there is
9686a606180SHugo Santos 	// no need to clone the buffer again.
9696a606180SHugo Santos 	return Enqueue(buffer);
9706a606180SHugo Santos }
9716a606180SHugo Santos 
9726a606180SHugo Santos 
973c22d69bfSAxel Dörfler // #pragma mark - protocol interface
974c22d69bfSAxel Dörfler 
975c22d69bfSAxel Dörfler 
976c22d69bfSAxel Dörfler net_protocol *
977c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
978c22d69bfSAxel Dörfler {
979c22d69bfSAxel Dörfler 	socket->protocol = IPPROTO_UDP;
980c22d69bfSAxel Dörfler 
981c22d69bfSAxel Dörfler 	UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
982bf48e753SHugo Santos 	if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
983bf48e753SHugo Santos 		delete endpoint;
984bf48e753SHugo Santos 		return NULL;
985bf48e753SHugo Santos 	}
986bf48e753SHugo Santos 
987c22d69bfSAxel Dörfler 	return endpoint;
988c22d69bfSAxel Dörfler }
989c22d69bfSAxel Dörfler 
990c22d69bfSAxel Dörfler 
991c22d69bfSAxel Dörfler status_t
992c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
993c22d69bfSAxel Dörfler {
994bf48e753SHugo Santos 	delete (UdpEndpoint *)protocol;
995c22d69bfSAxel Dörfler 	return B_OK;
996c22d69bfSAxel Dörfler }
997c22d69bfSAxel Dörfler 
998c22d69bfSAxel Dörfler 
999c22d69bfSAxel Dörfler status_t
1000c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1001c22d69bfSAxel Dörfler {
1002bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Open();
1003c22d69bfSAxel Dörfler }
1004c22d69bfSAxel Dörfler 
1005c22d69bfSAxel Dörfler 
1006c22d69bfSAxel Dörfler status_t
1007c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1008c22d69bfSAxel Dörfler {
1009bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Close();
1010c22d69bfSAxel Dörfler }
1011c22d69bfSAxel Dörfler 
1012c22d69bfSAxel Dörfler 
1013c22d69bfSAxel Dörfler status_t
1014c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1015c22d69bfSAxel Dörfler {
1016bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Free();
1017c22d69bfSAxel Dörfler }
1018c22d69bfSAxel Dörfler 
1019c22d69bfSAxel Dörfler 
1020c22d69bfSAxel Dörfler status_t
1021c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1022c22d69bfSAxel Dörfler {
1023bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Connect(address);
1024c22d69bfSAxel Dörfler }
1025c22d69bfSAxel Dörfler 
1026c22d69bfSAxel Dörfler 
1027c22d69bfSAxel Dörfler status_t
1028c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1029c22d69bfSAxel Dörfler {
1030c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1031c22d69bfSAxel Dörfler }
1032c22d69bfSAxel Dörfler 
1033c22d69bfSAxel Dörfler 
1034c22d69bfSAxel Dörfler status_t
1035c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1036c22d69bfSAxel Dörfler 	size_t *_length)
1037c22d69bfSAxel Dörfler {
1038c22d69bfSAxel Dörfler 	return protocol->next->module->control(protocol->next, level, option,
1039c22d69bfSAxel Dörfler 		value, _length);
1040c22d69bfSAxel Dörfler }
1041c22d69bfSAxel Dörfler 
1042c22d69bfSAxel Dörfler 
1043c22d69bfSAxel Dörfler status_t
1044c22d69bfSAxel Dörfler udp_bind(net_protocol *protocol, struct sockaddr *address)
1045c22d69bfSAxel Dörfler {
1046bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Bind(address);
1047c22d69bfSAxel Dörfler }
1048c22d69bfSAxel Dörfler 
1049c22d69bfSAxel Dörfler 
1050c22d69bfSAxel Dörfler status_t
1051c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1052c22d69bfSAxel Dörfler {
1053bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->Unbind(address);
1054c22d69bfSAxel Dörfler }
1055c22d69bfSAxel Dörfler 
1056c22d69bfSAxel Dörfler 
1057c22d69bfSAxel Dörfler status_t
1058c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1059c22d69bfSAxel Dörfler {
1060c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1061c22d69bfSAxel Dörfler }
1062c22d69bfSAxel Dörfler 
1063c22d69bfSAxel Dörfler 
1064c22d69bfSAxel Dörfler status_t
1065c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1066c22d69bfSAxel Dörfler {
1067c22d69bfSAxel Dörfler 	return EOPNOTSUPP;
1068c22d69bfSAxel Dörfler }
1069c22d69bfSAxel Dörfler 
1070c22d69bfSAxel Dörfler 
1071c22d69bfSAxel Dörfler status_t
1072c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1073c22d69bfSAxel Dörfler 	net_buffer *buffer)
1074c22d69bfSAxel Dörfler {
1075bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1076c22d69bfSAxel Dörfler }
1077c22d69bfSAxel Dörfler 
1078c22d69bfSAxel Dörfler 
1079c22d69bfSAxel Dörfler status_t
1080c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1081c22d69bfSAxel Dörfler {
1082bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->SendData(buffer);
1083c22d69bfSAxel Dörfler }
1084c22d69bfSAxel Dörfler 
1085c22d69bfSAxel Dörfler 
1086c22d69bfSAxel Dörfler ssize_t
1087c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1088c22d69bfSAxel Dörfler {
1089bf48e753SHugo Santos 	return protocol->socket->send.buffer_size;
1090c22d69bfSAxel Dörfler }
1091c22d69bfSAxel Dörfler 
1092c22d69bfSAxel Dörfler 
1093c22d69bfSAxel Dörfler status_t
1094c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1095c22d69bfSAxel Dörfler 	net_buffer **_buffer)
1096c22d69bfSAxel Dörfler {
1097bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1098c22d69bfSAxel Dörfler }
1099c22d69bfSAxel Dörfler 
1100c22d69bfSAxel Dörfler 
1101c22d69bfSAxel Dörfler ssize_t
1102c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1103c22d69bfSAxel Dörfler {
1104bf48e753SHugo Santos 	return ((UdpEndpoint *)protocol)->BytesAvailable();
1105c22d69bfSAxel Dörfler }
1106c22d69bfSAxel Dörfler 
1107c22d69bfSAxel Dörfler 
1108c22d69bfSAxel Dörfler struct net_domain *
1109c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1110c22d69bfSAxel Dörfler {
1111c22d69bfSAxel Dörfler 	return protocol->next->module->get_domain(protocol->next);
1112c22d69bfSAxel Dörfler }
1113c22d69bfSAxel Dörfler 
1114c22d69bfSAxel Dörfler 
1115c22d69bfSAxel Dörfler size_t
1116c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1117c22d69bfSAxel Dörfler {
1118c22d69bfSAxel Dörfler 	return protocol->next->module->get_mtu(protocol->next, address);
1119c22d69bfSAxel Dörfler }
1120c22d69bfSAxel Dörfler 
1121c22d69bfSAxel Dörfler 
1122c22d69bfSAxel Dörfler status_t
1123c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1124c22d69bfSAxel Dörfler {
1125c22d69bfSAxel Dörfler 	return sUdpEndpointManager->ReceiveData(buffer);
1126c22d69bfSAxel Dörfler }
1127c22d69bfSAxel Dörfler 
1128c22d69bfSAxel Dörfler 
1129c22d69bfSAxel Dörfler status_t
11306a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
11316a606180SHugo Santos {
11326a606180SHugo Santos 	return ((UdpEndpoint *)protocol)->DeliverData(buffer);
11336a606180SHugo Santos }
11346a606180SHugo Santos 
11356a606180SHugo Santos 
11366a606180SHugo Santos status_t
1137c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data)
1138c22d69bfSAxel Dörfler {
1139c22d69bfSAxel Dörfler 	return B_ERROR;
1140c22d69bfSAxel Dörfler }
1141c22d69bfSAxel Dörfler 
1142c22d69bfSAxel Dörfler 
1143c22d69bfSAxel Dörfler status_t
1144c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
1145c22d69bfSAxel Dörfler 	void *errorData)
1146c22d69bfSAxel Dörfler {
1147c22d69bfSAxel Dörfler 	return B_ERROR;
1148c22d69bfSAxel Dörfler }
1149c22d69bfSAxel Dörfler 
1150c22d69bfSAxel Dörfler 
1151c22d69bfSAxel Dörfler //	#pragma mark - module interface
1152c22d69bfSAxel Dörfler 
1153c22d69bfSAxel Dörfler 
1154c22d69bfSAxel Dörfler static status_t
1155c22d69bfSAxel Dörfler init_udp()
1156c22d69bfSAxel Dörfler {
1157c22d69bfSAxel Dörfler 	status_t status;
1158bf48e753SHugo Santos 	TRACE_EPM("init_udp()");
1159c22d69bfSAxel Dörfler 
1160c22d69bfSAxel Dörfler 	sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1161658a5506SHugo Santos 	if (sUdpEndpointManager == NULL)
1162658a5506SHugo Santos 		return B_NO_MEMORY;
1163658a5506SHugo Santos 
1164c22d69bfSAxel Dörfler 	status = sUdpEndpointManager->InitCheck();
1165c22d69bfSAxel Dörfler 	if (status != B_OK)
1166d438fa4cSHugo Santos 		goto err1;
1167c22d69bfSAxel Dörfler 
1168bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP,
1169c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1170c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1171c22d69bfSAxel Dörfler 		NULL);
1172c22d69bfSAxel Dörfler 	if (status < B_OK)
1173658a5506SHugo Santos 		goto err1;
1174bfb45f71SHugo Santos 	status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
1175c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1176c22d69bfSAxel Dörfler 		"network/protocols/ipv4/v1",
1177c22d69bfSAxel Dörfler 		NULL);
1178c22d69bfSAxel Dörfler 	if (status < B_OK)
1179658a5506SHugo Santos 		goto err1;
1180c22d69bfSAxel Dörfler 
1181bfb45f71SHugo Santos 	status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
1182c22d69bfSAxel Dörfler 		"network/protocols/udp/v1");
1183c22d69bfSAxel Dörfler 	if (status < B_OK)
1184658a5506SHugo Santos 		goto err1;
1185c22d69bfSAxel Dörfler 
1186c22d69bfSAxel Dörfler 	return B_OK;
1187c22d69bfSAxel Dörfler 
1188c22d69bfSAxel Dörfler err1:
1189658a5506SHugo Santos 	delete sUdpEndpointManager;
1190c22d69bfSAxel Dörfler 
1191bf48e753SHugo Santos 	TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
1192c22d69bfSAxel Dörfler 	return status;
1193c22d69bfSAxel Dörfler }
1194c22d69bfSAxel Dörfler 
1195c22d69bfSAxel Dörfler 
1196c22d69bfSAxel Dörfler static status_t
1197c22d69bfSAxel Dörfler uninit_udp()
1198c22d69bfSAxel Dörfler {
1199bf48e753SHugo Santos 	TRACE_EPM("uninit_udp()");
1200c22d69bfSAxel Dörfler 	delete sUdpEndpointManager;
1201c22d69bfSAxel Dörfler 	return B_OK;
1202c22d69bfSAxel Dörfler }
1203c22d69bfSAxel Dörfler 
1204c22d69bfSAxel Dörfler 
1205c22d69bfSAxel Dörfler static status_t
1206c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1207c22d69bfSAxel Dörfler {
1208c22d69bfSAxel Dörfler 	switch (op) {
1209c22d69bfSAxel Dörfler 		case B_MODULE_INIT:
1210c22d69bfSAxel Dörfler 			return init_udp();
1211c22d69bfSAxel Dörfler 
1212c22d69bfSAxel Dörfler 		case B_MODULE_UNINIT:
1213c22d69bfSAxel Dörfler 			return uninit_udp();
1214c22d69bfSAxel Dörfler 
1215c22d69bfSAxel Dörfler 		default:
1216c22d69bfSAxel Dörfler 			return B_ERROR;
1217c22d69bfSAxel Dörfler 	}
1218c22d69bfSAxel Dörfler }
1219c22d69bfSAxel Dörfler 
1220c22d69bfSAxel Dörfler 
1221c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1222c22d69bfSAxel Dörfler 	{
1223c22d69bfSAxel Dörfler 		"network/protocols/udp/v1",
1224c22d69bfSAxel Dörfler 		0,
1225c22d69bfSAxel Dörfler 		udp_std_ops
1226c22d69bfSAxel Dörfler 	},
1227c22d69bfSAxel Dörfler 	udp_init_protocol,
1228c22d69bfSAxel Dörfler 	udp_uninit_protocol,
1229c22d69bfSAxel Dörfler 	udp_open,
1230c22d69bfSAxel Dörfler 	udp_close,
1231c22d69bfSAxel Dörfler 	udp_free,
1232c22d69bfSAxel Dörfler 	udp_connect,
1233c22d69bfSAxel Dörfler 	udp_accept,
1234c22d69bfSAxel Dörfler 	udp_control,
1235c22d69bfSAxel Dörfler 	udp_bind,
1236c22d69bfSAxel Dörfler 	udp_unbind,
1237c22d69bfSAxel Dörfler 	udp_listen,
1238c22d69bfSAxel Dörfler 	udp_shutdown,
1239c22d69bfSAxel Dörfler 	udp_send_data,
1240c22d69bfSAxel Dörfler 	udp_send_routed_data,
1241c22d69bfSAxel Dörfler 	udp_send_avail,
1242c22d69bfSAxel Dörfler 	udp_read_data,
1243c22d69bfSAxel Dörfler 	udp_read_avail,
1244c22d69bfSAxel Dörfler 	udp_get_domain,
1245c22d69bfSAxel Dörfler 	udp_get_mtu,
1246c22d69bfSAxel Dörfler 	udp_receive_data,
12476a606180SHugo Santos 	udp_deliver_data,
1248c22d69bfSAxel Dörfler 	udp_error,
1249c22d69bfSAxel Dörfler 	udp_error_reply,
1250c22d69bfSAxel Dörfler };
1251c22d69bfSAxel Dörfler 
1252658a5506SHugo Santos module_dependency module_dependencies[] = {
1253658a5506SHugo Santos 	{NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1254658a5506SHugo Santos 	{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1255658a5506SHugo Santos 	{NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1256658a5506SHugo Santos 	{}
1257658a5506SHugo Santos };
1258658a5506SHugo Santos 
1259c22d69bfSAxel Dörfler module_info *modules[] = {
1260c22d69bfSAxel Dörfler 	(module_info *)&sUDPModule,
1261c22d69bfSAxel Dörfler 	NULL
1262c22d69bfSAxel Dörfler };
1263