1c22d69bfSAxel Dörfler /* 22bb43d82SAxel Dörfler * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. 3c22d69bfSAxel Dörfler * Distributed under the terms of the MIT License. 4c22d69bfSAxel Dörfler * 5c22d69bfSAxel Dörfler * Authors: 6c22d69bfSAxel Dörfler * Oliver Tappe, zooey@hirschkaefer.de 7c3e054c8SHugo Santos * Hugo Santos, hugosantos@gmail.com 8c22d69bfSAxel Dörfler */ 9c22d69bfSAxel Dörfler 10c22d69bfSAxel Dörfler 11c22d69bfSAxel Dörfler #include <net_buffer.h> 12c22d69bfSAxel Dörfler #include <net_datalink.h> 13c22d69bfSAxel Dörfler #include <net_protocol.h> 14c22d69bfSAxel Dörfler #include <net_stack.h> 15c22d69bfSAxel Dörfler 16c22d69bfSAxel Dörfler #include <lock.h> 17c22d69bfSAxel Dörfler #include <util/AutoLock.h> 18bf48e753SHugo Santos #include <util/DoublyLinkedList.h> 1940bbf860SHugo Santos #include <util/OpenHashTable.h> 20c22d69bfSAxel Dörfler 21c22d69bfSAxel Dörfler #include <KernelExport.h> 22c22d69bfSAxel Dörfler 23c22d69bfSAxel Dörfler #include <NetBufferUtilities.h> 24c22d69bfSAxel Dörfler #include <NetUtilities.h> 25bfb45f71SHugo Santos #include <ProtocolUtilities.h> 26c22d69bfSAxel Dörfler 272bb43d82SAxel Dörfler #include <algorithm> 28c22d69bfSAxel Dörfler #include <netinet/in.h> 292bb43d82SAxel Dörfler #include <netinet/ip.h> 30c22d69bfSAxel Dörfler #include <new> 31c22d69bfSAxel Dörfler #include <stdlib.h> 32c22d69bfSAxel Dörfler #include <string.h> 33c3e054c8SHugo Santos #include <utility> 34c22d69bfSAxel Dörfler 35727ad0b0SHugo Santos 36727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's 37727ad0b0SHugo Santos // lock before holding a child UdpEndpoint's lock. This restriction 38727ad0b0SHugo Santos // is dictated by the receive path as blind access to the endpoint 39f861e599SFrançois Revol // hash is required when holding the DomainSupport's lock. 40727ad0b0SHugo Santos 41727ad0b0SHugo Santos 42af3a31f7SAxel Dörfler //#define TRACE_UDP 43c22d69bfSAxel Dörfler #ifdef TRACE_UDP 44c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) dump_block x 45bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this 46bf48e753SHugo Santos // to compile with gcc 2.95 47bf48e753SHugo Santos # define TRACE_EP(format, args...) dprintf("UDP [%llu] %p " format "\n", \ 48bf48e753SHugo Santos system_time(), this , ##args) 49bf48e753SHugo Santos # define TRACE_EPM(format, args...) dprintf("UDP [%llu] " format "\n", \ 50bf48e753SHugo Santos system_time() , ##args) 51bf48e753SHugo Santos # define TRACE_DOMAIN(format, args...) dprintf("UDP [%llu] (%d) " format \ 52bf48e753SHugo Santos "\n", system_time(), Domain()->family , ##args) 53c22d69bfSAxel Dörfler #else 54c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) 55bf48e753SHugo Santos # define TRACE_EP(args...) do { } while (0) 56bf48e753SHugo Santos # define TRACE_EPM(args...) do { } while (0) 57bf48e753SHugo Santos # define TRACE_DOMAIN(args...) do { } while (0) 58c22d69bfSAxel Dörfler #endif 59c22d69bfSAxel Dörfler 60c22d69bfSAxel Dörfler 61c22d69bfSAxel Dörfler struct udp_header { 62c22d69bfSAxel Dörfler uint16 source_port; 63c22d69bfSAxel Dörfler uint16 destination_port; 64c22d69bfSAxel Dörfler uint16 udp_length; 65c22d69bfSAxel Dörfler uint16 udp_checksum; 66c22d69bfSAxel Dörfler } _PACKED; 67c22d69bfSAxel Dörfler 68c22d69bfSAxel Dörfler 696c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)> 706c353509SHugo Santos UDPChecksumField; 716c353509SHugo Santos 72bf48e753SHugo Santos class UdpDomainSupport; 736c353509SHugo Santos 74bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> { 75c22d69bfSAxel Dörfler public: 76c22d69bfSAxel Dörfler UdpEndpoint(net_socket *socket); 77bf48e753SHugo Santos 7853f23f85SHugo Santos status_t Bind(const sockaddr *newAddr); 79c22d69bfSAxel Dörfler status_t Unbind(sockaddr *newAddr); 80c22d69bfSAxel Dörfler status_t Connect(const sockaddr *newAddr); 81c22d69bfSAxel Dörfler 82c22d69bfSAxel Dörfler status_t Open(); 83c22d69bfSAxel Dörfler status_t Close(); 84c22d69bfSAxel Dörfler status_t Free(); 85c22d69bfSAxel Dörfler 8656f097ebSOliver Tappe status_t SendRoutedData(net_buffer *buffer, 8756f097ebSOliver Tappe net_route *route); 88bf48e753SHugo Santos status_t SendData(net_buffer *buffer); 89c22d69bfSAxel Dörfler 90c22d69bfSAxel Dörfler ssize_t BytesAvailable(); 91c22d69bfSAxel Dörfler status_t FetchData(size_t numBytes, uint32 flags, 92c22d69bfSAxel Dörfler net_buffer **_buffer); 93c22d69bfSAxel Dörfler 94c22d69bfSAxel Dörfler status_t StoreData(net_buffer *buffer); 956a606180SHugo Santos status_t DeliverData(net_buffer *buffer); 96c22d69bfSAxel Dörfler 97727ad0b0SHugo Santos // only the domain support will change/check the Active flag so 98727ad0b0SHugo Santos // we don't really need to protect it with the socket lock. 99727ad0b0SHugo Santos bool IsActive() const { return fActive; } 100727ad0b0SHugo Santos void SetActive(bool newValue) { fActive = newValue; } 101bf48e753SHugo Santos 1025147963dSStephan Aßmus UdpEndpoint *&HashTableLink() { return fLink; } 10340bbf860SHugo Santos 104c22d69bfSAxel Dörfler private: 105c72ab92dSHugo Santos UdpDomainSupport *fManager; 106c22d69bfSAxel Dörfler bool fActive; 10756f097ebSOliver Tappe // an active UdpEndpoint is part of the 10856f097ebSOliver Tappe // endpoint hash (and it is bound and optionally 10956f097ebSOliver Tappe // connected) 11040bbf860SHugo Santos 1115147963dSStephan Aßmus UdpEndpoint *fLink; 11240bbf860SHugo Santos }; 11340bbf860SHugo Santos 11440bbf860SHugo Santos 11540bbf860SHugo Santos class UdpDomainSupport; 11640bbf860SHugo Santos 11740bbf860SHugo Santos struct UdpHashDefinition { 11840bbf860SHugo Santos typedef net_address_module_info ParentType; 11940bbf860SHugo Santos typedef std::pair<const sockaddr *, const sockaddr *> KeyType; 12040bbf860SHugo Santos typedef UdpEndpoint ValueType; 12140bbf860SHugo Santos 12284052230SAxel Dörfler UdpHashDefinition(net_address_module_info *_module) 12384052230SAxel Dörfler : module(_module) {} 12484052230SAxel Dörfler UdpHashDefinition(const UdpHashDefinition& definition) 12584052230SAxel Dörfler : module(definition.module) {} 12640bbf860SHugo Santos 12740bbf860SHugo Santos size_t HashKey(const KeyType &key) const 12840bbf860SHugo Santos { 12940bbf860SHugo Santos return _Mix(module->hash_address_pair(key.first, key.second)); 13040bbf860SHugo Santos } 13140bbf860SHugo Santos 13240bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const 13340bbf860SHugo Santos { 13456f097ebSOliver Tappe return _Mix(endpoint->LocalAddress().HashPair( 13556f097ebSOliver Tappe *endpoint->PeerAddress())); 13640bbf860SHugo Santos } 13740bbf860SHugo Santos 13840bbf860SHugo Santos static size_t _Mix(size_t hash) 13940bbf860SHugo Santos { 14056f097ebSOliver Tappe // move the bits into the relevant range (as defined by kNumHashBuckets) 14140bbf860SHugo Santos return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11 14240bbf860SHugo Santos ^ (hash & 0xFFC00000UL) >> 22; 14340bbf860SHugo Santos } 14440bbf860SHugo Santos 14540bbf860SHugo Santos bool Compare(const KeyType &key, UdpEndpoint *endpoint) const 14640bbf860SHugo Santos { 14740bbf860SHugo Santos return endpoint->LocalAddress().EqualTo(key.first, true) 14840bbf860SHugo Santos && endpoint->PeerAddress().EqualTo(key.second, true); 14940bbf860SHugo Santos } 15040bbf860SHugo Santos 1515147963dSStephan Aßmus UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const 15240bbf860SHugo Santos { 15340bbf860SHugo Santos return endpoint->HashTableLink(); 15440bbf860SHugo Santos } 15540bbf860SHugo Santos 15640bbf860SHugo Santos net_address_module_info *module; 157c22d69bfSAxel Dörfler }; 158c22d69bfSAxel Dörfler 159c22d69bfSAxel Dörfler 160bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> { 161c22d69bfSAxel Dörfler public: 162bf48e753SHugo Santos UdpDomainSupport(net_domain *domain); 163727ad0b0SHugo Santos ~UdpDomainSupport(); 164c22d69bfSAxel Dörfler 165276aa463SIngo Weinhold status_t Init(); 166bf48e753SHugo Santos 167bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 168bf48e753SHugo Santos 169bf48e753SHugo Santos void Ref() { fEndpointCount++; } 170727ad0b0SHugo Santos bool Put() { fEndpointCount--; return fEndpointCount == 0; } 171bf48e753SHugo Santos 172bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer* buffer); 1732bb43d82SAxel Dörfler status_t DeliverError(status_t error, net_buffer* buffer); 174727ad0b0SHugo Santos 175727ad0b0SHugo Santos status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 176727ad0b0SHugo Santos status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 177727ad0b0SHugo Santos status_t UnbindEndpoint(UdpEndpoint *endpoint); 178727ad0b0SHugo Santos 179cf5d9f4bSHugo Santos void DumpEndpoints() const; 180bf48e753SHugo Santos 181c22d69bfSAxel Dörfler private: 182727ad0b0SHugo Santos status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 183727ad0b0SHugo Santos status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address); 184727ad0b0SHugo Santos status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address); 185727ad0b0SHugo Santos status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address); 186727ad0b0SHugo Santos 18740bbf860SHugo Santos UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress, 18840bbf860SHugo Santos const sockaddr *peerAddress); 189bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer); 190bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer); 191bf48e753SHugo Santos 192bf48e753SHugo Santos uint16 _GetNextEphemeral(); 193727ad0b0SHugo Santos UdpEndpoint *_EndpointWithPort(uint16 port) const; 194bf48e753SHugo Santos 195bf48e753SHugo Santos net_address_module_info *AddressModule() const 196727ad0b0SHugo Santos { return fDomain->address_module; } 197bf48e753SHugo Santos 1985147963dSStephan Aßmus typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable; 19940bbf860SHugo Santos 2002b07b8e0SIngo Weinhold mutex fLock; 201bf48e753SHugo Santos net_domain *fDomain; 202bf48e753SHugo Santos uint16 fLastUsedEphemeral; 20340bbf860SHugo Santos EndpointTable fActiveEndpoints; 204bf48e753SHugo Santos uint32 fEndpointCount; 205bf48e753SHugo Santos 206bf48e753SHugo Santos static const uint16 kFirst = 49152; 207bf48e753SHugo Santos static const uint16 kLast = 65535; 208bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800; 209bf48e753SHugo Santos // if you change this, adjust the shifting in 210bf48e753SHugo Santos // Hash() accordingly! 211bf48e753SHugo Santos }; 212bf48e753SHugo Santos 213bf48e753SHugo Santos 214bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList; 215bf48e753SHugo Santos 216bf48e753SHugo Santos 217bf48e753SHugo Santos class UdpEndpointManager { 218c22d69bfSAxel Dörfler public: 219c22d69bfSAxel Dörfler UdpEndpointManager(); 220c22d69bfSAxel Dörfler ~UdpEndpointManager(); 221c22d69bfSAxel Dörfler 2222bb43d82SAxel Dörfler status_t InitCheck() const; 2232bb43d82SAxel Dörfler 224c22d69bfSAxel Dörfler status_t ReceiveData(net_buffer* buffer); 2252bb43d82SAxel Dörfler status_t ReceiveError(status_t error, 2262bb43d82SAxel Dörfler net_buffer* buffer); 2276a606180SHugo Santos status_t Deframe(net_buffer* buffer); 228c22d69bfSAxel Dörfler 229bf48e753SHugo Santos UdpDomainSupport* OpenEndpoint(UdpEndpoint* endpoint); 230bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport* domain); 231c22d69bfSAxel Dörfler 232cf5d9f4bSHugo Santos static int DumpEndpoints(int argc, char *argv[]); 233cf5d9f4bSHugo Santos 234c22d69bfSAxel Dörfler private: 235bf48e753SHugo Santos UdpDomainSupport* _GetDomain(net_domain *domain, bool create); 2362bb43d82SAxel Dörfler UdpDomainSupport* _GetDomain(net_buffer* buffer); 237bf48e753SHugo Santos 2382b07b8e0SIngo Weinhold mutex fLock; 239c22d69bfSAxel Dörfler status_t fStatus; 240bf48e753SHugo Santos UdpDomainList fDomains; 241c22d69bfSAxel Dörfler }; 242c22d69bfSAxel Dörfler 243c22d69bfSAxel Dörfler 244c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager; 245c22d69bfSAxel Dörfler 246c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule; 247658a5506SHugo Santos net_datalink_module_info *gDatalinkModule; 248658a5506SHugo Santos net_stack_module_info *gStackModule; 2492bb43d82SAxel Dörfler net_socket_module_info *gSocketModule; 250c22d69bfSAxel Dörfler 251c22d69bfSAxel Dörfler 252c22d69bfSAxel Dörfler // #pragma mark - 253c22d69bfSAxel Dörfler 254c22d69bfSAxel Dörfler 255bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain) 256c22d69bfSAxel Dörfler : 257bf48e753SHugo Santos fDomain(domain), 258276aa463SIngo Weinhold fActiveEndpoints(domain->address_module), 259bf48e753SHugo Santos fEndpointCount(0) 260c22d69bfSAxel Dörfler { 2612b07b8e0SIngo Weinhold mutex_init(&fLock, "udp domain"); 262727ad0b0SHugo Santos 263727ad0b0SHugo Santos fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst); 264727ad0b0SHugo Santos } 265727ad0b0SHugo Santos 266727ad0b0SHugo Santos 267727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport() 268727ad0b0SHugo Santos { 2692b07b8e0SIngo Weinhold mutex_destroy(&fLock); 270bf48e753SHugo Santos } 271bf48e753SHugo Santos 272bf48e753SHugo Santos 273bf48e753SHugo Santos status_t 274276aa463SIngo Weinhold UdpDomainSupport::Init() 275bf48e753SHugo Santos { 276276aa463SIngo Weinhold return fActiveEndpoints.Init(kNumHashBuckets); 277bf48e753SHugo Santos } 278bf48e753SHugo Santos 279bf48e753SHugo Santos 280bf48e753SHugo Santos status_t 281bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer) 282bf48e753SHugo Santos { 2832bb43d82SAxel Dörfler // NOTE: multicast is delivered directly to the endpoint 2842b07b8e0SIngo Weinhold MutexLocker _(fLock); 285727ad0b0SHugo Santos 2862bb43d82SAxel Dörfler if ((buffer->flags & MSG_BCAST) != 0) 287bf48e753SHugo Santos return _DemuxBroadcast(buffer); 2882bb43d82SAxel Dörfler if ((buffer->flags & MSG_MCAST) != 0) 289727ad0b0SHugo Santos return B_ERROR; 290bf48e753SHugo Santos 291bf48e753SHugo Santos return _DemuxUnicast(buffer); 292bf48e753SHugo Santos } 293bf48e753SHugo Santos 294bf48e753SHugo Santos 295bf48e753SHugo Santos status_t 2962bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer) 2972bb43d82SAxel Dörfler { 2982bb43d82SAxel Dörfler if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0) 2992bb43d82SAxel Dörfler return B_ERROR; 3002bb43d82SAxel Dörfler 3012bb43d82SAxel Dörfler MutexLocker _(fLock); 3022bb43d82SAxel Dörfler 3032e1729d0SAxel Dörfler // Forward the error to the socket 3042e1729d0SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source, 3052e1729d0SAxel Dörfler buffer->destination); 3062e1729d0SAxel Dörfler if (endpoint != NULL) { 3072bb43d82SAxel Dörfler gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error); 3082e1729d0SAxel Dörfler endpoint->NotifyOne(); 3092e1729d0SAxel Dörfler } 3102bb43d82SAxel Dörfler 3112bb43d82SAxel Dörfler gBufferModule->free(buffer); 3122bb43d82SAxel Dörfler return B_OK; 3132bb43d82SAxel Dörfler } 3142bb43d82SAxel Dörfler 3152bb43d82SAxel Dörfler 3162bb43d82SAxel Dörfler status_t 317727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint, 318727ad0b0SHugo Santos const sockaddr *address) 319727ad0b0SHugo Santos { 32056f097ebSOliver Tappe if (!AddressModule()->is_same_family(address)) 32156f097ebSOliver Tappe return EAFNOSUPPORT; 32256f097ebSOliver Tappe 3232b07b8e0SIngo Weinhold MutexLocker _(fLock); 324727ad0b0SHugo Santos 325727ad0b0SHugo Santos if (endpoint->IsActive()) 326727ad0b0SHugo Santos return EINVAL; 327727ad0b0SHugo Santos 328727ad0b0SHugo Santos return _BindEndpoint(endpoint, address); 329727ad0b0SHugo Santos } 330727ad0b0SHugo Santos 331727ad0b0SHugo Santos 332727ad0b0SHugo Santos status_t 333727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint, 334727ad0b0SHugo Santos const sockaddr *address) 335727ad0b0SHugo Santos { 3362b07b8e0SIngo Weinhold MutexLocker _(fLock); 337727ad0b0SHugo Santos 338727ad0b0SHugo Santos if (endpoint->IsActive()) { 339727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 340727ad0b0SHugo Santos endpoint->SetActive(false); 341727ad0b0SHugo Santos } 342727ad0b0SHugo Santos 343727ad0b0SHugo Santos if (address->sa_family == AF_UNSPEC) { 344727ad0b0SHugo Santos // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect", 345727ad0b0SHugo Santos // so we reset the peer address: 346727ad0b0SHugo Santos endpoint->PeerAddress().SetToEmpty(); 347727ad0b0SHugo Santos } else { 34856f097ebSOliver Tappe if (!AddressModule()->is_same_family(address)) 34956f097ebSOliver Tappe return EAFNOSUPPORT; 35056f097ebSOliver Tappe 35156f097ebSOliver Tappe // consider destination address INADDR_ANY as INADDR_LOOPBACK 35256f097ebSOliver Tappe sockaddr_storage _address; 35356f097ebSOliver Tappe if (AddressModule()->is_empty_address(address, false)) { 35456f097ebSOliver Tappe AddressModule()->get_loopback_address((sockaddr *)&_address); 35556f097ebSOliver Tappe // for IPv4 and IPv6 the port is at the same offset 35656f097ebSOliver Tappe ((sockaddr_in&)_address).sin_port 35756f097ebSOliver Tappe = ((sockaddr_in *)address)->sin_port; 35856f097ebSOliver Tappe address = (sockaddr *)&_address; 35956f097ebSOliver Tappe } 36056f097ebSOliver Tappe 361727ad0b0SHugo Santos status_t status = endpoint->PeerAddress().SetTo(address); 362727ad0b0SHugo Santos if (status < B_OK) 363727ad0b0SHugo Santos return status; 3644e45de0eSOliver Tappe struct net_route *routeToDestination 3654e45de0eSOliver Tappe = gDatalinkModule->get_route(fDomain, address); 3664e45de0eSOliver Tappe if (routeToDestination) { 3674e45de0eSOliver Tappe status = endpoint->LocalAddress().SetTo( 36861729d93SAxel Dörfler routeToDestination->interface_address->local); 3694e45de0eSOliver Tappe gDatalinkModule->put_route(fDomain, routeToDestination); 3704e45de0eSOliver Tappe if (status < B_OK) 3714e45de0eSOliver Tappe return status; 3724e45de0eSOliver Tappe } 373727ad0b0SHugo Santos } 374727ad0b0SHugo Santos 375727ad0b0SHugo Santos // we need to activate no matter whether or not we have just disconnected, 376727ad0b0SHugo Santos // as calling connect() always triggers an implicit bind(): 377727ad0b0SHugo Santos return _BindEndpoint(endpoint, *endpoint->LocalAddress()); 378727ad0b0SHugo Santos } 379727ad0b0SHugo Santos 380727ad0b0SHugo Santos 381727ad0b0SHugo Santos status_t 382727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint) 383727ad0b0SHugo Santos { 3842b07b8e0SIngo Weinhold MutexLocker _(fLock); 385727ad0b0SHugo Santos 386727ad0b0SHugo Santos if (endpoint->IsActive()) 387727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 388727ad0b0SHugo Santos 389727ad0b0SHugo Santos endpoint->SetActive(false); 390727ad0b0SHugo Santos 391727ad0b0SHugo Santos return B_OK; 392727ad0b0SHugo Santos } 393727ad0b0SHugo Santos 394727ad0b0SHugo Santos 395cf5d9f4bSHugo Santos void 396cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const 397cf5d9f4bSHugo Santos { 398cf5d9f4bSHugo Santos kprintf("-------- UDP Domain %p ---------\n", this); 399cf5d9f4bSHugo Santos kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q"); 400cf5d9f4bSHugo Santos 401cf5d9f4bSHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 402cf5d9f4bSHugo Santos 403cf5d9f4bSHugo Santos while (it.HasNext()) { 404cf5d9f4bSHugo Santos UdpEndpoint *endpoint = it.Next(); 405cf5d9f4bSHugo Santos 406cf5d9f4bSHugo Santos char localBuf[64], peerBuf[64]; 407cf5d9f4bSHugo Santos endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true); 408cf5d9f4bSHugo Santos endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true); 409cf5d9f4bSHugo Santos 410cf5d9f4bSHugo Santos kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf, 411cf5d9f4bSHugo Santos endpoint->AvailableData()); 412cf5d9f4bSHugo Santos } 413cf5d9f4bSHugo Santos } 414cf5d9f4bSHugo Santos 415cf5d9f4bSHugo Santos 416727ad0b0SHugo Santos status_t 417727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint, 418727ad0b0SHugo Santos const sockaddr *address) 419727ad0b0SHugo Santos { 420727ad0b0SHugo Santos if (AddressModule()->get_port(address) == 0) 421727ad0b0SHugo Santos return _BindToEphemeral(endpoint, address); 422727ad0b0SHugo Santos 423727ad0b0SHugo Santos return _Bind(endpoint, address); 424727ad0b0SHugo Santos } 425727ad0b0SHugo Santos 426727ad0b0SHugo Santos 427727ad0b0SHugo Santos status_t 428727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address) 429727ad0b0SHugo Santos { 430727ad0b0SHugo Santos int socketOptions = endpoint->Socket()->options; 43140bbf860SHugo Santos 43240bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 433bf48e753SHugo Santos 434bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind 435bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]): 436727ad0b0SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain, 437727ad0b0SHugo Santos address, true).Data()); 438727ad0b0SHugo Santos 43940bbf860SHugo Santos while (it.HasNext()) { 44040bbf860SHugo Santos UdpEndpoint *otherEndpoint = it.Next(); 44125a2744fSHugo Santos 442bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint, 4435084c839SHugo Santos ntohs(otherEndpoint->LocalAddress().Port())); 44425a2744fSHugo Santos 44525a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualPorts(address)) { 446bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required: 44756f097ebSOliver Tappe if ((otherEndpoint->Socket()->options 44856f097ebSOliver Tappe & (SO_REUSEADDR | SO_REUSEPORT)) == 0 449d0eaec30SMichael Lotz || (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0) 450727ad0b0SHugo Santos return EADDRINUSE; 45125a2744fSHugo Santos 452bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required: 45325a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualTo(address, false) 454d0eaec30SMichael Lotz && ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0 455d0eaec30SMichael Lotz || (socketOptions & SO_REUSEPORT) == 0)) 456727ad0b0SHugo Santos return EADDRINUSE; 457bf48e753SHugo Santos } 458bf48e753SHugo Santos } 459bf48e753SHugo Santos 460727ad0b0SHugo Santos return _FinishBind(endpoint, address); 461bf48e753SHugo Santos } 462bf48e753SHugo Santos 463bf48e753SHugo Santos 464bf48e753SHugo Santos status_t 465727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint, 466727ad0b0SHugo Santos const sockaddr *address) 467727ad0b0SHugo Santos { 468727ad0b0SHugo Santos SocketAddressStorage newAddress(AddressModule()); 469727ad0b0SHugo Santos status_t status = newAddress.SetTo(address); 470727ad0b0SHugo Santos if (status < B_OK) 471727ad0b0SHugo Santos return status; 472727ad0b0SHugo Santos 473727ad0b0SHugo Santos uint16 allocedPort = _GetNextEphemeral(); 474727ad0b0SHugo Santos if (allocedPort == 0) 475727ad0b0SHugo Santos return ENOBUFS; 476727ad0b0SHugo Santos 4779e051839SOliver Tappe newAddress.SetPort(htons(allocedPort)); 478727ad0b0SHugo Santos 479727ad0b0SHugo Santos return _FinishBind(endpoint, *newAddress); 480727ad0b0SHugo Santos } 481727ad0b0SHugo Santos 482727ad0b0SHugo Santos 483727ad0b0SHugo Santos status_t 484727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address) 485727ad0b0SHugo Santos { 486727ad0b0SHugo Santos status_t status = endpoint->next->module->bind(endpoint->next, address); 487727ad0b0SHugo Santos if (status < B_OK) 488727ad0b0SHugo Santos return status; 48940bbf860SHugo Santos 49040bbf860SHugo Santos fActiveEndpoints.Insert(endpoint); 491727ad0b0SHugo Santos endpoint->SetActive(true); 492727ad0b0SHugo Santos 49340bbf860SHugo Santos return B_OK; 494bf48e753SHugo Santos } 495bf48e753SHugo Santos 496bf48e753SHugo Santos 497c22d69bfSAxel Dörfler UdpEndpoint * 49840bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress, 49940bbf860SHugo Santos const sockaddr *peerAddress) 500c22d69bfSAxel Dörfler { 5012e1729d0SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock); 5022e1729d0SAxel Dörfler 5039e051839SOliver Tappe TRACE_DOMAIN("finding Endpoint for %s <- %s", 504bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(), 505bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data()); 506c3e054c8SHugo Santos 50740bbf860SHugo Santos return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress)); 508c22d69bfSAxel Dörfler } 509c22d69bfSAxel Dörfler 510c22d69bfSAxel Dörfler 511c22d69bfSAxel Dörfler status_t 512bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) 513c22d69bfSAxel Dörfler { 51479a0d252SHugo Santos sockaddr *peerAddr = buffer->source; 51579a0d252SHugo Santos sockaddr *broadcastAddr = buffer->destination; 516c22d69bfSAxel Dörfler sockaddr *mask = NULL; 51761729d93SAxel Dörfler if (buffer->interface_address != NULL) 51861729d93SAxel Dörfler mask = (sockaddr *)buffer->interface_address->mask; 519c22d69bfSAxel Dörfler 520bf48e753SHugo Santos TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); 521c22d69bfSAxel Dörfler 522bf48e753SHugo Santos uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 523c22d69bfSAxel Dörfler 52440bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 52540bbf860SHugo Santos 52640bbf860SHugo Santos while (it.HasNext()) { 52740bbf860SHugo Santos UdpEndpoint *endpoint = it.Next(); 528c22d69bfSAxel Dörfler 52925a2744fSHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", 53025a2744fSHugo Santos AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); 53125a2744fSHugo Santos 5325084c839SHugo Santos if (endpoint->LocalAddress().Port() != incomingPort) { 533c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint... 534c22d69bfSAxel Dörfler continue; 535c22d69bfSAxel Dörfler } 536c22d69bfSAxel Dörfler 53725a2744fSHugo Santos if (!endpoint->PeerAddress().IsEmpty(true)) { 538c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if 539c22d69bfSAxel Dörfler // this datagram is from there: 54025a2744fSHugo Santos if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) { 541c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to 542c22d69bfSAxel Dörfler // this endpoint... 543c22d69bfSAxel Dörfler continue; 544c22d69bfSAxel Dörfler } 545c22d69bfSAxel Dörfler } 546c22d69bfSAxel Dörfler 54725a2744fSHugo Santos if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) 54825a2744fSHugo Santos || endpoint->LocalAddress().IsEmpty(false)) { 549c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint: 550c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 551c22d69bfSAxel Dörfler } 552c22d69bfSAxel Dörfler } 55340bbf860SHugo Santos 554c22d69bfSAxel Dörfler return B_OK; 555c22d69bfSAxel Dörfler } 556c22d69bfSAxel Dörfler 557c22d69bfSAxel Dörfler 558c22d69bfSAxel Dörfler status_t 559bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer) 560c22d69bfSAxel Dörfler { 561bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer); 562c22d69bfSAxel Dörfler 5632e1729d0SAxel Dörfler const sockaddr* localAddress = buffer->destination; 5642e1729d0SAxel Dörfler const sockaddr* peerAddress = buffer->source; 5652e1729d0SAxel Dörfler 5662e1729d0SAxel Dörfler // look for full (most special) match: 5672e1729d0SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress); 5682e1729d0SAxel Dörfler if (endpoint == NULL) { 5692e1729d0SAxel Dörfler // look for endpoint matching local address & port: 5702e1729d0SAxel Dörfler endpoint = _FindActiveEndpoint(localAddress, NULL); 5712e1729d0SAxel Dörfler if (endpoint == NULL) { 5722e1729d0SAxel Dörfler // look for endpoint matching peer address & port and local port: 5732e1729d0SAxel Dörfler SocketAddressStorage local(AddressModule()); 5742e1729d0SAxel Dörfler local.SetToEmpty(); 5752e1729d0SAxel Dörfler local.SetPort(AddressModule()->get_port(localAddress)); 5762e1729d0SAxel Dörfler endpoint = _FindActiveEndpoint(*local, peerAddress); 5772e1729d0SAxel Dörfler if (endpoint == NULL) { 5782e1729d0SAxel Dörfler // last chance: look for endpoint matching local port only: 5792e1729d0SAxel Dörfler endpoint = _FindActiveEndpoint(*local, NULL); 5802e1729d0SAxel Dörfler } 5812e1729d0SAxel Dörfler } 5822e1729d0SAxel Dörfler } 5832e1729d0SAxel Dörfler 5842bb43d82SAxel Dörfler if (endpoint == NULL) { 5852bb43d82SAxel Dörfler TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer); 586c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND; 5879e051839SOliver Tappe } 588c22d69bfSAxel Dörfler 589c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 590c22d69bfSAxel Dörfler return B_OK; 591c22d69bfSAxel Dörfler } 592c22d69bfSAxel Dörfler 593c22d69bfSAxel Dörfler 594bf48e753SHugo Santos uint16 595bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral() 596c22d69bfSAxel Dörfler { 59740bbf860SHugo Santos uint16 stop, curr; 598bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) { 599bf48e753SHugo Santos stop = fLastUsedEphemeral; 600bf48e753SHugo Santos curr = fLastUsedEphemeral + 1; 601bf48e753SHugo Santos } else { 602bf48e753SHugo Santos stop = kLast; 603bf48e753SHugo Santos curr = kFirst; 604bf48e753SHugo Santos } 605c22d69bfSAxel Dörfler 606727ad0b0SHugo Santos TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu", 607727ad0b0SHugo Santos fLastUsedEphemeral, curr, stop); 60840bbf860SHugo Santos 6099e051839SOliver Tappe // TODO: a free list could be used to avoid the impact of these two 6109e051839SOliver Tappe // nested loops most of the time... let's see how bad this really is 611727ad0b0SHugo Santos for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) { 612bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr); 61340bbf860SHugo Santos 614727ad0b0SHugo Santos if (_EndpointWithPort(htons(curr)) == NULL) { 615bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr); 616bf48e753SHugo Santos fLastUsedEphemeral = curr; 617bf48e753SHugo Santos return curr; 618bf48e753SHugo Santos } 619727ad0b0SHugo Santos } 620727ad0b0SHugo Santos 621727ad0b0SHugo Santos return 0; 622727ad0b0SHugo Santos } 623727ad0b0SHugo Santos 624727ad0b0SHugo Santos 625727ad0b0SHugo Santos UdpEndpoint * 626727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const 627727ad0b0SHugo Santos { 628727ad0b0SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 629727ad0b0SHugo Santos 630727ad0b0SHugo Santos while (it.HasNext()) { 631727ad0b0SHugo Santos UdpEndpoint *endpoint = it.Next(); 632727ad0b0SHugo Santos if (endpoint->LocalAddress().Port() == port) 633727ad0b0SHugo Santos return endpoint; 634727ad0b0SHugo Santos } 635727ad0b0SHugo Santos 636727ad0b0SHugo Santos return NULL; 637727ad0b0SHugo Santos } 638c22d69bfSAxel Dörfler 639bf48e753SHugo Santos 640bf48e753SHugo Santos // #pragma mark - 641bf48e753SHugo Santos 642bf48e753SHugo Santos 643bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager() 644bf48e753SHugo Santos { 6452b07b8e0SIngo Weinhold mutex_init(&fLock, "UDP endpoints"); 6462b07b8e0SIngo Weinhold fStatus = B_OK; 647bf48e753SHugo Santos } 648bf48e753SHugo Santos 649bf48e753SHugo Santos 650bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 651bf48e753SHugo Santos { 6522b07b8e0SIngo Weinhold mutex_destroy(&fLock); 653bf48e753SHugo Santos } 654bf48e753SHugo Santos 655bf48e753SHugo Santos 656bf48e753SHugo Santos status_t 657bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 658bf48e753SHugo Santos { 659bf48e753SHugo Santos return fStatus; 660bf48e753SHugo Santos } 661bf48e753SHugo Santos 662bf48e753SHugo Santos 663cf5d9f4bSHugo Santos int 664cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[]) 665cf5d9f4bSHugo Santos { 666cf5d9f4bSHugo Santos UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator(); 667cf5d9f4bSHugo Santos 668cf5d9f4bSHugo Santos while (it.HasNext()) 669cf5d9f4bSHugo Santos it.Next()->DumpEndpoints(); 670cf5d9f4bSHugo Santos 671cf5d9f4bSHugo Santos return 0; 672cf5d9f4bSHugo Santos } 673cf5d9f4bSHugo Santos 674cf5d9f4bSHugo Santos 675bf48e753SHugo Santos // #pragma mark - inbound 676bf48e753SHugo Santos 677bf48e753SHugo Santos 678bf48e753SHugo Santos status_t 679c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer) 680c22d69bfSAxel Dörfler { 6812bb43d82SAxel Dörfler TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 6822bb43d82SAxel Dörfler 6832bb43d82SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomain(buffer); 6842bb43d82SAxel Dörfler if (domainSupport == NULL) { 6852bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as 6862bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets. 6872bb43d82SAxel Dörfler return B_ERROR; 6882bb43d82SAxel Dörfler } 6892bb43d82SAxel Dörfler 6906a606180SHugo Santos status_t status = Deframe(buffer); 6912bb43d82SAxel Dörfler if (status != B_OK) 6926a606180SHugo Santos return status; 6936a606180SHugo Santos 6942bb43d82SAxel Dörfler status = domainSupport->DemuxIncomingBuffer(buffer); 6952bb43d82SAxel Dörfler if (status != B_OK) { 6962bb43d82SAxel Dörfler TRACE_EPM(" ReceiveData(): no endpoint."); 6972bb43d82SAxel Dörfler // Send port unreachable error 6982bb43d82SAxel Dörfler domainSupport->Domain()->module->error_reply(NULL, buffer, 699*2b415445SAxel Dörfler B_NET_ERROR_UNREACH_PORT, NULL); 7002bb43d82SAxel Dörfler return B_ERROR; 7012bb43d82SAxel Dörfler } 7022bb43d82SAxel Dörfler 7032bb43d82SAxel Dörfler gBufferModule->free(buffer); 7042bb43d82SAxel Dörfler return B_OK; 7052bb43d82SAxel Dörfler } 7062bb43d82SAxel Dörfler 7072bb43d82SAxel Dörfler 7082bb43d82SAxel Dörfler status_t 7092bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) 7102bb43d82SAxel Dörfler { 7112bb43d82SAxel Dörfler TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])", 7122bb43d82SAxel Dörfler error, buffer, buffer->size); 7132bb43d82SAxel Dörfler 7142bb43d82SAxel Dörfler // We only really need the port information 7152bb43d82SAxel Dörfler if (buffer->size < 4) 7162bb43d82SAxel Dörfler return B_BAD_VALUE; 7172bb43d82SAxel Dörfler 7182bb43d82SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomain(buffer); 7192bb43d82SAxel Dörfler if (domainSupport == NULL) { 7202bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as 7212bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets. 7222bb43d82SAxel Dörfler return B_ERROR; 7232bb43d82SAxel Dörfler } 7242bb43d82SAxel Dörfler 7252bb43d82SAxel Dörfler // Deframe the buffer manually, as we usually only get 8 bytes from the 7262bb43d82SAxel Dörfler // original packet 7272bb43d82SAxel Dörfler udp_header header; 7282bb43d82SAxel Dörfler if (gBufferModule->read(buffer, 0, &header, 7292bb43d82SAxel Dörfler std::min(buffer->size, sizeof(udp_header))) != B_OK) 7302bb43d82SAxel Dörfler return B_BAD_VALUE; 731bf48e753SHugo Santos 73261729d93SAxel Dörfler net_domain* domain = buffer->interface_address->domain; 7332bb43d82SAxel Dörfler net_address_module_info* addressModule = domain->address_module; 7346a606180SHugo Santos 7352bb43d82SAxel Dörfler SocketAddress source(addressModule, buffer->source); 7362bb43d82SAxel Dörfler SocketAddress destination(addressModule, buffer->destination); 7376a606180SHugo Santos 7382bb43d82SAxel Dörfler source.SetPort(header.source_port); 7392bb43d82SAxel Dörfler destination.SetPort(header.destination_port); 740727ad0b0SHugo Santos 7412bb43d82SAxel Dörfler status_t status = domainSupport->DeliverError(error, buffer); 7422bb43d82SAxel Dörfler if (status != B_OK) 7432bb43d82SAxel Dörfler return status; 7446a606180SHugo Santos 745a1deb55eSHugo Santos gBufferModule->free(buffer); 746a1deb55eSHugo Santos return B_OK; 7476a606180SHugo Santos } 7486a606180SHugo Santos 7496a606180SHugo Santos 7506a606180SHugo Santos status_t 7516a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer) 7526a606180SHugo Santos { 7536a606180SHugo Santos TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); 7546a606180SHugo Santos 75587001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer); 756c22d69bfSAxel Dörfler if (bufferHeader.Status() < B_OK) 757c22d69bfSAxel Dörfler return bufferHeader.Status(); 758c22d69bfSAxel Dörfler 759c22d69bfSAxel Dörfler udp_header &header = bufferHeader.Data(); 760c22d69bfSAxel Dörfler 76161729d93SAxel Dörfler if (buffer->interface_address == NULL 76261729d93SAxel Dörfler || buffer->interface_address->domain == NULL) { 7636a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " 76461729d93SAxel Dörfler "specified (interface address %p).", buffer->interface_address); 765c22d69bfSAxel Dörfler return B_BAD_VALUE; 766c22d69bfSAxel Dörfler } 767bf48e753SHugo Santos 76861729d93SAxel Dörfler net_domain *domain = buffer->interface_address->domain; 769bf48e753SHugo Santos net_address_module_info *addressModule = domain->address_module; 770bf48e753SHugo Santos 77179a0d252SHugo Santos SocketAddress source(addressModule, buffer->source); 77279a0d252SHugo Santos SocketAddress destination(addressModule, buffer->destination); 773bf48e753SHugo Santos 7744e8a1b33SHugo Santos source.SetPort(header.source_port); 7754e8a1b33SHugo Santos destination.SetPort(header.destination_port); 7764e8a1b33SHugo Santos 7774e8a1b33SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(), 7784e8a1b33SHugo Santos destination.AsString(true).Data()); 779c22d69bfSAxel Dörfler 780c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length); 781c22d69bfSAxel Dörfler if (udpLength > buffer->size) { 7826a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", 783bf48e753SHugo Santos udpLength); 784c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES; 785c22d69bfSAxel Dörfler } 786bf48e753SHugo Santos 787bf48e753SHugo Santos if (buffer->size > udpLength) 788c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength); 789c22d69bfSAxel Dörfler 790c22d69bfSAxel Dörfler if (header.udp_checksum != 0) { 791c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"): 792d5b5a2c2SHugo Santos uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule, 793d5b5a2c2SHugo Santos buffer, IPPROTO_UDP); 794c22d69bfSAxel Dörfler if (sum != 0) { 7956a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); 796c22d69bfSAxel Dörfler return B_BAD_VALUE; 797c22d69bfSAxel Dörfler } 798c22d69bfSAxel Dörfler } 799c22d69bfSAxel Dörfler 800c22d69bfSAxel Dörfler bufferHeader.Remove(); 801c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on 802c22d69bfSAxel Dörfler 8036a606180SHugo Santos return B_OK; 804c22d69bfSAxel Dörfler } 805c22d69bfSAxel Dörfler 806c22d69bfSAxel Dörfler 807bf48e753SHugo Santos UdpDomainSupport * 808c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) 809c22d69bfSAxel Dörfler { 8102b07b8e0SIngo Weinhold MutexLocker _(fLock); 811bf48e753SHugo Santos 812bf48e753SHugo Santos UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); 813bf48e753SHugo Santos if (domain) 814bf48e753SHugo Santos domain->Ref(); 815bf48e753SHugo Santos return domain; 816bf48e753SHugo Santos } 817bf48e753SHugo Santos 818bf48e753SHugo Santos 819bf48e753SHugo Santos status_t 820bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) 821bf48e753SHugo Santos { 8222b07b8e0SIngo Weinhold MutexLocker _(fLock); 823bf48e753SHugo Santos 824727ad0b0SHugo Santos if (domain->Put()) { 825bf48e753SHugo Santos fDomains.Remove(domain); 826bf48e753SHugo Santos delete domain; 827bf48e753SHugo Santos } 828bf48e753SHugo Santos 829bf48e753SHugo Santos return B_OK; 830bf48e753SHugo Santos } 831bf48e753SHugo Santos 832bf48e753SHugo Santos 833bf48e753SHugo Santos // #pragma mark - 834bf48e753SHugo Santos 835bf48e753SHugo Santos 836bf48e753SHugo Santos UdpDomainSupport * 837bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create) 838bf48e753SHugo Santos { 839bf48e753SHugo Santos UdpDomainList::Iterator it = fDomains.GetIterator(); 840bf48e753SHugo Santos 841bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain 842bf48e753SHugo Santos // receiver handlers that forward the requests to the 843bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while 844bf48e753SHugo Santos // being constructed UdpDomainSupport could call 845bf48e753SHugo Santos // register_domain_receiving_protocol() with the right 846bf48e753SHugo Santos // family. 847bf48e753SHugo Santos while (it.HasNext()) { 848bf48e753SHugo Santos UdpDomainSupport *domainSupport = it.Next(); 849bf48e753SHugo Santos if (domainSupport->Domain() == domain) 850bf48e753SHugo Santos return domainSupport; 851bf48e753SHugo Santos } 852bf48e753SHugo Santos 853bf48e753SHugo Santos if (!create) 854bf48e753SHugo Santos return NULL; 855bf48e753SHugo Santos 856bf48e753SHugo Santos UdpDomainSupport *domainSupport = 857bf48e753SHugo Santos new (std::nothrow) UdpDomainSupport(domain); 858276aa463SIngo Weinhold if (domainSupport == NULL || domainSupport->Init() < B_OK) { 859bf48e753SHugo Santos delete domainSupport; 860bf48e753SHugo Santos return NULL; 861bf48e753SHugo Santos } 862bf48e753SHugo Santos 863bf48e753SHugo Santos fDomains.Add(domainSupport); 864bf48e753SHugo Santos return domainSupport; 865c22d69bfSAxel Dörfler } 866c22d69bfSAxel Dörfler 867c22d69bfSAxel Dörfler 8682bb43d82SAxel Dörfler UdpDomainSupport* 8692bb43d82SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer) 8702bb43d82SAxel Dörfler { 87161729d93SAxel Dörfler if (buffer->interface_address == NULL) 8722bb43d82SAxel Dörfler return NULL; 8732bb43d82SAxel Dörfler 8742bb43d82SAxel Dörfler MutexLocker _(fLock); 87561729d93SAxel Dörfler return _GetDomain(buffer->interface_address->domain, false); 8762bb43d82SAxel Dörfler // TODO: we don't want to hold to the manager's lock during the 8772bb43d82SAxel Dörfler // whole RX path, we may not hold an endpoint's lock with the 8782bb43d82SAxel Dörfler // manager lock held. 8792bb43d82SAxel Dörfler // But we should increase the domain's refcount here. 8802bb43d82SAxel Dörfler } 8812bb43d82SAxel Dörfler 8822bb43d82SAxel Dörfler 883c22d69bfSAxel Dörfler // #pragma mark - 884c22d69bfSAxel Dörfler 885c22d69bfSAxel Dörfler 886c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 887c72ab92dSHugo Santos : DatagramSocket<>("udp endpoint", socket), fActive(false) {} 888bf48e753SHugo Santos 889bf48e753SHugo Santos 890c22d69bfSAxel Dörfler // #pragma mark - activation 891c22d69bfSAxel Dörfler 892c22d69bfSAxel Dörfler 893c22d69bfSAxel Dörfler status_t 89453f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address) 895c22d69bfSAxel Dörfler { 896bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 897727ad0b0SHugo Santos return fManager->BindEndpoint(this, address); 898c22d69bfSAxel Dörfler } 899c22d69bfSAxel Dörfler 900c22d69bfSAxel Dörfler 901c22d69bfSAxel Dörfler status_t 902c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 903c22d69bfSAxel Dörfler { 904bf48e753SHugo Santos TRACE_EP("Unbind()"); 905727ad0b0SHugo Santos return fManager->UnbindEndpoint(this); 906c22d69bfSAxel Dörfler } 907c22d69bfSAxel Dörfler 908c22d69bfSAxel Dörfler 909c22d69bfSAxel Dörfler status_t 910c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 911c22d69bfSAxel Dörfler { 912bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 913727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address); 914c22d69bfSAxel Dörfler } 915c22d69bfSAxel Dörfler 916c22d69bfSAxel Dörfler 917c22d69bfSAxel Dörfler status_t 918c22d69bfSAxel Dörfler UdpEndpoint::Open() 919c22d69bfSAxel Dörfler { 920bf48e753SHugo Santos TRACE_EP("Open()"); 921bf48e753SHugo Santos 922119c6cddSIngo Weinhold AutoLocker _(fLock); 923727ad0b0SHugo Santos 924c72ab92dSHugo Santos status_t status = ProtocolSocket::Open(); 925c72ab92dSHugo Santos if (status < B_OK) 926c72ab92dSHugo Santos return status; 927bf48e753SHugo Santos 928c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this); 929c72ab92dSHugo Santos if (fManager == NULL) 930bf48e753SHugo Santos return EAFNOSUPPORT; 931bf48e753SHugo Santos 932bf48e753SHugo Santos return B_OK; 933c22d69bfSAxel Dörfler } 934c22d69bfSAxel Dörfler 935c22d69bfSAxel Dörfler 936c22d69bfSAxel Dörfler status_t 937c22d69bfSAxel Dörfler UdpEndpoint::Close() 938c22d69bfSAxel Dörfler { 939bf48e753SHugo Santos TRACE_EP("Close()"); 940bf48e753SHugo Santos return B_OK; 941c22d69bfSAxel Dörfler } 942c22d69bfSAxel Dörfler 943c22d69bfSAxel Dörfler 944c22d69bfSAxel Dörfler status_t 945c22d69bfSAxel Dörfler UdpEndpoint::Free() 946c22d69bfSAxel Dörfler { 947bf48e753SHugo Santos TRACE_EP("Free()"); 9480086fe20SHugo Santos fManager->UnbindEndpoint(this); 949c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager); 950c22d69bfSAxel Dörfler } 951c22d69bfSAxel Dörfler 952c22d69bfSAxel Dörfler 953c22d69bfSAxel Dörfler // #pragma mark - outbound 954c22d69bfSAxel Dörfler 955c22d69bfSAxel Dörfler 956c22d69bfSAxel Dörfler status_t 957bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 958c22d69bfSAxel Dörfler { 959bf48e753SHugo Santos TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route); 960bf48e753SHugo Santos 961d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 962c22d69bfSAxel Dörfler return EMSGSIZE; 963c22d69bfSAxel Dörfler 964c22d69bfSAxel Dörfler buffer->protocol = IPPROTO_UDP; 965c22d69bfSAxel Dörfler 966c22d69bfSAxel Dörfler // add and fill UDP-specific header: 9676c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 9686c353509SHugo Santos if (header.Status() < B_OK) 9696c353509SHugo Santos return header.Status(); 970c22d69bfSAxel Dörfler 97179a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source); 97279a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination); 9736c353509SHugo Santos header->udp_length = htons(buffer->size); 974c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 9756c353509SHugo Santos header->udp_checksum = 0; 9766c353509SHugo Santos 9776c353509SHugo Santos header.Sync(); 978c22d69bfSAxel Dörfler 979d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(), 980d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP); 9816c353509SHugo Santos if (calculatedChecksum == 0) 9826c353509SHugo Santos calculatedChecksum = 0xffff; 9836c353509SHugo Santos 9846c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 985c22d69bfSAxel Dörfler 986c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 987c22d69bfSAxel Dörfler } 988c22d69bfSAxel Dörfler 989c22d69bfSAxel Dörfler 990bf48e753SHugo Santos status_t 991bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 992bf48e753SHugo Santos { 993bf48e753SHugo Santos TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size); 994bf48e753SHugo Santos 9952651e51dSAxel Dörfler return gDatalinkModule->send_data(this, NULL, buffer); 996bf48e753SHugo Santos } 997bf48e753SHugo Santos 998bf48e753SHugo Santos 999c22d69bfSAxel Dörfler // #pragma mark - inbound 1000c22d69bfSAxel Dörfler 1001c22d69bfSAxel Dörfler 1002c22d69bfSAxel Dörfler ssize_t 1003c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 1004c22d69bfSAxel Dörfler { 1005bfb45f71SHugo Santos size_t bytes = AvailableData(); 1006bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 1007bfb45f71SHugo Santos return bytes; 1008c22d69bfSAxel Dörfler } 1009c22d69bfSAxel Dörfler 1010c22d69bfSAxel Dörfler 1011c22d69bfSAxel Dörfler status_t 1012c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 1013c22d69bfSAxel Dörfler { 1014bf48e753SHugo Santos TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags); 1015bf48e753SHugo Santos 10162651e51dSAxel Dörfler status_t status = Dequeue(flags, _buffer); 1017bf48e753SHugo Santos TRACE_EP(" FetchData(): returned from fifo status=0x%lx", status); 10182651e51dSAxel Dörfler if (status != B_OK) 1019c22d69bfSAxel Dörfler return status; 1020c22d69bfSAxel Dörfler 1021bfb45f71SHugo Santos TRACE_EP(" FetchData(): returns buffer with %ld bytes", (*_buffer)->size); 1022c22d69bfSAxel Dörfler return B_OK; 1023c22d69bfSAxel Dörfler } 1024c22d69bfSAxel Dörfler 1025c22d69bfSAxel Dörfler 1026c22d69bfSAxel Dörfler status_t 1027bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 1028c22d69bfSAxel Dörfler { 1029bf48e753SHugo Santos TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size); 1030c22d69bfSAxel Dörfler 10312651e51dSAxel Dörfler return EnqueueClone(buffer); 1032c22d69bfSAxel Dörfler } 1033c22d69bfSAxel Dörfler 1034c22d69bfSAxel Dörfler 10356a606180SHugo Santos status_t 10366a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 10376a606180SHugo Santos { 1038f6cfc5afSHugo Santos TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size); 1039f6cfc5afSHugo Santos 10406a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 10416a606180SHugo Santos if (buffer == NULL) 10426a606180SHugo Santos return B_NO_MEMORY; 10436a606180SHugo Santos 10446a606180SHugo Santos status_t status = sUdpEndpointManager->Deframe(buffer); 10456a606180SHugo Santos if (status < B_OK) { 10466a606180SHugo Santos gBufferModule->free(buffer); 10476a606180SHugo Santos return status; 10486a606180SHugo Santos } 10496a606180SHugo Santos 10506a606180SHugo Santos return Enqueue(buffer); 10516a606180SHugo Santos } 10526a606180SHugo Santos 10536a606180SHugo Santos 1054c22d69bfSAxel Dörfler // #pragma mark - protocol interface 1055c22d69bfSAxel Dörfler 1056c22d69bfSAxel Dörfler 1057c22d69bfSAxel Dörfler net_protocol * 1058c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 1059c22d69bfSAxel Dörfler { 1060c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 1061c22d69bfSAxel Dörfler 1062c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 1063bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 1064bf48e753SHugo Santos delete endpoint; 1065bf48e753SHugo Santos return NULL; 1066bf48e753SHugo Santos } 1067bf48e753SHugo Santos 1068c22d69bfSAxel Dörfler return endpoint; 1069c22d69bfSAxel Dörfler } 1070c22d69bfSAxel Dörfler 1071c22d69bfSAxel Dörfler 1072c22d69bfSAxel Dörfler status_t 1073c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 1074c22d69bfSAxel Dörfler { 1075bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 1076c22d69bfSAxel Dörfler return B_OK; 1077c22d69bfSAxel Dörfler } 1078c22d69bfSAxel Dörfler 1079c22d69bfSAxel Dörfler 1080c22d69bfSAxel Dörfler status_t 1081c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 1082c22d69bfSAxel Dörfler { 1083bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 1084c22d69bfSAxel Dörfler } 1085c22d69bfSAxel Dörfler 1086c22d69bfSAxel Dörfler 1087c22d69bfSAxel Dörfler status_t 1088c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 1089c22d69bfSAxel Dörfler { 1090bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 1091c22d69bfSAxel Dörfler } 1092c22d69bfSAxel Dörfler 1093c22d69bfSAxel Dörfler 1094c22d69bfSAxel Dörfler status_t 1095c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 1096c22d69bfSAxel Dörfler { 1097bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 1098c22d69bfSAxel Dörfler } 1099c22d69bfSAxel Dörfler 1100c22d69bfSAxel Dörfler 1101c22d69bfSAxel Dörfler status_t 1102c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1103c22d69bfSAxel Dörfler { 1104bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1105c22d69bfSAxel Dörfler } 1106c22d69bfSAxel Dörfler 1107c22d69bfSAxel Dörfler 1108c22d69bfSAxel Dörfler status_t 1109c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1110c22d69bfSAxel Dörfler { 1111ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1112c22d69bfSAxel Dörfler } 1113c22d69bfSAxel Dörfler 1114c22d69bfSAxel Dörfler 1115c22d69bfSAxel Dörfler status_t 1116c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1117c22d69bfSAxel Dörfler size_t *_length) 1118c22d69bfSAxel Dörfler { 1119c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1120c22d69bfSAxel Dörfler value, _length); 1121c22d69bfSAxel Dörfler } 1122c22d69bfSAxel Dörfler 1123c22d69bfSAxel Dörfler 1124c22d69bfSAxel Dörfler status_t 112545b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value, 112645b5203bSHugo Santos int *length) 112745b5203bSHugo Santos { 112845b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option, 112945b5203bSHugo Santos value, length); 113045b5203bSHugo Santos } 113145b5203bSHugo Santos 113245b5203bSHugo Santos 113345b5203bSHugo Santos status_t 113445b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option, 113545b5203bSHugo Santos const void *value, int length) 113645b5203bSHugo Santos { 113745b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option, 113845b5203bSHugo Santos value, length); 113945b5203bSHugo Santos } 114045b5203bSHugo Santos 114145b5203bSHugo Santos 114245b5203bSHugo Santos status_t 114353f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address) 1144c22d69bfSAxel Dörfler { 1145bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1146c22d69bfSAxel Dörfler } 1147c22d69bfSAxel Dörfler 1148c22d69bfSAxel Dörfler 1149c22d69bfSAxel Dörfler status_t 1150c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1151c22d69bfSAxel Dörfler { 1152bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1153c22d69bfSAxel Dörfler } 1154c22d69bfSAxel Dörfler 1155c22d69bfSAxel Dörfler 1156c22d69bfSAxel Dörfler status_t 1157c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1158c22d69bfSAxel Dörfler { 1159ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1160c22d69bfSAxel Dörfler } 1161c22d69bfSAxel Dörfler 1162c22d69bfSAxel Dörfler 1163c22d69bfSAxel Dörfler status_t 1164c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1165c22d69bfSAxel Dörfler { 1166ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1167c22d69bfSAxel Dörfler } 1168c22d69bfSAxel Dörfler 1169c22d69bfSAxel Dörfler 1170c22d69bfSAxel Dörfler status_t 1171c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1172c22d69bfSAxel Dörfler net_buffer *buffer) 1173c22d69bfSAxel Dörfler { 1174bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1175c22d69bfSAxel Dörfler } 1176c22d69bfSAxel Dörfler 1177c22d69bfSAxel Dörfler 1178c22d69bfSAxel Dörfler status_t 1179c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1180c22d69bfSAxel Dörfler { 1181bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1182c22d69bfSAxel Dörfler } 1183c22d69bfSAxel Dörfler 1184c22d69bfSAxel Dörfler 1185c22d69bfSAxel Dörfler ssize_t 1186c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1187c22d69bfSAxel Dörfler { 1188bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1189c22d69bfSAxel Dörfler } 1190c22d69bfSAxel Dörfler 1191c22d69bfSAxel Dörfler 1192c22d69bfSAxel Dörfler status_t 1193c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1194c22d69bfSAxel Dörfler net_buffer **_buffer) 1195c22d69bfSAxel Dörfler { 1196bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1197c22d69bfSAxel Dörfler } 1198c22d69bfSAxel Dörfler 1199c22d69bfSAxel Dörfler 1200c22d69bfSAxel Dörfler ssize_t 1201c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1202c22d69bfSAxel Dörfler { 1203bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1204c22d69bfSAxel Dörfler } 1205c22d69bfSAxel Dörfler 1206c22d69bfSAxel Dörfler 1207c22d69bfSAxel Dörfler struct net_domain * 1208c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1209c22d69bfSAxel Dörfler { 1210c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1211c22d69bfSAxel Dörfler } 1212c22d69bfSAxel Dörfler 1213c22d69bfSAxel Dörfler 1214c22d69bfSAxel Dörfler size_t 1215c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1216c22d69bfSAxel Dörfler { 1217c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1218c22d69bfSAxel Dörfler } 1219c22d69bfSAxel Dörfler 1220c22d69bfSAxel Dörfler 1221c22d69bfSAxel Dörfler status_t 1222c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1223c22d69bfSAxel Dörfler { 1224c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1225c22d69bfSAxel Dörfler } 1226c22d69bfSAxel Dörfler 1227c22d69bfSAxel Dörfler 1228c22d69bfSAxel Dörfler status_t 12296a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 12306a606180SHugo Santos { 12316a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 12326a606180SHugo Santos } 12336a606180SHugo Santos 12346a606180SHugo Santos 12356a606180SHugo Santos status_t 1236*2b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer) 1237c22d69bfSAxel Dörfler { 1238*2b415445SAxel Dörfler status_t notifyError = B_OK; 12392bb43d82SAxel Dörfler 1240*2b415445SAxel Dörfler switch (error) { 1241*2b415445SAxel Dörfler case B_NET_ERROR_UNREACH_NET: 1242*2b415445SAxel Dörfler notifyError = ENETUNREACH; 12432bb43d82SAxel Dörfler break; 1244*2b415445SAxel Dörfler case B_NET_ERROR_UNREACH_HOST: 1245*2b415445SAxel Dörfler case B_NET_ERROR_TRANSIT_TIME_EXCEEDED: 1246*2b415445SAxel Dörfler notifyError = EHOSTUNREACH; 12472bb43d82SAxel Dörfler break; 1248*2b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PROTOCOL: 1249*2b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PORT: 1250*2b415445SAxel Dörfler notifyError = ECONNREFUSED; 12512bb43d82SAxel Dörfler break; 1252*2b415445SAxel Dörfler case B_NET_ERROR_MESSAGE_SIZE: 1253*2b415445SAxel Dörfler notifyError = EMSGSIZE; 1254*2b415445SAxel Dörfler break; 1255*2b415445SAxel Dörfler case B_NET_ERROR_PARAMETER_PROBLEM: 1256*2b415445SAxel Dörfler notifyError = ENOPROTOOPT; 1257*2b415445SAxel Dörfler break; 1258*2b415445SAxel Dörfler 1259*2b415445SAxel Dörfler case B_NET_ERROR_QUENCH: 12602bb43d82SAxel Dörfler default: 12612bb43d82SAxel Dörfler // ignore them 12622bb43d82SAxel Dörfler break; 12632bb43d82SAxel Dörfler } 12642bb43d82SAxel Dörfler 1265*2b415445SAxel Dörfler if (notifyError != B_OK) 1266*2b415445SAxel Dörfler sUdpEndpointManager->ReceiveError(notifyError, buffer); 12672bb43d82SAxel Dörfler 12682bb43d82SAxel Dörfler gBufferModule->free(buffer); 12692bb43d82SAxel Dörfler return B_OK; 1270c22d69bfSAxel Dörfler } 1271c22d69bfSAxel Dörfler 1272c22d69bfSAxel Dörfler 1273c22d69bfSAxel Dörfler status_t 1274*2b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error, 1275*2b415445SAxel Dörfler net_error_data *errorData) 1276c22d69bfSAxel Dörfler { 1277c22d69bfSAxel Dörfler return B_ERROR; 1278c22d69bfSAxel Dörfler } 1279c22d69bfSAxel Dörfler 1280c22d69bfSAxel Dörfler 128178888c44SAxel Dörfler ssize_t 128278888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol, 128378888c44SAxel Dörfler net_buffer* buffer, void *data, size_t dataSize) 128478888c44SAxel Dörfler { 128578888c44SAxel Dörfler return protocol->next->module->process_ancillary_data_no_container( 128678888c44SAxel Dörfler protocol, buffer, data, dataSize); 128778888c44SAxel Dörfler } 128878888c44SAxel Dörfler 128978888c44SAxel Dörfler 1290c22d69bfSAxel Dörfler // #pragma mark - module interface 1291c22d69bfSAxel Dörfler 1292c22d69bfSAxel Dörfler 1293c22d69bfSAxel Dörfler static status_t 1294c22d69bfSAxel Dörfler init_udp() 1295c22d69bfSAxel Dörfler { 1296c22d69bfSAxel Dörfler status_t status; 1297bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1298c22d69bfSAxel Dörfler 1299c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1300658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1301658a5506SHugo Santos return B_NO_MEMORY; 1302658a5506SHugo Santos 1303c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1304c22d69bfSAxel Dörfler if (status != B_OK) 1305d438fa4cSHugo Santos goto err1; 1306c22d69bfSAxel Dörfler 130761729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 130861729d93SAxel Dörfler IPPROTO_IP, 1309c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1310c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1311c22d69bfSAxel Dörfler NULL); 1312c22d69bfSAxel Dörfler if (status < B_OK) 1313658a5506SHugo Santos goto err1; 131461729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 131561729d93SAxel Dörfler IPPROTO_IP, 13168d1485faSAxel Dörfler "network/protocols/udp/v1", 13178d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13188d1485faSAxel Dörfler NULL); 13198d1485faSAxel Dörfler if (status < B_OK) 13208d1485faSAxel Dörfler goto err1; 13218d1485faSAxel Dörfler 132261729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 132361729d93SAxel Dörfler IPPROTO_UDP, 1324c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1325c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1326c22d69bfSAxel Dörfler NULL); 1327c22d69bfSAxel Dörfler if (status < B_OK) 1328658a5506SHugo Santos goto err1; 132961729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 133061729d93SAxel Dörfler IPPROTO_UDP, 13318d1485faSAxel Dörfler "network/protocols/udp/v1", 13328d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13338d1485faSAxel Dörfler NULL); 13348d1485faSAxel Dörfler if (status < B_OK) 13358d1485faSAxel Dörfler goto err1; 1336c22d69bfSAxel Dörfler 133761729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET, 133861729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 1339c22d69bfSAxel Dörfler if (status < B_OK) 1340658a5506SHugo Santos goto err1; 134161729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET6, 134261729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 13438d1485faSAxel Dörfler if (status < B_OK) 13448d1485faSAxel Dörfler goto err1; 1345c22d69bfSAxel Dörfler 1346cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints, 1347cf5d9f4bSHugo Santos "lists all open UDP endpoints"); 1348cf5d9f4bSHugo Santos 1349c22d69bfSAxel Dörfler return B_OK; 1350c22d69bfSAxel Dörfler 1351c22d69bfSAxel Dörfler err1: 13528d1485faSAxel Dörfler // TODO: shouldn't unregister the protocols here? 1353658a5506SHugo Santos delete sUdpEndpointManager; 1354c22d69bfSAxel Dörfler 1355bf48e753SHugo Santos TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status)); 1356c22d69bfSAxel Dörfler return status; 1357c22d69bfSAxel Dörfler } 1358c22d69bfSAxel Dörfler 1359c22d69bfSAxel Dörfler 1360c22d69bfSAxel Dörfler static status_t 1361c22d69bfSAxel Dörfler uninit_udp() 1362c22d69bfSAxel Dörfler { 1363bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1364cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints", 1365cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints); 1366c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1367c22d69bfSAxel Dörfler return B_OK; 1368c22d69bfSAxel Dörfler } 1369c22d69bfSAxel Dörfler 1370c22d69bfSAxel Dörfler 1371c22d69bfSAxel Dörfler static status_t 1372c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1373c22d69bfSAxel Dörfler { 1374c22d69bfSAxel Dörfler switch (op) { 1375c22d69bfSAxel Dörfler case B_MODULE_INIT: 1376c22d69bfSAxel Dörfler return init_udp(); 1377c22d69bfSAxel Dörfler 1378c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1379c22d69bfSAxel Dörfler return uninit_udp(); 1380c22d69bfSAxel Dörfler 1381c22d69bfSAxel Dörfler default: 1382c22d69bfSAxel Dörfler return B_ERROR; 1383c22d69bfSAxel Dörfler } 1384c22d69bfSAxel Dörfler } 1385c22d69bfSAxel Dörfler 1386c22d69bfSAxel Dörfler 1387c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1388c22d69bfSAxel Dörfler { 1389c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1390c22d69bfSAxel Dörfler 0, 1391c22d69bfSAxel Dörfler udp_std_ops 1392c22d69bfSAxel Dörfler }, 13936f58064fSAxel Dörfler NET_PROTOCOL_ATOMIC_MESSAGES, 13946f58064fSAxel Dörfler 1395c22d69bfSAxel Dörfler udp_init_protocol, 1396c22d69bfSAxel Dörfler udp_uninit_protocol, 1397c22d69bfSAxel Dörfler udp_open, 1398c22d69bfSAxel Dörfler udp_close, 1399c22d69bfSAxel Dörfler udp_free, 1400c22d69bfSAxel Dörfler udp_connect, 1401c22d69bfSAxel Dörfler udp_accept, 1402c22d69bfSAxel Dörfler udp_control, 140345b5203bSHugo Santos udp_getsockopt, 140445b5203bSHugo Santos udp_setsockopt, 1405c22d69bfSAxel Dörfler udp_bind, 1406c22d69bfSAxel Dörfler udp_unbind, 1407c22d69bfSAxel Dörfler udp_listen, 1408c22d69bfSAxel Dörfler udp_shutdown, 1409c22d69bfSAxel Dörfler udp_send_data, 1410c22d69bfSAxel Dörfler udp_send_routed_data, 1411c22d69bfSAxel Dörfler udp_send_avail, 1412c22d69bfSAxel Dörfler udp_read_data, 1413c22d69bfSAxel Dörfler udp_read_avail, 1414c22d69bfSAxel Dörfler udp_get_domain, 1415c22d69bfSAxel Dörfler udp_get_mtu, 1416c22d69bfSAxel Dörfler udp_receive_data, 14176a606180SHugo Santos udp_deliver_data, 14182bb43d82SAxel Dörfler udp_error_received, 1419c22d69bfSAxel Dörfler udp_error_reply, 14209871124eSAxel Dörfler NULL, // add_ancillary_data() 14219871124eSAxel Dörfler NULL, // process_ancillary_data() 142278888c44SAxel Dörfler udp_process_ancillary_data_no_container, 14239871124eSAxel Dörfler NULL, // send_data_no_buffer() 14249871124eSAxel Dörfler NULL // read_data_no_buffer() 1425c22d69bfSAxel Dörfler }; 1426c22d69bfSAxel Dörfler 1427658a5506SHugo Santos module_dependency module_dependencies[] = { 1428658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1429658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1430658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 14312bb43d82SAxel Dörfler {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule}, 1432658a5506SHugo Santos {} 1433658a5506SHugo Santos }; 1434658a5506SHugo Santos 1435c22d69bfSAxel Dörfler module_info *modules[] = { 1436c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1437c22d69bfSAxel Dörfler NULL 1438c22d69bfSAxel Dörfler }; 1439