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 104cb99c915SAxel Dörfler void Dump() const; 105cb99c915SAxel Dörfler 106c22d69bfSAxel Dörfler private: 107c72ab92dSHugo Santos UdpDomainSupport* fManager; 108c22d69bfSAxel Dörfler bool fActive; 10956f097ebSOliver Tappe // an active UdpEndpoint is part of the 110cb99c915SAxel Dörfler // endpoint hash (and it is bound and 111cb99c915SAxel Dörfler // optionally connected) 11240bbf860SHugo Santos 1135147963dSStephan Aßmus UdpEndpoint* fLink; 11440bbf860SHugo Santos }; 11540bbf860SHugo Santos 11640bbf860SHugo Santos 11740bbf860SHugo Santos class UdpDomainSupport; 11840bbf860SHugo Santos 11940bbf860SHugo Santos struct UdpHashDefinition { 12040bbf860SHugo Santos typedef net_address_module_info ParentType; 12140bbf860SHugo Santos typedef std::pair<const sockaddr *, const sockaddr *> KeyType; 12240bbf860SHugo Santos typedef UdpEndpoint ValueType; 12340bbf860SHugo Santos 12484052230SAxel Dörfler UdpHashDefinition(net_address_module_info *_module) 12584052230SAxel Dörfler : module(_module) {} 12684052230SAxel Dörfler UdpHashDefinition(const UdpHashDefinition& definition) 12784052230SAxel Dörfler : module(definition.module) {} 12840bbf860SHugo Santos 12940bbf860SHugo Santos size_t HashKey(const KeyType &key) const 13040bbf860SHugo Santos { 13140bbf860SHugo Santos return _Mix(module->hash_address_pair(key.first, key.second)); 13240bbf860SHugo Santos } 13340bbf860SHugo Santos 13440bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const 13540bbf860SHugo Santos { 13656f097ebSOliver Tappe return _Mix(endpoint->LocalAddress().HashPair( 13756f097ebSOliver Tappe *endpoint->PeerAddress())); 13840bbf860SHugo Santos } 13940bbf860SHugo Santos 14040bbf860SHugo Santos static size_t _Mix(size_t hash) 14140bbf860SHugo Santos { 14256f097ebSOliver Tappe // move the bits into the relevant range (as defined by kNumHashBuckets) 14340bbf860SHugo Santos return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11 14440bbf860SHugo Santos ^ (hash & 0xFFC00000UL) >> 22; 14540bbf860SHugo Santos } 14640bbf860SHugo Santos 14740bbf860SHugo Santos bool Compare(const KeyType &key, UdpEndpoint *endpoint) const 14840bbf860SHugo Santos { 14940bbf860SHugo Santos return endpoint->LocalAddress().EqualTo(key.first, true) 15040bbf860SHugo Santos && endpoint->PeerAddress().EqualTo(key.second, true); 15140bbf860SHugo Santos } 15240bbf860SHugo Santos 1535147963dSStephan Aßmus UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const 15440bbf860SHugo Santos { 15540bbf860SHugo Santos return endpoint->HashTableLink(); 15640bbf860SHugo Santos } 15740bbf860SHugo Santos 15840bbf860SHugo Santos net_address_module_info *module; 159c22d69bfSAxel Dörfler }; 160c22d69bfSAxel Dörfler 161c22d69bfSAxel Dörfler 162bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> { 163c22d69bfSAxel Dörfler public: 164bf48e753SHugo Santos UdpDomainSupport(net_domain *domain); 165727ad0b0SHugo Santos ~UdpDomainSupport(); 166c22d69bfSAxel Dörfler 167276aa463SIngo Weinhold status_t Init(); 168bf48e753SHugo Santos 169bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 170bf48e753SHugo Santos 171bf48e753SHugo Santos void Ref() { fEndpointCount++; } 172727ad0b0SHugo Santos bool Put() { fEndpointCount--; return fEndpointCount == 0; } 173bf48e753SHugo Santos 174bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer* buffer); 1752bb43d82SAxel Dörfler status_t DeliverError(status_t error, net_buffer* buffer); 176727ad0b0SHugo Santos 177727ad0b0SHugo Santos status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 178727ad0b0SHugo Santos status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 179727ad0b0SHugo Santos status_t UnbindEndpoint(UdpEndpoint *endpoint); 180727ad0b0SHugo Santos 181cf5d9f4bSHugo Santos void DumpEndpoints() const; 182bf48e753SHugo Santos 183c22d69bfSAxel Dörfler private: 184727ad0b0SHugo Santos status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 185727ad0b0SHugo Santos status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address); 186727ad0b0SHugo Santos status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address); 187727ad0b0SHugo Santos status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address); 188727ad0b0SHugo Santos 18940bbf860SHugo Santos UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress, 190bbbb5592SAxel Dörfler const sockaddr *peerAddress, uint32 index = 0); 191bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer); 192bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer); 193bf48e753SHugo Santos 194bf48e753SHugo Santos uint16 _GetNextEphemeral(); 195727ad0b0SHugo Santos UdpEndpoint *_EndpointWithPort(uint16 port) const; 196bf48e753SHugo Santos 197bf48e753SHugo Santos net_address_module_info *AddressModule() const 198727ad0b0SHugo Santos { return fDomain->address_module; } 199bf48e753SHugo Santos 2005147963dSStephan Aßmus typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable; 20140bbf860SHugo Santos 2022b07b8e0SIngo Weinhold mutex fLock; 203bf48e753SHugo Santos net_domain *fDomain; 204bf48e753SHugo Santos uint16 fLastUsedEphemeral; 20540bbf860SHugo Santos EndpointTable fActiveEndpoints; 206bf48e753SHugo Santos uint32 fEndpointCount; 207bf48e753SHugo Santos 208bf48e753SHugo Santos static const uint16 kFirst = 49152; 209bf48e753SHugo Santos static const uint16 kLast = 65535; 210bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800; 211bf48e753SHugo Santos // if you change this, adjust the shifting in 212bf48e753SHugo Santos // Hash() accordingly! 213bf48e753SHugo Santos }; 214bf48e753SHugo Santos 215bf48e753SHugo Santos 216bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList; 217bf48e753SHugo Santos 218bf48e753SHugo Santos 219bf48e753SHugo Santos class UdpEndpointManager { 220c22d69bfSAxel Dörfler public: 221c22d69bfSAxel Dörfler UdpEndpointManager(); 222c22d69bfSAxel Dörfler ~UdpEndpointManager(); 223c22d69bfSAxel Dörfler 2242bb43d82SAxel Dörfler status_t InitCheck() const; 2252bb43d82SAxel Dörfler 226c22d69bfSAxel Dörfler status_t ReceiveData(net_buffer* buffer); 2272bb43d82SAxel Dörfler status_t ReceiveError(status_t error, 2282bb43d82SAxel Dörfler net_buffer* buffer); 2296a606180SHugo Santos status_t Deframe(net_buffer* buffer); 230c22d69bfSAxel Dörfler 231bf48e753SHugo Santos UdpDomainSupport* OpenEndpoint(UdpEndpoint* endpoint); 232bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport* domain); 233c22d69bfSAxel Dörfler 234cf5d9f4bSHugo Santos static int DumpEndpoints(int argc, char *argv[]); 235cf5d9f4bSHugo Santos 236c22d69bfSAxel Dörfler private: 2379d433190SAxel Dörfler inline net_domain* _GetDomain(net_buffer* buffer); 2389d433190SAxel Dörfler UdpDomainSupport* _GetDomainSupport(net_domain* domain, 2399d433190SAxel Dörfler bool create); 2409d433190SAxel Dörfler UdpDomainSupport* _GetDomainSupport(net_buffer* buffer); 241bf48e753SHugo Santos 2422b07b8e0SIngo Weinhold mutex fLock; 243c22d69bfSAxel Dörfler status_t fStatus; 244bf48e753SHugo Santos UdpDomainList fDomains; 245c22d69bfSAxel Dörfler }; 246c22d69bfSAxel Dörfler 247c22d69bfSAxel Dörfler 248c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager; 249c22d69bfSAxel Dörfler 250c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule; 251658a5506SHugo Santos net_datalink_module_info *gDatalinkModule; 252658a5506SHugo Santos net_stack_module_info *gStackModule; 2532bb43d82SAxel Dörfler net_socket_module_info *gSocketModule; 254c22d69bfSAxel Dörfler 255c22d69bfSAxel Dörfler 256c22d69bfSAxel Dörfler // #pragma mark - 257c22d69bfSAxel Dörfler 258c22d69bfSAxel Dörfler 259bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain) 260c22d69bfSAxel Dörfler : 261bf48e753SHugo Santos fDomain(domain), 262276aa463SIngo Weinhold fActiveEndpoints(domain->address_module), 263bf48e753SHugo Santos fEndpointCount(0) 264c22d69bfSAxel Dörfler { 2652b07b8e0SIngo Weinhold mutex_init(&fLock, "udp domain"); 266727ad0b0SHugo Santos 267727ad0b0SHugo Santos fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst); 268727ad0b0SHugo Santos } 269727ad0b0SHugo Santos 270727ad0b0SHugo Santos 271727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport() 272727ad0b0SHugo Santos { 2732b07b8e0SIngo Weinhold mutex_destroy(&fLock); 274bf48e753SHugo Santos } 275bf48e753SHugo Santos 276bf48e753SHugo Santos 277bf48e753SHugo Santos status_t 278276aa463SIngo Weinhold UdpDomainSupport::Init() 279bf48e753SHugo Santos { 280276aa463SIngo Weinhold return fActiveEndpoints.Init(kNumHashBuckets); 281bf48e753SHugo Santos } 282bf48e753SHugo Santos 283bf48e753SHugo Santos 284bf48e753SHugo Santos status_t 285bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer) 286bf48e753SHugo Santos { 2872bb43d82SAxel Dörfler // NOTE: multicast is delivered directly to the endpoint 2882b07b8e0SIngo Weinhold MutexLocker _(fLock); 289727ad0b0SHugo Santos 2902bb43d82SAxel Dörfler if ((buffer->flags & MSG_BCAST) != 0) 291bf48e753SHugo Santos return _DemuxBroadcast(buffer); 2922bb43d82SAxel Dörfler if ((buffer->flags & MSG_MCAST) != 0) 293727ad0b0SHugo Santos return B_ERROR; 294bf48e753SHugo Santos 295bf48e753SHugo Santos return _DemuxUnicast(buffer); 296bf48e753SHugo Santos } 297bf48e753SHugo Santos 298bf48e753SHugo Santos 299bf48e753SHugo Santos status_t 3002bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer) 3012bb43d82SAxel Dörfler { 3022bb43d82SAxel Dörfler if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0) 3032bb43d82SAxel Dörfler return B_ERROR; 3042bb43d82SAxel Dörfler 3052bb43d82SAxel Dörfler MutexLocker _(fLock); 3062bb43d82SAxel Dörfler 3072e1729d0SAxel Dörfler // Forward the error to the socket 3082e1729d0SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source, 3092e1729d0SAxel Dörfler buffer->destination); 3102e1729d0SAxel Dörfler if (endpoint != NULL) { 3112bb43d82SAxel Dörfler gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error); 3122e1729d0SAxel Dörfler endpoint->NotifyOne(); 3132e1729d0SAxel Dörfler } 3142bb43d82SAxel Dörfler 3152bb43d82SAxel Dörfler gBufferModule->free(buffer); 3162bb43d82SAxel Dörfler return B_OK; 3172bb43d82SAxel Dörfler } 3182bb43d82SAxel Dörfler 3192bb43d82SAxel Dörfler 3202bb43d82SAxel Dörfler status_t 321727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint, 322727ad0b0SHugo Santos const sockaddr *address) 323727ad0b0SHugo Santos { 32456f097ebSOliver Tappe if (!AddressModule()->is_same_family(address)) 32556f097ebSOliver Tappe return EAFNOSUPPORT; 32656f097ebSOliver Tappe 3272b07b8e0SIngo Weinhold MutexLocker _(fLock); 328727ad0b0SHugo Santos 329727ad0b0SHugo Santos if (endpoint->IsActive()) 330727ad0b0SHugo Santos return EINVAL; 331727ad0b0SHugo Santos 332727ad0b0SHugo Santos return _BindEndpoint(endpoint, address); 333727ad0b0SHugo Santos } 334727ad0b0SHugo Santos 335727ad0b0SHugo Santos 336727ad0b0SHugo Santos status_t 337727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint, 338727ad0b0SHugo Santos const sockaddr *address) 339727ad0b0SHugo Santos { 3402b07b8e0SIngo Weinhold MutexLocker _(fLock); 341727ad0b0SHugo Santos 342727ad0b0SHugo Santos if (endpoint->IsActive()) { 343727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 344727ad0b0SHugo Santos endpoint->SetActive(false); 345727ad0b0SHugo Santos } 346727ad0b0SHugo Santos 347727ad0b0SHugo Santos if (address->sa_family == AF_UNSPEC) { 348727ad0b0SHugo Santos // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect", 349727ad0b0SHugo Santos // so we reset the peer address: 350727ad0b0SHugo Santos endpoint->PeerAddress().SetToEmpty(); 351727ad0b0SHugo Santos } else { 35256f097ebSOliver Tappe if (!AddressModule()->is_same_family(address)) 35356f097ebSOliver Tappe return EAFNOSUPPORT; 35456f097ebSOliver Tappe 35556f097ebSOliver Tappe // consider destination address INADDR_ANY as INADDR_LOOPBACK 35656f097ebSOliver Tappe sockaddr_storage _address; 35756f097ebSOliver Tappe if (AddressModule()->is_empty_address(address, false)) { 35856f097ebSOliver Tappe AddressModule()->get_loopback_address((sockaddr *)&_address); 35956f097ebSOliver Tappe // for IPv4 and IPv6 the port is at the same offset 36056f097ebSOliver Tappe ((sockaddr_in&)_address).sin_port 36156f097ebSOliver Tappe = ((sockaddr_in *)address)->sin_port; 36256f097ebSOliver Tappe address = (sockaddr *)&_address; 36356f097ebSOliver Tappe } 36456f097ebSOliver Tappe 365727ad0b0SHugo Santos status_t status = endpoint->PeerAddress().SetTo(address); 366727ad0b0SHugo Santos if (status < B_OK) 367727ad0b0SHugo Santos return status; 3684e45de0eSOliver Tappe struct net_route *routeToDestination 3694e45de0eSOliver Tappe = gDatalinkModule->get_route(fDomain, address); 3704e45de0eSOliver Tappe if (routeToDestination) { 3714e45de0eSOliver Tappe status = endpoint->LocalAddress().SetTo( 37261729d93SAxel Dörfler routeToDestination->interface_address->local); 3734e45de0eSOliver Tappe gDatalinkModule->put_route(fDomain, routeToDestination); 3744e45de0eSOliver Tappe if (status < B_OK) 3754e45de0eSOliver Tappe return status; 3764e45de0eSOliver Tappe } 377727ad0b0SHugo Santos } 378727ad0b0SHugo Santos 379727ad0b0SHugo Santos // we need to activate no matter whether or not we have just disconnected, 380727ad0b0SHugo Santos // as calling connect() always triggers an implicit bind(): 381727ad0b0SHugo Santos return _BindEndpoint(endpoint, *endpoint->LocalAddress()); 382727ad0b0SHugo Santos } 383727ad0b0SHugo Santos 384727ad0b0SHugo Santos 385727ad0b0SHugo Santos status_t 386727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint) 387727ad0b0SHugo Santos { 3882b07b8e0SIngo Weinhold MutexLocker _(fLock); 389727ad0b0SHugo Santos 390727ad0b0SHugo Santos if (endpoint->IsActive()) 391727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 392727ad0b0SHugo Santos 393727ad0b0SHugo Santos endpoint->SetActive(false); 394727ad0b0SHugo Santos 395727ad0b0SHugo Santos return B_OK; 396727ad0b0SHugo Santos } 397727ad0b0SHugo Santos 398727ad0b0SHugo Santos 399cf5d9f4bSHugo Santos void 400cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const 401cf5d9f4bSHugo Santos { 402cf5d9f4bSHugo Santos kprintf("-------- UDP Domain %p ---------\n", this); 403cf5d9f4bSHugo Santos kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q"); 404cf5d9f4bSHugo Santos 405cf5d9f4bSHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 406cf5d9f4bSHugo Santos 407cb99c915SAxel Dörfler while (UdpEndpoint* endpoint = it.Next()) { 408cb99c915SAxel Dörfler endpoint->Dump(); 409cf5d9f4bSHugo Santos } 410cf5d9f4bSHugo Santos } 411cf5d9f4bSHugo Santos 412cf5d9f4bSHugo Santos 413727ad0b0SHugo Santos status_t 414727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint, 415727ad0b0SHugo Santos const sockaddr *address) 416727ad0b0SHugo Santos { 417727ad0b0SHugo Santos if (AddressModule()->get_port(address) == 0) 418727ad0b0SHugo Santos return _BindToEphemeral(endpoint, address); 419727ad0b0SHugo Santos 420727ad0b0SHugo Santos return _Bind(endpoint, address); 421727ad0b0SHugo Santos } 422727ad0b0SHugo Santos 423727ad0b0SHugo Santos 424727ad0b0SHugo Santos status_t 425727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address) 426727ad0b0SHugo Santos { 427727ad0b0SHugo Santos int socketOptions = endpoint->Socket()->options; 42840bbf860SHugo Santos 42940bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 430bf48e753SHugo Santos 431bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind 432bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]): 433727ad0b0SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain, 434727ad0b0SHugo Santos address, true).Data()); 435727ad0b0SHugo Santos 43640bbf860SHugo Santos while (it.HasNext()) { 43740bbf860SHugo Santos UdpEndpoint *otherEndpoint = it.Next(); 43825a2744fSHugo Santos 439bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint, 4405084c839SHugo Santos ntohs(otherEndpoint->LocalAddress().Port())); 44125a2744fSHugo Santos 44225a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualPorts(address)) { 443bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required: 44456f097ebSOliver Tappe if ((otherEndpoint->Socket()->options 44556f097ebSOliver Tappe & (SO_REUSEADDR | SO_REUSEPORT)) == 0 446d0eaec30SMichael Lotz || (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0) 447727ad0b0SHugo Santos return EADDRINUSE; 44825a2744fSHugo Santos 449bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required: 45025a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualTo(address, false) 451d0eaec30SMichael Lotz && ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0 452d0eaec30SMichael Lotz || (socketOptions & SO_REUSEPORT) == 0)) 453727ad0b0SHugo Santos return EADDRINUSE; 454bf48e753SHugo Santos } 455bf48e753SHugo Santos } 456bf48e753SHugo Santos 457727ad0b0SHugo Santos return _FinishBind(endpoint, address); 458bf48e753SHugo Santos } 459bf48e753SHugo Santos 460bf48e753SHugo Santos 461bf48e753SHugo Santos status_t 462727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint, 463727ad0b0SHugo Santos const sockaddr *address) 464727ad0b0SHugo Santos { 465727ad0b0SHugo Santos SocketAddressStorage newAddress(AddressModule()); 466727ad0b0SHugo Santos status_t status = newAddress.SetTo(address); 467727ad0b0SHugo Santos if (status < B_OK) 468727ad0b0SHugo Santos return status; 469727ad0b0SHugo Santos 470727ad0b0SHugo Santos uint16 allocedPort = _GetNextEphemeral(); 471727ad0b0SHugo Santos if (allocedPort == 0) 472727ad0b0SHugo Santos return ENOBUFS; 473727ad0b0SHugo Santos 4749e051839SOliver Tappe newAddress.SetPort(htons(allocedPort)); 475727ad0b0SHugo Santos 476727ad0b0SHugo Santos return _FinishBind(endpoint, *newAddress); 477727ad0b0SHugo Santos } 478727ad0b0SHugo Santos 479727ad0b0SHugo Santos 480727ad0b0SHugo Santos status_t 481727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address) 482727ad0b0SHugo Santos { 483727ad0b0SHugo Santos status_t status = endpoint->next->module->bind(endpoint->next, address); 484727ad0b0SHugo Santos if (status < B_OK) 485727ad0b0SHugo Santos return status; 48640bbf860SHugo Santos 48740bbf860SHugo Santos fActiveEndpoints.Insert(endpoint); 488727ad0b0SHugo Santos endpoint->SetActive(true); 489727ad0b0SHugo Santos 49040bbf860SHugo Santos return B_OK; 491bf48e753SHugo Santos } 492bf48e753SHugo Santos 493bf48e753SHugo Santos 494c22d69bfSAxel Dörfler UdpEndpoint * 49540bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress, 496bbbb5592SAxel Dörfler const sockaddr *peerAddress, uint32 index) 497c22d69bfSAxel Dörfler { 4982e1729d0SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock); 4992e1729d0SAxel Dörfler 5009e051839SOliver Tappe TRACE_DOMAIN("finding Endpoint for %s <- %s", 501bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(), 502bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data()); 503c3e054c8SHugo Santos 504bbbb5592SAxel Dörfler UdpEndpoint* endpoint = fActiveEndpoints.Lookup( 505bbbb5592SAxel Dörfler std::make_pair(ourAddress, peerAddress)); 506bbbb5592SAxel Dörfler 507bbbb5592SAxel Dörfler // Make sure the bound_to_device constraint is fulfilled 508*da0d7409SAxel Dörfler while (endpoint != NULL && endpoint->socket->bound_to_device != 0 509*da0d7409SAxel Dörfler && index != 0 && endpoint->socket->bound_to_device != index) { 510bbbb5592SAxel Dörfler endpoint = endpoint->HashTableLink(); 511bbbb5592SAxel Dörfler if (endpoint != NULL 512bbbb5592SAxel Dörfler && (!endpoint->LocalAddress().EqualTo(ourAddress, true) 513bbbb5592SAxel Dörfler || !endpoint->PeerAddress().EqualTo(peerAddress, true))) 514bbbb5592SAxel Dörfler return NULL; 515bbbb5592SAxel Dörfler } 516bbbb5592SAxel Dörfler 517bbbb5592SAxel Dörfler return endpoint; 518c22d69bfSAxel Dörfler } 519c22d69bfSAxel Dörfler 520c22d69bfSAxel Dörfler 521c22d69bfSAxel Dörfler status_t 522bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer) 523c22d69bfSAxel Dörfler { 52479a0d252SHugo Santos sockaddr* peerAddr = buffer->source; 52579a0d252SHugo Santos sockaddr* broadcastAddr = buffer->destination; 5269d433190SAxel Dörfler uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 5279d433190SAxel Dörfler 528c22d69bfSAxel Dörfler sockaddr* mask = NULL; 52961729d93SAxel Dörfler if (buffer->interface_address != NULL) 53061729d93SAxel Dörfler mask = (sockaddr*)buffer->interface_address->mask; 531c22d69bfSAxel Dörfler 5329d433190SAxel Dörfler TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask); 533c22d69bfSAxel Dörfler 5349d433190SAxel Dörfler EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator(); 535c22d69bfSAxel Dörfler 5369d433190SAxel Dörfler while (UdpEndpoint* endpoint = iterator.Next()) { 53725a2744fSHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", 53825a2744fSHugo Santos AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); 53925a2744fSHugo Santos 540bbbb5592SAxel Dörfler if (endpoint->socket->bound_to_device != 0 541bbbb5592SAxel Dörfler && buffer->index != endpoint->socket->bound_to_device) 542bbbb5592SAxel Dörfler continue; 543bbbb5592SAxel Dörfler 5445084c839SHugo Santos if (endpoint->LocalAddress().Port() != incomingPort) { 545c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint... 546c22d69bfSAxel Dörfler continue; 547c22d69bfSAxel Dörfler } 548c22d69bfSAxel Dörfler 54925a2744fSHugo Santos if (!endpoint->PeerAddress().IsEmpty(true)) { 550c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if 551c22d69bfSAxel Dörfler // this datagram is from there: 55225a2744fSHugo Santos if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) { 553c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to 554c22d69bfSAxel Dörfler // this endpoint... 555c22d69bfSAxel Dörfler continue; 556c22d69bfSAxel Dörfler } 557c22d69bfSAxel Dörfler } 558c22d69bfSAxel Dörfler 55925a2744fSHugo Santos if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) 5609d433190SAxel Dörfler || mask == NULL || endpoint->LocalAddress().IsEmpty(false)) { 561c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint: 562c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 563c22d69bfSAxel Dörfler } 564c22d69bfSAxel Dörfler } 56540bbf860SHugo Santos 566c22d69bfSAxel Dörfler return B_OK; 567c22d69bfSAxel Dörfler } 568c22d69bfSAxel Dörfler 569c22d69bfSAxel Dörfler 570c22d69bfSAxel Dörfler status_t 571bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer) 572c22d69bfSAxel Dörfler { 573bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer); 574c22d69bfSAxel Dörfler 5752e1729d0SAxel Dörfler const sockaddr* localAddress = buffer->destination; 5762e1729d0SAxel Dörfler const sockaddr* peerAddress = buffer->source; 5772e1729d0SAxel Dörfler 5782e1729d0SAxel Dörfler // look for full (most special) match: 579bbbb5592SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress, 580bbbb5592SAxel Dörfler buffer->index); 5812e1729d0SAxel Dörfler if (endpoint == NULL) { 5822e1729d0SAxel Dörfler // look for endpoint matching local address & port: 583bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index); 5842e1729d0SAxel Dörfler if (endpoint == NULL) { 5852e1729d0SAxel Dörfler // look for endpoint matching peer address & port and local port: 5862e1729d0SAxel Dörfler SocketAddressStorage local(AddressModule()); 5872e1729d0SAxel Dörfler local.SetToEmpty(); 5882e1729d0SAxel Dörfler local.SetPort(AddressModule()->get_port(localAddress)); 589bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index); 5902e1729d0SAxel Dörfler if (endpoint == NULL) { 5912e1729d0SAxel Dörfler // last chance: look for endpoint matching local port only: 592bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(*local, NULL, buffer->index); 5932e1729d0SAxel Dörfler } 5942e1729d0SAxel Dörfler } 5952e1729d0SAxel Dörfler } 5962e1729d0SAxel Dörfler 5972bb43d82SAxel Dörfler if (endpoint == NULL) { 5982bb43d82SAxel Dörfler TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer); 599c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND; 6009e051839SOliver Tappe } 601c22d69bfSAxel Dörfler 602c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 603c22d69bfSAxel Dörfler return B_OK; 604c22d69bfSAxel Dörfler } 605c22d69bfSAxel Dörfler 606c22d69bfSAxel Dörfler 607bf48e753SHugo Santos uint16 608bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral() 609c22d69bfSAxel Dörfler { 61040bbf860SHugo Santos uint16 stop, curr; 611bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) { 612bf48e753SHugo Santos stop = fLastUsedEphemeral; 613bf48e753SHugo Santos curr = fLastUsedEphemeral + 1; 614bf48e753SHugo Santos } else { 615bf48e753SHugo Santos stop = kLast; 616bf48e753SHugo Santos curr = kFirst; 617bf48e753SHugo Santos } 618c22d69bfSAxel Dörfler 619727ad0b0SHugo Santos TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu", 620727ad0b0SHugo Santos fLastUsedEphemeral, curr, stop); 62140bbf860SHugo Santos 6229e051839SOliver Tappe // TODO: a free list could be used to avoid the impact of these two 6239e051839SOliver Tappe // nested loops most of the time... let's see how bad this really is 624727ad0b0SHugo Santos for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) { 625bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr); 62640bbf860SHugo Santos 627727ad0b0SHugo Santos if (_EndpointWithPort(htons(curr)) == NULL) { 628bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr); 629bf48e753SHugo Santos fLastUsedEphemeral = curr; 630bf48e753SHugo Santos return curr; 631bf48e753SHugo Santos } 632727ad0b0SHugo Santos } 633727ad0b0SHugo Santos 634727ad0b0SHugo Santos return 0; 635727ad0b0SHugo Santos } 636727ad0b0SHugo Santos 637727ad0b0SHugo Santos 638727ad0b0SHugo Santos UdpEndpoint * 639727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const 640727ad0b0SHugo Santos { 641727ad0b0SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 642727ad0b0SHugo Santos 643727ad0b0SHugo Santos while (it.HasNext()) { 644727ad0b0SHugo Santos UdpEndpoint *endpoint = it.Next(); 645727ad0b0SHugo Santos if (endpoint->LocalAddress().Port() == port) 646727ad0b0SHugo Santos return endpoint; 647727ad0b0SHugo Santos } 648727ad0b0SHugo Santos 649727ad0b0SHugo Santos return NULL; 650727ad0b0SHugo Santos } 651c22d69bfSAxel Dörfler 652bf48e753SHugo Santos 653bf48e753SHugo Santos // #pragma mark - 654bf48e753SHugo Santos 655bf48e753SHugo Santos 656bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager() 657bf48e753SHugo Santos { 6582b07b8e0SIngo Weinhold mutex_init(&fLock, "UDP endpoints"); 6592b07b8e0SIngo Weinhold fStatus = B_OK; 660bf48e753SHugo Santos } 661bf48e753SHugo Santos 662bf48e753SHugo Santos 663bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 664bf48e753SHugo Santos { 6652b07b8e0SIngo Weinhold mutex_destroy(&fLock); 666bf48e753SHugo Santos } 667bf48e753SHugo Santos 668bf48e753SHugo Santos 669bf48e753SHugo Santos status_t 670bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 671bf48e753SHugo Santos { 672bf48e753SHugo Santos return fStatus; 673bf48e753SHugo Santos } 674bf48e753SHugo Santos 675bf48e753SHugo Santos 676cf5d9f4bSHugo Santos int 677cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[]) 678cf5d9f4bSHugo Santos { 679cf5d9f4bSHugo Santos UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator(); 680cf5d9f4bSHugo Santos 681cf5d9f4bSHugo Santos while (it.HasNext()) 682cf5d9f4bSHugo Santos it.Next()->DumpEndpoints(); 683cf5d9f4bSHugo Santos 684cf5d9f4bSHugo Santos return 0; 685cf5d9f4bSHugo Santos } 686cf5d9f4bSHugo Santos 687cf5d9f4bSHugo Santos 688bf48e753SHugo Santos // #pragma mark - inbound 689bf48e753SHugo Santos 690bf48e753SHugo Santos 691bf48e753SHugo Santos status_t 692c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer) 693c22d69bfSAxel Dörfler { 6942bb43d82SAxel Dörfler TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 6952bb43d82SAxel Dörfler 6969d433190SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomainSupport(buffer); 6972bb43d82SAxel Dörfler if (domainSupport == NULL) { 6982bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as 6992bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets. 7002bb43d82SAxel Dörfler return B_ERROR; 7012bb43d82SAxel Dörfler } 7022bb43d82SAxel Dörfler 7036a606180SHugo Santos status_t status = Deframe(buffer); 7042bb43d82SAxel Dörfler if (status != B_OK) 7056a606180SHugo Santos return status; 7066a606180SHugo Santos 7072bb43d82SAxel Dörfler status = domainSupport->DemuxIncomingBuffer(buffer); 7082bb43d82SAxel Dörfler if (status != B_OK) { 7092bb43d82SAxel Dörfler TRACE_EPM(" ReceiveData(): no endpoint."); 7102bb43d82SAxel Dörfler // Send port unreachable error 7112bb43d82SAxel Dörfler domainSupport->Domain()->module->error_reply(NULL, buffer, 7122b415445SAxel Dörfler B_NET_ERROR_UNREACH_PORT, NULL); 7132bb43d82SAxel Dörfler return B_ERROR; 7142bb43d82SAxel Dörfler } 7152bb43d82SAxel Dörfler 7162bb43d82SAxel Dörfler gBufferModule->free(buffer); 7172bb43d82SAxel Dörfler return B_OK; 7182bb43d82SAxel Dörfler } 7192bb43d82SAxel Dörfler 7202bb43d82SAxel Dörfler 7212bb43d82SAxel Dörfler status_t 7222bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) 7232bb43d82SAxel Dörfler { 7242bb43d82SAxel Dörfler TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])", 7252bb43d82SAxel Dörfler error, buffer, buffer->size); 7262bb43d82SAxel Dörfler 7272bb43d82SAxel Dörfler // We only really need the port information 7282bb43d82SAxel Dörfler if (buffer->size < 4) 7292bb43d82SAxel Dörfler return B_BAD_VALUE; 7302bb43d82SAxel Dörfler 7319d433190SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomainSupport(buffer); 7322bb43d82SAxel Dörfler if (domainSupport == NULL) { 7332bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as 7342bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets. 7352bb43d82SAxel Dörfler return B_ERROR; 7362bb43d82SAxel Dörfler } 7372bb43d82SAxel Dörfler 7382bb43d82SAxel Dörfler // Deframe the buffer manually, as we usually only get 8 bytes from the 7392bb43d82SAxel Dörfler // original packet 7402bb43d82SAxel Dörfler udp_header header; 7412bb43d82SAxel Dörfler if (gBufferModule->read(buffer, 0, &header, 7422bb43d82SAxel Dörfler std::min(buffer->size, sizeof(udp_header))) != B_OK) 7432bb43d82SAxel Dörfler return B_BAD_VALUE; 744bf48e753SHugo Santos 74561729d93SAxel Dörfler net_domain* domain = buffer->interface_address->domain; 7462bb43d82SAxel Dörfler net_address_module_info* addressModule = domain->address_module; 7476a606180SHugo Santos 7482bb43d82SAxel Dörfler SocketAddress source(addressModule, buffer->source); 7492bb43d82SAxel Dörfler SocketAddress destination(addressModule, buffer->destination); 7506a606180SHugo Santos 7512bb43d82SAxel Dörfler source.SetPort(header.source_port); 7522bb43d82SAxel Dörfler destination.SetPort(header.destination_port); 753727ad0b0SHugo Santos 7543f2a18bdSAxel Dörfler return domainSupport->DeliverError(error, buffer); 7556a606180SHugo Santos } 7566a606180SHugo Santos 7576a606180SHugo Santos 7586a606180SHugo Santos status_t 7596a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer* buffer) 7606a606180SHugo Santos { 7616a606180SHugo Santos TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); 7626a606180SHugo Santos 76387001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer); 7649d433190SAxel Dörfler if (bufferHeader.Status() != B_OK) 765c22d69bfSAxel Dörfler return bufferHeader.Status(); 766c22d69bfSAxel Dörfler 767c22d69bfSAxel Dörfler udp_header& header = bufferHeader.Data(); 768c22d69bfSAxel Dörfler 7699d433190SAxel Dörfler net_domain* domain = _GetDomain(buffer); 7709d433190SAxel Dörfler if (domain == NULL) { 7716a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " 77261729d93SAxel Dörfler "specified (interface address %p).", buffer->interface_address); 773c22d69bfSAxel Dörfler return B_BAD_VALUE; 774c22d69bfSAxel Dörfler } 775bf48e753SHugo Santos net_address_module_info* addressModule = domain->address_module; 776bf48e753SHugo Santos 77779a0d252SHugo Santos SocketAddress source(addressModule, buffer->source); 77879a0d252SHugo Santos SocketAddress destination(addressModule, buffer->destination); 779bf48e753SHugo Santos 7804e8a1b33SHugo Santos source.SetPort(header.source_port); 7814e8a1b33SHugo Santos destination.SetPort(header.destination_port); 7824e8a1b33SHugo Santos 7834e8a1b33SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(), 7844e8a1b33SHugo Santos destination.AsString(true).Data()); 785c22d69bfSAxel Dörfler 786c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length); 787c22d69bfSAxel Dörfler if (udpLength > buffer->size) { 7886a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", 789bf48e753SHugo Santos udpLength); 790c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES; 791c22d69bfSAxel Dörfler } 792bf48e753SHugo Santos 793bf48e753SHugo Santos if (buffer->size > udpLength) 794c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength); 795c22d69bfSAxel Dörfler 796c22d69bfSAxel Dörfler if (header.udp_checksum != 0) { 797c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"): 798d5b5a2c2SHugo Santos uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule, 799d5b5a2c2SHugo Santos buffer, IPPROTO_UDP); 800c22d69bfSAxel Dörfler if (sum != 0) { 8016a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); 802c22d69bfSAxel Dörfler return B_BAD_VALUE; 803c22d69bfSAxel Dörfler } 804c22d69bfSAxel Dörfler } 805c22d69bfSAxel Dörfler 806c22d69bfSAxel Dörfler bufferHeader.Remove(); 807c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on 808c22d69bfSAxel Dörfler 8096a606180SHugo Santos return B_OK; 810c22d69bfSAxel Dörfler } 811c22d69bfSAxel Dörfler 812c22d69bfSAxel Dörfler 813bf48e753SHugo Santos UdpDomainSupport * 814c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) 815c22d69bfSAxel Dörfler { 8162b07b8e0SIngo Weinhold MutexLocker _(fLock); 817bf48e753SHugo Santos 8189d433190SAxel Dörfler UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true); 819bf48e753SHugo Santos if (domain) 820bf48e753SHugo Santos domain->Ref(); 821bf48e753SHugo Santos return domain; 822bf48e753SHugo Santos } 823bf48e753SHugo Santos 824bf48e753SHugo Santos 825bf48e753SHugo Santos status_t 826bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) 827bf48e753SHugo Santos { 8282b07b8e0SIngo Weinhold MutexLocker _(fLock); 829bf48e753SHugo Santos 830727ad0b0SHugo Santos if (domain->Put()) { 831bf48e753SHugo Santos fDomains.Remove(domain); 832bf48e753SHugo Santos delete domain; 833bf48e753SHugo Santos } 834bf48e753SHugo Santos 835bf48e753SHugo Santos return B_OK; 836bf48e753SHugo Santos } 837bf48e753SHugo Santos 838bf48e753SHugo Santos 839bf48e753SHugo Santos // #pragma mark - 840bf48e753SHugo Santos 841bf48e753SHugo Santos 8429d433190SAxel Dörfler inline net_domain* 8439d433190SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer) 844bf48e753SHugo Santos { 8459d433190SAxel Dörfler if (buffer->interface_address != NULL) 8469d433190SAxel Dörfler return buffer->interface_address->domain; 8479d433190SAxel Dörfler 8489d433190SAxel Dörfler return gStackModule->get_domain(buffer->destination->sa_family); 8499d433190SAxel Dörfler } 8509d433190SAxel Dörfler 8519d433190SAxel Dörfler 8529d433190SAxel Dörfler UdpDomainSupport* 8539d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create) 8549d433190SAxel Dörfler { 8559d433190SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock); 8569d433190SAxel Dörfler 8579d433190SAxel Dörfler if (domain == NULL) 8589d433190SAxel Dörfler return NULL; 859bf48e753SHugo Santos 860bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain 861bf48e753SHugo Santos // receiver handlers that forward the requests to the 862bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while 863bf48e753SHugo Santos // being constructed UdpDomainSupport could call 864bf48e753SHugo Santos // register_domain_receiving_protocol() with the right 865bf48e753SHugo Santos // family. 8669d433190SAxel Dörfler UdpDomainList::Iterator iterator = fDomains.GetIterator(); 8679d433190SAxel Dörfler while (UdpDomainSupport* domainSupport = iterator.Next()) { 868bf48e753SHugo Santos if (domainSupport->Domain() == domain) 869bf48e753SHugo Santos return domainSupport; 870bf48e753SHugo Santos } 871bf48e753SHugo Santos 872bf48e753SHugo Santos if (!create) 873bf48e753SHugo Santos return NULL; 874bf48e753SHugo Santos 8759d433190SAxel Dörfler UdpDomainSupport* domainSupport 8769d433190SAxel Dörfler = new (std::nothrow) UdpDomainSupport(domain); 877276aa463SIngo Weinhold if (domainSupport == NULL || domainSupport->Init() < B_OK) { 878bf48e753SHugo Santos delete domainSupport; 879bf48e753SHugo Santos return NULL; 880bf48e753SHugo Santos } 881bf48e753SHugo Santos 882bf48e753SHugo Santos fDomains.Add(domainSupport); 883bf48e753SHugo Santos return domainSupport; 884c22d69bfSAxel Dörfler } 885c22d69bfSAxel Dörfler 886c22d69bfSAxel Dörfler 8879d433190SAxel Dörfler /*! Retrieves the UdpDomainSupport object responsible for this buffer, if the 8889d433190SAxel Dörfler domain can be determined. This is only successful if the domain support is 8899d433190SAxel Dörfler already existing, ie. there must already be an endpoint for the domain. 8909d433190SAxel Dörfler */ 8912bb43d82SAxel Dörfler UdpDomainSupport* 8929d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer) 8932bb43d82SAxel Dörfler { 8942bb43d82SAxel Dörfler MutexLocker _(fLock); 8959d433190SAxel Dörfler 8969d433190SAxel Dörfler return _GetDomainSupport(_GetDomain(buffer), false); 8972bb43d82SAxel Dörfler // TODO: we don't want to hold to the manager's lock during the 8982bb43d82SAxel Dörfler // whole RX path, we may not hold an endpoint's lock with the 8992bb43d82SAxel Dörfler // manager lock held. 9002bb43d82SAxel Dörfler // But we should increase the domain's refcount here. 9012bb43d82SAxel Dörfler } 9022bb43d82SAxel Dörfler 9032bb43d82SAxel Dörfler 904c22d69bfSAxel Dörfler // #pragma mark - 905c22d69bfSAxel Dörfler 906c22d69bfSAxel Dörfler 907c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 908cb99c915SAxel Dörfler : 909cb99c915SAxel Dörfler DatagramSocket<>("udp endpoint", socket), 910cb99c915SAxel Dörfler fActive(false) 911cb99c915SAxel Dörfler { 912cb99c915SAxel Dörfler } 913bf48e753SHugo Santos 914bf48e753SHugo Santos 915c22d69bfSAxel Dörfler // #pragma mark - activation 916c22d69bfSAxel Dörfler 917c22d69bfSAxel Dörfler 918c22d69bfSAxel Dörfler status_t 91953f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address) 920c22d69bfSAxel Dörfler { 921bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 922727ad0b0SHugo Santos return fManager->BindEndpoint(this, address); 923c22d69bfSAxel Dörfler } 924c22d69bfSAxel Dörfler 925c22d69bfSAxel Dörfler 926c22d69bfSAxel Dörfler status_t 927c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 928c22d69bfSAxel Dörfler { 929bf48e753SHugo Santos TRACE_EP("Unbind()"); 930727ad0b0SHugo Santos return fManager->UnbindEndpoint(this); 931c22d69bfSAxel Dörfler } 932c22d69bfSAxel Dörfler 933c22d69bfSAxel Dörfler 934c22d69bfSAxel Dörfler status_t 935c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 936c22d69bfSAxel Dörfler { 937bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 938727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address); 939c22d69bfSAxel Dörfler } 940c22d69bfSAxel Dörfler 941c22d69bfSAxel Dörfler 942c22d69bfSAxel Dörfler status_t 943c22d69bfSAxel Dörfler UdpEndpoint::Open() 944c22d69bfSAxel Dörfler { 945bf48e753SHugo Santos TRACE_EP("Open()"); 946bf48e753SHugo Santos 947119c6cddSIngo Weinhold AutoLocker _(fLock); 948727ad0b0SHugo Santos 949c72ab92dSHugo Santos status_t status = ProtocolSocket::Open(); 950c72ab92dSHugo Santos if (status < B_OK) 951c72ab92dSHugo Santos return status; 952bf48e753SHugo Santos 953c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this); 954c72ab92dSHugo Santos if (fManager == NULL) 955bf48e753SHugo Santos return EAFNOSUPPORT; 956bf48e753SHugo Santos 957bf48e753SHugo Santos return B_OK; 958c22d69bfSAxel Dörfler } 959c22d69bfSAxel Dörfler 960c22d69bfSAxel Dörfler 961c22d69bfSAxel Dörfler status_t 962c22d69bfSAxel Dörfler UdpEndpoint::Close() 963c22d69bfSAxel Dörfler { 964bf48e753SHugo Santos TRACE_EP("Close()"); 965bf48e753SHugo Santos return B_OK; 966c22d69bfSAxel Dörfler } 967c22d69bfSAxel Dörfler 968c22d69bfSAxel Dörfler 969c22d69bfSAxel Dörfler status_t 970c22d69bfSAxel Dörfler UdpEndpoint::Free() 971c22d69bfSAxel Dörfler { 972bf48e753SHugo Santos TRACE_EP("Free()"); 9730086fe20SHugo Santos fManager->UnbindEndpoint(this); 974c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager); 975c22d69bfSAxel Dörfler } 976c22d69bfSAxel Dörfler 977c22d69bfSAxel Dörfler 978c22d69bfSAxel Dörfler // #pragma mark - outbound 979c22d69bfSAxel Dörfler 980c22d69bfSAxel Dörfler 981c22d69bfSAxel Dörfler status_t 982bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 983c22d69bfSAxel Dörfler { 984bf48e753SHugo Santos TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route); 985bf48e753SHugo Santos 986d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 987c22d69bfSAxel Dörfler return EMSGSIZE; 988c22d69bfSAxel Dörfler 989c22d69bfSAxel Dörfler buffer->protocol = IPPROTO_UDP; 990c22d69bfSAxel Dörfler 991c22d69bfSAxel Dörfler // add and fill UDP-specific header: 9926c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 9936c353509SHugo Santos if (header.Status() < B_OK) 9946c353509SHugo Santos return header.Status(); 995c22d69bfSAxel Dörfler 99679a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source); 99779a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination); 9986c353509SHugo Santos header->udp_length = htons(buffer->size); 999c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 10006c353509SHugo Santos header->udp_checksum = 0; 10016c353509SHugo Santos 10026c353509SHugo Santos header.Sync(); 1003c22d69bfSAxel Dörfler 1004d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(), 1005d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP); 10066c353509SHugo Santos if (calculatedChecksum == 0) 10076c353509SHugo Santos calculatedChecksum = 0xffff; 10086c353509SHugo Santos 10096c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 1010c22d69bfSAxel Dörfler 1011c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 1012c22d69bfSAxel Dörfler } 1013c22d69bfSAxel Dörfler 1014c22d69bfSAxel Dörfler 1015bf48e753SHugo Santos status_t 1016bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 1017bf48e753SHugo Santos { 1018bf48e753SHugo Santos TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size); 1019bf48e753SHugo Santos 10202651e51dSAxel Dörfler return gDatalinkModule->send_data(this, NULL, buffer); 1021bf48e753SHugo Santos } 1022bf48e753SHugo Santos 1023bf48e753SHugo Santos 1024c22d69bfSAxel Dörfler // #pragma mark - inbound 1025c22d69bfSAxel Dörfler 1026c22d69bfSAxel Dörfler 1027c22d69bfSAxel Dörfler ssize_t 1028c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 1029c22d69bfSAxel Dörfler { 1030bfb45f71SHugo Santos size_t bytes = AvailableData(); 1031bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 1032bfb45f71SHugo Santos return bytes; 1033c22d69bfSAxel Dörfler } 1034c22d69bfSAxel Dörfler 1035c22d69bfSAxel Dörfler 1036c22d69bfSAxel Dörfler status_t 1037c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 1038c22d69bfSAxel Dörfler { 1039bf48e753SHugo Santos TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags); 1040bf48e753SHugo Santos 10412651e51dSAxel Dörfler status_t status = Dequeue(flags, _buffer); 1042cb99c915SAxel Dörfler TRACE_EP(" FetchData(): returned from fifo status: %s", strerror(status)); 10432651e51dSAxel Dörfler if (status != B_OK) 1044c22d69bfSAxel Dörfler return status; 1045c22d69bfSAxel Dörfler 1046bfb45f71SHugo Santos TRACE_EP(" FetchData(): returns buffer with %ld bytes", (*_buffer)->size); 1047c22d69bfSAxel Dörfler return B_OK; 1048c22d69bfSAxel Dörfler } 1049c22d69bfSAxel Dörfler 1050c22d69bfSAxel Dörfler 1051c22d69bfSAxel Dörfler status_t 1052bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 1053c22d69bfSAxel Dörfler { 1054bf48e753SHugo Santos TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size); 1055c22d69bfSAxel Dörfler 10562651e51dSAxel Dörfler return EnqueueClone(buffer); 1057c22d69bfSAxel Dörfler } 1058c22d69bfSAxel Dörfler 1059c22d69bfSAxel Dörfler 10606a606180SHugo Santos status_t 10616a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 10626a606180SHugo Santos { 1063f6cfc5afSHugo Santos TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size); 1064f6cfc5afSHugo Santos 10656a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 10666a606180SHugo Santos if (buffer == NULL) 10676a606180SHugo Santos return B_NO_MEMORY; 10686a606180SHugo Santos 10696a606180SHugo Santos status_t status = sUdpEndpointManager->Deframe(buffer); 10706a606180SHugo Santos if (status < B_OK) { 10716a606180SHugo Santos gBufferModule->free(buffer); 10726a606180SHugo Santos return status; 10736a606180SHugo Santos } 10746a606180SHugo Santos 10756a606180SHugo Santos return Enqueue(buffer); 10766a606180SHugo Santos } 10776a606180SHugo Santos 10786a606180SHugo Santos 1079cb99c915SAxel Dörfler void 1080cb99c915SAxel Dörfler UdpEndpoint::Dump() const 1081cb99c915SAxel Dörfler { 1082cb99c915SAxel Dörfler char local[64]; 1083cb99c915SAxel Dörfler LocalAddress().AsString(local, sizeof(local), true); 1084cb99c915SAxel Dörfler char peer[64]; 1085cb99c915SAxel Dörfler PeerAddress().AsString(peer, sizeof(peer), true); 1086cb99c915SAxel Dörfler 1087cb99c915SAxel Dörfler kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes); 1088cb99c915SAxel Dörfler } 1089cb99c915SAxel Dörfler 1090cb99c915SAxel Dörfler 1091c22d69bfSAxel Dörfler // #pragma mark - protocol interface 1092c22d69bfSAxel Dörfler 1093c22d69bfSAxel Dörfler 1094c22d69bfSAxel Dörfler net_protocol * 1095c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 1096c22d69bfSAxel Dörfler { 1097c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 1098c22d69bfSAxel Dörfler 1099c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 1100bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 1101bf48e753SHugo Santos delete endpoint; 1102bf48e753SHugo Santos return NULL; 1103bf48e753SHugo Santos } 1104bf48e753SHugo Santos 1105c22d69bfSAxel Dörfler return endpoint; 1106c22d69bfSAxel Dörfler } 1107c22d69bfSAxel Dörfler 1108c22d69bfSAxel Dörfler 1109c22d69bfSAxel Dörfler status_t 1110c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 1111c22d69bfSAxel Dörfler { 1112bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 1113c22d69bfSAxel Dörfler return B_OK; 1114c22d69bfSAxel Dörfler } 1115c22d69bfSAxel Dörfler 1116c22d69bfSAxel Dörfler 1117c22d69bfSAxel Dörfler status_t 1118c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 1119c22d69bfSAxel Dörfler { 1120bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 1121c22d69bfSAxel Dörfler } 1122c22d69bfSAxel Dörfler 1123c22d69bfSAxel Dörfler 1124c22d69bfSAxel Dörfler status_t 1125c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 1126c22d69bfSAxel Dörfler { 1127bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 1128c22d69bfSAxel Dörfler } 1129c22d69bfSAxel Dörfler 1130c22d69bfSAxel Dörfler 1131c22d69bfSAxel Dörfler status_t 1132c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 1133c22d69bfSAxel Dörfler { 1134bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 1135c22d69bfSAxel Dörfler } 1136c22d69bfSAxel Dörfler 1137c22d69bfSAxel Dörfler 1138c22d69bfSAxel Dörfler status_t 1139c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1140c22d69bfSAxel Dörfler { 1141bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1142c22d69bfSAxel Dörfler } 1143c22d69bfSAxel Dörfler 1144c22d69bfSAxel Dörfler 1145c22d69bfSAxel Dörfler status_t 1146c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1147c22d69bfSAxel Dörfler { 1148ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1149c22d69bfSAxel Dörfler } 1150c22d69bfSAxel Dörfler 1151c22d69bfSAxel Dörfler 1152c22d69bfSAxel Dörfler status_t 1153c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1154c22d69bfSAxel Dörfler size_t *_length) 1155c22d69bfSAxel Dörfler { 1156c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1157c22d69bfSAxel Dörfler value, _length); 1158c22d69bfSAxel Dörfler } 1159c22d69bfSAxel Dörfler 1160c22d69bfSAxel Dörfler 1161c22d69bfSAxel Dörfler status_t 116245b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value, 116345b5203bSHugo Santos int *length) 116445b5203bSHugo Santos { 116545b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option, 116645b5203bSHugo Santos value, length); 116745b5203bSHugo Santos } 116845b5203bSHugo Santos 116945b5203bSHugo Santos 117045b5203bSHugo Santos status_t 117145b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option, 117245b5203bSHugo Santos const void *value, int length) 117345b5203bSHugo Santos { 117445b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option, 117545b5203bSHugo Santos value, length); 117645b5203bSHugo Santos } 117745b5203bSHugo Santos 117845b5203bSHugo Santos 117945b5203bSHugo Santos status_t 118053f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address) 1181c22d69bfSAxel Dörfler { 1182bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1183c22d69bfSAxel Dörfler } 1184c22d69bfSAxel Dörfler 1185c22d69bfSAxel Dörfler 1186c22d69bfSAxel Dörfler status_t 1187c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1188c22d69bfSAxel Dörfler { 1189bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1190c22d69bfSAxel Dörfler } 1191c22d69bfSAxel Dörfler 1192c22d69bfSAxel Dörfler 1193c22d69bfSAxel Dörfler status_t 1194c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1195c22d69bfSAxel Dörfler { 1196ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1197c22d69bfSAxel Dörfler } 1198c22d69bfSAxel Dörfler 1199c22d69bfSAxel Dörfler 1200c22d69bfSAxel Dörfler status_t 1201c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1202c22d69bfSAxel Dörfler { 1203ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1204c22d69bfSAxel Dörfler } 1205c22d69bfSAxel Dörfler 1206c22d69bfSAxel Dörfler 1207c22d69bfSAxel Dörfler status_t 1208c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1209c22d69bfSAxel Dörfler net_buffer *buffer) 1210c22d69bfSAxel Dörfler { 1211bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1212c22d69bfSAxel Dörfler } 1213c22d69bfSAxel Dörfler 1214c22d69bfSAxel Dörfler 1215c22d69bfSAxel Dörfler status_t 1216c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1217c22d69bfSAxel Dörfler { 1218bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1219c22d69bfSAxel Dörfler } 1220c22d69bfSAxel Dörfler 1221c22d69bfSAxel Dörfler 1222c22d69bfSAxel Dörfler ssize_t 1223c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1224c22d69bfSAxel Dörfler { 1225bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1226c22d69bfSAxel Dörfler } 1227c22d69bfSAxel Dörfler 1228c22d69bfSAxel Dörfler 1229c22d69bfSAxel Dörfler status_t 1230c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1231c22d69bfSAxel Dörfler net_buffer **_buffer) 1232c22d69bfSAxel Dörfler { 1233bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1234c22d69bfSAxel Dörfler } 1235c22d69bfSAxel Dörfler 1236c22d69bfSAxel Dörfler 1237c22d69bfSAxel Dörfler ssize_t 1238c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1239c22d69bfSAxel Dörfler { 1240bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1241c22d69bfSAxel Dörfler } 1242c22d69bfSAxel Dörfler 1243c22d69bfSAxel Dörfler 1244c22d69bfSAxel Dörfler struct net_domain * 1245c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1246c22d69bfSAxel Dörfler { 1247c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1248c22d69bfSAxel Dörfler } 1249c22d69bfSAxel Dörfler 1250c22d69bfSAxel Dörfler 1251c22d69bfSAxel Dörfler size_t 1252c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1253c22d69bfSAxel Dörfler { 1254c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1255c22d69bfSAxel Dörfler } 1256c22d69bfSAxel Dörfler 1257c22d69bfSAxel Dörfler 1258c22d69bfSAxel Dörfler status_t 1259c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1260c22d69bfSAxel Dörfler { 1261c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1262c22d69bfSAxel Dörfler } 1263c22d69bfSAxel Dörfler 1264c22d69bfSAxel Dörfler 1265c22d69bfSAxel Dörfler status_t 12666a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 12676a606180SHugo Santos { 12686a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 12696a606180SHugo Santos } 12706a606180SHugo Santos 12716a606180SHugo Santos 12726a606180SHugo Santos status_t 12732b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer) 1274c22d69bfSAxel Dörfler { 12752b415445SAxel Dörfler status_t notifyError = B_OK; 12762bb43d82SAxel Dörfler 12772b415445SAxel Dörfler switch (error) { 12782b415445SAxel Dörfler case B_NET_ERROR_UNREACH_NET: 12792b415445SAxel Dörfler notifyError = ENETUNREACH; 12802bb43d82SAxel Dörfler break; 12812b415445SAxel Dörfler case B_NET_ERROR_UNREACH_HOST: 12822b415445SAxel Dörfler case B_NET_ERROR_TRANSIT_TIME_EXCEEDED: 12832b415445SAxel Dörfler notifyError = EHOSTUNREACH; 12842bb43d82SAxel Dörfler break; 12852b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PROTOCOL: 12862b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PORT: 12872b415445SAxel Dörfler notifyError = ECONNREFUSED; 12882bb43d82SAxel Dörfler break; 12892b415445SAxel Dörfler case B_NET_ERROR_MESSAGE_SIZE: 12902b415445SAxel Dörfler notifyError = EMSGSIZE; 12912b415445SAxel Dörfler break; 12922b415445SAxel Dörfler case B_NET_ERROR_PARAMETER_PROBLEM: 12932b415445SAxel Dörfler notifyError = ENOPROTOOPT; 12942b415445SAxel Dörfler break; 12952b415445SAxel Dörfler 12962b415445SAxel Dörfler case B_NET_ERROR_QUENCH: 12972bb43d82SAxel Dörfler default: 12982bb43d82SAxel Dörfler // ignore them 12992bb43d82SAxel Dörfler gBufferModule->free(buffer); 13002bb43d82SAxel Dörfler return B_OK; 1301c22d69bfSAxel Dörfler } 1302c22d69bfSAxel Dörfler 13037e046eabSAxel Dörfler ASSERT(notifyError != B_OK); 13047e046eabSAxel Dörfler 13057e046eabSAxel Dörfler return sUdpEndpointManager->ReceiveError(notifyError, buffer); 13067e046eabSAxel Dörfler } 13077e046eabSAxel Dörfler 1308c22d69bfSAxel Dörfler 1309c22d69bfSAxel Dörfler status_t 13102b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error, 13112b415445SAxel Dörfler net_error_data *errorData) 1312c22d69bfSAxel Dörfler { 1313c22d69bfSAxel Dörfler return B_ERROR; 1314c22d69bfSAxel Dörfler } 1315c22d69bfSAxel Dörfler 1316c22d69bfSAxel Dörfler 131778888c44SAxel Dörfler ssize_t 131878888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol, 131978888c44SAxel Dörfler net_buffer* buffer, void *data, size_t dataSize) 132078888c44SAxel Dörfler { 132178888c44SAxel Dörfler return protocol->next->module->process_ancillary_data_no_container( 132278888c44SAxel Dörfler protocol, buffer, data, dataSize); 132378888c44SAxel Dörfler } 132478888c44SAxel Dörfler 132578888c44SAxel Dörfler 1326c22d69bfSAxel Dörfler // #pragma mark - module interface 1327c22d69bfSAxel Dörfler 1328c22d69bfSAxel Dörfler 1329c22d69bfSAxel Dörfler static status_t 1330c22d69bfSAxel Dörfler init_udp() 1331c22d69bfSAxel Dörfler { 1332c22d69bfSAxel Dörfler status_t status; 1333bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1334c22d69bfSAxel Dörfler 1335c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1336658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1337658a5506SHugo Santos return B_NO_MEMORY; 1338658a5506SHugo Santos 1339c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1340c22d69bfSAxel Dörfler if (status != B_OK) 1341d438fa4cSHugo Santos goto err1; 1342c22d69bfSAxel Dörfler 134361729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 134461729d93SAxel Dörfler IPPROTO_IP, 1345c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1346c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1347c22d69bfSAxel Dörfler NULL); 1348c22d69bfSAxel Dörfler if (status < B_OK) 1349658a5506SHugo Santos goto err1; 135061729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 135161729d93SAxel Dörfler IPPROTO_IP, 13528d1485faSAxel Dörfler "network/protocols/udp/v1", 13538d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13548d1485faSAxel Dörfler NULL); 13558d1485faSAxel Dörfler if (status < B_OK) 13568d1485faSAxel Dörfler goto err1; 13578d1485faSAxel Dörfler 135861729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 135961729d93SAxel Dörfler IPPROTO_UDP, 1360c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1361c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1362c22d69bfSAxel Dörfler NULL); 1363c22d69bfSAxel Dörfler if (status < B_OK) 1364658a5506SHugo Santos goto err1; 136561729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 136661729d93SAxel Dörfler IPPROTO_UDP, 13678d1485faSAxel Dörfler "network/protocols/udp/v1", 13688d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13698d1485faSAxel Dörfler NULL); 13708d1485faSAxel Dörfler if (status < B_OK) 13718d1485faSAxel Dörfler goto err1; 1372c22d69bfSAxel Dörfler 137361729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET, 137461729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 1375c22d69bfSAxel Dörfler if (status < B_OK) 1376658a5506SHugo Santos goto err1; 137761729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET6, 137861729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 13798d1485faSAxel Dörfler if (status < B_OK) 13808d1485faSAxel Dörfler goto err1; 1381c22d69bfSAxel Dörfler 1382cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints, 1383cf5d9f4bSHugo Santos "lists all open UDP endpoints"); 1384cf5d9f4bSHugo Santos 1385c22d69bfSAxel Dörfler return B_OK; 1386c22d69bfSAxel Dörfler 1387c22d69bfSAxel Dörfler err1: 13888d1485faSAxel Dörfler // TODO: shouldn't unregister the protocols here? 1389658a5506SHugo Santos delete sUdpEndpointManager; 1390c22d69bfSAxel Dörfler 1391bf48e753SHugo Santos TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status)); 1392c22d69bfSAxel Dörfler return status; 1393c22d69bfSAxel Dörfler } 1394c22d69bfSAxel Dörfler 1395c22d69bfSAxel Dörfler 1396c22d69bfSAxel Dörfler static status_t 1397c22d69bfSAxel Dörfler uninit_udp() 1398c22d69bfSAxel Dörfler { 1399bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1400cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints", 1401cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints); 1402c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1403c22d69bfSAxel Dörfler return B_OK; 1404c22d69bfSAxel Dörfler } 1405c22d69bfSAxel Dörfler 1406c22d69bfSAxel Dörfler 1407c22d69bfSAxel Dörfler static status_t 1408c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1409c22d69bfSAxel Dörfler { 1410c22d69bfSAxel Dörfler switch (op) { 1411c22d69bfSAxel Dörfler case B_MODULE_INIT: 1412c22d69bfSAxel Dörfler return init_udp(); 1413c22d69bfSAxel Dörfler 1414c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1415c22d69bfSAxel Dörfler return uninit_udp(); 1416c22d69bfSAxel Dörfler 1417c22d69bfSAxel Dörfler default: 1418c22d69bfSAxel Dörfler return B_ERROR; 1419c22d69bfSAxel Dörfler } 1420c22d69bfSAxel Dörfler } 1421c22d69bfSAxel Dörfler 1422c22d69bfSAxel Dörfler 1423c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1424c22d69bfSAxel Dörfler { 1425c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1426c22d69bfSAxel Dörfler 0, 1427c22d69bfSAxel Dörfler udp_std_ops 1428c22d69bfSAxel Dörfler }, 14296f58064fSAxel Dörfler NET_PROTOCOL_ATOMIC_MESSAGES, 14306f58064fSAxel Dörfler 1431c22d69bfSAxel Dörfler udp_init_protocol, 1432c22d69bfSAxel Dörfler udp_uninit_protocol, 1433c22d69bfSAxel Dörfler udp_open, 1434c22d69bfSAxel Dörfler udp_close, 1435c22d69bfSAxel Dörfler udp_free, 1436c22d69bfSAxel Dörfler udp_connect, 1437c22d69bfSAxel Dörfler udp_accept, 1438c22d69bfSAxel Dörfler udp_control, 143945b5203bSHugo Santos udp_getsockopt, 144045b5203bSHugo Santos udp_setsockopt, 1441c22d69bfSAxel Dörfler udp_bind, 1442c22d69bfSAxel Dörfler udp_unbind, 1443c22d69bfSAxel Dörfler udp_listen, 1444c22d69bfSAxel Dörfler udp_shutdown, 1445c22d69bfSAxel Dörfler udp_send_data, 1446c22d69bfSAxel Dörfler udp_send_routed_data, 1447c22d69bfSAxel Dörfler udp_send_avail, 1448c22d69bfSAxel Dörfler udp_read_data, 1449c22d69bfSAxel Dörfler udp_read_avail, 1450c22d69bfSAxel Dörfler udp_get_domain, 1451c22d69bfSAxel Dörfler udp_get_mtu, 1452c22d69bfSAxel Dörfler udp_receive_data, 14536a606180SHugo Santos udp_deliver_data, 14542bb43d82SAxel Dörfler udp_error_received, 1455c22d69bfSAxel Dörfler udp_error_reply, 14569871124eSAxel Dörfler NULL, // add_ancillary_data() 14579871124eSAxel Dörfler NULL, // process_ancillary_data() 145878888c44SAxel Dörfler udp_process_ancillary_data_no_container, 14599871124eSAxel Dörfler NULL, // send_data_no_buffer() 14609871124eSAxel Dörfler NULL // read_data_no_buffer() 1461c22d69bfSAxel Dörfler }; 1462c22d69bfSAxel Dörfler 1463658a5506SHugo Santos module_dependency module_dependencies[] = { 1464658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1465658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1466658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 14672bb43d82SAxel Dörfler {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule}, 1468658a5506SHugo Santos {} 1469658a5506SHugo Santos }; 1470658a5506SHugo Santos 1471c22d69bfSAxel Dörfler module_info *modules[] = { 1472c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1473c22d69bfSAxel Dörfler NULL 1474c22d69bfSAxel Dörfler }; 1475