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 47bf9a85cbSJérôme Duval # define TRACE_EP(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \ 48bf9a85cbSJérôme Duval B_PRIu32 "] %p " format "\n", system_time(), \ 49bf9a85cbSJérôme Duval thread_get_current_thread_id(), this , ##args) 50bf9a85cbSJérôme Duval # define TRACE_EPM(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \ 51bf9a85cbSJérôme Duval B_PRIu32 "] " format "\n", system_time() , \ 52bf9a85cbSJérôme Duval thread_get_current_thread_id() , ##args) 53bf9a85cbSJérôme Duval # define TRACE_DOMAIN(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \ 54bf9a85cbSJérôme Duval B_PRIu32 "] (%d) " format "\n", system_time(), \ 55bf9a85cbSJérôme Duval thread_get_current_thread_id(), Domain()->family , ##args) 56c22d69bfSAxel Dörfler #else 57c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) 58bf48e753SHugo Santos # define TRACE_EP(args...) do { } while (0) 59bf48e753SHugo Santos # define TRACE_EPM(args...) do { } while (0) 60bf48e753SHugo Santos # define TRACE_DOMAIN(args...) do { } while (0) 61c22d69bfSAxel Dörfler #endif 62c22d69bfSAxel Dörfler 63c22d69bfSAxel Dörfler 64c22d69bfSAxel Dörfler struct udp_header { 65c22d69bfSAxel Dörfler uint16 source_port; 66c22d69bfSAxel Dörfler uint16 destination_port; 67c22d69bfSAxel Dörfler uint16 udp_length; 68c22d69bfSAxel Dörfler uint16 udp_checksum; 69c22d69bfSAxel Dörfler } _PACKED; 70c22d69bfSAxel Dörfler 71c22d69bfSAxel Dörfler 726c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)> 736c353509SHugo Santos UDPChecksumField; 746c353509SHugo Santos 75bf48e753SHugo Santos class UdpDomainSupport; 766c353509SHugo Santos 77bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> { 78c22d69bfSAxel Dörfler public: 79c22d69bfSAxel Dörfler UdpEndpoint(net_socket* socket); 80bf48e753SHugo Santos 8153f23f85SHugo Santos status_t Bind(const sockaddr* newAddr); 82c22d69bfSAxel Dörfler status_t Unbind(sockaddr* newAddr); 83c22d69bfSAxel Dörfler status_t Connect(const sockaddr* newAddr); 84c22d69bfSAxel Dörfler 85c22d69bfSAxel Dörfler status_t Open(); 86c22d69bfSAxel Dörfler status_t Close(); 87c22d69bfSAxel Dörfler status_t Free(); 88c22d69bfSAxel Dörfler 8956f097ebSOliver Tappe status_t SendRoutedData(net_buffer* buffer, 9056f097ebSOliver Tappe net_route* route); 91bf48e753SHugo Santos status_t SendData(net_buffer* buffer); 92c22d69bfSAxel Dörfler 93c22d69bfSAxel Dörfler ssize_t BytesAvailable(); 94c22d69bfSAxel Dörfler status_t FetchData(size_t numBytes, uint32 flags, 95c22d69bfSAxel Dörfler net_buffer** _buffer); 96c22d69bfSAxel Dörfler 97c22d69bfSAxel Dörfler status_t StoreData(net_buffer* buffer); 986a606180SHugo Santos status_t DeliverData(net_buffer* buffer); 99c22d69bfSAxel Dörfler 100727ad0b0SHugo Santos // only the domain support will change/check the Active flag so 101727ad0b0SHugo Santos // we don't really need to protect it with the socket lock. 102727ad0b0SHugo Santos bool IsActive() const { return fActive; } 103727ad0b0SHugo Santos void SetActive(bool newValue) { fActive = newValue; } 104bf48e753SHugo Santos 1055147963dSStephan Aßmus UdpEndpoint*& HashTableLink() { return fLink; } 10640bbf860SHugo Santos 107cb99c915SAxel Dörfler void Dump() const; 108cb99c915SAxel Dörfler 109c22d69bfSAxel Dörfler private: 110c72ab92dSHugo Santos UdpDomainSupport* fManager; 111c22d69bfSAxel Dörfler bool fActive; 11256f097ebSOliver Tappe // an active UdpEndpoint is part of the 113cb99c915SAxel Dörfler // endpoint hash (and it is bound and 114cb99c915SAxel Dörfler // optionally connected) 11540bbf860SHugo Santos 1165147963dSStephan Aßmus UdpEndpoint* fLink; 11740bbf860SHugo Santos }; 11840bbf860SHugo Santos 11940bbf860SHugo Santos 12040bbf860SHugo Santos class UdpDomainSupport; 12140bbf860SHugo Santos 12240bbf860SHugo Santos struct UdpHashDefinition { 12340bbf860SHugo Santos typedef net_address_module_info ParentType; 12440bbf860SHugo Santos typedef std::pair<const sockaddr *, const sockaddr *> KeyType; 12540bbf860SHugo Santos typedef UdpEndpoint ValueType; 12640bbf860SHugo Santos 12784052230SAxel Dörfler UdpHashDefinition(net_address_module_info *_module) 12884052230SAxel Dörfler : module(_module) {} 12984052230SAxel Dörfler UdpHashDefinition(const UdpHashDefinition& definition) 13084052230SAxel Dörfler : module(definition.module) {} 13140bbf860SHugo Santos 13240bbf860SHugo Santos size_t HashKey(const KeyType &key) const 13340bbf860SHugo Santos { 13440bbf860SHugo Santos return _Mix(module->hash_address_pair(key.first, key.second)); 13540bbf860SHugo Santos } 13640bbf860SHugo Santos 13740bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const 13840bbf860SHugo Santos { 13956f097ebSOliver Tappe return _Mix(endpoint->LocalAddress().HashPair( 14056f097ebSOliver Tappe *endpoint->PeerAddress())); 14140bbf860SHugo Santos } 14240bbf860SHugo Santos 14340bbf860SHugo Santos static size_t _Mix(size_t hash) 14440bbf860SHugo Santos { 14556f097ebSOliver Tappe // move the bits into the relevant range (as defined by kNumHashBuckets) 14640bbf860SHugo Santos return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11 14740bbf860SHugo Santos ^ (hash & 0xFFC00000UL) >> 22; 14840bbf860SHugo Santos } 14940bbf860SHugo Santos 15040bbf860SHugo Santos bool Compare(const KeyType &key, UdpEndpoint *endpoint) const 15140bbf860SHugo Santos { 15240bbf860SHugo Santos return endpoint->LocalAddress().EqualTo(key.first, true) 15340bbf860SHugo Santos && endpoint->PeerAddress().EqualTo(key.second, true); 15440bbf860SHugo Santos } 15540bbf860SHugo Santos 1565147963dSStephan Aßmus UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const 15740bbf860SHugo Santos { 15840bbf860SHugo Santos return endpoint->HashTableLink(); 15940bbf860SHugo Santos } 16040bbf860SHugo Santos 16140bbf860SHugo Santos net_address_module_info *module; 162c22d69bfSAxel Dörfler }; 163c22d69bfSAxel Dörfler 164c22d69bfSAxel Dörfler 165bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> { 166c22d69bfSAxel Dörfler public: 167bf48e753SHugo Santos UdpDomainSupport(net_domain *domain); 168727ad0b0SHugo Santos ~UdpDomainSupport(); 169c22d69bfSAxel Dörfler 170276aa463SIngo Weinhold status_t Init(); 171bf48e753SHugo Santos 172bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 173bf48e753SHugo Santos 174bf48e753SHugo Santos void Ref() { fEndpointCount++; } 175727ad0b0SHugo Santos bool Put() { fEndpointCount--; return fEndpointCount == 0; } 176bf48e753SHugo Santos 177bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer* buffer); 1782bb43d82SAxel Dörfler status_t DeliverError(status_t error, net_buffer* buffer); 179727ad0b0SHugo Santos 180727ad0b0SHugo Santos status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 181727ad0b0SHugo Santos status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 182727ad0b0SHugo Santos status_t UnbindEndpoint(UdpEndpoint *endpoint); 183727ad0b0SHugo Santos 184cf5d9f4bSHugo Santos void DumpEndpoints() const; 185bf48e753SHugo Santos 186c22d69bfSAxel Dörfler private: 187727ad0b0SHugo Santos status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 188727ad0b0SHugo Santos status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address); 189727ad0b0SHugo Santos status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address); 190727ad0b0SHugo Santos status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address); 191727ad0b0SHugo Santos 19240bbf860SHugo Santos UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress, 193bbbb5592SAxel Dörfler const sockaddr *peerAddress, uint32 index = 0); 194bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer); 195bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer); 196bf48e753SHugo Santos 197bf48e753SHugo Santos uint16 _GetNextEphemeral(); 198727ad0b0SHugo Santos UdpEndpoint *_EndpointWithPort(uint16 port) const; 199bf48e753SHugo Santos 200bf48e753SHugo Santos net_address_module_info *AddressModule() const 201727ad0b0SHugo Santos { return fDomain->address_module; } 202bf48e753SHugo Santos 2035147963dSStephan Aßmus typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable; 20440bbf860SHugo Santos 2052b07b8e0SIngo Weinhold mutex fLock; 206bf48e753SHugo Santos net_domain *fDomain; 207bf48e753SHugo Santos uint16 fLastUsedEphemeral; 20840bbf860SHugo Santos EndpointTable fActiveEndpoints; 209bf48e753SHugo Santos uint32 fEndpointCount; 210bf48e753SHugo Santos 211bf48e753SHugo Santos static const uint16 kFirst = 49152; 212bf48e753SHugo Santos static const uint16 kLast = 65535; 213bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800; 214bf48e753SHugo Santos // if you change this, adjust the shifting in 215bf48e753SHugo Santos // Hash() accordingly! 216bf48e753SHugo Santos }; 217bf48e753SHugo Santos 218bf48e753SHugo Santos 219bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList; 220bf48e753SHugo Santos 221bf48e753SHugo Santos 222bf48e753SHugo Santos class UdpEndpointManager { 223c22d69bfSAxel Dörfler public: 224c22d69bfSAxel Dörfler UdpEndpointManager(); 225c22d69bfSAxel Dörfler ~UdpEndpointManager(); 226c22d69bfSAxel Dörfler 2272bb43d82SAxel Dörfler status_t InitCheck() const; 2282bb43d82SAxel Dörfler 22974e1a530SJérôme Duval status_t ReceiveData(net_buffer* buffer); 2302bb43d82SAxel Dörfler status_t ReceiveError(status_t error, 2312bb43d82SAxel Dörfler net_buffer* buffer); 23274e1a530SJérôme Duval status_t Deframe(net_buffer* buffer); 233c22d69bfSAxel Dörfler 234bf48e753SHugo Santos UdpDomainSupport* OpenEndpoint(UdpEndpoint* endpoint); 235bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport* domain); 236c22d69bfSAxel Dörfler 237cf5d9f4bSHugo Santos static int DumpEndpoints(int argc, char *argv[]); 238cf5d9f4bSHugo Santos 239c22d69bfSAxel Dörfler private: 2409d433190SAxel Dörfler inline net_domain* _GetDomain(net_buffer* buffer); 2419d433190SAxel Dörfler UdpDomainSupport* _GetDomainSupport(net_domain* domain, 2429d433190SAxel Dörfler bool create); 2439d433190SAxel Dörfler UdpDomainSupport* _GetDomainSupport(net_buffer* buffer); 244bf48e753SHugo Santos 2452b07b8e0SIngo Weinhold mutex fLock; 246c22d69bfSAxel Dörfler status_t fStatus; 247bf48e753SHugo Santos UdpDomainList fDomains; 248c22d69bfSAxel Dörfler }; 249c22d69bfSAxel Dörfler 250c22d69bfSAxel Dörfler 251c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager; 252c22d69bfSAxel Dörfler 253c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule; 254658a5506SHugo Santos net_datalink_module_info *gDatalinkModule; 255658a5506SHugo Santos net_stack_module_info *gStackModule; 2562bb43d82SAxel Dörfler net_socket_module_info *gSocketModule; 257c22d69bfSAxel Dörfler 258c22d69bfSAxel Dörfler 259c22d69bfSAxel Dörfler // #pragma mark - 260c22d69bfSAxel Dörfler 261c22d69bfSAxel Dörfler 262bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain) 263c22d69bfSAxel Dörfler : 264bf48e753SHugo Santos fDomain(domain), 265276aa463SIngo Weinhold fActiveEndpoints(domain->address_module), 266bf48e753SHugo Santos fEndpointCount(0) 267c22d69bfSAxel Dörfler { 2682b07b8e0SIngo Weinhold mutex_init(&fLock, "udp domain"); 269727ad0b0SHugo Santos 270727ad0b0SHugo Santos fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst); 271727ad0b0SHugo Santos } 272727ad0b0SHugo Santos 273727ad0b0SHugo Santos 274727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport() 275727ad0b0SHugo Santos { 2762b07b8e0SIngo Weinhold mutex_destroy(&fLock); 277bf48e753SHugo Santos } 278bf48e753SHugo Santos 279bf48e753SHugo Santos 280bf48e753SHugo Santos status_t 281276aa463SIngo Weinhold UdpDomainSupport::Init() 282bf48e753SHugo Santos { 283276aa463SIngo Weinhold return fActiveEndpoints.Init(kNumHashBuckets); 284bf48e753SHugo Santos } 285bf48e753SHugo Santos 286bf48e753SHugo Santos 287bf48e753SHugo Santos status_t 288bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer) 289bf48e753SHugo Santos { 2902bb43d82SAxel Dörfler // NOTE: multicast is delivered directly to the endpoint 2912b07b8e0SIngo Weinhold MutexLocker _(fLock); 292727ad0b0SHugo Santos 2932bb43d82SAxel Dörfler if ((buffer->flags & MSG_BCAST) != 0) 294bf48e753SHugo Santos return _DemuxBroadcast(buffer); 2952bb43d82SAxel Dörfler if ((buffer->flags & MSG_MCAST) != 0) 296727ad0b0SHugo Santos return B_ERROR; 297bf48e753SHugo Santos 298bf48e753SHugo Santos return _DemuxUnicast(buffer); 299bf48e753SHugo Santos } 300bf48e753SHugo Santos 301bf48e753SHugo Santos 302bf48e753SHugo Santos status_t 3032bb43d82SAxel Dörfler UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer) 3042bb43d82SAxel Dörfler { 3052bb43d82SAxel Dörfler if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0) 3062bb43d82SAxel Dörfler return B_ERROR; 3072bb43d82SAxel Dörfler 3082bb43d82SAxel Dörfler MutexLocker _(fLock); 3092bb43d82SAxel Dörfler 3102e1729d0SAxel Dörfler // Forward the error to the socket 3112e1729d0SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source, 3122e1729d0SAxel Dörfler buffer->destination); 3132e1729d0SAxel Dörfler if (endpoint != NULL) { 3142bb43d82SAxel Dörfler gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error); 3152e1729d0SAxel Dörfler endpoint->NotifyOne(); 3162e1729d0SAxel Dörfler } 3172bb43d82SAxel Dörfler 3182bb43d82SAxel Dörfler gBufferModule->free(buffer); 3192bb43d82SAxel Dörfler return B_OK; 3202bb43d82SAxel Dörfler } 3212bb43d82SAxel Dörfler 3222bb43d82SAxel Dörfler 3232bb43d82SAxel Dörfler status_t 324727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint, 325727ad0b0SHugo Santos const sockaddr *address) 326727ad0b0SHugo Santos { 32756f097ebSOliver Tappe if (!AddressModule()->is_same_family(address)) 32856f097ebSOliver Tappe return EAFNOSUPPORT; 32956f097ebSOliver Tappe 3302b07b8e0SIngo Weinhold MutexLocker _(fLock); 331727ad0b0SHugo Santos 332727ad0b0SHugo Santos if (endpoint->IsActive()) 333727ad0b0SHugo Santos return EINVAL; 334727ad0b0SHugo Santos 335727ad0b0SHugo Santos return _BindEndpoint(endpoint, address); 336727ad0b0SHugo Santos } 337727ad0b0SHugo Santos 338727ad0b0SHugo Santos 339727ad0b0SHugo Santos status_t 340727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint, 341727ad0b0SHugo Santos const sockaddr *address) 342727ad0b0SHugo Santos { 3432b07b8e0SIngo Weinhold MutexLocker _(fLock); 344727ad0b0SHugo Santos 345727ad0b0SHugo Santos if (endpoint->IsActive()) { 346727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 347727ad0b0SHugo Santos endpoint->SetActive(false); 348727ad0b0SHugo Santos } 349727ad0b0SHugo Santos 350727ad0b0SHugo Santos if (address->sa_family == AF_UNSPEC) { 351727ad0b0SHugo Santos // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect", 352727ad0b0SHugo Santos // so we reset the peer address: 353727ad0b0SHugo Santos endpoint->PeerAddress().SetToEmpty(); 354727ad0b0SHugo Santos } else { 35556f097ebSOliver Tappe if (!AddressModule()->is_same_family(address)) 35656f097ebSOliver Tappe return EAFNOSUPPORT; 35756f097ebSOliver Tappe 35856f097ebSOliver Tappe // consider destination address INADDR_ANY as INADDR_LOOPBACK 35956f097ebSOliver Tappe sockaddr_storage _address; 36056f097ebSOliver Tappe if (AddressModule()->is_empty_address(address, false)) { 36156f097ebSOliver Tappe AddressModule()->get_loopback_address((sockaddr *)&_address); 36256f097ebSOliver Tappe // for IPv4 and IPv6 the port is at the same offset 36356f097ebSOliver Tappe ((sockaddr_in&)_address).sin_port 36456f097ebSOliver Tappe = ((sockaddr_in *)address)->sin_port; 36556f097ebSOliver Tappe address = (sockaddr *)&_address; 36656f097ebSOliver Tappe } 36756f097ebSOliver Tappe 368727ad0b0SHugo Santos status_t status = endpoint->PeerAddress().SetTo(address); 369727ad0b0SHugo Santos if (status < B_OK) 370727ad0b0SHugo Santos return status; 3714e45de0eSOliver Tappe struct net_route *routeToDestination 3724e45de0eSOliver Tappe = gDatalinkModule->get_route(fDomain, address); 3734e45de0eSOliver Tappe if (routeToDestination) { 374184fada4SPhilippe Houdoin // stay bound to current local port, if any. 375184fada4SPhilippe Houdoin uint16 port = endpoint->LocalAddress().Port(); 3764e45de0eSOliver Tappe status = endpoint->LocalAddress().SetTo( 37761729d93SAxel Dörfler routeToDestination->interface_address->local); 378184fada4SPhilippe Houdoin endpoint->LocalAddress().SetPort(port); 3794e45de0eSOliver Tappe gDatalinkModule->put_route(fDomain, routeToDestination); 3804e45de0eSOliver Tappe if (status < B_OK) 3814e45de0eSOliver Tappe return status; 3824e45de0eSOliver Tappe } 383727ad0b0SHugo Santos } 384727ad0b0SHugo Santos 385727ad0b0SHugo Santos // we need to activate no matter whether or not we have just disconnected, 386727ad0b0SHugo Santos // as calling connect() always triggers an implicit bind(): 387*a03ed4faSJérôme Duval status_t status = _BindEndpoint(endpoint, *endpoint->LocalAddress()); 388*a03ed4faSJérôme Duval if (status == B_OK) 389*a03ed4faSJérôme Duval gSocketModule->set_connected(endpoint->Socket()); 390*a03ed4faSJérôme Duval return status; 391727ad0b0SHugo Santos } 392727ad0b0SHugo Santos 393727ad0b0SHugo Santos 394727ad0b0SHugo Santos status_t 395727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint) 396727ad0b0SHugo Santos { 3972b07b8e0SIngo Weinhold MutexLocker _(fLock); 398727ad0b0SHugo Santos 399727ad0b0SHugo Santos if (endpoint->IsActive()) 400727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 401727ad0b0SHugo Santos 402727ad0b0SHugo Santos endpoint->SetActive(false); 403727ad0b0SHugo Santos 404727ad0b0SHugo Santos return B_OK; 405727ad0b0SHugo Santos } 406727ad0b0SHugo Santos 407727ad0b0SHugo Santos 408cf5d9f4bSHugo Santos void 409cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const 410cf5d9f4bSHugo Santos { 411cf5d9f4bSHugo Santos kprintf("-------- UDP Domain %p ---------\n", this); 412cf5d9f4bSHugo Santos kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q"); 413cf5d9f4bSHugo Santos 414cf5d9f4bSHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 415cf5d9f4bSHugo Santos 416cb99c915SAxel Dörfler while (UdpEndpoint* endpoint = it.Next()) { 417cb99c915SAxel Dörfler endpoint->Dump(); 418cf5d9f4bSHugo Santos } 419cf5d9f4bSHugo Santos } 420cf5d9f4bSHugo Santos 421cf5d9f4bSHugo Santos 422727ad0b0SHugo Santos status_t 423727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint, 424727ad0b0SHugo Santos const sockaddr *address) 425727ad0b0SHugo Santos { 426727ad0b0SHugo Santos if (AddressModule()->get_port(address) == 0) 427727ad0b0SHugo Santos return _BindToEphemeral(endpoint, address); 428727ad0b0SHugo Santos 429727ad0b0SHugo Santos return _Bind(endpoint, address); 430727ad0b0SHugo Santos } 431727ad0b0SHugo Santos 432727ad0b0SHugo Santos 433727ad0b0SHugo Santos status_t 434727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address) 435727ad0b0SHugo Santos { 436727ad0b0SHugo Santos int socketOptions = endpoint->Socket()->options; 43740bbf860SHugo Santos 43840bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 439bf48e753SHugo Santos 440bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind 441bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]): 442727ad0b0SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain, 443727ad0b0SHugo Santos address, true).Data()); 444727ad0b0SHugo Santos 44540bbf860SHugo Santos while (it.HasNext()) { 44640bbf860SHugo Santos UdpEndpoint *otherEndpoint = it.Next(); 44725a2744fSHugo Santos 448bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint, 4495084c839SHugo Santos ntohs(otherEndpoint->LocalAddress().Port())); 45025a2744fSHugo Santos 45125a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualPorts(address)) { 452bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required: 45356f097ebSOliver Tappe if ((otherEndpoint->Socket()->options 45456f097ebSOliver Tappe & (SO_REUSEADDR | SO_REUSEPORT)) == 0 455d0eaec30SMichael Lotz || (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0) 456727ad0b0SHugo Santos return EADDRINUSE; 45725a2744fSHugo Santos 458bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required: 45925a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualTo(address, false) 460d0eaec30SMichael Lotz && ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0 461d0eaec30SMichael Lotz || (socketOptions & SO_REUSEPORT) == 0)) 462727ad0b0SHugo Santos return EADDRINUSE; 463bf48e753SHugo Santos } 464bf48e753SHugo Santos } 465bf48e753SHugo Santos 466727ad0b0SHugo Santos return _FinishBind(endpoint, address); 467bf48e753SHugo Santos } 468bf48e753SHugo Santos 469bf48e753SHugo Santos 470bf48e753SHugo Santos status_t 471727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint, 472727ad0b0SHugo Santos const sockaddr *address) 473727ad0b0SHugo Santos { 474727ad0b0SHugo Santos SocketAddressStorage newAddress(AddressModule()); 475727ad0b0SHugo Santos status_t status = newAddress.SetTo(address); 476727ad0b0SHugo Santos if (status < B_OK) 477727ad0b0SHugo Santos return status; 478727ad0b0SHugo Santos 479727ad0b0SHugo Santos uint16 allocedPort = _GetNextEphemeral(); 480727ad0b0SHugo Santos if (allocedPort == 0) 481727ad0b0SHugo Santos return ENOBUFS; 482727ad0b0SHugo Santos 4839e051839SOliver Tappe newAddress.SetPort(htons(allocedPort)); 484727ad0b0SHugo Santos 485727ad0b0SHugo Santos return _FinishBind(endpoint, *newAddress); 486727ad0b0SHugo Santos } 487727ad0b0SHugo Santos 488727ad0b0SHugo Santos 489727ad0b0SHugo Santos status_t 490727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address) 491727ad0b0SHugo Santos { 492727ad0b0SHugo Santos status_t status = endpoint->next->module->bind(endpoint->next, address); 493727ad0b0SHugo Santos if (status < B_OK) 494727ad0b0SHugo Santos return status; 49540bbf860SHugo Santos 49640bbf860SHugo Santos fActiveEndpoints.Insert(endpoint); 497727ad0b0SHugo Santos endpoint->SetActive(true); 498727ad0b0SHugo Santos 49940bbf860SHugo Santos return B_OK; 500bf48e753SHugo Santos } 501bf48e753SHugo Santos 502bf48e753SHugo Santos 503c22d69bfSAxel Dörfler UdpEndpoint * 50440bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress, 505bbbb5592SAxel Dörfler const sockaddr *peerAddress, uint32 index) 506c22d69bfSAxel Dörfler { 5072e1729d0SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock); 5082e1729d0SAxel Dörfler 5099e051839SOliver Tappe TRACE_DOMAIN("finding Endpoint for %s <- %s", 510bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(), 511bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data()); 512c3e054c8SHugo Santos 513bbbb5592SAxel Dörfler UdpEndpoint* endpoint = fActiveEndpoints.Lookup( 514bbbb5592SAxel Dörfler std::make_pair(ourAddress, peerAddress)); 515bbbb5592SAxel Dörfler 516bbbb5592SAxel Dörfler // Make sure the bound_to_device constraint is fulfilled 517da0d7409SAxel Dörfler while (endpoint != NULL && endpoint->socket->bound_to_device != 0 518da0d7409SAxel Dörfler && index != 0 && endpoint->socket->bound_to_device != index) { 519bbbb5592SAxel Dörfler endpoint = endpoint->HashTableLink(); 520bbbb5592SAxel Dörfler if (endpoint != NULL 521bbbb5592SAxel Dörfler && (!endpoint->LocalAddress().EqualTo(ourAddress, true) 522bbbb5592SAxel Dörfler || !endpoint->PeerAddress().EqualTo(peerAddress, true))) 523bbbb5592SAxel Dörfler return NULL; 524bbbb5592SAxel Dörfler } 525bbbb5592SAxel Dörfler 526bbbb5592SAxel Dörfler return endpoint; 527c22d69bfSAxel Dörfler } 528c22d69bfSAxel Dörfler 529c22d69bfSAxel Dörfler 530c22d69bfSAxel Dörfler status_t 531bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer) 532c22d69bfSAxel Dörfler { 53379a0d252SHugo Santos sockaddr* peerAddr = buffer->source; 53479a0d252SHugo Santos sockaddr* broadcastAddr = buffer->destination; 5359d433190SAxel Dörfler uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 5369d433190SAxel Dörfler 537c22d69bfSAxel Dörfler sockaddr* mask = NULL; 53861729d93SAxel Dörfler if (buffer->interface_address != NULL) 53961729d93SAxel Dörfler mask = (sockaddr*)buffer->interface_address->mask; 540c22d69bfSAxel Dörfler 5419d433190SAxel Dörfler TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask); 542c22d69bfSAxel Dörfler 5439d433190SAxel Dörfler EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator(); 544c22d69bfSAxel Dörfler 5459d433190SAxel Dörfler while (UdpEndpoint* endpoint = iterator.Next()) { 54625a2744fSHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", 54725a2744fSHugo Santos AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); 54825a2744fSHugo Santos 549bbbb5592SAxel Dörfler if (endpoint->socket->bound_to_device != 0 550bbbb5592SAxel Dörfler && buffer->index != endpoint->socket->bound_to_device) 551bbbb5592SAxel Dörfler continue; 552bbbb5592SAxel Dörfler 5535084c839SHugo Santos if (endpoint->LocalAddress().Port() != incomingPort) { 554c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint... 555c22d69bfSAxel Dörfler continue; 556c22d69bfSAxel Dörfler } 557c22d69bfSAxel Dörfler 55825a2744fSHugo Santos if (!endpoint->PeerAddress().IsEmpty(true)) { 559c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if 560c22d69bfSAxel Dörfler // this datagram is from there: 56125a2744fSHugo Santos if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) { 562c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to 563c22d69bfSAxel Dörfler // this endpoint... 564c22d69bfSAxel Dörfler continue; 565c22d69bfSAxel Dörfler } 566c22d69bfSAxel Dörfler } 567c22d69bfSAxel Dörfler 56825a2744fSHugo Santos if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) 5699d433190SAxel Dörfler || mask == NULL || endpoint->LocalAddress().IsEmpty(false)) { 570c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint: 571c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 572c22d69bfSAxel Dörfler } 573c22d69bfSAxel Dörfler } 57440bbf860SHugo Santos 575c22d69bfSAxel Dörfler return B_OK; 576c22d69bfSAxel Dörfler } 577c22d69bfSAxel Dörfler 578c22d69bfSAxel Dörfler 579c22d69bfSAxel Dörfler status_t 580bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer* buffer) 581c22d69bfSAxel Dörfler { 582bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer); 583c22d69bfSAxel Dörfler 5842e1729d0SAxel Dörfler const sockaddr* localAddress = buffer->destination; 5852e1729d0SAxel Dörfler const sockaddr* peerAddress = buffer->source; 5862e1729d0SAxel Dörfler 5872e1729d0SAxel Dörfler // look for full (most special) match: 588bbbb5592SAxel Dörfler UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress, 589bbbb5592SAxel Dörfler buffer->index); 5902e1729d0SAxel Dörfler if (endpoint == NULL) { 5912e1729d0SAxel Dörfler // look for endpoint matching local address & port: 592bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index); 5932e1729d0SAxel Dörfler if (endpoint == NULL) { 5942e1729d0SAxel Dörfler // look for endpoint matching peer address & port and local port: 5952e1729d0SAxel Dörfler SocketAddressStorage local(AddressModule()); 5962e1729d0SAxel Dörfler local.SetToEmpty(); 5972e1729d0SAxel Dörfler local.SetPort(AddressModule()->get_port(localAddress)); 598bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index); 5992e1729d0SAxel Dörfler if (endpoint == NULL) { 6002e1729d0SAxel Dörfler // last chance: look for endpoint matching local port only: 601bbbb5592SAxel Dörfler endpoint = _FindActiveEndpoint(*local, NULL, buffer->index); 6022e1729d0SAxel Dörfler } 6032e1729d0SAxel Dörfler } 6042e1729d0SAxel Dörfler } 6052e1729d0SAxel Dörfler 6062bb43d82SAxel Dörfler if (endpoint == NULL) { 6072bb43d82SAxel Dörfler TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer); 608c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND; 6099e051839SOliver Tappe } 610c22d69bfSAxel Dörfler 611c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 612c22d69bfSAxel Dörfler return B_OK; 613c22d69bfSAxel Dörfler } 614c22d69bfSAxel Dörfler 615c22d69bfSAxel Dörfler 616bf48e753SHugo Santos uint16 617bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral() 618c22d69bfSAxel Dörfler { 61940bbf860SHugo Santos uint16 stop, curr; 620bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) { 621bf48e753SHugo Santos stop = fLastUsedEphemeral; 622bf48e753SHugo Santos curr = fLastUsedEphemeral + 1; 623bf48e753SHugo Santos } else { 624bf48e753SHugo Santos stop = kLast; 625bf48e753SHugo Santos curr = kFirst; 626bf48e753SHugo Santos } 627c22d69bfSAxel Dörfler 628727ad0b0SHugo Santos TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu", 629727ad0b0SHugo Santos fLastUsedEphemeral, curr, stop); 63040bbf860SHugo Santos 6319e051839SOliver Tappe // TODO: a free list could be used to avoid the impact of these two 6329e051839SOliver Tappe // nested loops most of the time... let's see how bad this really is 633727ad0b0SHugo Santos for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) { 634bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr); 63540bbf860SHugo Santos 636727ad0b0SHugo Santos if (_EndpointWithPort(htons(curr)) == NULL) { 637bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr); 638bf48e753SHugo Santos fLastUsedEphemeral = curr; 639bf48e753SHugo Santos return curr; 640bf48e753SHugo Santos } 641727ad0b0SHugo Santos } 642727ad0b0SHugo Santos 643727ad0b0SHugo Santos return 0; 644727ad0b0SHugo Santos } 645727ad0b0SHugo Santos 646727ad0b0SHugo Santos 647727ad0b0SHugo Santos UdpEndpoint * 648727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const 649727ad0b0SHugo Santos { 650727ad0b0SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 651727ad0b0SHugo Santos 652727ad0b0SHugo Santos while (it.HasNext()) { 653727ad0b0SHugo Santos UdpEndpoint *endpoint = it.Next(); 654727ad0b0SHugo Santos if (endpoint->LocalAddress().Port() == port) 655727ad0b0SHugo Santos return endpoint; 656727ad0b0SHugo Santos } 657727ad0b0SHugo Santos 658727ad0b0SHugo Santos return NULL; 659727ad0b0SHugo Santos } 660c22d69bfSAxel Dörfler 661bf48e753SHugo Santos 662bf48e753SHugo Santos // #pragma mark - 663bf48e753SHugo Santos 664bf48e753SHugo Santos 665bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager() 666bf48e753SHugo Santos { 6672b07b8e0SIngo Weinhold mutex_init(&fLock, "UDP endpoints"); 6682b07b8e0SIngo Weinhold fStatus = B_OK; 669bf48e753SHugo Santos } 670bf48e753SHugo Santos 671bf48e753SHugo Santos 672bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 673bf48e753SHugo Santos { 6742b07b8e0SIngo Weinhold mutex_destroy(&fLock); 675bf48e753SHugo Santos } 676bf48e753SHugo Santos 677bf48e753SHugo Santos 678bf48e753SHugo Santos status_t 679bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 680bf48e753SHugo Santos { 681bf48e753SHugo Santos return fStatus; 682bf48e753SHugo Santos } 683bf48e753SHugo Santos 684bf48e753SHugo Santos 685cf5d9f4bSHugo Santos int 686cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[]) 687cf5d9f4bSHugo Santos { 688cf5d9f4bSHugo Santos UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator(); 689cf5d9f4bSHugo Santos 690eb5604bcSAdrien Destugues kprintf("===== UDP domain manager %p =====\n", sUdpEndpointManager); 691eb5604bcSAdrien Destugues 692cf5d9f4bSHugo Santos while (it.HasNext()) 693cf5d9f4bSHugo Santos it.Next()->DumpEndpoints(); 694cf5d9f4bSHugo Santos 695cf5d9f4bSHugo Santos return 0; 696cf5d9f4bSHugo Santos } 697cf5d9f4bSHugo Santos 698cf5d9f4bSHugo Santos 699bf48e753SHugo Santos // #pragma mark - inbound 700bf48e753SHugo Santos 701bf48e753SHugo Santos 702bf48e753SHugo Santos status_t 70374e1a530SJérôme Duval UdpEndpointManager::ReceiveData(net_buffer *buffer) 704c22d69bfSAxel Dörfler { 7052bb43d82SAxel Dörfler TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 7062bb43d82SAxel Dörfler 7079d433190SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomainSupport(buffer); 7082bb43d82SAxel Dörfler if (domainSupport == NULL) { 7092bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as 7102bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets. 7112bb43d82SAxel Dörfler return B_ERROR; 7122bb43d82SAxel Dörfler } 7132bb43d82SAxel Dörfler 71474e1a530SJérôme Duval status_t status = Deframe(buffer); 715eb5604bcSAdrien Destugues if (status != B_OK) { 716eb5604bcSAdrien Destugues sUdpEndpointManager->FreeEndpoint(domainSupport); 7176a606180SHugo Santos return status; 718eb5604bcSAdrien Destugues } 7196a606180SHugo Santos 7202bb43d82SAxel Dörfler status = domainSupport->DemuxIncomingBuffer(buffer); 7212bb43d82SAxel Dörfler if (status != B_OK) { 7222bb43d82SAxel Dörfler TRACE_EPM(" ReceiveData(): no endpoint."); 7232bb43d82SAxel Dörfler // Send port unreachable error 7242bb43d82SAxel Dörfler domainSupport->Domain()->module->error_reply(NULL, buffer, 7252b415445SAxel Dörfler B_NET_ERROR_UNREACH_PORT, NULL); 726eb5604bcSAdrien Destugues sUdpEndpointManager->FreeEndpoint(domainSupport); 7272bb43d82SAxel Dörfler return B_ERROR; 7282bb43d82SAxel Dörfler } 7292bb43d82SAxel Dörfler 7302bb43d82SAxel Dörfler gBufferModule->free(buffer); 731eb5604bcSAdrien Destugues sUdpEndpointManager->FreeEndpoint(domainSupport); 7322bb43d82SAxel Dörfler return B_OK; 7332bb43d82SAxel Dörfler } 7342bb43d82SAxel Dörfler 7352bb43d82SAxel Dörfler 7362bb43d82SAxel Dörfler status_t 7372bb43d82SAxel Dörfler UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) 7382bb43d82SAxel Dörfler { 7392bb43d82SAxel Dörfler TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])", 7402bb43d82SAxel Dörfler error, buffer, buffer->size); 7412bb43d82SAxel Dörfler 7422bb43d82SAxel Dörfler // We only really need the port information 7432bb43d82SAxel Dörfler if (buffer->size < 4) 7442bb43d82SAxel Dörfler return B_BAD_VALUE; 7452bb43d82SAxel Dörfler 7469d433190SAxel Dörfler UdpDomainSupport* domainSupport = _GetDomainSupport(buffer); 7472bb43d82SAxel Dörfler if (domainSupport == NULL) { 7482bb43d82SAxel Dörfler // we don't instantiate domain supports in the receiving path, as 7492bb43d82SAxel Dörfler // we are only interested in delivering data to existing sockets. 7502bb43d82SAxel Dörfler return B_ERROR; 7512bb43d82SAxel Dörfler } 7522bb43d82SAxel Dörfler 7532bb43d82SAxel Dörfler // Deframe the buffer manually, as we usually only get 8 bytes from the 7542bb43d82SAxel Dörfler // original packet 7552bb43d82SAxel Dörfler udp_header header; 7562bb43d82SAxel Dörfler if (gBufferModule->read(buffer, 0, &header, 757eb5604bcSAdrien Destugues std::min((size_t)buffer->size, sizeof(udp_header))) != B_OK) { 758eb5604bcSAdrien Destugues sUdpEndpointManager->FreeEndpoint(domainSupport); 7592bb43d82SAxel Dörfler return B_BAD_VALUE; 760eb5604bcSAdrien Destugues } 761bf48e753SHugo Santos 76261729d93SAxel Dörfler net_domain* domain = buffer->interface_address->domain; 7632bb43d82SAxel Dörfler net_address_module_info* addressModule = domain->address_module; 7646a606180SHugo Santos 7652bb43d82SAxel Dörfler SocketAddress source(addressModule, buffer->source); 7662bb43d82SAxel Dörfler SocketAddress destination(addressModule, buffer->destination); 7676a606180SHugo Santos 7682bb43d82SAxel Dörfler source.SetPort(header.source_port); 7692bb43d82SAxel Dörfler destination.SetPort(header.destination_port); 770727ad0b0SHugo Santos 771eb5604bcSAdrien Destugues error = domainSupport->DeliverError(error, buffer); 772eb5604bcSAdrien Destugues sUdpEndpointManager->FreeEndpoint(domainSupport); 773eb5604bcSAdrien Destugues return error; 7746a606180SHugo Santos } 7756a606180SHugo Santos 7766a606180SHugo Santos 7776a606180SHugo Santos status_t 77874e1a530SJérôme Duval UdpEndpointManager::Deframe(net_buffer* buffer) 7796a606180SHugo Santos { 780bf9a85cbSJérôme Duval TRACE_EPM("Deframe(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 7816a606180SHugo Santos 78287001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer); 7839d433190SAxel Dörfler if (bufferHeader.Status() != B_OK) 784c22d69bfSAxel Dörfler return bufferHeader.Status(); 785c22d69bfSAxel Dörfler 786c22d69bfSAxel Dörfler udp_header& header = bufferHeader.Data(); 787c22d69bfSAxel Dörfler 7889d433190SAxel Dörfler net_domain* domain = _GetDomain(buffer); 7899d433190SAxel Dörfler if (domain == NULL) { 7906a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " 79161729d93SAxel Dörfler "specified (interface address %p).", buffer->interface_address); 792c22d69bfSAxel Dörfler return B_BAD_VALUE; 793c22d69bfSAxel Dörfler } 794bf48e753SHugo Santos net_address_module_info* addressModule = domain->address_module; 795bf48e753SHugo Santos 79679a0d252SHugo Santos SocketAddress source(addressModule, buffer->source); 79779a0d252SHugo Santos SocketAddress destination(addressModule, buffer->destination); 798bf48e753SHugo Santos 7994e8a1b33SHugo Santos source.SetPort(header.source_port); 8004e8a1b33SHugo Santos destination.SetPort(header.destination_port); 8014e8a1b33SHugo Santos 8024e8a1b33SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(), 8034e8a1b33SHugo Santos destination.AsString(true).Data()); 804c22d69bfSAxel Dörfler 805c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length); 806c22d69bfSAxel Dörfler if (udpLength > buffer->size) { 8076a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", 808bf48e753SHugo Santos udpLength); 809c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES; 810c22d69bfSAxel Dörfler } 811bf48e753SHugo Santos 81274e1a530SJérôme Duval if (buffer->size > udpLength) 813c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength); 814c22d69bfSAxel Dörfler 815c22d69bfSAxel Dörfler if (header.udp_checksum != 0) { 816c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"): 817d5b5a2c2SHugo Santos uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule, 81874e1a530SJérôme Duval buffer, IPPROTO_UDP); 819c22d69bfSAxel Dörfler if (sum != 0) { 8206a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); 821c22d69bfSAxel Dörfler return B_BAD_VALUE; 822c22d69bfSAxel Dörfler } 823c22d69bfSAxel Dörfler } 824c22d69bfSAxel Dörfler 825c22d69bfSAxel Dörfler bufferHeader.Remove(); 826c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on 827c22d69bfSAxel Dörfler 8286a606180SHugo Santos return B_OK; 829c22d69bfSAxel Dörfler } 830c22d69bfSAxel Dörfler 831c22d69bfSAxel Dörfler 832bf48e753SHugo Santos UdpDomainSupport * 833c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) 834c22d69bfSAxel Dörfler { 8352b07b8e0SIngo Weinhold MutexLocker _(fLock); 836bf48e753SHugo Santos 8379d433190SAxel Dörfler UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true); 838bf48e753SHugo Santos if (domain) 839bf48e753SHugo Santos domain->Ref(); 840bf48e753SHugo Santos return domain; 841bf48e753SHugo Santos } 842bf48e753SHugo Santos 843bf48e753SHugo Santos 844bf48e753SHugo Santos status_t 845bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) 846bf48e753SHugo Santos { 8472b07b8e0SIngo Weinhold MutexLocker _(fLock); 848bf48e753SHugo Santos 849727ad0b0SHugo Santos if (domain->Put()) { 850bf48e753SHugo Santos fDomains.Remove(domain); 851bf48e753SHugo Santos delete domain; 852bf48e753SHugo Santos } 853bf48e753SHugo Santos 854bf48e753SHugo Santos return B_OK; 855bf48e753SHugo Santos } 856bf48e753SHugo Santos 857bf48e753SHugo Santos 858bf48e753SHugo Santos // #pragma mark - 859bf48e753SHugo Santos 860bf48e753SHugo Santos 8619d433190SAxel Dörfler inline net_domain* 8629d433190SAxel Dörfler UdpEndpointManager::_GetDomain(net_buffer* buffer) 863bf48e753SHugo Santos { 8649d433190SAxel Dörfler if (buffer->interface_address != NULL) 8659d433190SAxel Dörfler return buffer->interface_address->domain; 8669d433190SAxel Dörfler 8679d433190SAxel Dörfler return gStackModule->get_domain(buffer->destination->sa_family); 8689d433190SAxel Dörfler } 8699d433190SAxel Dörfler 8709d433190SAxel Dörfler 8719d433190SAxel Dörfler UdpDomainSupport* 8729d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create) 8739d433190SAxel Dörfler { 8749d433190SAxel Dörfler ASSERT_LOCKED_MUTEX(&fLock); 8759d433190SAxel Dörfler 8769d433190SAxel Dörfler if (domain == NULL) 8779d433190SAxel Dörfler return NULL; 878bf48e753SHugo Santos 879bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain 880bf48e753SHugo Santos // receiver handlers that forward the requests to the 881bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while 882bf48e753SHugo Santos // being constructed UdpDomainSupport could call 883bf48e753SHugo Santos // register_domain_receiving_protocol() with the right 884bf48e753SHugo Santos // family. 8859d433190SAxel Dörfler UdpDomainList::Iterator iterator = fDomains.GetIterator(); 8869d433190SAxel Dörfler while (UdpDomainSupport* domainSupport = iterator.Next()) { 887bf48e753SHugo Santos if (domainSupport->Domain() == domain) 888bf48e753SHugo Santos return domainSupport; 889bf48e753SHugo Santos } 890bf48e753SHugo Santos 891bf48e753SHugo Santos if (!create) 892bf48e753SHugo Santos return NULL; 893bf48e753SHugo Santos 8949d433190SAxel Dörfler UdpDomainSupport* domainSupport 8959d433190SAxel Dörfler = new (std::nothrow) UdpDomainSupport(domain); 896276aa463SIngo Weinhold if (domainSupport == NULL || domainSupport->Init() < B_OK) { 897bf48e753SHugo Santos delete domainSupport; 898bf48e753SHugo Santos return NULL; 899bf48e753SHugo Santos } 900bf48e753SHugo Santos 901bf48e753SHugo Santos fDomains.Add(domainSupport); 902bf48e753SHugo Santos return domainSupport; 903c22d69bfSAxel Dörfler } 904c22d69bfSAxel Dörfler 905c22d69bfSAxel Dörfler 9069d433190SAxel Dörfler /*! Retrieves the UdpDomainSupport object responsible for this buffer, if the 9079d433190SAxel Dörfler domain can be determined. This is only successful if the domain support is 9089d433190SAxel Dörfler already existing, ie. there must already be an endpoint for the domain. 9099d433190SAxel Dörfler */ 9102bb43d82SAxel Dörfler UdpDomainSupport* 9119d433190SAxel Dörfler UdpEndpointManager::_GetDomainSupport(net_buffer* buffer) 9122bb43d82SAxel Dörfler { 9132bb43d82SAxel Dörfler MutexLocker _(fLock); 9149d433190SAxel Dörfler 915eb5604bcSAdrien Destugues UdpDomainSupport* support = _GetDomainSupport(_GetDomain(buffer), false); 916eb5604bcSAdrien Destugues if (support) 917eb5604bcSAdrien Destugues support->Ref(); 918eb5604bcSAdrien Destugues return support; 9192bb43d82SAxel Dörfler } 9202bb43d82SAxel Dörfler 9212bb43d82SAxel Dörfler 922c22d69bfSAxel Dörfler // #pragma mark - 923c22d69bfSAxel Dörfler 924c22d69bfSAxel Dörfler 925c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 926cb99c915SAxel Dörfler : 927cb99c915SAxel Dörfler DatagramSocket<>("udp endpoint", socket), 928cb99c915SAxel Dörfler fActive(false) 929cb99c915SAxel Dörfler { 930cb99c915SAxel Dörfler } 931bf48e753SHugo Santos 932bf48e753SHugo Santos 933c22d69bfSAxel Dörfler // #pragma mark - activation 934c22d69bfSAxel Dörfler 935c22d69bfSAxel Dörfler 936c22d69bfSAxel Dörfler status_t 93753f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address) 938c22d69bfSAxel Dörfler { 939bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 940727ad0b0SHugo Santos return fManager->BindEndpoint(this, address); 941c22d69bfSAxel Dörfler } 942c22d69bfSAxel Dörfler 943c22d69bfSAxel Dörfler 944c22d69bfSAxel Dörfler status_t 945c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 946c22d69bfSAxel Dörfler { 947bf48e753SHugo Santos TRACE_EP("Unbind()"); 948727ad0b0SHugo Santos return fManager->UnbindEndpoint(this); 949c22d69bfSAxel Dörfler } 950c22d69bfSAxel Dörfler 951c22d69bfSAxel Dörfler 952c22d69bfSAxel Dörfler status_t 953c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 954c22d69bfSAxel Dörfler { 955bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 956727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address); 957c22d69bfSAxel Dörfler } 958c22d69bfSAxel Dörfler 959c22d69bfSAxel Dörfler 960c22d69bfSAxel Dörfler status_t 961c22d69bfSAxel Dörfler UdpEndpoint::Open() 962c22d69bfSAxel Dörfler { 963bf48e753SHugo Santos TRACE_EP("Open()"); 964bf48e753SHugo Santos 965119c6cddSIngo Weinhold AutoLocker _(fLock); 966727ad0b0SHugo Santos 967c72ab92dSHugo Santos status_t status = ProtocolSocket::Open(); 968c72ab92dSHugo Santos if (status < B_OK) 969c72ab92dSHugo Santos return status; 970bf48e753SHugo Santos 971c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this); 972c72ab92dSHugo Santos if (fManager == NULL) 973bf48e753SHugo Santos return EAFNOSUPPORT; 974bf48e753SHugo Santos 975bf48e753SHugo Santos return B_OK; 976c22d69bfSAxel Dörfler } 977c22d69bfSAxel Dörfler 978c22d69bfSAxel Dörfler 979c22d69bfSAxel Dörfler status_t 980c22d69bfSAxel Dörfler UdpEndpoint::Close() 981c22d69bfSAxel Dörfler { 982bf48e753SHugo Santos TRACE_EP("Close()"); 98383fd8a61SPawel Dziepak fSocket->error = EBADF; 98483fd8a61SPawel Dziepak WakeAll(); 985bf48e753SHugo Santos return B_OK; 986c22d69bfSAxel Dörfler } 987c22d69bfSAxel Dörfler 988c22d69bfSAxel Dörfler 989c22d69bfSAxel Dörfler status_t 990c22d69bfSAxel Dörfler UdpEndpoint::Free() 991c22d69bfSAxel Dörfler { 992bf48e753SHugo Santos TRACE_EP("Free()"); 9930086fe20SHugo Santos fManager->UnbindEndpoint(this); 994c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager); 995c22d69bfSAxel Dörfler } 996c22d69bfSAxel Dörfler 997c22d69bfSAxel Dörfler 998c22d69bfSAxel Dörfler // #pragma mark - outbound 999c22d69bfSAxel Dörfler 1000c22d69bfSAxel Dörfler 1001c22d69bfSAxel Dörfler status_t 1002bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 1003c22d69bfSAxel Dörfler { 1004bf9a85cbSJérôme Duval TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer, 1005bf9a85cbSJérôme Duval buffer->size, route); 1006bf48e753SHugo Santos 1007d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 1008c22d69bfSAxel Dörfler return EMSGSIZE; 1009c22d69bfSAxel Dörfler 101074e1a530SJérôme Duval buffer->protocol = IPPROTO_UDP; 1011c22d69bfSAxel Dörfler 1012c22d69bfSAxel Dörfler // add and fill UDP-specific header: 10136c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 10146c353509SHugo Santos if (header.Status() < B_OK) 10156c353509SHugo Santos return header.Status(); 1016c22d69bfSAxel Dörfler 101779a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source); 101879a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination); 10196c353509SHugo Santos header->udp_length = htons(buffer->size); 1020c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 10216c353509SHugo Santos header->udp_checksum = 0; 10226c353509SHugo Santos 10236c353509SHugo Santos header.Sync(); 1024c22d69bfSAxel Dörfler 1025d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(), 1026d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP); 10276c353509SHugo Santos if (calculatedChecksum == 0) 10286c353509SHugo Santos calculatedChecksum = 0xffff; 10296c353509SHugo Santos 10306c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 1031c22d69bfSAxel Dörfler 1032c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 1033c22d69bfSAxel Dörfler } 1034c22d69bfSAxel Dörfler 1035c22d69bfSAxel Dörfler 1036bf48e753SHugo Santos status_t 1037bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 1038bf48e753SHugo Santos { 1039bf9a85cbSJérôme Duval TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 1040bf48e753SHugo Santos 10412651e51dSAxel Dörfler return gDatalinkModule->send_data(this, NULL, buffer); 1042bf48e753SHugo Santos } 1043bf48e753SHugo Santos 1044bf48e753SHugo Santos 1045c22d69bfSAxel Dörfler // #pragma mark - inbound 1046c22d69bfSAxel Dörfler 1047c22d69bfSAxel Dörfler 1048c22d69bfSAxel Dörfler ssize_t 1049c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 1050c22d69bfSAxel Dörfler { 1051bfb45f71SHugo Santos size_t bytes = AvailableData(); 1052bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 1053bfb45f71SHugo Santos return bytes; 1054c22d69bfSAxel Dörfler } 1055c22d69bfSAxel Dörfler 1056c22d69bfSAxel Dörfler 1057c22d69bfSAxel Dörfler status_t 1058c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 1059c22d69bfSAxel Dörfler { 1060bf9a85cbSJérôme Duval TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags); 1061bf48e753SHugo Santos 10622651e51dSAxel Dörfler status_t status = Dequeue(flags, _buffer); 1063cb99c915SAxel Dörfler TRACE_EP(" FetchData(): returned from fifo status: %s", strerror(status)); 10642651e51dSAxel Dörfler if (status != B_OK) 1065c22d69bfSAxel Dörfler return status; 1066c22d69bfSAxel Dörfler 1067bf9a85cbSJérôme Duval TRACE_EP(" FetchData(): returns buffer with %" B_PRIu32 " bytes", 1068bf9a85cbSJérôme Duval (*_buffer)->size); 1069c22d69bfSAxel Dörfler return B_OK; 1070c22d69bfSAxel Dörfler } 1071c22d69bfSAxel Dörfler 1072c22d69bfSAxel Dörfler 1073c22d69bfSAxel Dörfler status_t 1074bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 1075c22d69bfSAxel Dörfler { 1076bf9a85cbSJérôme Duval TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); 1077c22d69bfSAxel Dörfler 10782651e51dSAxel Dörfler return EnqueueClone(buffer); 1079c22d69bfSAxel Dörfler } 1080c22d69bfSAxel Dörfler 1081c22d69bfSAxel Dörfler 10826a606180SHugo Santos status_t 10836a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 10846a606180SHugo Santos { 1085bf9a85cbSJérôme Duval TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size); 1086f6cfc5afSHugo Santos 10876a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 10886a606180SHugo Santos if (buffer == NULL) 10896a606180SHugo Santos return B_NO_MEMORY; 10906a606180SHugo Santos 109174e1a530SJérôme Duval status_t status = sUdpEndpointManager->Deframe(buffer); 10926a606180SHugo Santos if (status < B_OK) { 10936a606180SHugo Santos gBufferModule->free(buffer); 10946a606180SHugo Santos return status; 10956a606180SHugo Santos } 10966a606180SHugo Santos 10976a606180SHugo Santos return Enqueue(buffer); 10986a606180SHugo Santos } 10996a606180SHugo Santos 11006a606180SHugo Santos 1101cb99c915SAxel Dörfler void 1102cb99c915SAxel Dörfler UdpEndpoint::Dump() const 1103cb99c915SAxel Dörfler { 1104cb99c915SAxel Dörfler char local[64]; 1105cb99c915SAxel Dörfler LocalAddress().AsString(local, sizeof(local), true); 1106cb99c915SAxel Dörfler char peer[64]; 1107cb99c915SAxel Dörfler PeerAddress().AsString(peer, sizeof(peer), true); 1108cb99c915SAxel Dörfler 1109cb99c915SAxel Dörfler kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes); 1110cb99c915SAxel Dörfler } 1111cb99c915SAxel Dörfler 1112cb99c915SAxel Dörfler 1113c22d69bfSAxel Dörfler // #pragma mark - protocol interface 1114c22d69bfSAxel Dörfler 1115c22d69bfSAxel Dörfler 1116c22d69bfSAxel Dörfler net_protocol * 1117c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 1118c22d69bfSAxel Dörfler { 1119c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 1120c22d69bfSAxel Dörfler 1121c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 1122bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 1123bf48e753SHugo Santos delete endpoint; 1124bf48e753SHugo Santos return NULL; 1125bf48e753SHugo Santos } 1126bf48e753SHugo Santos 1127c22d69bfSAxel Dörfler return endpoint; 1128c22d69bfSAxel Dörfler } 1129c22d69bfSAxel Dörfler 1130c22d69bfSAxel Dörfler 1131c22d69bfSAxel Dörfler status_t 1132c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 1133c22d69bfSAxel Dörfler { 1134bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 1135c22d69bfSAxel Dörfler return B_OK; 1136c22d69bfSAxel Dörfler } 1137c22d69bfSAxel Dörfler 1138c22d69bfSAxel Dörfler 1139c22d69bfSAxel Dörfler status_t 1140c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 1141c22d69bfSAxel Dörfler { 1142bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 1143c22d69bfSAxel Dörfler } 1144c22d69bfSAxel Dörfler 1145c22d69bfSAxel Dörfler 1146c22d69bfSAxel Dörfler status_t 1147c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 1148c22d69bfSAxel Dörfler { 1149bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 1150c22d69bfSAxel Dörfler } 1151c22d69bfSAxel Dörfler 1152c22d69bfSAxel Dörfler 1153c22d69bfSAxel Dörfler status_t 1154c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 1155c22d69bfSAxel Dörfler { 1156bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 1157c22d69bfSAxel Dörfler } 1158c22d69bfSAxel Dörfler 1159c22d69bfSAxel Dörfler 1160c22d69bfSAxel Dörfler status_t 1161c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1162c22d69bfSAxel Dörfler { 1163bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1164c22d69bfSAxel Dörfler } 1165c22d69bfSAxel Dörfler 1166c22d69bfSAxel Dörfler 1167c22d69bfSAxel Dörfler status_t 1168c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1169c22d69bfSAxel Dörfler { 1170ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1171c22d69bfSAxel Dörfler } 1172c22d69bfSAxel Dörfler 1173c22d69bfSAxel Dörfler 1174c22d69bfSAxel Dörfler status_t 1175c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1176c22d69bfSAxel Dörfler size_t *_length) 1177c22d69bfSAxel Dörfler { 1178c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1179c22d69bfSAxel Dörfler value, _length); 1180c22d69bfSAxel Dörfler } 1181c22d69bfSAxel Dörfler 1182c22d69bfSAxel Dörfler 1183c22d69bfSAxel Dörfler status_t 118445b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value, 118545b5203bSHugo Santos int *length) 118645b5203bSHugo Santos { 118745b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option, 118845b5203bSHugo Santos value, length); 118945b5203bSHugo Santos } 119045b5203bSHugo Santos 119145b5203bSHugo Santos 119245b5203bSHugo Santos status_t 119345b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option, 119445b5203bSHugo Santos const void *value, int length) 119545b5203bSHugo Santos { 119645b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option, 119745b5203bSHugo Santos value, length); 119845b5203bSHugo Santos } 119945b5203bSHugo Santos 120045b5203bSHugo Santos 120145b5203bSHugo Santos status_t 120253f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address) 1203c22d69bfSAxel Dörfler { 1204bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1205c22d69bfSAxel Dörfler } 1206c22d69bfSAxel Dörfler 1207c22d69bfSAxel Dörfler 1208c22d69bfSAxel Dörfler status_t 1209c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1210c22d69bfSAxel Dörfler { 1211bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1212c22d69bfSAxel Dörfler } 1213c22d69bfSAxel Dörfler 1214c22d69bfSAxel Dörfler 1215c22d69bfSAxel Dörfler status_t 1216c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1217c22d69bfSAxel Dörfler { 1218ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1219c22d69bfSAxel Dörfler } 1220c22d69bfSAxel Dörfler 1221c22d69bfSAxel Dörfler 1222c22d69bfSAxel Dörfler status_t 1223c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1224c22d69bfSAxel Dörfler { 1225ca215dfeSAxel Dörfler return B_NOT_SUPPORTED; 1226c22d69bfSAxel Dörfler } 1227c22d69bfSAxel Dörfler 1228c22d69bfSAxel Dörfler 1229c22d69bfSAxel Dörfler status_t 1230c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1231c22d69bfSAxel Dörfler net_buffer *buffer) 1232c22d69bfSAxel Dörfler { 1233bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1234c22d69bfSAxel Dörfler } 1235c22d69bfSAxel Dörfler 1236c22d69bfSAxel Dörfler 1237c22d69bfSAxel Dörfler status_t 1238c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1239c22d69bfSAxel Dörfler { 1240bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1241c22d69bfSAxel Dörfler } 1242c22d69bfSAxel Dörfler 1243c22d69bfSAxel Dörfler 1244c22d69bfSAxel Dörfler ssize_t 1245c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1246c22d69bfSAxel Dörfler { 1247bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1248c22d69bfSAxel Dörfler } 1249c22d69bfSAxel Dörfler 1250c22d69bfSAxel Dörfler 1251c22d69bfSAxel Dörfler status_t 1252c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1253c22d69bfSAxel Dörfler net_buffer **_buffer) 1254c22d69bfSAxel Dörfler { 1255bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1256c22d69bfSAxel Dörfler } 1257c22d69bfSAxel Dörfler 1258c22d69bfSAxel Dörfler 1259c22d69bfSAxel Dörfler ssize_t 1260c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1261c22d69bfSAxel Dörfler { 1262bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1263c22d69bfSAxel Dörfler } 1264c22d69bfSAxel Dörfler 1265c22d69bfSAxel Dörfler 1266c22d69bfSAxel Dörfler struct net_domain * 1267c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1268c22d69bfSAxel Dörfler { 1269c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1270c22d69bfSAxel Dörfler } 1271c22d69bfSAxel Dörfler 1272c22d69bfSAxel Dörfler 1273c22d69bfSAxel Dörfler size_t 1274c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1275c22d69bfSAxel Dörfler { 1276c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1277c22d69bfSAxel Dörfler } 1278c22d69bfSAxel Dörfler 1279c22d69bfSAxel Dörfler 1280c22d69bfSAxel Dörfler status_t 1281c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1282c22d69bfSAxel Dörfler { 1283c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1284c22d69bfSAxel Dörfler } 1285c22d69bfSAxel Dörfler 1286c22d69bfSAxel Dörfler 1287c22d69bfSAxel Dörfler status_t 12886a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 12896a606180SHugo Santos { 12906a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 12916a606180SHugo Santos } 12926a606180SHugo Santos 12936a606180SHugo Santos 12946a606180SHugo Santos status_t 12952b415445SAxel Dörfler udp_error_received(net_error error, net_buffer* buffer) 1296c22d69bfSAxel Dörfler { 12972b415445SAxel Dörfler status_t notifyError = B_OK; 12982bb43d82SAxel Dörfler 12992b415445SAxel Dörfler switch (error) { 13002b415445SAxel Dörfler case B_NET_ERROR_UNREACH_NET: 13012b415445SAxel Dörfler notifyError = ENETUNREACH; 13022bb43d82SAxel Dörfler break; 13032b415445SAxel Dörfler case B_NET_ERROR_UNREACH_HOST: 13042b415445SAxel Dörfler case B_NET_ERROR_TRANSIT_TIME_EXCEEDED: 13052b415445SAxel Dörfler notifyError = EHOSTUNREACH; 13062bb43d82SAxel Dörfler break; 13072b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PROTOCOL: 13082b415445SAxel Dörfler case B_NET_ERROR_UNREACH_PORT: 13092b415445SAxel Dörfler notifyError = ECONNREFUSED; 13102bb43d82SAxel Dörfler break; 13112b415445SAxel Dörfler case B_NET_ERROR_MESSAGE_SIZE: 13122b415445SAxel Dörfler notifyError = EMSGSIZE; 13132b415445SAxel Dörfler break; 13142b415445SAxel Dörfler case B_NET_ERROR_PARAMETER_PROBLEM: 13152b415445SAxel Dörfler notifyError = ENOPROTOOPT; 13162b415445SAxel Dörfler break; 13172b415445SAxel Dörfler 13182b415445SAxel Dörfler case B_NET_ERROR_QUENCH: 13192bb43d82SAxel Dörfler default: 13202bb43d82SAxel Dörfler // ignore them 13212bb43d82SAxel Dörfler gBufferModule->free(buffer); 13222bb43d82SAxel Dörfler return B_OK; 1323c22d69bfSAxel Dörfler } 1324c22d69bfSAxel Dörfler 13257e046eabSAxel Dörfler ASSERT(notifyError != B_OK); 13267e046eabSAxel Dörfler 13277e046eabSAxel Dörfler return sUdpEndpointManager->ReceiveError(notifyError, buffer); 13287e046eabSAxel Dörfler } 13297e046eabSAxel Dörfler 1330c22d69bfSAxel Dörfler 1331c22d69bfSAxel Dörfler status_t 13322b415445SAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error, 13332b415445SAxel Dörfler net_error_data *errorData) 1334c22d69bfSAxel Dörfler { 1335c22d69bfSAxel Dörfler return B_ERROR; 1336c22d69bfSAxel Dörfler } 1337c22d69bfSAxel Dörfler 1338c22d69bfSAxel Dörfler 133978888c44SAxel Dörfler ssize_t 134078888c44SAxel Dörfler udp_process_ancillary_data_no_container(net_protocol *protocol, 134178888c44SAxel Dörfler net_buffer* buffer, void *data, size_t dataSize) 134278888c44SAxel Dörfler { 134378888c44SAxel Dörfler return protocol->next->module->process_ancillary_data_no_container( 134478888c44SAxel Dörfler protocol, buffer, data, dataSize); 134578888c44SAxel Dörfler } 134678888c44SAxel Dörfler 134778888c44SAxel Dörfler 1348c22d69bfSAxel Dörfler // #pragma mark - module interface 1349c22d69bfSAxel Dörfler 1350c22d69bfSAxel Dörfler 1351c22d69bfSAxel Dörfler static status_t 1352c22d69bfSAxel Dörfler init_udp() 1353c22d69bfSAxel Dörfler { 1354c22d69bfSAxel Dörfler status_t status; 1355bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1356c22d69bfSAxel Dörfler 1357c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1358658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1359658a5506SHugo Santos return B_NO_MEMORY; 1360658a5506SHugo Santos 1361c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1362c22d69bfSAxel Dörfler if (status != B_OK) 1363d438fa4cSHugo Santos goto err1; 1364c22d69bfSAxel Dörfler 136561729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 136661729d93SAxel Dörfler IPPROTO_IP, 1367c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1368c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1369c22d69bfSAxel Dörfler NULL); 1370c22d69bfSAxel Dörfler if (status < B_OK) 1371658a5506SHugo Santos goto err1; 137261729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 137361729d93SAxel Dörfler IPPROTO_IP, 13748d1485faSAxel Dörfler "network/protocols/udp/v1", 13758d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13768d1485faSAxel Dörfler NULL); 13778d1485faSAxel Dörfler if (status < B_OK) 13788d1485faSAxel Dörfler goto err1; 13798d1485faSAxel Dörfler 138061729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, 138161729d93SAxel Dörfler IPPROTO_UDP, 1382c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1383c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1384c22d69bfSAxel Dörfler NULL); 1385c22d69bfSAxel Dörfler if (status < B_OK) 1386658a5506SHugo Santos goto err1; 138761729d93SAxel Dörfler status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, 138861729d93SAxel Dörfler IPPROTO_UDP, 13898d1485faSAxel Dörfler "network/protocols/udp/v1", 13908d1485faSAxel Dörfler "network/protocols/ipv6/v1", 13918d1485faSAxel Dörfler NULL); 13928d1485faSAxel Dörfler if (status < B_OK) 13938d1485faSAxel Dörfler goto err1; 1394c22d69bfSAxel Dörfler 139561729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET, 139661729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 1397c22d69bfSAxel Dörfler if (status < B_OK) 1398658a5506SHugo Santos goto err1; 139961729d93SAxel Dörfler status = gStackModule->register_domain_receiving_protocol(AF_INET6, 140061729d93SAxel Dörfler IPPROTO_UDP, "network/protocols/udp/v1"); 14018d1485faSAxel Dörfler if (status < B_OK) 14028d1485faSAxel Dörfler goto err1; 1403c22d69bfSAxel Dörfler 1404cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints, 1405cf5d9f4bSHugo Santos "lists all open UDP endpoints"); 1406cf5d9f4bSHugo Santos 1407c22d69bfSAxel Dörfler return B_OK; 1408c22d69bfSAxel Dörfler 1409c22d69bfSAxel Dörfler err1: 14108d1485faSAxel Dörfler // TODO: shouldn't unregister the protocols here? 1411658a5506SHugo Santos delete sUdpEndpointManager; 1412c22d69bfSAxel Dörfler 1413bf9a85cbSJérôme Duval TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status, 1414bf9a85cbSJérôme Duval strerror(status)); 1415c22d69bfSAxel Dörfler return status; 1416c22d69bfSAxel Dörfler } 1417c22d69bfSAxel Dörfler 1418c22d69bfSAxel Dörfler 1419c22d69bfSAxel Dörfler static status_t 1420c22d69bfSAxel Dörfler uninit_udp() 1421c22d69bfSAxel Dörfler { 1422bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1423cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints", 1424cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints); 1425c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1426c22d69bfSAxel Dörfler return B_OK; 1427c22d69bfSAxel Dörfler } 1428c22d69bfSAxel Dörfler 1429c22d69bfSAxel Dörfler 1430c22d69bfSAxel Dörfler static status_t 1431c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1432c22d69bfSAxel Dörfler { 1433c22d69bfSAxel Dörfler switch (op) { 1434c22d69bfSAxel Dörfler case B_MODULE_INIT: 1435c22d69bfSAxel Dörfler return init_udp(); 1436c22d69bfSAxel Dörfler 1437c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1438c22d69bfSAxel Dörfler return uninit_udp(); 1439c22d69bfSAxel Dörfler 1440c22d69bfSAxel Dörfler default: 1441c22d69bfSAxel Dörfler return B_ERROR; 1442c22d69bfSAxel Dörfler } 1443c22d69bfSAxel Dörfler } 1444c22d69bfSAxel Dörfler 1445c22d69bfSAxel Dörfler 1446c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1447c22d69bfSAxel Dörfler { 1448c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1449c22d69bfSAxel Dörfler 0, 1450c22d69bfSAxel Dörfler udp_std_ops 1451c22d69bfSAxel Dörfler }, 14526f58064fSAxel Dörfler NET_PROTOCOL_ATOMIC_MESSAGES, 14536f58064fSAxel Dörfler 1454c22d69bfSAxel Dörfler udp_init_protocol, 1455c22d69bfSAxel Dörfler udp_uninit_protocol, 1456c22d69bfSAxel Dörfler udp_open, 1457c22d69bfSAxel Dörfler udp_close, 1458c22d69bfSAxel Dörfler udp_free, 1459c22d69bfSAxel Dörfler udp_connect, 1460c22d69bfSAxel Dörfler udp_accept, 1461c22d69bfSAxel Dörfler udp_control, 146245b5203bSHugo Santos udp_getsockopt, 146345b5203bSHugo Santos udp_setsockopt, 1464c22d69bfSAxel Dörfler udp_bind, 1465c22d69bfSAxel Dörfler udp_unbind, 1466c22d69bfSAxel Dörfler udp_listen, 1467c22d69bfSAxel Dörfler udp_shutdown, 1468c22d69bfSAxel Dörfler udp_send_data, 1469c22d69bfSAxel Dörfler udp_send_routed_data, 1470c22d69bfSAxel Dörfler udp_send_avail, 1471c22d69bfSAxel Dörfler udp_read_data, 1472c22d69bfSAxel Dörfler udp_read_avail, 1473c22d69bfSAxel Dörfler udp_get_domain, 1474c22d69bfSAxel Dörfler udp_get_mtu, 1475c22d69bfSAxel Dörfler udp_receive_data, 14766a606180SHugo Santos udp_deliver_data, 14772bb43d82SAxel Dörfler udp_error_received, 1478c22d69bfSAxel Dörfler udp_error_reply, 14799871124eSAxel Dörfler NULL, // add_ancillary_data() 14809871124eSAxel Dörfler NULL, // process_ancillary_data() 148178888c44SAxel Dörfler udp_process_ancillary_data_no_container, 14829871124eSAxel Dörfler NULL, // send_data_no_buffer() 14839871124eSAxel Dörfler NULL // read_data_no_buffer() 1484c22d69bfSAxel Dörfler }; 1485c22d69bfSAxel Dörfler 1486658a5506SHugo Santos module_dependency module_dependencies[] = { 1487658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1488658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1489658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 14902bb43d82SAxel Dörfler {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule}, 1491658a5506SHugo Santos {} 1492658a5506SHugo Santos }; 1493658a5506SHugo Santos 1494c22d69bfSAxel Dörfler module_info *modules[] = { 1495c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1496c22d69bfSAxel Dörfler NULL 1497c22d69bfSAxel Dörfler }; 1498