1c22d69bfSAxel Dörfler /* 2*cb319968SAdrien 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 21*cb319968SAdrien 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. 103727ad0b0SHugo Santos bool IsActive() const { return fActive; } 104727ad0b0SHugo Santos void SetActive(bool newValue) { fActive = newValue; } 105bf48e753SHugo Santos 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 12884052230SAxel Dörfler UdpHashDefinition(net_address_module_info *_module) 12984052230SAxel Dörfler : module(_module) {} 13084052230SAxel Dörfler UdpHashDefinition(const UdpHashDefinition& definition) 13184052230SAxel Dörfler : module(definition.module) {} 13240bbf860SHugo Santos 13340bbf860SHugo 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 13840bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const 13940bbf860SHugo Santos { 14056f097ebSOliver Tappe return _Mix(endpoint->LocalAddress().HashPair( 14156f097ebSOliver Tappe *endpoint->PeerAddress())); 14240bbf860SHugo Santos } 14340bbf860SHugo Santos 14440bbf860SHugo 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 15140bbf860SHugo 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 1575147963dSStephan 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 173bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 174bf48e753SHugo Santos 175bf48e753SHugo Santos void Ref() { fEndpointCount++; } 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 201bf48e753SHugo 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 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 275727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport() 276727ad0b0SHugo Santos { 2772b07b8e0SIngo Weinhold mutex_destroy(&fLock); 278bf48e753SHugo Santos } 279bf48e753SHugo Santos 280bf48e753SHugo Santos 281bf48e753SHugo Santos status_t 282276aa463SIngo Weinhold UdpDomainSupport::Init() 283bf48e753SHugo Santos { 284276aa463SIngo Weinhold return fActiveEndpoints.Init(kNumHashBuckets); 285bf48e753SHugo Santos } 286bf48e753SHugo Santos 287bf48e753SHugo Santos 288bf48e753SHugo Santos status_t 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 2942bb43d82SAxel Dörfler if ((buffer->flags & MSG_BCAST) != 0) 295bf48e753SHugo Santos return _DemuxBroadcast(buffer); 2962bb43d82SAxel Dörfler if ((buffer->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 3042bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer) 3052bb43d82SAxel Dörfler { 3062bb43d82SAxel Dörfler if ((buffer->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 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 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 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 410cf5d9f4bSHugo 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 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 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 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 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 * 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 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 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 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 * 649727ad0b0SHugo 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 666bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager() 667bf48e753SHugo Santos { 6682b07b8e0SIngo Weinhold mutex_init(&fLock, "UDP endpoints"); 6692b07b8e0SIngo Weinhold fStatus = B_OK; 670bf48e753SHugo Santos } 671bf48e753SHugo Santos 672bf48e753SHugo Santos 673bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 674bf48e753SHugo Santos { 6752b07b8e0SIngo Weinhold mutex_destroy(&fLock); 676bf48e753SHugo Santos } 677bf48e753SHugo Santos 678bf48e753SHugo Santos 679bf48e753SHugo Santos status_t 680bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 681bf48e753SHugo Santos { 682bf48e753SHugo Santos return fStatus; 683bf48e753SHugo Santos } 684bf48e753SHugo Santos 685bf48e753SHugo Santos 686cf5d9f4bSHugo Santos int 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 703*cb319968SAdrien Destugues struct DomainSupportDelete 704*cb319968SAdrien Destugues { 705*cb319968SAdrien Destugues inline void operator()(UdpDomainSupport* object) 706*cb319968SAdrien Destugues { 707*cb319968SAdrien Destugues sUdpEndpointManager->FreeEndpoint(object); 708*cb319968SAdrien Destugues } 709*cb319968SAdrien Destugues }; 710*cb319968SAdrien Destugues 711*cb319968SAdrien Destugues 712*cb319968SAdrien Destugues struct DomainSupportDeleter 713*cb319968SAdrien Destugues : BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete> 714*cb319968SAdrien Destugues { 715*cb319968SAdrien Destugues DomainSupportDeleter(UdpDomainSupport* object) 716*cb319968SAdrien Destugues : BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>(object) 717*cb319968SAdrien Destugues {} 718*cb319968SAdrien Destugues }; 719*cb319968SAdrien Destugues 720*cb319968SAdrien Destugues 721bf48e753SHugo Santos status_t 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 } 732*cb319968SAdrien 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 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 } 769*cb319968SAdrien 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 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 831c22d69bfSAxel Dörfler if (header.udp_checksum != 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 * 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 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* 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* 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()) { 901*cb319968SAdrien Destugues if (domainSupport->Domain() == domain) { 902*cb319968SAdrien Destugues domainSupport->Ref(); 903bf48e753SHugo Santos return domainSupport; 904bf48e753SHugo Santos } 905*cb319968SAdrien 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); 918*cb319968SAdrien 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* 9289d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer) 9292bb43d82SAxel Dörfler { 9302bb43d82SAxel Dörfler MutexLocker _(fLock); 9319d433190SAxel Dörfler 932eb5604bcSAdrien Destugues UdpDomainSupport* support = _GetDomainSupport(_GetDomain(buffer), false); 933*cb319968SAdrien Destugues if (support != NULL) 934eb5604bcSAdrien Destugues support->Ref(); 935eb5604bcSAdrien Destugues return support; 9362bb43d82SAxel Dörfler } 9372bb43d82SAxel Dörfler 9382bb43d82SAxel Dörfler 939c22d69bfSAxel Dörfler // #pragma mark - 940c22d69bfSAxel Dörfler 941c22d69bfSAxel Dörfler 942c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 943cb99c915SAxel Dörfler : 944cb99c915SAxel Dörfler DatagramSocket<>("udp endpoint", socket), 945cb99c915SAxel Dörfler fActive(false) 946cb99c915SAxel Dörfler { 947cb99c915SAxel Dörfler } 948bf48e753SHugo Santos 949bf48e753SHugo Santos 950c22d69bfSAxel Dörfler // #pragma mark - activation 951c22d69bfSAxel Dörfler 952c22d69bfSAxel Dörfler 953c22d69bfSAxel Dörfler status_t 95453f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address) 955c22d69bfSAxel Dörfler { 956bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 957727ad0b0SHugo Santos return fManager->BindEndpoint(this, address); 958c22d69bfSAxel Dörfler } 959c22d69bfSAxel Dörfler 960c22d69bfSAxel Dörfler 961c22d69bfSAxel Dörfler status_t 962c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 963c22d69bfSAxel Dörfler { 964bf48e753SHugo Santos TRACE_EP("Unbind()"); 965727ad0b0SHugo Santos return fManager->UnbindEndpoint(this); 966c22d69bfSAxel Dörfler } 967c22d69bfSAxel Dörfler 968c22d69bfSAxel Dörfler 969c22d69bfSAxel Dörfler status_t 970c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 971c22d69bfSAxel Dörfler { 972bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 973727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address); 974c22d69bfSAxel Dörfler } 975c22d69bfSAxel Dörfler 976c22d69bfSAxel Dörfler 977c22d69bfSAxel Dörfler status_t 978c22d69bfSAxel Dörfler UdpEndpoint::Open() 979c22d69bfSAxel Dörfler { 980bf48e753SHugo Santos TRACE_EP("Open()"); 981bf48e753SHugo Santos 982119c6cddSIngo Weinhold AutoLocker _(fLock); 983727ad0b0SHugo Santos 984c72ab92dSHugo Santos status_t status = ProtocolSocket::Open(); 985c72ab92dSHugo Santos if (status < B_OK) 986c72ab92dSHugo Santos return status; 987bf48e753SHugo Santos 988c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this); 989c72ab92dSHugo Santos if (fManager == NULL) 990bf48e753SHugo Santos return EAFNOSUPPORT; 991bf48e753SHugo Santos 992bf48e753SHugo Santos return B_OK; 993c22d69bfSAxel Dörfler } 994c22d69bfSAxel Dörfler 995c22d69bfSAxel Dörfler 996c22d69bfSAxel Dörfler status_t 997c22d69bfSAxel Dörfler UdpEndpoint::Close() 998c22d69bfSAxel Dörfler { 999bf48e753SHugo Santos TRACE_EP("Close()"); 100083fd8a61SPawel Dziepak fSocket->error = EBADF; 100183fd8a61SPawel Dziepak WakeAll(); 1002bf48e753SHugo Santos return B_OK; 1003c22d69bfSAxel Dörfler } 1004c22d69bfSAxel Dörfler 1005c22d69bfSAxel Dörfler 1006c22d69bfSAxel Dörfler status_t 1007c22d69bfSAxel Dörfler UdpEndpoint::Free() 1008c22d69bfSAxel Dörfler { 1009bf48e753SHugo Santos TRACE_EP("Free()"); 10100086fe20SHugo Santos fManager->UnbindEndpoint(this); 1011c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager); 1012c22d69bfSAxel Dörfler } 1013c22d69bfSAxel Dörfler 1014c22d69bfSAxel Dörfler 1015c22d69bfSAxel Dörfler // #pragma mark - outbound 1016c22d69bfSAxel Dörfler 1017c22d69bfSAxel Dörfler 1018c22d69bfSAxel Dörfler status_t 1019bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 1020c22d69bfSAxel Dörfler { 1021bf9a85cbSJérôme Duval TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer, 1022bf9a85cbSJérôme Duval buffer->size, route); 1023bf48e753SHugo Santos 1024d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 1025c22d69bfSAxel Dörfler return EMSGSIZE; 1026c22d69bfSAxel Dörfler 102774e1a530SJérôme Duval buffer->protocol = IPPROTO_UDP; 1028c22d69bfSAxel Dörfler 1029c22d69bfSAxel Dörfler // add and fill UDP-specific header: 10306c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 10316c353509SHugo Santos if (header.Status() < B_OK) 10326c353509SHugo Santos return header.Status(); 1033c22d69bfSAxel Dörfler 103479a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source); 103579a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination); 10366c353509SHugo Santos header->udp_length = htons(buffer->size); 1037c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 10386c353509SHugo Santos header->udp_checksum = 0; 10396c353509SHugo Santos 10406c353509SHugo Santos header.Sync(); 1041c22d69bfSAxel Dörfler 1042d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(), 1043d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP); 10446c353509SHugo Santos if (calculatedChecksum == 0) 10456c353509SHugo Santos calculatedChecksum = 0xffff; 10466c353509SHugo Santos 10476c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 1048c22d69bfSAxel Dörfler 1049c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 1050c22d69bfSAxel Dörfler } 1051c22d69bfSAxel Dörfler 1052c22d69bfSAxel Dörfler 1053bf48e753SHugo Santos status_t 1054bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 1055bf48e753SHugo Santos { 1056bf9a85cbSJérôme Duval TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 1057bf48e753SHugo Santos 10582651e51dSAxel Dörfler return gDatalinkModule->send_data(this, NULL, buffer); 1059bf48e753SHugo Santos } 1060bf48e753SHugo Santos 1061bf48e753SHugo Santos 1062c22d69bfSAxel Dörfler // #pragma mark - inbound 1063c22d69bfSAxel Dörfler 1064c22d69bfSAxel Dörfler 1065c22d69bfSAxel Dörfler ssize_t 1066c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 1067c22d69bfSAxel Dörfler { 1068bfb45f71SHugo Santos size_t bytes = AvailableData(); 1069bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 1070bfb45f71SHugo Santos return bytes; 1071c22d69bfSAxel Dörfler } 1072c22d69bfSAxel Dörfler 1073c22d69bfSAxel Dörfler 1074c22d69bfSAxel Dörfler status_t 1075c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 1076c22d69bfSAxel Dörfler { 1077bf9a85cbSJérôme Duval TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags); 1078bf48e753SHugo Santos 10792651e51dSAxel Dörfler status_t status = Dequeue(flags, _buffer); 1080cb99c915SAxel Dörfler TRACE_EP(" FetchData(): returned from fifo status: %s", strerror(status)); 10812651e51dSAxel Dörfler if (status != B_OK) 1082c22d69bfSAxel Dörfler return status; 1083c22d69bfSAxel Dörfler 1084bf9a85cbSJérôme Duval TRACE_EP(" FetchData(): returns buffer with %" B_PRIu32 " bytes", 1085bf9a85cbSJérôme Duval (*_buffer)->size); 1086c22d69bfSAxel Dörfler return B_OK; 1087c22d69bfSAxel Dörfler } 1088c22d69bfSAxel Dörfler 1089c22d69bfSAxel Dörfler 1090c22d69bfSAxel Dörfler status_t 1091bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 1092c22d69bfSAxel Dörfler { 1093bf9a85cbSJérôme Duval TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 1094c22d69bfSAxel Dörfler 10952651e51dSAxel Dörfler return EnqueueClone(buffer); 1096c22d69bfSAxel Dörfler } 1097c22d69bfSAxel Dörfler 1098c22d69bfSAxel Dörfler 10996a606180SHugo Santos status_t 11006a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 11016a606180SHugo Santos { 1102bf9a85cbSJérôme Duval TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size); 1103f6cfc5afSHugo Santos 11046a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 11056a606180SHugo Santos if (buffer == NULL) 11066a606180SHugo Santos return B_NO_MEMORY; 11076a606180SHugo Santos 110874e1a530SJérôme Duval status_t status = sUdpEndpointManager->Deframe(buffer); 11096a606180SHugo Santos if (status < B_OK) { 11106a606180SHugo Santos gBufferModule->free(buffer); 11116a606180SHugo Santos return status; 11126a606180SHugo Santos } 11136a606180SHugo Santos 11146a606180SHugo Santos return Enqueue(buffer); 11156a606180SHugo Santos } 11166a606180SHugo Santos 11176a606180SHugo Santos 1118cb99c915SAxel Dörfler void 1119cb99c915SAxel Dörfler UdpEndpoint::Dump() const 1120cb99c915SAxel Dörfler { 1121cb99c915SAxel Dörfler char local[64]; 1122cb99c915SAxel Dörfler LocalAddress().AsString(local, sizeof(local), true); 1123cb99c915SAxel Dörfler char peer[64]; 1124cb99c915SAxel Dörfler PeerAddress().AsString(peer, sizeof(peer), true); 1125cb99c915SAxel Dörfler 1126cb99c915SAxel Dörfler kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes); 1127cb99c915SAxel Dörfler } 1128cb99c915SAxel Dörfler 1129cb99c915SAxel Dörfler 1130c22d69bfSAxel Dörfler // #pragma mark - protocol interface 1131c22d69bfSAxel Dörfler 1132c22d69bfSAxel Dörfler 1133c22d69bfSAxel Dörfler net_protocol * 1134c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 1135c22d69bfSAxel Dörfler { 1136c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 1137c22d69bfSAxel Dörfler 1138c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 1139bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 1140bf48e753SHugo Santos delete endpoint; 1141bf48e753SHugo Santos return NULL; 1142bf48e753SHugo Santos } 1143bf48e753SHugo Santos 1144c22d69bfSAxel Dörfler return endpoint; 1145c22d69bfSAxel Dörfler } 1146c22d69bfSAxel Dörfler 1147c22d69bfSAxel Dörfler 1148c22d69bfSAxel Dörfler status_t 1149c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 1150c22d69bfSAxel Dörfler { 1151bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 1152c22d69bfSAxel Dörfler return B_OK; 1153c22d69bfSAxel Dörfler } 1154c22d69bfSAxel Dörfler 1155c22d69bfSAxel Dörfler 1156c22d69bfSAxel Dörfler status_t 1157c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 1158c22d69bfSAxel Dörfler { 1159bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 1160c22d69bfSAxel Dörfler } 1161c22d69bfSAxel Dörfler 1162c22d69bfSAxel Dörfler 1163c22d69bfSAxel Dörfler status_t 1164c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 1165c22d69bfSAxel Dörfler { 1166bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 1167c22d69bfSAxel Dörfler } 1168c22d69bfSAxel Dörfler 1169c22d69bfSAxel Dörfler 1170c22d69bfSAxel Dörfler status_t 1171c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 1172c22d69bfSAxel Dörfler { 1173bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 1174c22d69bfSAxel Dörfler } 1175c22d69bfSAxel Dörfler 1176c22d69bfSAxel Dörfler 1177c22d69bfSAxel Dörfler status_t 1178c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1179c22d69bfSAxel Dörfler { 1180bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1181c22d69bfSAxel Dörfler } 1182c22d69bfSAxel Dörfler 1183c22d69bfSAxel Dörfler 1184c22d69bfSAxel Dörfler status_t 1185c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1186c22d69bfSAxel Dörfler { 1187ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1188c22d69bfSAxel Dörfler } 1189c22d69bfSAxel Dörfler 1190c22d69bfSAxel Dörfler 1191c22d69bfSAxel Dörfler status_t 1192c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1193c22d69bfSAxel Dörfler size_t *_length) 1194c22d69bfSAxel Dörfler { 1195c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1196c22d69bfSAxel Dörfler value, _length); 1197c22d69bfSAxel Dörfler } 1198c22d69bfSAxel Dörfler 1199c22d69bfSAxel Dörfler 1200c22d69bfSAxel Dörfler status_t 120145b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value, 120245b5203bSHugo Santos int *length) 120345b5203bSHugo Santos { 120445b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option, 120545b5203bSHugo Santos value, length); 120645b5203bSHugo Santos } 120745b5203bSHugo Santos 120845b5203bSHugo Santos 120945b5203bSHugo Santos status_t 121045b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option, 121145b5203bSHugo Santos const void *value, int length) 121245b5203bSHugo Santos { 121345b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option, 121445b5203bSHugo Santos value, length); 121545b5203bSHugo Santos } 121645b5203bSHugo Santos 121745b5203bSHugo Santos 121845b5203bSHugo Santos status_t 121953f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address) 1220c22d69bfSAxel Dörfler { 1221bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1222c22d69bfSAxel Dörfler } 1223c22d69bfSAxel Dörfler 1224c22d69bfSAxel Dörfler 1225c22d69bfSAxel Dörfler status_t 1226c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1227c22d69bfSAxel Dörfler { 1228bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1229c22d69bfSAxel Dörfler } 1230c22d69bfSAxel Dörfler 1231c22d69bfSAxel Dörfler 1232c22d69bfSAxel Dörfler status_t 1233c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1234c22d69bfSAxel Dörfler { 1235ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1236c22d69bfSAxel Dörfler } 1237c22d69bfSAxel Dörfler 1238c22d69bfSAxel Dörfler 1239c22d69bfSAxel Dörfler status_t 1240c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1241c22d69bfSAxel Dörfler { 1242ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1243c22d69bfSAxel Dörfler } 1244c22d69bfSAxel Dörfler 1245c22d69bfSAxel Dörfler 1246c22d69bfSAxel Dörfler status_t 1247c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1248c22d69bfSAxel Dörfler net_buffer *buffer) 1249c22d69bfSAxel Dörfler { 1250bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1251c22d69bfSAxel Dörfler } 1252c22d69bfSAxel Dörfler 1253c22d69bfSAxel Dörfler 1254c22d69bfSAxel Dörfler status_t 1255c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1256c22d69bfSAxel Dörfler { 1257bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1258c22d69bfSAxel Dörfler } 1259c22d69bfSAxel Dörfler 1260c22d69bfSAxel Dörfler 1261c22d69bfSAxel Dörfler ssize_t 1262c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1263c22d69bfSAxel Dörfler { 1264bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1265c22d69bfSAxel Dörfler } 1266c22d69bfSAxel Dörfler 1267c22d69bfSAxel Dörfler 1268c22d69bfSAxel Dörfler status_t 1269c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1270c22d69bfSAxel Dörfler net_buffer **_buffer) 1271c22d69bfSAxel Dörfler { 1272bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1273c22d69bfSAxel Dörfler } 1274c22d69bfSAxel Dörfler 1275c22d69bfSAxel Dörfler 1276c22d69bfSAxel Dörfler ssize_t 1277c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1278c22d69bfSAxel Dörfler { 1279bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1280c22d69bfSAxel Dörfler } 1281c22d69bfSAxel Dörfler 1282c22d69bfSAxel Dörfler 1283c22d69bfSAxel Dörfler struct net_domain * 1284c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1285c22d69bfSAxel Dörfler { 1286c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1287c22d69bfSAxel Dörfler } 1288c22d69bfSAxel Dörfler 1289c22d69bfSAxel Dörfler 1290c22d69bfSAxel Dörfler size_t 1291c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1292c22d69bfSAxel Dörfler { 1293c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1294c22d69bfSAxel Dörfler } 1295c22d69bfSAxel Dörfler 1296c22d69bfSAxel Dörfler 1297c22d69bfSAxel Dörfler status_t 1298c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1299c22d69bfSAxel Dörfler { 1300c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1301c22d69bfSAxel Dörfler } 1302c22d69bfSAxel Dörfler 1303c22d69bfSAxel Dörfler 1304c22d69bfSAxel Dörfler status_t 13056a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 13066a606180SHugo Santos { 13076a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 13086a606180SHugo Santos } 13096a606180SHugo Santos 13106a606180SHugo Santos 13116a606180SHugo Santos status_t 13122b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer) 1313c22d69bfSAxel Dörfler { 13142b415445SAxel Dörfler status_t notifyError = B_OK; 13152bb43d82SAxel Dörfler 13162b415445SAxel Dörfler switch (error) { 13172b415445SAxel Dörfler case B_NET_ERROR_UNREACH_NET: 13182b415445SAxel Dörfler notifyError = ENETUNREACH; 13192bb43d82SAxel Dörfler break; 13202b415445SAxel Dörfler case B_NET_ERROR_UNREACH_HOST: 13212b415445SAxel Dörfler case B_NET_ERROR_TRANSIT_TIME_EXCEEDED: 13222b415445SAxel Dörfler notifyError = EHOSTUNREACH; 13232bb43d82SAxel Dörfler break; 13242b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PROTOCOL: 13252b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PORT: 13262b415445SAxel Dörfler notifyError = ECONNREFUSED; 13272bb43d82SAxel Dörfler break; 13282b415445SAxel Dörfler case B_NET_ERROR_MESSAGE_SIZE: 13292b415445SAxel Dörfler notifyError = EMSGSIZE; 13302b415445SAxel Dörfler break; 13312b415445SAxel Dörfler case B_NET_ERROR_PARAMETER_PROBLEM: 13322b415445SAxel Dörfler notifyError = ENOPROTOOPT; 13332b415445SAxel Dörfler break; 13342b415445SAxel Dörfler 13352b415445SAxel Dörfler case B_NET_ERROR_QUENCH: 13362bb43d82SAxel Dörfler default: 13372bb43d82SAxel Dörfler // ignore them 13382bb43d82SAxel Dörfler gBufferModule->free(buffer); 13392bb43d82SAxel Dörfler return B_OK; 1340c22d69bfSAxel Dörfler } 1341c22d69bfSAxel Dörfler 13427e046eabSAxel Dörfler ASSERT(notifyError != B_OK); 13437e046eabSAxel Dörfler 13447e046eabSAxel Dörfler return sUdpEndpointManager->ReceiveError(notifyError, buffer); 13457e046eabSAxel Dörfler } 13467e046eabSAxel Dörfler 1347c22d69bfSAxel Dörfler 1348c22d69bfSAxel Dörfler status_t 13492b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error, 13502b415445SAxel Dörfler net_error_data *errorData) 1351c22d69bfSAxel Dörfler { 1352c22d69bfSAxel Dörfler return B_ERROR; 1353c22d69bfSAxel Dörfler } 1354c22d69bfSAxel Dörfler 1355c22d69bfSAxel Dörfler 135678888c44SAxel Dörfler ssize_t 135778888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol, 135878888c44SAxel Dörfler net_buffer* buffer, void *data, size_t dataSize) 135978888c44SAxel Dörfler { 136078888c44SAxel Dörfler return protocol->next->module->process_ancillary_data_no_container( 136178888c44SAxel Dörfler protocol, buffer, data, dataSize); 136278888c44SAxel Dörfler } 136378888c44SAxel Dörfler 136478888c44SAxel Dörfler 1365c22d69bfSAxel Dörfler // #pragma mark - module interface 1366c22d69bfSAxel Dörfler 1367c22d69bfSAxel Dörfler 1368c22d69bfSAxel Dörfler static status_t 1369c22d69bfSAxel Dörfler init_udp() 1370c22d69bfSAxel Dörfler { 1371c22d69bfSAxel Dörfler status_t status; 1372bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1373c22d69bfSAxel Dörfler 1374c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1375658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1376658a5506SHugo Santos return B_NO_MEMORY; 1377658a5506SHugo Santos 1378c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1379c22d69bfSAxel Dörfler if (status != B_OK) 1380d438fa4cSHugo Santos goto err1; 1381c22d69bfSAxel Dörfler 138261729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 138361729d93SAxel Dörfler IPPROTO_IP, 1384c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1385c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1386c22d69bfSAxel Dörfler NULL); 1387c22d69bfSAxel Dörfler if (status < B_OK) 1388658a5506SHugo Santos goto err1; 138961729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 139061729d93SAxel Dörfler IPPROTO_IP, 13918d1485faSAxel Dörfler "network/protocols/udp/v1", 13928d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13938d1485faSAxel Dörfler NULL); 13948d1485faSAxel Dörfler if (status < B_OK) 13958d1485faSAxel Dörfler goto err1; 13968d1485faSAxel Dörfler 139761729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 139861729d93SAxel Dörfler IPPROTO_UDP, 1399c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1400c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1401c22d69bfSAxel Dörfler NULL); 1402c22d69bfSAxel Dörfler if (status < B_OK) 1403658a5506SHugo Santos goto err1; 140461729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 140561729d93SAxel Dörfler IPPROTO_UDP, 14068d1485faSAxel Dörfler "network/protocols/udp/v1", 14078d1485faSAxel Dörfler "network/protocols/ipv6/v1", 14088d1485faSAxel Dörfler NULL); 14098d1485faSAxel Dörfler if (status < B_OK) 14108d1485faSAxel Dörfler goto err1; 1411c22d69bfSAxel Dörfler 141261729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET, 141361729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 1414c22d69bfSAxel Dörfler if (status < B_OK) 1415658a5506SHugo Santos goto err1; 141661729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET6, 141761729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 14188d1485faSAxel Dörfler if (status < B_OK) 14198d1485faSAxel Dörfler goto err1; 1420c22d69bfSAxel Dörfler 1421cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints, 1422cf5d9f4bSHugo Santos "lists all open UDP endpoints"); 1423cf5d9f4bSHugo Santos 1424c22d69bfSAxel Dörfler return B_OK; 1425c22d69bfSAxel Dörfler 1426c22d69bfSAxel Dörfler err1: 14278d1485faSAxel Dörfler // TODO: shouldn't unregister the protocols here? 1428658a5506SHugo Santos delete sUdpEndpointManager; 1429c22d69bfSAxel Dörfler 1430bf9a85cbSJérôme Duval TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status, 1431bf9a85cbSJérôme Duval strerror(status)); 1432c22d69bfSAxel Dörfler return status; 1433c22d69bfSAxel Dörfler } 1434c22d69bfSAxel Dörfler 1435c22d69bfSAxel Dörfler 1436c22d69bfSAxel Dörfler static status_t 1437c22d69bfSAxel Dörfler uninit_udp() 1438c22d69bfSAxel Dörfler { 1439bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1440cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints", 1441cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints); 1442c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1443c22d69bfSAxel Dörfler return B_OK; 1444c22d69bfSAxel Dörfler } 1445c22d69bfSAxel Dörfler 1446c22d69bfSAxel Dörfler 1447c22d69bfSAxel Dörfler static status_t 1448c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1449c22d69bfSAxel Dörfler { 1450c22d69bfSAxel Dörfler switch (op) { 1451c22d69bfSAxel Dörfler case B_MODULE_INIT: 1452c22d69bfSAxel Dörfler return init_udp(); 1453c22d69bfSAxel Dörfler 1454c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1455c22d69bfSAxel Dörfler return uninit_udp(); 1456c22d69bfSAxel Dörfler 1457c22d69bfSAxel Dörfler default: 1458c22d69bfSAxel Dörfler return B_ERROR; 1459c22d69bfSAxel Dörfler } 1460c22d69bfSAxel Dörfler } 1461c22d69bfSAxel Dörfler 1462c22d69bfSAxel Dörfler 1463c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1464c22d69bfSAxel Dörfler { 1465c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1466c22d69bfSAxel Dörfler 0, 1467c22d69bfSAxel Dörfler udp_std_ops 1468c22d69bfSAxel Dörfler }, 14696f58064fSAxel Dörfler NET_PROTOCOL_ATOMIC_MESSAGES, 14706f58064fSAxel Dörfler 1471c22d69bfSAxel Dörfler udp_init_protocol, 1472c22d69bfSAxel Dörfler udp_uninit_protocol, 1473c22d69bfSAxel Dörfler udp_open, 1474c22d69bfSAxel Dörfler udp_close, 1475c22d69bfSAxel Dörfler udp_free, 1476c22d69bfSAxel Dörfler udp_connect, 1477c22d69bfSAxel Dörfler udp_accept, 1478c22d69bfSAxel Dörfler udp_control, 147945b5203bSHugo Santos udp_getsockopt, 148045b5203bSHugo Santos udp_setsockopt, 1481c22d69bfSAxel Dörfler udp_bind, 1482c22d69bfSAxel Dörfler udp_unbind, 1483c22d69bfSAxel Dörfler udp_listen, 1484c22d69bfSAxel Dörfler udp_shutdown, 1485c22d69bfSAxel Dörfler udp_send_data, 1486c22d69bfSAxel Dörfler udp_send_routed_data, 1487c22d69bfSAxel Dörfler udp_send_avail, 1488c22d69bfSAxel Dörfler udp_read_data, 1489c22d69bfSAxel Dörfler udp_read_avail, 1490c22d69bfSAxel Dörfler udp_get_domain, 1491c22d69bfSAxel Dörfler udp_get_mtu, 1492c22d69bfSAxel Dörfler udp_receive_data, 14936a606180SHugo Santos udp_deliver_data, 14942bb43d82SAxel Dörfler udp_error_received, 1495c22d69bfSAxel Dörfler udp_error_reply, 14969871124eSAxel Dörfler NULL, // add_ancillary_data() 14979871124eSAxel Dörfler NULL, // process_ancillary_data() 149878888c44SAxel Dörfler udp_process_ancillary_data_no_container, 14999871124eSAxel Dörfler NULL, // send_data_no_buffer() 15009871124eSAxel Dörfler NULL // read_data_no_buffer() 1501c22d69bfSAxel Dörfler }; 1502c22d69bfSAxel Dörfler 1503658a5506SHugo Santos module_dependency module_dependencies[] = { 1504658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1505658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1506658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 15072bb43d82SAxel Dörfler {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule}, 1508658a5506SHugo Santos {} 1509658a5506SHugo Santos }; 1510658a5506SHugo Santos 1511c22d69bfSAxel Dörfler module_info *modules[] = { 1512c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1513c22d69bfSAxel Dörfler NULL 1514c22d69bfSAxel Dörfler }; 1515