1c22d69bfSAxel Dörfler /*
2cb319968SAdrien Destugues * Copyright 2006-2021, Haiku, Inc. All Rights Reserved.
3c22d69bfSAxel Dörfler * Distributed under the terms of the MIT License.
4c22d69bfSAxel Dörfler *
5c22d69bfSAxel Dörfler * Authors:
6c22d69bfSAxel Dörfler * Oliver Tappe, zooey@hirschkaefer.de
7c3e054c8SHugo Santos * Hugo Santos, hugosantos@gmail.com
8c22d69bfSAxel Dörfler */
9c22d69bfSAxel Dörfler
10c22d69bfSAxel Dörfler
11c22d69bfSAxel Dörfler #include <net_buffer.h>
12c22d69bfSAxel Dörfler #include <net_datalink.h>
13c22d69bfSAxel Dörfler #include <net_protocol.h>
14c22d69bfSAxel Dörfler #include <net_stack.h>
15c22d69bfSAxel Dörfler
16c22d69bfSAxel Dörfler #include <lock.h>
17c22d69bfSAxel Dörfler #include <util/AutoLock.h>
18bf48e753SHugo Santos #include <util/DoublyLinkedList.h>
1940bbf860SHugo Santos #include <util/OpenHashTable.h>
20c22d69bfSAxel Dörfler
21cb319968SAdrien Destugues #include <AutoDeleter.h>
22c22d69bfSAxel Dörfler #include <KernelExport.h>
23c22d69bfSAxel Dörfler
24c22d69bfSAxel Dörfler #include <NetBufferUtilities.h>
25c22d69bfSAxel Dörfler #include <NetUtilities.h>
26bfb45f71SHugo Santos #include <ProtocolUtilities.h>
27c22d69bfSAxel Dörfler
282bb43d82SAxel Dörfler #include <algorithm>
29c22d69bfSAxel Dörfler #include <netinet/in.h>
302bb43d82SAxel Dörfler #include <netinet/ip.h>
31c22d69bfSAxel Dörfler #include <new>
32c22d69bfSAxel Dörfler #include <stdlib.h>
33c22d69bfSAxel Dörfler #include <string.h>
34c3e054c8SHugo Santos #include <utility>
35c22d69bfSAxel Dörfler
36727ad0b0SHugo Santos
37727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
38727ad0b0SHugo Santos // lock before holding a child UdpEndpoint's lock. This restriction
39727ad0b0SHugo Santos // is dictated by the receive path as blind access to the endpoint
40f861e599SFrançois Revol // hash is required when holding the DomainSupport's lock.
41727ad0b0SHugo Santos
42727ad0b0SHugo Santos
43af3a31f7SAxel Dörfler //#define TRACE_UDP
44c22d69bfSAxel Dörfler #ifdef TRACE_UDP
45c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) dump_block x
46bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this
47bf48e753SHugo Santos // to compile with gcc 2.95
48bf9a85cbSJérôme Duval # define TRACE_EP(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \
49bf9a85cbSJérôme Duval B_PRIu32 "] %p " format "\n", system_time(), \
50bf9a85cbSJérôme Duval thread_get_current_thread_id(), this , ##args)
51bf9a85cbSJérôme Duval # define TRACE_EPM(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \
52bf9a85cbSJérôme Duval B_PRIu32 "] " format "\n", system_time() , \
53bf9a85cbSJérôme Duval thread_get_current_thread_id() , ##args)
54bf9a85cbSJérôme Duval # define TRACE_DOMAIN(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \
55bf9a85cbSJérôme Duval B_PRIu32 "] (%d) " format "\n", system_time(), \
56bf9a85cbSJérôme Duval thread_get_current_thread_id(), Domain()->family , ##args)
57c22d69bfSAxel Dörfler #else
58c22d69bfSAxel Dörfler # define TRACE_BLOCK(x)
59bf48e753SHugo Santos # define TRACE_EP(args...) do { } while (0)
60bf48e753SHugo Santos # define TRACE_EPM(args...) do { } while (0)
61bf48e753SHugo Santos # define TRACE_DOMAIN(args...) do { } while (0)
62c22d69bfSAxel Dörfler #endif
63c22d69bfSAxel Dörfler
64c22d69bfSAxel Dörfler
65c22d69bfSAxel Dörfler struct udp_header {
66c22d69bfSAxel Dörfler uint16 source_port;
67c22d69bfSAxel Dörfler uint16 destination_port;
68c22d69bfSAxel Dörfler uint16 udp_length;
69c22d69bfSAxel Dörfler uint16 udp_checksum;
70c22d69bfSAxel Dörfler } _PACKED;
71c22d69bfSAxel Dörfler
72c22d69bfSAxel Dörfler
736c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
746c353509SHugo Santos UDPChecksumField;
756c353509SHugo Santos
76bf48e753SHugo Santos class UdpDomainSupport;
776c353509SHugo Santos
78bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> {
79c22d69bfSAxel Dörfler public:
80c22d69bfSAxel Dörfler UdpEndpoint(net_socket* socket);
81bf48e753SHugo Santos
8253f23f85SHugo Santos status_t Bind(const sockaddr* newAddr);
83c22d69bfSAxel Dörfler status_t Unbind(sockaddr* newAddr);
84c22d69bfSAxel Dörfler status_t Connect(const sockaddr* newAddr);
85c22d69bfSAxel Dörfler
86c22d69bfSAxel Dörfler status_t Open();
87c22d69bfSAxel Dörfler status_t Close();
88c22d69bfSAxel Dörfler status_t Free();
89c22d69bfSAxel Dörfler
9056f097ebSOliver Tappe status_t SendRoutedData(net_buffer* buffer,
9156f097ebSOliver Tappe net_route* route);
92bf48e753SHugo Santos status_t SendData(net_buffer* buffer);
93c22d69bfSAxel Dörfler
94c22d69bfSAxel Dörfler ssize_t BytesAvailable();
95c22d69bfSAxel Dörfler status_t FetchData(size_t numBytes, uint32 flags,
96c22d69bfSAxel Dörfler net_buffer** _buffer);
97c22d69bfSAxel Dörfler
98c22d69bfSAxel Dörfler status_t StoreData(net_buffer* buffer);
996a606180SHugo Santos status_t DeliverData(net_buffer* buffer);
100c22d69bfSAxel Dörfler
101727ad0b0SHugo Santos // only the domain support will change/check the Active flag so
102727ad0b0SHugo Santos // we don't really need to protect it with the socket lock.
IsActive() const103727ad0b0SHugo Santos bool IsActive() const { return fActive; }
SetActive(bool newValue)104727ad0b0SHugo Santos void SetActive(bool newValue) { fActive = newValue; }
105bf48e753SHugo Santos
HashTableLink()1065147963dSStephan Aßmus UdpEndpoint*& HashTableLink() { return fLink; }
10740bbf860SHugo Santos
108cb99c915SAxel Dörfler void Dump() const;
109cb99c915SAxel Dörfler
110c22d69bfSAxel Dörfler private:
111c72ab92dSHugo Santos UdpDomainSupport* fManager;
112c22d69bfSAxel Dörfler bool fActive;
11356f097ebSOliver Tappe // an active UdpEndpoint is part of the
114cb99c915SAxel Dörfler // endpoint hash (and it is bound and
115cb99c915SAxel Dörfler // optionally connected)
11640bbf860SHugo Santos
1175147963dSStephan Aßmus UdpEndpoint* fLink;
11840bbf860SHugo Santos };
11940bbf860SHugo Santos
12040bbf860SHugo Santos
12140bbf860SHugo Santos class UdpDomainSupport;
12240bbf860SHugo Santos
12340bbf860SHugo Santos struct UdpHashDefinition {
12440bbf860SHugo Santos typedef net_address_module_info ParentType;
12540bbf860SHugo Santos typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
12640bbf860SHugo Santos typedef UdpEndpoint ValueType;
12740bbf860SHugo Santos
UdpHashDefinitionUdpHashDefinition12884052230SAxel Dörfler UdpHashDefinition(net_address_module_info *_module)
12984052230SAxel Dörfler : module(_module) {}
UdpHashDefinitionUdpHashDefinition13084052230SAxel Dörfler UdpHashDefinition(const UdpHashDefinition& definition)
13184052230SAxel Dörfler : module(definition.module) {}
13240bbf860SHugo Santos
HashKeyUdpHashDefinition13340bbf860SHugo Santos size_t HashKey(const KeyType &key) const
13440bbf860SHugo Santos {
13540bbf860SHugo Santos return _Mix(module->hash_address_pair(key.first, key.second));
13640bbf860SHugo Santos }
13740bbf860SHugo Santos
HashUdpHashDefinition13840bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const
13940bbf860SHugo Santos {
14056f097ebSOliver Tappe return _Mix(endpoint->LocalAddress().HashPair(
14156f097ebSOliver Tappe *endpoint->PeerAddress()));
14240bbf860SHugo Santos }
14340bbf860SHugo Santos
_MixUdpHashDefinition14440bbf860SHugo Santos static size_t _Mix(size_t hash)
14540bbf860SHugo Santos {
14656f097ebSOliver Tappe // move the bits into the relevant range (as defined by kNumHashBuckets)
14740bbf860SHugo Santos return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
14840bbf860SHugo Santos ^ (hash & 0xFFC00000UL) >> 22;
14940bbf860SHugo Santos }
15040bbf860SHugo Santos
CompareUdpHashDefinition15140bbf860SHugo Santos bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
15240bbf860SHugo Santos {
15340bbf860SHugo Santos return endpoint->LocalAddress().EqualTo(key.first, true)
15440bbf860SHugo Santos && endpoint->PeerAddress().EqualTo(key.second, true);
15540bbf860SHugo Santos }
15640bbf860SHugo Santos
GetLinkUdpHashDefinition1575147963dSStephan Aßmus UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const
15840bbf860SHugo Santos {
15940bbf860SHugo Santos return endpoint->HashTableLink();
16040bbf860SHugo Santos }
16140bbf860SHugo Santos
16240bbf860SHugo Santos net_address_module_info *module;
163c22d69bfSAxel Dörfler };
164c22d69bfSAxel Dörfler
165c22d69bfSAxel Dörfler
166bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
167c22d69bfSAxel Dörfler public:
168bf48e753SHugo Santos UdpDomainSupport(net_domain *domain);
169727ad0b0SHugo Santos ~UdpDomainSupport();
170c22d69bfSAxel Dörfler
171276aa463SIngo Weinhold status_t Init();
172bf48e753SHugo Santos
Domain() const173bf48e753SHugo Santos net_domain *Domain() const { return fDomain; }
174bf48e753SHugo Santos
Ref()175bf48e753SHugo Santos void Ref() { fEndpointCount++; }
Put()176727ad0b0SHugo Santos bool Put() { fEndpointCount--; return fEndpointCount == 0; }
177bf48e753SHugo Santos
178bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer* buffer);
1792bb43d82SAxel Dörfler status_t DeliverError(status_t error, net_buffer* buffer);
180727ad0b0SHugo Santos
181727ad0b0SHugo Santos status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
182727ad0b0SHugo Santos status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
183727ad0b0SHugo Santos status_t UnbindEndpoint(UdpEndpoint *endpoint);
184727ad0b0SHugo Santos
185cf5d9f4bSHugo Santos void DumpEndpoints() const;
186bf48e753SHugo Santos
187c22d69bfSAxel Dörfler private:
188727ad0b0SHugo Santos status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
189727ad0b0SHugo Santos status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
190727ad0b0SHugo Santos status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
191727ad0b0SHugo Santos status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
192727ad0b0SHugo Santos
19340bbf860SHugo Santos UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
194bbbb5592SAxel Dörfler const sockaddr *peerAddress, uint32 index = 0);
195bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer);
196bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer);
197bf48e753SHugo Santos
198bf48e753SHugo Santos uint16 _GetNextEphemeral();
199727ad0b0SHugo Santos UdpEndpoint *_EndpointWithPort(uint16 port) const;
200bf48e753SHugo Santos
AddressModule() const201bf48e753SHugo Santos net_address_module_info *AddressModule() const
202727ad0b0SHugo Santos { return fDomain->address_module; }
203bf48e753SHugo Santos
2045147963dSStephan Aßmus typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable;
20540bbf860SHugo Santos
2062b07b8e0SIngo Weinhold mutex fLock;
207bf48e753SHugo Santos net_domain *fDomain;
208bf48e753SHugo Santos uint16 fLastUsedEphemeral;
20940bbf860SHugo Santos EndpointTable fActiveEndpoints;
210bf48e753SHugo Santos uint32 fEndpointCount;
211bf48e753SHugo Santos
212bf48e753SHugo Santos static const uint16 kFirst = 49152;
213bf48e753SHugo Santos static const uint16 kLast = 65535;
214bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800;
215bf48e753SHugo Santos // if you change this, adjust the shifting in
216bf48e753SHugo Santos // Hash() accordingly!
217bf48e753SHugo Santos };
218bf48e753SHugo Santos
219bf48e753SHugo Santos
220bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
221bf48e753SHugo Santos
222bf48e753SHugo Santos
223bf48e753SHugo Santos class UdpEndpointManager {
224c22d69bfSAxel Dörfler public:
225c22d69bfSAxel Dörfler UdpEndpointManager();
226c22d69bfSAxel Dörfler ~UdpEndpointManager();
227c22d69bfSAxel Dörfler
2282bb43d82SAxel Dörfler status_t InitCheck() const;
2292bb43d82SAxel Dörfler
23074e1a530SJérôme Duval status_t ReceiveData(net_buffer* buffer);
2312bb43d82SAxel Dörfler status_t ReceiveError(status_t error,
2322bb43d82SAxel Dörfler net_buffer* buffer);
23374e1a530SJérôme Duval status_t Deframe(net_buffer* buffer);
234c22d69bfSAxel Dörfler
235bf48e753SHugo Santos UdpDomainSupport* OpenEndpoint(UdpEndpoint* endpoint);
236bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport* domain);
237c22d69bfSAxel Dörfler
238cf5d9f4bSHugo Santos static int DumpEndpoints(int argc, char *argv[]);
239cf5d9f4bSHugo Santos
240c22d69bfSAxel Dörfler private:
2419d433190SAxel Dörfler inline net_domain* _GetDomain(net_buffer* buffer);
2429d433190SAxel Dörfler UdpDomainSupport* _GetDomainSupport(net_domain* domain,
2439d433190SAxel Dörfler bool create);
2449d433190SAxel Dörfler UdpDomainSupport* _GetDomainSupport(net_buffer* buffer);
245bf48e753SHugo Santos
2462b07b8e0SIngo Weinhold mutex fLock;
247c22d69bfSAxel Dörfler status_t fStatus;
248bf48e753SHugo Santos UdpDomainList fDomains;
249c22d69bfSAxel Dörfler };
250c22d69bfSAxel Dörfler
251c22d69bfSAxel Dörfler
252c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager;
253c22d69bfSAxel Dörfler
254c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule;
255658a5506SHugo Santos net_datalink_module_info *gDatalinkModule;
256658a5506SHugo Santos net_stack_module_info *gStackModule;
2572bb43d82SAxel Dörfler net_socket_module_info *gSocketModule;
258c22d69bfSAxel Dörfler
259c22d69bfSAxel Dörfler
260c22d69bfSAxel Dörfler // #pragma mark -
261c22d69bfSAxel Dörfler
262c22d69bfSAxel Dörfler
UdpDomainSupport(net_domain * domain)263bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain)
264c22d69bfSAxel Dörfler :
265bf48e753SHugo Santos fDomain(domain),
266276aa463SIngo Weinhold fActiveEndpoints(domain->address_module),
267bf48e753SHugo Santos fEndpointCount(0)
268c22d69bfSAxel Dörfler {
2692b07b8e0SIngo Weinhold mutex_init(&fLock, "udp domain");
270727ad0b0SHugo Santos
271727ad0b0SHugo Santos fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
272727ad0b0SHugo Santos }
273727ad0b0SHugo Santos
274727ad0b0SHugo Santos
~UdpDomainSupport()275727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport()
276727ad0b0SHugo Santos {
2772b07b8e0SIngo Weinhold mutex_destroy(&fLock);
278bf48e753SHugo Santos }
279bf48e753SHugo Santos
280bf48e753SHugo Santos
281bf48e753SHugo Santos status_t
Init()282276aa463SIngo Weinhold UdpDomainSupport::Init()
283bf48e753SHugo Santos {
284276aa463SIngo Weinhold return fActiveEndpoints.Init(kNumHashBuckets);
285bf48e753SHugo Santos }
286bf48e753SHugo Santos
287bf48e753SHugo Santos
288bf48e753SHugo Santos status_t
DemuxIncomingBuffer(net_buffer * buffer)289bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
290bf48e753SHugo Santos {
2912bb43d82SAxel Dörfler // NOTE: multicast is delivered directly to the endpoint
2922b07b8e0SIngo Weinhold MutexLocker _(fLock);
293727ad0b0SHugo Santos
294e864e939SAugustin Cavalier if ((buffer->msg_flags & MSG_BCAST) != 0)
295bf48e753SHugo Santos return _DemuxBroadcast(buffer);
296e864e939SAugustin Cavalier if ((buffer->msg_flags & MSG_MCAST) != 0)
297727ad0b0SHugo Santos return B_ERROR;
298bf48e753SHugo Santos
299bf48e753SHugo Santos return _DemuxUnicast(buffer);
300bf48e753SHugo Santos }
301bf48e753SHugo Santos
302bf48e753SHugo Santos
303bf48e753SHugo Santos status_t
DeliverError(status_t error,net_buffer * buffer)3042bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
3052bb43d82SAxel Dörfler {
306e864e939SAugustin Cavalier if ((buffer->msg_flags & (MSG_BCAST | MSG_MCAST)) != 0)
3072bb43d82SAxel Dörfler return B_ERROR;
3082bb43d82SAxel Dörfler
3092bb43d82SAxel Dörfler MutexLocker _(fLock);
3102bb43d82SAxel Dörfler
3112e1729d0SAxel Dörfler // Forward the error to the socket
3122e1729d0SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source,
3132e1729d0SAxel Dörfler buffer->destination);
3142e1729d0SAxel Dörfler if (endpoint != NULL) {
3152bb43d82SAxel Dörfler gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error);
3162e1729d0SAxel Dörfler endpoint->NotifyOne();
3172e1729d0SAxel Dörfler }
3182bb43d82SAxel Dörfler
3192bb43d82SAxel Dörfler gBufferModule->free(buffer);
3202bb43d82SAxel Dörfler return B_OK;
3212bb43d82SAxel Dörfler }
3222bb43d82SAxel Dörfler
3232bb43d82SAxel Dörfler
3242bb43d82SAxel Dörfler status_t
BindEndpoint(UdpEndpoint * endpoint,const sockaddr * address)325727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
326727ad0b0SHugo Santos const sockaddr *address)
327727ad0b0SHugo Santos {
32856f097ebSOliver Tappe if (!AddressModule()->is_same_family(address))
32956f097ebSOliver Tappe return EAFNOSUPPORT;
33056f097ebSOliver Tappe
3312b07b8e0SIngo Weinhold MutexLocker _(fLock);
332727ad0b0SHugo Santos
333727ad0b0SHugo Santos if (endpoint->IsActive())
334727ad0b0SHugo Santos return EINVAL;
335727ad0b0SHugo Santos
336727ad0b0SHugo Santos return _BindEndpoint(endpoint, address);
337727ad0b0SHugo Santos }
338727ad0b0SHugo Santos
339727ad0b0SHugo Santos
340727ad0b0SHugo Santos status_t
ConnectEndpoint(UdpEndpoint * endpoint,const sockaddr * address)341727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
342727ad0b0SHugo Santos const sockaddr *address)
343727ad0b0SHugo Santos {
3442b07b8e0SIngo Weinhold MutexLocker _(fLock);
345727ad0b0SHugo Santos
346727ad0b0SHugo Santos if (endpoint->IsActive()) {
347727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint);
348727ad0b0SHugo Santos endpoint->SetActive(false);
349727ad0b0SHugo Santos }
350727ad0b0SHugo Santos
351727ad0b0SHugo Santos if (address->sa_family == AF_UNSPEC) {
352727ad0b0SHugo Santos // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
353727ad0b0SHugo Santos // so we reset the peer address:
354727ad0b0SHugo Santos endpoint->PeerAddress().SetToEmpty();
355727ad0b0SHugo Santos } else {
35656f097ebSOliver Tappe if (!AddressModule()->is_same_family(address))
35756f097ebSOliver Tappe return EAFNOSUPPORT;
35856f097ebSOliver Tappe
35956f097ebSOliver Tappe // consider destination address INADDR_ANY as INADDR_LOOPBACK
36056f097ebSOliver Tappe sockaddr_storage _address;
36156f097ebSOliver Tappe if (AddressModule()->is_empty_address(address, false)) {
36256f097ebSOliver Tappe AddressModule()->get_loopback_address((sockaddr *)&_address);
36356f097ebSOliver Tappe // for IPv4 and IPv6 the port is at the same offset
36456f097ebSOliver Tappe ((sockaddr_in&)_address).sin_port
36556f097ebSOliver Tappe = ((sockaddr_in *)address)->sin_port;
36656f097ebSOliver Tappe address = (sockaddr *)&_address;
36756f097ebSOliver Tappe }
36856f097ebSOliver Tappe
369727ad0b0SHugo Santos status_t status = endpoint->PeerAddress().SetTo(address);
370727ad0b0SHugo Santos if (status < B_OK)
371727ad0b0SHugo Santos return status;
3724e45de0eSOliver Tappe struct net_route *routeToDestination
3734e45de0eSOliver Tappe = gDatalinkModule->get_route(fDomain, address);
3744e45de0eSOliver Tappe if (routeToDestination) {
375184fada4SPhilippe Houdoin // stay bound to current local port, if any.
376184fada4SPhilippe Houdoin uint16 port = endpoint->LocalAddress().Port();
3774e45de0eSOliver Tappe status = endpoint->LocalAddress().SetTo(
37861729d93SAxel Dörfler routeToDestination->interface_address->local);
379184fada4SPhilippe Houdoin endpoint->LocalAddress().SetPort(port);
3804e45de0eSOliver Tappe gDatalinkModule->put_route(fDomain, routeToDestination);
3814e45de0eSOliver Tappe if (status < B_OK)
3824e45de0eSOliver Tappe return status;
3834e45de0eSOliver Tappe }
384727ad0b0SHugo Santos }
385727ad0b0SHugo Santos
386727ad0b0SHugo Santos // we need to activate no matter whether or not we have just disconnected,
387727ad0b0SHugo Santos // as calling connect() always triggers an implicit bind():
388a03ed4faSJérôme Duval status_t status = _BindEndpoint(endpoint, *endpoint->LocalAddress());
389a03ed4faSJérôme Duval if (status == B_OK)
390a03ed4faSJérôme Duval gSocketModule->set_connected(endpoint->Socket());
391a03ed4faSJérôme Duval return status;
392727ad0b0SHugo Santos }
393727ad0b0SHugo Santos
394727ad0b0SHugo Santos
395727ad0b0SHugo Santos status_t
UnbindEndpoint(UdpEndpoint * endpoint)396727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
397727ad0b0SHugo Santos {
3982b07b8e0SIngo Weinhold MutexLocker _(fLock);
399727ad0b0SHugo Santos
400727ad0b0SHugo Santos if (endpoint->IsActive())
401727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint);
402727ad0b0SHugo Santos
403727ad0b0SHugo Santos endpoint->SetActive(false);
404727ad0b0SHugo Santos
405727ad0b0SHugo Santos return B_OK;
406727ad0b0SHugo Santos }
407727ad0b0SHugo Santos
408727ad0b0SHugo Santos
409cf5d9f4bSHugo Santos void
DumpEndpoints() const410cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const
411cf5d9f4bSHugo Santos {
412cf5d9f4bSHugo Santos kprintf("-------- UDP Domain %p ---------\n", this);
413cf5d9f4bSHugo Santos kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
414cf5d9f4bSHugo Santos
415cf5d9f4bSHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
416cf5d9f4bSHugo Santos
417cb99c915SAxel Dörfler while (UdpEndpoint* endpoint = it.Next()) {
418cb99c915SAxel Dörfler endpoint->Dump();
419cf5d9f4bSHugo Santos }
420cf5d9f4bSHugo Santos }
421cf5d9f4bSHugo Santos
422cf5d9f4bSHugo Santos
423727ad0b0SHugo Santos status_t
_BindEndpoint(UdpEndpoint * endpoint,const sockaddr * address)424727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
425727ad0b0SHugo Santos const sockaddr *address)
426727ad0b0SHugo Santos {
427727ad0b0SHugo Santos if (AddressModule()->get_port(address) == 0)
428727ad0b0SHugo Santos return _BindToEphemeral(endpoint, address);
429727ad0b0SHugo Santos
430727ad0b0SHugo Santos return _Bind(endpoint, address);
431727ad0b0SHugo Santos }
432727ad0b0SHugo Santos
433727ad0b0SHugo Santos
434727ad0b0SHugo Santos status_t
_Bind(UdpEndpoint * endpoint,const sockaddr * address)435727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
436727ad0b0SHugo Santos {
437727ad0b0SHugo Santos int socketOptions = endpoint->Socket()->options;
43840bbf860SHugo Santos
43940bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
440bf48e753SHugo Santos
441bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind
442bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
443727ad0b0SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
444727ad0b0SHugo Santos address, true).Data());
445727ad0b0SHugo Santos
44640bbf860SHugo Santos while (it.HasNext()) {
44740bbf860SHugo Santos UdpEndpoint *otherEndpoint = it.Next();
44825a2744fSHugo Santos
449bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint,
4505084c839SHugo Santos ntohs(otherEndpoint->LocalAddress().Port()));
45125a2744fSHugo Santos
45225a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualPorts(address)) {
453bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
45456f097ebSOliver Tappe if ((otherEndpoint->Socket()->options
45556f097ebSOliver Tappe & (SO_REUSEADDR | SO_REUSEPORT)) == 0
456d0eaec30SMichael Lotz || (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
457727ad0b0SHugo Santos return EADDRINUSE;
45825a2744fSHugo Santos
459bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required:
46025a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualTo(address, false)
461d0eaec30SMichael Lotz && ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
462d0eaec30SMichael Lotz || (socketOptions & SO_REUSEPORT) == 0))
463727ad0b0SHugo Santos return EADDRINUSE;
464bf48e753SHugo Santos }
465bf48e753SHugo Santos }
466bf48e753SHugo Santos
467727ad0b0SHugo Santos return _FinishBind(endpoint, address);
468bf48e753SHugo Santos }
469bf48e753SHugo Santos
470bf48e753SHugo Santos
471bf48e753SHugo Santos status_t
_BindToEphemeral(UdpEndpoint * endpoint,const sockaddr * address)472727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
473727ad0b0SHugo Santos const sockaddr *address)
474727ad0b0SHugo Santos {
475727ad0b0SHugo Santos SocketAddressStorage newAddress(AddressModule());
476727ad0b0SHugo Santos status_t status = newAddress.SetTo(address);
477727ad0b0SHugo Santos if (status < B_OK)
478727ad0b0SHugo Santos return status;
479727ad0b0SHugo Santos
480727ad0b0SHugo Santos uint16 allocedPort = _GetNextEphemeral();
481727ad0b0SHugo Santos if (allocedPort == 0)
482727ad0b0SHugo Santos return ENOBUFS;
483727ad0b0SHugo Santos
4849e051839SOliver Tappe newAddress.SetPort(htons(allocedPort));
485727ad0b0SHugo Santos
486727ad0b0SHugo Santos return _FinishBind(endpoint, *newAddress);
487727ad0b0SHugo Santos }
488727ad0b0SHugo Santos
489727ad0b0SHugo Santos
490727ad0b0SHugo Santos status_t
_FinishBind(UdpEndpoint * endpoint,const sockaddr * address)491727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
492727ad0b0SHugo Santos {
493727ad0b0SHugo Santos status_t status = endpoint->next->module->bind(endpoint->next, address);
494727ad0b0SHugo Santos if (status < B_OK)
495727ad0b0SHugo Santos return status;
49640bbf860SHugo Santos
49740bbf860SHugo Santos fActiveEndpoints.Insert(endpoint);
498727ad0b0SHugo Santos endpoint->SetActive(true);
499727ad0b0SHugo Santos
50040bbf860SHugo Santos return B_OK;
501bf48e753SHugo Santos }
502bf48e753SHugo Santos
503bf48e753SHugo Santos
504c22d69bfSAxel Dörfler UdpEndpoint *
_FindActiveEndpoint(const sockaddr * ourAddress,const sockaddr * peerAddress,uint32 index)50540bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
506bbbb5592SAxel Dörfler const sockaddr *peerAddress, uint32 index)
507c22d69bfSAxel Dörfler {
5082e1729d0SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock);
5092e1729d0SAxel Dörfler
5109e051839SOliver Tappe TRACE_DOMAIN("finding Endpoint for %s <- %s",
511bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(),
512bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data());
513c3e054c8SHugo Santos
514bbbb5592SAxel Dörfler UdpEndpoint* endpoint = fActiveEndpoints.Lookup(
515bbbb5592SAxel Dörfler std::make_pair(ourAddress, peerAddress));
516bbbb5592SAxel Dörfler
517bbbb5592SAxel Dörfler // Make sure the bound_to_device constraint is fulfilled
518da0d7409SAxel Dörfler while (endpoint != NULL && endpoint->socket->bound_to_device != 0
519da0d7409SAxel Dörfler && index != 0 && endpoint->socket->bound_to_device != index) {
520bbbb5592SAxel Dörfler endpoint = endpoint->HashTableLink();
521bbbb5592SAxel Dörfler if (endpoint != NULL
522bbbb5592SAxel Dörfler && (!endpoint->LocalAddress().EqualTo(ourAddress, true)
523bbbb5592SAxel Dörfler || !endpoint->PeerAddress().EqualTo(peerAddress, true)))
524bbbb5592SAxel Dörfler return NULL;
525bbbb5592SAxel Dörfler }
526bbbb5592SAxel Dörfler
527bbbb5592SAxel Dörfler return endpoint;
528c22d69bfSAxel Dörfler }
529c22d69bfSAxel Dörfler
530c22d69bfSAxel Dörfler
531c22d69bfSAxel Dörfler status_t
_DemuxBroadcast(net_buffer * buffer)532bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
533c22d69bfSAxel Dörfler {
53479a0d252SHugo Santos sockaddr* peerAddr = buffer->source;
53579a0d252SHugo Santos sockaddr* broadcastAddr = buffer->destination;
5369d433190SAxel Dörfler uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
5379d433190SAxel Dörfler
538c22d69bfSAxel Dörfler sockaddr* mask = NULL;
53961729d93SAxel Dörfler if (buffer->interface_address != NULL)
54061729d93SAxel Dörfler mask = (sockaddr*)buffer->interface_address->mask;
541c22d69bfSAxel Dörfler
5429d433190SAxel Dörfler TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
543c22d69bfSAxel Dörfler
5449d433190SAxel Dörfler EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
545c22d69bfSAxel Dörfler
5469d433190SAxel Dörfler while (UdpEndpoint* endpoint = iterator.Next()) {
54725a2744fSHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...",
54825a2744fSHugo Santos AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
54925a2744fSHugo Santos
550bbbb5592SAxel Dörfler if (endpoint->socket->bound_to_device != 0
551bbbb5592SAxel Dörfler && buffer->index != endpoint->socket->bound_to_device)
552bbbb5592SAxel Dörfler continue;
553bbbb5592SAxel Dörfler
5545084c839SHugo Santos if (endpoint->LocalAddress().Port() != incomingPort) {
555c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint...
556c22d69bfSAxel Dörfler continue;
557c22d69bfSAxel Dörfler }
558c22d69bfSAxel Dörfler
55925a2744fSHugo Santos if (!endpoint->PeerAddress().IsEmpty(true)) {
560c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if
561c22d69bfSAxel Dörfler // this datagram is from there:
56225a2744fSHugo Santos if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
563c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to
564c22d69bfSAxel Dörfler // this endpoint...
565c22d69bfSAxel Dörfler continue;
566c22d69bfSAxel Dörfler }
567c22d69bfSAxel Dörfler }
568c22d69bfSAxel Dörfler
56925a2744fSHugo Santos if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
5709d433190SAxel Dörfler || mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
571c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint:
572c22d69bfSAxel Dörfler endpoint->StoreData(buffer);
573c22d69bfSAxel Dörfler }
574c22d69bfSAxel Dörfler }
57540bbf860SHugo Santos
576c22d69bfSAxel Dörfler return B_OK;
577c22d69bfSAxel Dörfler }
578c22d69bfSAxel Dörfler
579c22d69bfSAxel Dörfler
580c22d69bfSAxel Dörfler status_t
_DemuxUnicast(net_buffer * buffer)581bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
582c22d69bfSAxel Dörfler {
583bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
584c22d69bfSAxel Dörfler
5852e1729d0SAxel Dörfler const sockaddr* localAddress = buffer->destination;
5862e1729d0SAxel Dörfler const sockaddr* peerAddress = buffer->source;
5872e1729d0SAxel Dörfler
5882e1729d0SAxel Dörfler // look for full (most special) match:
589bbbb5592SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress,
590bbbb5592SAxel Dörfler buffer->index);
5912e1729d0SAxel Dörfler if (endpoint == NULL) {
5922e1729d0SAxel Dörfler // look for endpoint matching local address & port:
593bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index);
5942e1729d0SAxel Dörfler if (endpoint == NULL) {
5952e1729d0SAxel Dörfler // look for endpoint matching peer address & port and local port:
5962e1729d0SAxel Dörfler SocketAddressStorage local(AddressModule());
5972e1729d0SAxel Dörfler local.SetToEmpty();
5982e1729d0SAxel Dörfler local.SetPort(AddressModule()->get_port(localAddress));
599bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index);
6002e1729d0SAxel Dörfler if (endpoint == NULL) {
6012e1729d0SAxel Dörfler // last chance: look for endpoint matching local port only:
602bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(*local, NULL, buffer->index);
6032e1729d0SAxel Dörfler }
6042e1729d0SAxel Dörfler }
6052e1729d0SAxel Dörfler }
6062e1729d0SAxel Dörfler
6072bb43d82SAxel Dörfler if (endpoint == NULL) {
6082bb43d82SAxel Dörfler TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
609c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND;
6109e051839SOliver Tappe }
611c22d69bfSAxel Dörfler
612c22d69bfSAxel Dörfler endpoint->StoreData(buffer);
613c22d69bfSAxel Dörfler return B_OK;
614c22d69bfSAxel Dörfler }
615c22d69bfSAxel Dörfler
616c22d69bfSAxel Dörfler
617bf48e753SHugo Santos uint16
_GetNextEphemeral()618bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral()
619c22d69bfSAxel Dörfler {
62040bbf860SHugo Santos uint16 stop, curr;
621bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) {
622bf48e753SHugo Santos stop = fLastUsedEphemeral;
623bf48e753SHugo Santos curr = fLastUsedEphemeral + 1;
624bf48e753SHugo Santos } else {
625bf48e753SHugo Santos stop = kLast;
626bf48e753SHugo Santos curr = kFirst;
627bf48e753SHugo Santos }
628c22d69bfSAxel Dörfler
629727ad0b0SHugo Santos TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
630727ad0b0SHugo Santos fLastUsedEphemeral, curr, stop);
63140bbf860SHugo Santos
6329e051839SOliver Tappe // TODO: a free list could be used to avoid the impact of these two
6339e051839SOliver Tappe // nested loops most of the time... let's see how bad this really is
634727ad0b0SHugo Santos for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
635bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr);
63640bbf860SHugo Santos
637727ad0b0SHugo Santos if (_EndpointWithPort(htons(curr)) == NULL) {
638bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr);
639bf48e753SHugo Santos fLastUsedEphemeral = curr;
640bf48e753SHugo Santos return curr;
641bf48e753SHugo Santos }
642727ad0b0SHugo Santos }
643727ad0b0SHugo Santos
644727ad0b0SHugo Santos return 0;
645727ad0b0SHugo Santos }
646727ad0b0SHugo Santos
647727ad0b0SHugo Santos
648727ad0b0SHugo Santos UdpEndpoint *
_EndpointWithPort(uint16 port) const649727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const
650727ad0b0SHugo Santos {
651727ad0b0SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
652727ad0b0SHugo Santos
653727ad0b0SHugo Santos while (it.HasNext()) {
654727ad0b0SHugo Santos UdpEndpoint *endpoint = it.Next();
655727ad0b0SHugo Santos if (endpoint->LocalAddress().Port() == port)
656727ad0b0SHugo Santos return endpoint;
657727ad0b0SHugo Santos }
658727ad0b0SHugo Santos
659727ad0b0SHugo Santos return NULL;
660727ad0b0SHugo Santos }
661c22d69bfSAxel Dörfler
662bf48e753SHugo Santos
663bf48e753SHugo Santos // #pragma mark -
664bf48e753SHugo Santos
665bf48e753SHugo Santos
UdpEndpointManager()666bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager()
667bf48e753SHugo Santos {
6682b07b8e0SIngo Weinhold mutex_init(&fLock, "UDP endpoints");
6692b07b8e0SIngo Weinhold fStatus = B_OK;
670bf48e753SHugo Santos }
671bf48e753SHugo Santos
672bf48e753SHugo Santos
~UdpEndpointManager()673bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager()
674bf48e753SHugo Santos {
6752b07b8e0SIngo Weinhold mutex_destroy(&fLock);
676bf48e753SHugo Santos }
677bf48e753SHugo Santos
678bf48e753SHugo Santos
679bf48e753SHugo Santos status_t
InitCheck() const680bf48e753SHugo Santos UdpEndpointManager::InitCheck() const
681bf48e753SHugo Santos {
682bf48e753SHugo Santos return fStatus;
683bf48e753SHugo Santos }
684bf48e753SHugo Santos
685bf48e753SHugo Santos
686cf5d9f4bSHugo Santos int
DumpEndpoints(int argc,char * argv[])687cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
688cf5d9f4bSHugo Santos {
689cf5d9f4bSHugo Santos UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
690cf5d9f4bSHugo Santos
691eb5604bcSAdrien Destugues kprintf("===== UDP domain manager %p =====\n", sUdpEndpointManager);
692eb5604bcSAdrien Destugues
693cf5d9f4bSHugo Santos while (it.HasNext())
694cf5d9f4bSHugo Santos it.Next()->DumpEndpoints();
695cf5d9f4bSHugo Santos
696cf5d9f4bSHugo Santos return 0;
697cf5d9f4bSHugo Santos }
698cf5d9f4bSHugo Santos
699cf5d9f4bSHugo Santos
700bf48e753SHugo Santos // #pragma mark - inbound
701bf48e753SHugo Santos
702bf48e753SHugo Santos
703cb319968SAdrien Destugues struct DomainSupportDelete
704cb319968SAdrien Destugues {
operator ()DomainSupportDelete705cb319968SAdrien Destugues inline void operator()(UdpDomainSupport* object)
706cb319968SAdrien Destugues {
707cb319968SAdrien Destugues sUdpEndpointManager->FreeEndpoint(object);
708cb319968SAdrien Destugues }
709cb319968SAdrien Destugues };
710cb319968SAdrien Destugues
711cb319968SAdrien Destugues
712cb319968SAdrien Destugues struct DomainSupportDeleter
713cb319968SAdrien Destugues : BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>
714cb319968SAdrien Destugues {
DomainSupportDeleterDomainSupportDeleter715cb319968SAdrien Destugues DomainSupportDeleter(UdpDomainSupport* object)
716cb319968SAdrien Destugues : BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>(object)
717cb319968SAdrien Destugues {}
718cb319968SAdrien Destugues };
719cb319968SAdrien Destugues
720cb319968SAdrien Destugues
721bf48e753SHugo Santos status_t
ReceiveData(net_buffer * buffer)72274e1a530SJérôme Duval UdpEndpointManager::ReceiveData(net_buffer *buffer)
723c22d69bfSAxel Dörfler {
7242bb43d82SAxel Dörfler TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
7252bb43d82SAxel Dörfler
7269d433190SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7272bb43d82SAxel Dörfler if (domainSupport == NULL) {
7282bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as
7292bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets.
7302bb43d82SAxel Dörfler return B_ERROR;
7312bb43d82SAxel Dörfler }
732cb319968SAdrien Destugues DomainSupportDeleter deleter(domainSupport);
7332bb43d82SAxel Dörfler
73474e1a530SJérôme Duval status_t status = Deframe(buffer);
735eb5604bcSAdrien Destugues if (status != B_OK) {
7366a606180SHugo Santos return status;
737eb5604bcSAdrien Destugues }
7386a606180SHugo Santos
7392bb43d82SAxel Dörfler status = domainSupport->DemuxIncomingBuffer(buffer);
7402bb43d82SAxel Dörfler if (status != B_OK) {
7412bb43d82SAxel Dörfler TRACE_EPM(" ReceiveData(): no endpoint.");
7422bb43d82SAxel Dörfler // Send port unreachable error
7432bb43d82SAxel Dörfler domainSupport->Domain()->module->error_reply(NULL, buffer,
7442b415445SAxel Dörfler B_NET_ERROR_UNREACH_PORT, NULL);
7452bb43d82SAxel Dörfler return B_ERROR;
7462bb43d82SAxel Dörfler }
7472bb43d82SAxel Dörfler
7482bb43d82SAxel Dörfler gBufferModule->free(buffer);
7492bb43d82SAxel Dörfler return B_OK;
7502bb43d82SAxel Dörfler }
7512bb43d82SAxel Dörfler
7522bb43d82SAxel Dörfler
7532bb43d82SAxel Dörfler status_t
ReceiveError(status_t error,net_buffer * buffer)7542bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
7552bb43d82SAxel Dörfler {
7562bb43d82SAxel Dörfler TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
7572bb43d82SAxel Dörfler error, buffer, buffer->size);
7582bb43d82SAxel Dörfler
7592bb43d82SAxel Dörfler // We only really need the port information
7602bb43d82SAxel Dörfler if (buffer->size < 4)
7612bb43d82SAxel Dörfler return B_BAD_VALUE;
7622bb43d82SAxel Dörfler
7639d433190SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
7642bb43d82SAxel Dörfler if (domainSupport == NULL) {
7652bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as
7662bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets.
7672bb43d82SAxel Dörfler return B_ERROR;
7682bb43d82SAxel Dörfler }
769cb319968SAdrien Destugues DomainSupportDeleter deleter(domainSupport);
7702bb43d82SAxel Dörfler
7712bb43d82SAxel Dörfler // Deframe the buffer manually, as we usually only get 8 bytes from the
7722bb43d82SAxel Dörfler // original packet
7732bb43d82SAxel Dörfler udp_header header;
7742bb43d82SAxel Dörfler if (gBufferModule->read(buffer, 0, &header,
775eb5604bcSAdrien Destugues std::min((size_t)buffer->size, sizeof(udp_header))) != B_OK) {
7762bb43d82SAxel Dörfler return B_BAD_VALUE;
777eb5604bcSAdrien Destugues }
778bf48e753SHugo Santos
77961729d93SAxel Dörfler net_domain* domain = buffer->interface_address->domain;
7802bb43d82SAxel Dörfler net_address_module_info* addressModule = domain->address_module;
7816a606180SHugo Santos
7822bb43d82SAxel Dörfler SocketAddress source(addressModule, buffer->source);
7832bb43d82SAxel Dörfler SocketAddress destination(addressModule, buffer->destination);
7846a606180SHugo Santos
7852bb43d82SAxel Dörfler source.SetPort(header.source_port);
7862bb43d82SAxel Dörfler destination.SetPort(header.destination_port);
787727ad0b0SHugo Santos
788eb5604bcSAdrien Destugues error = domainSupport->DeliverError(error, buffer);
789eb5604bcSAdrien Destugues return error;
7906a606180SHugo Santos }
7916a606180SHugo Santos
7926a606180SHugo Santos
7936a606180SHugo Santos status_t
Deframe(net_buffer * buffer)79474e1a530SJérôme Duval UdpEndpointManager::Deframe(net_buffer* buffer)
7956a606180SHugo Santos {
796bf9a85cbSJérôme Duval TRACE_EPM("Deframe(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
7976a606180SHugo Santos
79887001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer);
7999d433190SAxel Dörfler if (bufferHeader.Status() != B_OK)
800c22d69bfSAxel Dörfler return bufferHeader.Status();
801c22d69bfSAxel Dörfler
802c22d69bfSAxel Dörfler udp_header& header = bufferHeader.Data();
803c22d69bfSAxel Dörfler
8049d433190SAxel Dörfler net_domain* domain = _GetDomain(buffer);
8059d433190SAxel Dörfler if (domain == NULL) {
8066a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain "
80761729d93SAxel Dörfler "specified (interface address %p).", buffer->interface_address);
808c22d69bfSAxel Dörfler return B_BAD_VALUE;
809c22d69bfSAxel Dörfler }
810bf48e753SHugo Santos net_address_module_info* addressModule = domain->address_module;
811bf48e753SHugo Santos
81279a0d252SHugo Santos SocketAddress source(addressModule, buffer->source);
81379a0d252SHugo Santos SocketAddress destination(addressModule, buffer->destination);
814bf48e753SHugo Santos
8154e8a1b33SHugo Santos source.SetPort(header.source_port);
8164e8a1b33SHugo Santos destination.SetPort(header.destination_port);
8174e8a1b33SHugo Santos
8184e8a1b33SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(),
8194e8a1b33SHugo Santos destination.AsString(true).Data());
820c22d69bfSAxel Dörfler
821c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length);
822c22d69bfSAxel Dörfler if (udpLength > buffer->size) {
8236a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.",
824bf48e753SHugo Santos udpLength);
825c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES;
826c22d69bfSAxel Dörfler }
827bf48e753SHugo Santos
82874e1a530SJérôme Duval if (buffer->size > udpLength)
829c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength);
830c22d69bfSAxel Dörfler
831*2a2f213fSAugustin Cavalier if (header.udp_checksum != 0 && (buffer->buffer_flags & NET_BUFFER_L4_CHECKSUM_VALID) == 0) {
832c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"):
833d5b5a2c2SHugo Santos uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
83474e1a530SJérôme Duval buffer, IPPROTO_UDP);
835c22d69bfSAxel Dörfler if (sum != 0) {
8366a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum);
837c22d69bfSAxel Dörfler return B_BAD_VALUE;
838c22d69bfSAxel Dörfler }
839c22d69bfSAxel Dörfler }
840c22d69bfSAxel Dörfler
841c22d69bfSAxel Dörfler bufferHeader.Remove();
842c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on
843c22d69bfSAxel Dörfler
8446a606180SHugo Santos return B_OK;
845c22d69bfSAxel Dörfler }
846c22d69bfSAxel Dörfler
847c22d69bfSAxel Dörfler
848bf48e753SHugo Santos UdpDomainSupport *
OpenEndpoint(UdpEndpoint * endpoint)849c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
850c22d69bfSAxel Dörfler {
8512b07b8e0SIngo Weinhold MutexLocker _(fLock);
852bf48e753SHugo Santos
8539d433190SAxel Dörfler UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
854bf48e753SHugo Santos return domain;
855bf48e753SHugo Santos }
856bf48e753SHugo Santos
857bf48e753SHugo Santos
858bf48e753SHugo Santos status_t
FreeEndpoint(UdpDomainSupport * domain)859bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
860bf48e753SHugo Santos {
8612b07b8e0SIngo Weinhold MutexLocker _(fLock);
862bf48e753SHugo Santos
863727ad0b0SHugo Santos if (domain->Put()) {
864bf48e753SHugo Santos fDomains.Remove(domain);
865bf48e753SHugo Santos delete domain;
866bf48e753SHugo Santos }
867bf48e753SHugo Santos
868bf48e753SHugo Santos return B_OK;
869bf48e753SHugo Santos }
870bf48e753SHugo Santos
871bf48e753SHugo Santos
872bf48e753SHugo Santos // #pragma mark -
873bf48e753SHugo Santos
874bf48e753SHugo Santos
8759d433190SAxel Dörfler inline net_domain*
_GetDomain(net_buffer * buffer)8769d433190SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer)
877bf48e753SHugo Santos {
8789d433190SAxel Dörfler if (buffer->interface_address != NULL)
8799d433190SAxel Dörfler return buffer->interface_address->domain;
8809d433190SAxel Dörfler
8819d433190SAxel Dörfler return gStackModule->get_domain(buffer->destination->sa_family);
8829d433190SAxel Dörfler }
8839d433190SAxel Dörfler
8849d433190SAxel Dörfler
8859d433190SAxel Dörfler UdpDomainSupport*
_GetDomainSupport(net_domain * domain,bool create)8869d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create)
8879d433190SAxel Dörfler {
8889d433190SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock);
8899d433190SAxel Dörfler
8909d433190SAxel Dörfler if (domain == NULL)
8919d433190SAxel Dörfler return NULL;
892bf48e753SHugo Santos
893bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain
894bf48e753SHugo Santos // receiver handlers that forward the requests to the
895bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while
896bf48e753SHugo Santos // being constructed UdpDomainSupport could call
897bf48e753SHugo Santos // register_domain_receiving_protocol() with the right
898bf48e753SHugo Santos // family.
8999d433190SAxel Dörfler UdpDomainList::Iterator iterator = fDomains.GetIterator();
9009d433190SAxel Dörfler while (UdpDomainSupport* domainSupport = iterator.Next()) {
901cb319968SAdrien Destugues if (domainSupport->Domain() == domain) {
902cb319968SAdrien Destugues domainSupport->Ref();
903bf48e753SHugo Santos return domainSupport;
904bf48e753SHugo Santos }
905cb319968SAdrien Destugues }
906bf48e753SHugo Santos
907bf48e753SHugo Santos if (!create)
908bf48e753SHugo Santos return NULL;
909bf48e753SHugo Santos
9109d433190SAxel Dörfler UdpDomainSupport* domainSupport
9119d433190SAxel Dörfler = new (std::nothrow) UdpDomainSupport(domain);
912276aa463SIngo Weinhold if (domainSupport == NULL || domainSupport->Init() < B_OK) {
913bf48e753SHugo Santos delete domainSupport;
914bf48e753SHugo Santos return NULL;
915bf48e753SHugo Santos }
916bf48e753SHugo Santos
917bf48e753SHugo Santos fDomains.Add(domainSupport);
918cb319968SAdrien Destugues domainSupport->Ref();
919bf48e753SHugo Santos return domainSupport;
920c22d69bfSAxel Dörfler }
921c22d69bfSAxel Dörfler
922c22d69bfSAxel Dörfler
9239d433190SAxel Dörfler /*! Retrieves the UdpDomainSupport object responsible for this buffer, if the
9249d433190SAxel Dörfler domain can be determined. This is only successful if the domain support is
9259d433190SAxel Dörfler already existing, ie. there must already be an endpoint for the domain.
9269d433190SAxel Dörfler */
9272bb43d82SAxel Dörfler UdpDomainSupport*
_GetDomainSupport(net_buffer * buffer)9289d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
9292bb43d82SAxel Dörfler {
9302bb43d82SAxel Dörfler MutexLocker _(fLock);
9319d433190SAxel Dörfler
932e94ea7bcSAugustin Cavalier return _GetDomainSupport(_GetDomain(buffer), false);
9332bb43d82SAxel Dörfler }
9342bb43d82SAxel Dörfler
9352bb43d82SAxel Dörfler
936c22d69bfSAxel Dörfler // #pragma mark -
937c22d69bfSAxel Dörfler
938c22d69bfSAxel Dörfler
UdpEndpoint(net_socket * socket)939c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket)
940cb99c915SAxel Dörfler :
941cb99c915SAxel Dörfler DatagramSocket<>("udp endpoint", socket),
942cb99c915SAxel Dörfler fActive(false)
943cb99c915SAxel Dörfler {
944cb99c915SAxel Dörfler }
945bf48e753SHugo Santos
946bf48e753SHugo Santos
947c22d69bfSAxel Dörfler // #pragma mark - activation
948c22d69bfSAxel Dörfler
949c22d69bfSAxel Dörfler
950c22d69bfSAxel Dörfler status_t
Bind(const sockaddr * address)95153f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address)
952c22d69bfSAxel Dörfler {
953bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
954727ad0b0SHugo Santos return fManager->BindEndpoint(this, address);
955c22d69bfSAxel Dörfler }
956c22d69bfSAxel Dörfler
957c22d69bfSAxel Dörfler
958c22d69bfSAxel Dörfler status_t
Unbind(sockaddr * address)959c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address)
960c22d69bfSAxel Dörfler {
961bf48e753SHugo Santos TRACE_EP("Unbind()");
962727ad0b0SHugo Santos return fManager->UnbindEndpoint(this);
963c22d69bfSAxel Dörfler }
964c22d69bfSAxel Dörfler
965c22d69bfSAxel Dörfler
966c22d69bfSAxel Dörfler status_t
Connect(const sockaddr * address)967c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address)
968c22d69bfSAxel Dörfler {
969bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
970727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address);
971c22d69bfSAxel Dörfler }
972c22d69bfSAxel Dörfler
973c22d69bfSAxel Dörfler
974c22d69bfSAxel Dörfler status_t
Open()975c22d69bfSAxel Dörfler UdpEndpoint::Open()
976c22d69bfSAxel Dörfler {
977bf48e753SHugo Santos TRACE_EP("Open()");
978bf48e753SHugo Santos
979119c6cddSIngo Weinhold AutoLocker _(fLock);
980727ad0b0SHugo Santos
981c72ab92dSHugo Santos status_t status = ProtocolSocket::Open();
982c72ab92dSHugo Santos if (status < B_OK)
983c72ab92dSHugo Santos return status;
984bf48e753SHugo Santos
985c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this);
986c72ab92dSHugo Santos if (fManager == NULL)
987bf48e753SHugo Santos return EAFNOSUPPORT;
988bf48e753SHugo Santos
989bf48e753SHugo Santos return B_OK;
990c22d69bfSAxel Dörfler }
991c22d69bfSAxel Dörfler
992c22d69bfSAxel Dörfler
993c22d69bfSAxel Dörfler status_t
Close()994c22d69bfSAxel Dörfler UdpEndpoint::Close()
995c22d69bfSAxel Dörfler {
996bf48e753SHugo Santos TRACE_EP("Close()");
99783fd8a61SPawel Dziepak fSocket->error = EBADF;
99883fd8a61SPawel Dziepak WakeAll();
999bf48e753SHugo Santos return B_OK;
1000c22d69bfSAxel Dörfler }
1001c22d69bfSAxel Dörfler
1002c22d69bfSAxel Dörfler
1003c22d69bfSAxel Dörfler status_t
Free()1004c22d69bfSAxel Dörfler UdpEndpoint::Free()
1005c22d69bfSAxel Dörfler {
1006bf48e753SHugo Santos TRACE_EP("Free()");
10070086fe20SHugo Santos fManager->UnbindEndpoint(this);
1008c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager);
1009c22d69bfSAxel Dörfler }
1010c22d69bfSAxel Dörfler
1011c22d69bfSAxel Dörfler
1012c22d69bfSAxel Dörfler // #pragma mark - outbound
1013c22d69bfSAxel Dörfler
1014c22d69bfSAxel Dörfler
1015c22d69bfSAxel Dörfler status_t
SendRoutedData(net_buffer * buffer,net_route * route)1016bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
1017c22d69bfSAxel Dörfler {
1018bf9a85cbSJérôme Duval TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer,
1019bf9a85cbSJérôme Duval buffer->size, route);
1020bf48e753SHugo Santos
1021d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header)))
1022c22d69bfSAxel Dörfler return EMSGSIZE;
1023c22d69bfSAxel Dörfler
102474e1a530SJérôme Duval buffer->protocol = IPPROTO_UDP;
1025c22d69bfSAxel Dörfler
1026c22d69bfSAxel Dörfler // add and fill UDP-specific header:
10276c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer);
10286c353509SHugo Santos if (header.Status() < B_OK)
10296c353509SHugo Santos return header.Status();
1030c22d69bfSAxel Dörfler
103179a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source);
103279a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination);
10336c353509SHugo Santos header->udp_length = htons(buffer->size);
1034c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size
10356c353509SHugo Santos header->udp_checksum = 0;
10366c353509SHugo Santos
10376c353509SHugo Santos header.Sync();
1038c22d69bfSAxel Dörfler
1039d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1040d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP);
10416c353509SHugo Santos if (calculatedChecksum == 0)
10426c353509SHugo Santos calculatedChecksum = 0xffff;
10436c353509SHugo Santos
10446c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum;
1045*2a2f213fSAugustin Cavalier buffer->buffer_flags |= NET_BUFFER_L4_CHECKSUM_VALID;
1046c22d69bfSAxel Dörfler
1047c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer);
1048c22d69bfSAxel Dörfler }
1049c22d69bfSAxel Dörfler
1050c22d69bfSAxel Dörfler
1051bf48e753SHugo Santos status_t
SendData(net_buffer * buffer)1052bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer)
1053bf48e753SHugo Santos {
1054bf9a85cbSJérôme Duval TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1055bf48e753SHugo Santos
10562651e51dSAxel Dörfler return gDatalinkModule->send_data(this, NULL, buffer);
1057bf48e753SHugo Santos }
1058bf48e753SHugo Santos
1059bf48e753SHugo Santos
1060c22d69bfSAxel Dörfler // #pragma mark - inbound
1061c22d69bfSAxel Dörfler
1062c22d69bfSAxel Dörfler
1063c22d69bfSAxel Dörfler ssize_t
BytesAvailable()1064c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable()
1065c22d69bfSAxel Dörfler {
1066bfb45f71SHugo Santos size_t bytes = AvailableData();
1067bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes);
1068bfb45f71SHugo Santos return bytes;
1069c22d69bfSAxel Dörfler }
1070c22d69bfSAxel Dörfler
1071c22d69bfSAxel Dörfler
1072c22d69bfSAxel Dörfler status_t
FetchData(size_t numBytes,uint32 flags,net_buffer ** _buffer)1073c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1074c22d69bfSAxel Dörfler {
1075bf9a85cbSJérôme Duval TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags);
1076bf48e753SHugo Santos
10772651e51dSAxel Dörfler status_t status = Dequeue(flags, _buffer);
1078cb99c915SAxel Dörfler TRACE_EP(" FetchData(): returned from fifo status: %s", strerror(status));
10792651e51dSAxel Dörfler if (status != B_OK)
1080c22d69bfSAxel Dörfler return status;
1081c22d69bfSAxel Dörfler
1082bf9a85cbSJérôme Duval TRACE_EP(" FetchData(): returns buffer with %" B_PRIu32 " bytes",
1083bf9a85cbSJérôme Duval (*_buffer)->size);
1084c22d69bfSAxel Dörfler return B_OK;
1085c22d69bfSAxel Dörfler }
1086c22d69bfSAxel Dörfler
1087c22d69bfSAxel Dörfler
1088c22d69bfSAxel Dörfler status_t
StoreData(net_buffer * buffer)1089bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer)
1090c22d69bfSAxel Dörfler {
1091bf9a85cbSJérôme Duval TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1092c22d69bfSAxel Dörfler
10932651e51dSAxel Dörfler return EnqueueClone(buffer);
1094c22d69bfSAxel Dörfler }
1095c22d69bfSAxel Dörfler
1096c22d69bfSAxel Dörfler
10976a606180SHugo Santos status_t
DeliverData(net_buffer * _buffer)10986a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer)
10996a606180SHugo Santos {
1100bf9a85cbSJérôme Duval TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size);
1101f6cfc5afSHugo Santos
11026a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false);
11036a606180SHugo Santos if (buffer == NULL)
11046a606180SHugo Santos return B_NO_MEMORY;
11056a606180SHugo Santos
110674e1a530SJérôme Duval status_t status = sUdpEndpointManager->Deframe(buffer);
11076a606180SHugo Santos if (status < B_OK) {
11086a606180SHugo Santos gBufferModule->free(buffer);
11096a606180SHugo Santos return status;
11106a606180SHugo Santos }
11116a606180SHugo Santos
11126a606180SHugo Santos return Enqueue(buffer);
11136a606180SHugo Santos }
11146a606180SHugo Santos
11156a606180SHugo Santos
1116cb99c915SAxel Dörfler void
Dump() const1117cb99c915SAxel Dörfler UdpEndpoint::Dump() const
1118cb99c915SAxel Dörfler {
1119cb99c915SAxel Dörfler char local[64];
1120cb99c915SAxel Dörfler LocalAddress().AsString(local, sizeof(local), true);
1121cb99c915SAxel Dörfler char peer[64];
1122cb99c915SAxel Dörfler PeerAddress().AsString(peer, sizeof(peer), true);
1123cb99c915SAxel Dörfler
1124cb99c915SAxel Dörfler kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1125cb99c915SAxel Dörfler }
1126cb99c915SAxel Dörfler
1127cb99c915SAxel Dörfler
1128c22d69bfSAxel Dörfler // #pragma mark - protocol interface
1129c22d69bfSAxel Dörfler
1130c22d69bfSAxel Dörfler
1131c22d69bfSAxel Dörfler net_protocol *
udp_init_protocol(net_socket * socket)1132c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket)
1133c22d69bfSAxel Dörfler {
1134c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP;
1135c22d69bfSAxel Dörfler
1136c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1137bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1138bf48e753SHugo Santos delete endpoint;
1139bf48e753SHugo Santos return NULL;
1140bf48e753SHugo Santos }
1141bf48e753SHugo Santos
1142c22d69bfSAxel Dörfler return endpoint;
1143c22d69bfSAxel Dörfler }
1144c22d69bfSAxel Dörfler
1145c22d69bfSAxel Dörfler
1146c22d69bfSAxel Dörfler status_t
udp_uninit_protocol(net_protocol * protocol)1147c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol)
1148c22d69bfSAxel Dörfler {
1149bf48e753SHugo Santos delete (UdpEndpoint *)protocol;
1150c22d69bfSAxel Dörfler return B_OK;
1151c22d69bfSAxel Dörfler }
1152c22d69bfSAxel Dörfler
1153c22d69bfSAxel Dörfler
1154c22d69bfSAxel Dörfler status_t
udp_open(net_protocol * protocol)1155c22d69bfSAxel Dörfler udp_open(net_protocol *protocol)
1156c22d69bfSAxel Dörfler {
1157bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open();
1158c22d69bfSAxel Dörfler }
1159c22d69bfSAxel Dörfler
1160c22d69bfSAxel Dörfler
1161c22d69bfSAxel Dörfler status_t
udp_close(net_protocol * protocol)1162c22d69bfSAxel Dörfler udp_close(net_protocol *protocol)
1163c22d69bfSAxel Dörfler {
1164bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close();
1165c22d69bfSAxel Dörfler }
1166c22d69bfSAxel Dörfler
1167c22d69bfSAxel Dörfler
1168c22d69bfSAxel Dörfler status_t
udp_free(net_protocol * protocol)1169c22d69bfSAxel Dörfler udp_free(net_protocol *protocol)
1170c22d69bfSAxel Dörfler {
1171bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free();
1172c22d69bfSAxel Dörfler }
1173c22d69bfSAxel Dörfler
1174c22d69bfSAxel Dörfler
1175c22d69bfSAxel Dörfler status_t
udp_connect(net_protocol * protocol,const struct sockaddr * address)1176c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address)
1177c22d69bfSAxel Dörfler {
1178bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address);
1179c22d69bfSAxel Dörfler }
1180c22d69bfSAxel Dörfler
1181c22d69bfSAxel Dörfler
1182c22d69bfSAxel Dörfler status_t
udp_accept(net_protocol * protocol,struct net_socket ** _acceptedSocket)1183c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1184c22d69bfSAxel Dörfler {
1185ca215dfeSAxel Dörfler return B_NOT_SUPPORTED;
1186c22d69bfSAxel Dörfler }
1187c22d69bfSAxel Dörfler
1188c22d69bfSAxel Dörfler
1189c22d69bfSAxel Dörfler status_t
udp_control(net_protocol * protocol,int level,int option,void * value,size_t * _length)1190c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value,
1191c22d69bfSAxel Dörfler size_t *_length)
1192c22d69bfSAxel Dörfler {
1193c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option,
1194c22d69bfSAxel Dörfler value, _length);
1195c22d69bfSAxel Dörfler }
1196c22d69bfSAxel Dörfler
1197c22d69bfSAxel Dörfler
1198c22d69bfSAxel Dörfler status_t
udp_getsockopt(net_protocol * protocol,int level,int option,void * value,int * length)119945b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
120045b5203bSHugo Santos int *length)
120145b5203bSHugo Santos {
120245b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option,
120345b5203bSHugo Santos value, length);
120445b5203bSHugo Santos }
120545b5203bSHugo Santos
120645b5203bSHugo Santos
120745b5203bSHugo Santos status_t
udp_setsockopt(net_protocol * protocol,int level,int option,const void * value,int length)120845b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option,
120945b5203bSHugo Santos const void *value, int length)
121045b5203bSHugo Santos {
121145b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option,
121245b5203bSHugo Santos value, length);
121345b5203bSHugo Santos }
121445b5203bSHugo Santos
121545b5203bSHugo Santos
121645b5203bSHugo Santos status_t
udp_bind(net_protocol * protocol,const struct sockaddr * address)121753f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address)
1218c22d69bfSAxel Dörfler {
1219bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address);
1220c22d69bfSAxel Dörfler }
1221c22d69bfSAxel Dörfler
1222c22d69bfSAxel Dörfler
1223c22d69bfSAxel Dörfler status_t
udp_unbind(net_protocol * protocol,struct sockaddr * address)1224c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address)
1225c22d69bfSAxel Dörfler {
1226bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address);
1227c22d69bfSAxel Dörfler }
1228c22d69bfSAxel Dörfler
1229c22d69bfSAxel Dörfler
1230c22d69bfSAxel Dörfler status_t
udp_listen(net_protocol * protocol,int count)1231c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count)
1232c22d69bfSAxel Dörfler {
1233ca215dfeSAxel Dörfler return B_NOT_SUPPORTED;
1234c22d69bfSAxel Dörfler }
1235c22d69bfSAxel Dörfler
1236c22d69bfSAxel Dörfler
1237c22d69bfSAxel Dörfler status_t
udp_shutdown(net_protocol * protocol,int direction)1238c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction)
1239c22d69bfSAxel Dörfler {
1240ca215dfeSAxel Dörfler return B_NOT_SUPPORTED;
1241c22d69bfSAxel Dörfler }
1242c22d69bfSAxel Dörfler
1243c22d69bfSAxel Dörfler
1244c22d69bfSAxel Dörfler status_t
udp_send_routed_data(net_protocol * protocol,struct net_route * route,net_buffer * buffer)1245c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1246c22d69bfSAxel Dörfler net_buffer *buffer)
1247c22d69bfSAxel Dörfler {
1248bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1249c22d69bfSAxel Dörfler }
1250c22d69bfSAxel Dörfler
1251c22d69bfSAxel Dörfler
1252c22d69bfSAxel Dörfler status_t
udp_send_data(net_protocol * protocol,net_buffer * buffer)1253c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer)
1254c22d69bfSAxel Dörfler {
1255bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer);
1256c22d69bfSAxel Dörfler }
1257c22d69bfSAxel Dörfler
1258c22d69bfSAxel Dörfler
1259c22d69bfSAxel Dörfler ssize_t
udp_send_avail(net_protocol * protocol)1260c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol)
1261c22d69bfSAxel Dörfler {
1262bf48e753SHugo Santos return protocol->socket->send.buffer_size;
1263c22d69bfSAxel Dörfler }
1264c22d69bfSAxel Dörfler
1265c22d69bfSAxel Dörfler
1266c22d69bfSAxel Dörfler status_t
udp_read_data(net_protocol * protocol,size_t numBytes,uint32 flags,net_buffer ** _buffer)1267c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1268c22d69bfSAxel Dörfler net_buffer **_buffer)
1269c22d69bfSAxel Dörfler {
1270bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1271c22d69bfSAxel Dörfler }
1272c22d69bfSAxel Dörfler
1273c22d69bfSAxel Dörfler
1274c22d69bfSAxel Dörfler ssize_t
udp_read_avail(net_protocol * protocol)1275c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol)
1276c22d69bfSAxel Dörfler {
1277bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable();
1278c22d69bfSAxel Dörfler }
1279c22d69bfSAxel Dörfler
1280c22d69bfSAxel Dörfler
1281c22d69bfSAxel Dörfler struct net_domain *
udp_get_domain(net_protocol * protocol)1282c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol)
1283c22d69bfSAxel Dörfler {
1284c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next);
1285c22d69bfSAxel Dörfler }
1286c22d69bfSAxel Dörfler
1287c22d69bfSAxel Dörfler
1288c22d69bfSAxel Dörfler size_t
udp_get_mtu(net_protocol * protocol,const struct sockaddr * address)1289c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1290c22d69bfSAxel Dörfler {
1291c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address);
1292c22d69bfSAxel Dörfler }
1293c22d69bfSAxel Dörfler
1294c22d69bfSAxel Dörfler
1295c22d69bfSAxel Dörfler status_t
udp_receive_data(net_buffer * buffer)1296c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer)
1297c22d69bfSAxel Dörfler {
1298c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer);
1299c22d69bfSAxel Dörfler }
1300c22d69bfSAxel Dörfler
1301c22d69bfSAxel Dörfler
1302c22d69bfSAxel Dörfler status_t
udp_deliver_data(net_protocol * protocol,net_buffer * buffer)13036a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
13046a606180SHugo Santos {
13056a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer);
13066a606180SHugo Santos }
13076a606180SHugo Santos
13086a606180SHugo Santos
13096a606180SHugo Santos status_t
udp_error_received(net_error error,net_buffer * buffer)13102b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer)
1311c22d69bfSAxel Dörfler {
13122b415445SAxel Dörfler status_t notifyError = B_OK;
13132bb43d82SAxel Dörfler
13142b415445SAxel Dörfler switch (error) {
13152b415445SAxel Dörfler case B_NET_ERROR_UNREACH_NET:
13162b415445SAxel Dörfler notifyError = ENETUNREACH;
13172bb43d82SAxel Dörfler break;
13182b415445SAxel Dörfler case B_NET_ERROR_UNREACH_HOST:
13192b415445SAxel Dörfler case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
13202b415445SAxel Dörfler notifyError = EHOSTUNREACH;
13212bb43d82SAxel Dörfler break;
13222b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PROTOCOL:
13232b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PORT:
13242b415445SAxel Dörfler notifyError = ECONNREFUSED;
13252bb43d82SAxel Dörfler break;
13262b415445SAxel Dörfler case B_NET_ERROR_MESSAGE_SIZE:
13272b415445SAxel Dörfler notifyError = EMSGSIZE;
13282b415445SAxel Dörfler break;
13292b415445SAxel Dörfler case B_NET_ERROR_PARAMETER_PROBLEM:
13302b415445SAxel Dörfler notifyError = ENOPROTOOPT;
13312b415445SAxel Dörfler break;
13322b415445SAxel Dörfler
13332b415445SAxel Dörfler case B_NET_ERROR_QUENCH:
13342bb43d82SAxel Dörfler default:
13352bb43d82SAxel Dörfler // ignore them
13362bb43d82SAxel Dörfler gBufferModule->free(buffer);
13372bb43d82SAxel Dörfler return B_OK;
1338c22d69bfSAxel Dörfler }
1339c22d69bfSAxel Dörfler
13407e046eabSAxel Dörfler ASSERT(notifyError != B_OK);
13417e046eabSAxel Dörfler
13427e046eabSAxel Dörfler return sUdpEndpointManager->ReceiveError(notifyError, buffer);
13437e046eabSAxel Dörfler }
13447e046eabSAxel Dörfler
1345c22d69bfSAxel Dörfler
1346c22d69bfSAxel Dörfler status_t
udp_error_reply(net_protocol * protocol,net_buffer * cause,net_error error,net_error_data * errorData)13472b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
13482b415445SAxel Dörfler net_error_data *errorData)
1349c22d69bfSAxel Dörfler {
1350c22d69bfSAxel Dörfler return B_ERROR;
1351c22d69bfSAxel Dörfler }
1352c22d69bfSAxel Dörfler
1353c22d69bfSAxel Dörfler
135478888c44SAxel Dörfler ssize_t
udp_process_ancillary_data_no_container(net_protocol * protocol,net_buffer * buffer,void * data,size_t dataSize)135578888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol,
135678888c44SAxel Dörfler net_buffer* buffer, void *data, size_t dataSize)
135778888c44SAxel Dörfler {
135878888c44SAxel Dörfler return protocol->next->module->process_ancillary_data_no_container(
135978888c44SAxel Dörfler protocol, buffer, data, dataSize);
136078888c44SAxel Dörfler }
136178888c44SAxel Dörfler
136278888c44SAxel Dörfler
1363c22d69bfSAxel Dörfler // #pragma mark - module interface
1364c22d69bfSAxel Dörfler
1365c22d69bfSAxel Dörfler
1366c22d69bfSAxel Dörfler static status_t
init_udp()1367c22d69bfSAxel Dörfler init_udp()
1368c22d69bfSAxel Dörfler {
1369c22d69bfSAxel Dörfler status_t status;
1370bf48e753SHugo Santos TRACE_EPM("init_udp()");
1371c22d69bfSAxel Dörfler
1372c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1373658a5506SHugo Santos if (sUdpEndpointManager == NULL)
1374658a5506SHugo Santos return B_NO_MEMORY;
1375658a5506SHugo Santos
1376c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck();
1377c22d69bfSAxel Dörfler if (status != B_OK)
1378d438fa4cSHugo Santos goto err1;
1379c22d69bfSAxel Dörfler
138061729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
138161729d93SAxel Dörfler IPPROTO_IP,
1382c22d69bfSAxel Dörfler "network/protocols/udp/v1",
1383c22d69bfSAxel Dörfler "network/protocols/ipv4/v1",
1384c22d69bfSAxel Dörfler NULL);
1385c22d69bfSAxel Dörfler if (status < B_OK)
1386658a5506SHugo Santos goto err1;
138761729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
138861729d93SAxel Dörfler IPPROTO_IP,
13898d1485faSAxel Dörfler "network/protocols/udp/v1",
13908d1485faSAxel Dörfler "network/protocols/ipv6/v1",
13918d1485faSAxel Dörfler NULL);
13928d1485faSAxel Dörfler if (status < B_OK)
13938d1485faSAxel Dörfler goto err1;
13948d1485faSAxel Dörfler
139561729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
139661729d93SAxel Dörfler IPPROTO_UDP,
1397c22d69bfSAxel Dörfler "network/protocols/udp/v1",
1398c22d69bfSAxel Dörfler "network/protocols/ipv4/v1",
1399c22d69bfSAxel Dörfler NULL);
1400c22d69bfSAxel Dörfler if (status < B_OK)
1401658a5506SHugo Santos goto err1;
140261729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
140361729d93SAxel Dörfler IPPROTO_UDP,
14048d1485faSAxel Dörfler "network/protocols/udp/v1",
14058d1485faSAxel Dörfler "network/protocols/ipv6/v1",
14068d1485faSAxel Dörfler NULL);
14078d1485faSAxel Dörfler if (status < B_OK)
14088d1485faSAxel Dörfler goto err1;
1409c22d69bfSAxel Dörfler
141061729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET,
141161729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1");
1412c22d69bfSAxel Dörfler if (status < B_OK)
1413658a5506SHugo Santos goto err1;
141461729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET6,
141561729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1");
14168d1485faSAxel Dörfler if (status < B_OK)
14178d1485faSAxel Dörfler goto err1;
1418c22d69bfSAxel Dörfler
1419cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1420cf5d9f4bSHugo Santos "lists all open UDP endpoints");
1421cf5d9f4bSHugo Santos
1422c22d69bfSAxel Dörfler return B_OK;
1423c22d69bfSAxel Dörfler
1424c22d69bfSAxel Dörfler err1:
14258d1485faSAxel Dörfler // TODO: shouldn't unregister the protocols here?
1426658a5506SHugo Santos delete sUdpEndpointManager;
1427c22d69bfSAxel Dörfler
1428bf9a85cbSJérôme Duval TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status,
1429bf9a85cbSJérôme Duval strerror(status));
1430c22d69bfSAxel Dörfler return status;
1431c22d69bfSAxel Dörfler }
1432c22d69bfSAxel Dörfler
1433c22d69bfSAxel Dörfler
1434c22d69bfSAxel Dörfler static status_t
uninit_udp()1435c22d69bfSAxel Dörfler uninit_udp()
1436c22d69bfSAxel Dörfler {
1437bf48e753SHugo Santos TRACE_EPM("uninit_udp()");
1438cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints",
1439cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints);
1440c22d69bfSAxel Dörfler delete sUdpEndpointManager;
1441c22d69bfSAxel Dörfler return B_OK;
1442c22d69bfSAxel Dörfler }
1443c22d69bfSAxel Dörfler
1444c22d69bfSAxel Dörfler
1445c22d69bfSAxel Dörfler static status_t
udp_std_ops(int32 op,...)1446c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...)
1447c22d69bfSAxel Dörfler {
1448c22d69bfSAxel Dörfler switch (op) {
1449c22d69bfSAxel Dörfler case B_MODULE_INIT:
1450c22d69bfSAxel Dörfler return init_udp();
1451c22d69bfSAxel Dörfler
1452c22d69bfSAxel Dörfler case B_MODULE_UNINIT:
1453c22d69bfSAxel Dörfler return uninit_udp();
1454c22d69bfSAxel Dörfler
1455c22d69bfSAxel Dörfler default:
1456c22d69bfSAxel Dörfler return B_ERROR;
1457c22d69bfSAxel Dörfler }
1458c22d69bfSAxel Dörfler }
1459c22d69bfSAxel Dörfler
1460c22d69bfSAxel Dörfler
1461c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = {
1462c22d69bfSAxel Dörfler {
1463c22d69bfSAxel Dörfler "network/protocols/udp/v1",
1464c22d69bfSAxel Dörfler 0,
1465c22d69bfSAxel Dörfler udp_std_ops
1466c22d69bfSAxel Dörfler },
14676f58064fSAxel Dörfler NET_PROTOCOL_ATOMIC_MESSAGES,
14686f58064fSAxel Dörfler
1469c22d69bfSAxel Dörfler udp_init_protocol,
1470c22d69bfSAxel Dörfler udp_uninit_protocol,
1471c22d69bfSAxel Dörfler udp_open,
1472c22d69bfSAxel Dörfler udp_close,
1473c22d69bfSAxel Dörfler udp_free,
1474c22d69bfSAxel Dörfler udp_connect,
1475c22d69bfSAxel Dörfler udp_accept,
1476c22d69bfSAxel Dörfler udp_control,
147745b5203bSHugo Santos udp_getsockopt,
147845b5203bSHugo Santos udp_setsockopt,
1479c22d69bfSAxel Dörfler udp_bind,
1480c22d69bfSAxel Dörfler udp_unbind,
1481c22d69bfSAxel Dörfler udp_listen,
1482c22d69bfSAxel Dörfler udp_shutdown,
1483c22d69bfSAxel Dörfler udp_send_data,
1484c22d69bfSAxel Dörfler udp_send_routed_data,
1485c22d69bfSAxel Dörfler udp_send_avail,
1486c22d69bfSAxel Dörfler udp_read_data,
1487c22d69bfSAxel Dörfler udp_read_avail,
1488c22d69bfSAxel Dörfler udp_get_domain,
1489c22d69bfSAxel Dörfler udp_get_mtu,
1490c22d69bfSAxel Dörfler udp_receive_data,
14916a606180SHugo Santos udp_deliver_data,
14922bb43d82SAxel Dörfler udp_error_received,
1493c22d69bfSAxel Dörfler udp_error_reply,
14949871124eSAxel Dörfler NULL, // add_ancillary_data()
14959871124eSAxel Dörfler NULL, // process_ancillary_data()
149678888c44SAxel Dörfler udp_process_ancillary_data_no_container,
14979871124eSAxel Dörfler NULL, // send_data_no_buffer()
14989871124eSAxel Dörfler NULL // read_data_no_buffer()
1499c22d69bfSAxel Dörfler };
1500c22d69bfSAxel Dörfler
1501658a5506SHugo Santos module_dependency module_dependencies[] = {
1502658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1503658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1504658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
15052bb43d82SAxel Dörfler {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1506658a5506SHugo Santos {}
1507658a5506SHugo Santos };
1508658a5506SHugo Santos
1509c22d69bfSAxel Dörfler module_info *modules[] = {
1510c22d69bfSAxel Dörfler (module_info *)&sUDPModule,
1511c22d69bfSAxel Dörfler NULL
1512c22d69bfSAxel Dörfler };
1513