1c22d69bfSAxel Dörfler /* 2c3e054c8SHugo Santos * Copyright 2006-2007, 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 27c22d69bfSAxel Dörfler #include <netinet/in.h> 28c22d69bfSAxel Dörfler #include <new> 29c22d69bfSAxel Dörfler #include <stdlib.h> 30c22d69bfSAxel Dörfler #include <string.h> 31c3e054c8SHugo Santos #include <utility> 32c22d69bfSAxel Dörfler 33727ad0b0SHugo Santos 34727ad0b0SHugo Santos // NOTE the locking protocol dictates that we must hold UdpDomainSupport's 35727ad0b0SHugo Santos // lock before holding a child UdpEndpoint's lock. This restriction 36727ad0b0SHugo Santos // is dictated by the receive path as blind access to the endpoint 37727ad0b0SHugo Santos // hash is required when holding the DomainSuppport's lock. 38727ad0b0SHugo Santos 39727ad0b0SHugo Santos 40af3a31f7SAxel Dörfler //#define TRACE_UDP 41c22d69bfSAxel Dörfler #ifdef TRACE_UDP 42c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) dump_block x 43bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this 44bf48e753SHugo Santos // to compile with gcc 2.95 45bf48e753SHugo Santos # define TRACE_EP(format, args...) dprintf("UDP [%llu] %p " format "\n", \ 46bf48e753SHugo Santos system_time(), this , ##args) 47bf48e753SHugo Santos # define TRACE_EPM(format, args...) dprintf("UDP [%llu] " format "\n", \ 48bf48e753SHugo Santos system_time() , ##args) 49bf48e753SHugo Santos # define TRACE_DOMAIN(format, args...) dprintf("UDP [%llu] (%d) " format \ 50bf48e753SHugo Santos "\n", system_time(), Domain()->family , ##args) 51c22d69bfSAxel Dörfler #else 52c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) 53bf48e753SHugo Santos # define TRACE_EP(args...) do { } while (0) 54bf48e753SHugo Santos # define TRACE_EPM(args...) do { } while (0) 55bf48e753SHugo Santos # define TRACE_DOMAIN(args...) do { } while (0) 56c22d69bfSAxel Dörfler #endif 57c22d69bfSAxel Dörfler 58c22d69bfSAxel Dörfler 59c22d69bfSAxel Dörfler struct udp_header { 60c22d69bfSAxel Dörfler uint16 source_port; 61c22d69bfSAxel Dörfler uint16 destination_port; 62c22d69bfSAxel Dörfler uint16 udp_length; 63c22d69bfSAxel Dörfler uint16 udp_checksum; 64c22d69bfSAxel Dörfler } _PACKED; 65c22d69bfSAxel Dörfler 66c22d69bfSAxel Dörfler 676c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)> 686c353509SHugo Santos UDPChecksumField; 696c353509SHugo Santos 70bf48e753SHugo Santos class UdpDomainSupport; 716c353509SHugo Santos 72bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> { 73c22d69bfSAxel Dörfler public: 74c22d69bfSAxel Dörfler UdpEndpoint(net_socket *socket); 75bf48e753SHugo Santos 7653f23f85SHugo Santos status_t Bind(const sockaddr *newAddr); 77c22d69bfSAxel Dörfler status_t Unbind(sockaddr *newAddr); 78c22d69bfSAxel Dörfler status_t Connect(const sockaddr *newAddr); 79c22d69bfSAxel Dörfler 80c22d69bfSAxel Dörfler status_t Open(); 81c22d69bfSAxel Dörfler status_t Close(); 82c22d69bfSAxel Dörfler status_t Free(); 83c22d69bfSAxel Dörfler 84bf48e753SHugo Santos status_t SendRoutedData(net_buffer *buffer, net_route *route); 85bf48e753SHugo Santos status_t SendData(net_buffer *buffer); 86c22d69bfSAxel Dörfler 87c22d69bfSAxel Dörfler ssize_t BytesAvailable(); 88c22d69bfSAxel Dörfler status_t FetchData(size_t numBytes, uint32 flags, 89c22d69bfSAxel Dörfler net_buffer **_buffer); 90c22d69bfSAxel Dörfler 91c22d69bfSAxel Dörfler status_t StoreData(net_buffer *buffer); 926a606180SHugo Santos status_t DeliverData(net_buffer *buffer); 93c22d69bfSAxel Dörfler 94727ad0b0SHugo Santos // only the domain support will change/check the Active flag so 95727ad0b0SHugo Santos // we don't really need to protect it with the socket lock. 96727ad0b0SHugo Santos bool IsActive() const { return fActive; } 97727ad0b0SHugo Santos void SetActive(bool newValue) { fActive = newValue; } 98bf48e753SHugo Santos 9940bbf860SHugo Santos HashTableLink<UdpEndpoint> *HashTableLink() { return &fLink; } 10040bbf860SHugo Santos 101c22d69bfSAxel Dörfler private: 102c72ab92dSHugo Santos UdpDomainSupport *fManager; 103c22d69bfSAxel Dörfler bool fActive; 104c22d69bfSAxel Dörfler // an active UdpEndpoint is part of the endpoint 105c22d69bfSAxel Dörfler // hash (and it is bound and optionally connected) 10640bbf860SHugo Santos 10740bbf860SHugo Santos ::HashTableLink<UdpEndpoint> fLink; 10840bbf860SHugo Santos }; 10940bbf860SHugo Santos 11040bbf860SHugo Santos 11140bbf860SHugo Santos class UdpDomainSupport; 11240bbf860SHugo Santos 11340bbf860SHugo Santos struct UdpHashDefinition { 11440bbf860SHugo Santos typedef net_address_module_info ParentType; 11540bbf860SHugo Santos typedef std::pair<const sockaddr *, const sockaddr *> KeyType; 11640bbf860SHugo Santos typedef UdpEndpoint ValueType; 11740bbf860SHugo Santos 11840bbf860SHugo Santos UdpHashDefinition(net_address_module_info *parent) 11940bbf860SHugo Santos : module(parent) {} 12040bbf860SHugo Santos 12140bbf860SHugo Santos size_t HashKey(const KeyType &key) const 12240bbf860SHugo Santos { 12340bbf860SHugo Santos return _Mix(module->hash_address_pair(key.first, key.second)); 12440bbf860SHugo Santos } 12540bbf860SHugo Santos 12640bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const 12740bbf860SHugo Santos { 12840bbf860SHugo Santos return _Mix(endpoint->LocalAddress().HashPair(*endpoint->PeerAddress())); 12940bbf860SHugo Santos } 13040bbf860SHugo Santos 13140bbf860SHugo Santos static size_t _Mix(size_t hash) 13240bbf860SHugo Santos { 13340bbf860SHugo Santos // move the bits into the relevant range (as defined by kNumHashBuckets): 13440bbf860SHugo Santos return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11 13540bbf860SHugo Santos ^ (hash & 0xFFC00000UL) >> 22; 13640bbf860SHugo Santos } 13740bbf860SHugo Santos 13840bbf860SHugo Santos bool Compare(const KeyType &key, UdpEndpoint *endpoint) const 13940bbf860SHugo Santos { 14040bbf860SHugo Santos return endpoint->LocalAddress().EqualTo(key.first, true) 14140bbf860SHugo Santos && endpoint->PeerAddress().EqualTo(key.second, true); 14240bbf860SHugo Santos } 14340bbf860SHugo Santos 14440bbf860SHugo Santos HashTableLink<UdpEndpoint> *GetLink(UdpEndpoint *endpoint) const 14540bbf860SHugo Santos { 14640bbf860SHugo Santos return endpoint->HashTableLink(); 14740bbf860SHugo Santos } 14840bbf860SHugo Santos 14940bbf860SHugo Santos net_address_module_info *module; 150c22d69bfSAxel Dörfler }; 151c22d69bfSAxel Dörfler 152c22d69bfSAxel Dörfler 153bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> { 154c22d69bfSAxel Dörfler public: 155bf48e753SHugo Santos UdpDomainSupport(net_domain *domain); 156727ad0b0SHugo Santos ~UdpDomainSupport(); 157c22d69bfSAxel Dörfler 158bf48e753SHugo Santos status_t InitCheck() const; 159bf48e753SHugo Santos 160bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 161bf48e753SHugo Santos 162bf48e753SHugo Santos void Ref() { fEndpointCount++; } 163727ad0b0SHugo Santos bool Put() { fEndpointCount--; return fEndpointCount == 0; } 164bf48e753SHugo Santos 165bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer *buffer); 166727ad0b0SHugo Santos 167727ad0b0SHugo Santos status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 168727ad0b0SHugo Santos status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 169727ad0b0SHugo Santos status_t UnbindEndpoint(UdpEndpoint *endpoint); 170727ad0b0SHugo Santos 171cf5d9f4bSHugo Santos void DumpEndpoints() const; 172bf48e753SHugo Santos 173c22d69bfSAxel Dörfler private: 174727ad0b0SHugo Santos status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 175727ad0b0SHugo Santos status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address); 176727ad0b0SHugo Santos status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address); 177727ad0b0SHugo Santos status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address); 178727ad0b0SHugo Santos 17940bbf860SHugo Santos UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress, 18040bbf860SHugo Santos const sockaddr *peerAddress); 181bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer); 182bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer); 183bf48e753SHugo Santos 184bf48e753SHugo Santos uint16 _GetNextEphemeral(); 185727ad0b0SHugo Santos UdpEndpoint *_EndpointWithPort(uint16 port) const; 186bf48e753SHugo Santos 187bf48e753SHugo Santos net_address_module_info *AddressModule() const 188727ad0b0SHugo Santos { return fDomain->address_module; } 189bf48e753SHugo Santos 19040bbf860SHugo Santos typedef OpenHashTable<UdpHashDefinition, false> EndpointTable; 19140bbf860SHugo Santos 192727ad0b0SHugo Santos benaphore fLock; 193bf48e753SHugo Santos net_domain *fDomain; 194bf48e753SHugo Santos uint16 fLastUsedEphemeral; 19540bbf860SHugo Santos EndpointTable fActiveEndpoints; 196bf48e753SHugo Santos uint32 fEndpointCount; 197bf48e753SHugo Santos 198bf48e753SHugo Santos static const uint16 kFirst = 49152; 199bf48e753SHugo Santos static const uint16 kLast = 65535; 200bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800; 201bf48e753SHugo Santos // if you change this, adjust the shifting in 202bf48e753SHugo Santos // Hash() accordingly! 203bf48e753SHugo Santos }; 204bf48e753SHugo Santos 205bf48e753SHugo Santos 206bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList; 207bf48e753SHugo Santos 208bf48e753SHugo Santos 209bf48e753SHugo Santos class UdpEndpointManager { 210c22d69bfSAxel Dörfler public: 211c22d69bfSAxel Dörfler UdpEndpointManager(); 212c22d69bfSAxel Dörfler ~UdpEndpointManager(); 213c22d69bfSAxel Dörfler 214c22d69bfSAxel Dörfler status_t ReceiveData(net_buffer *buffer); 2156a606180SHugo Santos status_t Deframe(net_buffer *buffer); 216c22d69bfSAxel Dörfler 217bf48e753SHugo Santos UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint); 218bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport *domain); 219c22d69bfSAxel Dörfler 220c22d69bfSAxel Dörfler status_t InitCheck() const; 221bf48e753SHugo Santos 222cf5d9f4bSHugo Santos static int DumpEndpoints(int argc, char *argv[]); 223cf5d9f4bSHugo Santos 224c22d69bfSAxel Dörfler private: 225bf48e753SHugo Santos UdpDomainSupport *_GetDomain(net_domain *domain, bool create); 226bf48e753SHugo Santos 227c22d69bfSAxel Dörfler benaphore fLock; 228c22d69bfSAxel Dörfler status_t fStatus; 229bf48e753SHugo Santos UdpDomainList fDomains; 230c22d69bfSAxel Dörfler }; 231c22d69bfSAxel Dörfler 232c22d69bfSAxel Dörfler 233c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager; 234c22d69bfSAxel Dörfler 235c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule; 236658a5506SHugo Santos net_datalink_module_info *gDatalinkModule; 237658a5506SHugo Santos net_stack_module_info *gStackModule; 238c22d69bfSAxel Dörfler 239c22d69bfSAxel Dörfler 240c22d69bfSAxel Dörfler // #pragma mark - 241c22d69bfSAxel Dörfler 242c22d69bfSAxel Dörfler 243bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain) 244c22d69bfSAxel Dörfler : 245bf48e753SHugo Santos fDomain(domain), 24640bbf860SHugo Santos fActiveEndpoints(domain->address_module, kNumHashBuckets), 247bf48e753SHugo Santos fEndpointCount(0) 248c22d69bfSAxel Dörfler { 249727ad0b0SHugo Santos benaphore_init(&fLock, "udp domain"); 250727ad0b0SHugo Santos 251727ad0b0SHugo Santos fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst); 252727ad0b0SHugo Santos } 253727ad0b0SHugo Santos 254727ad0b0SHugo Santos 255727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport() 256727ad0b0SHugo Santos { 257727ad0b0SHugo Santos benaphore_destroy(&fLock); 258bf48e753SHugo Santos } 259bf48e753SHugo Santos 260bf48e753SHugo Santos 261bf48e753SHugo Santos status_t 262bf48e753SHugo Santos UdpDomainSupport::InitCheck() const 263bf48e753SHugo Santos { 264727ad0b0SHugo Santos if (fLock.sem < B_OK) 265727ad0b0SHugo Santos return fLock.sem; 266727ad0b0SHugo Santos 26740bbf860SHugo Santos return fActiveEndpoints.InitCheck(); 268bf48e753SHugo Santos } 269bf48e753SHugo Santos 270bf48e753SHugo Santos 271bf48e753SHugo Santos status_t 272bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer) 273bf48e753SHugo Santos { 274727ad0b0SHugo Santos // NOTE multicast is delivered directly to the endpoint 275727ad0b0SHugo Santos 276727ad0b0SHugo Santos BenaphoreLocker _(fLock); 277727ad0b0SHugo Santos 278bf48e753SHugo Santos if (buffer->flags & MSG_BCAST) 279bf48e753SHugo Santos return _DemuxBroadcast(buffer); 280bf48e753SHugo Santos else if (buffer->flags & MSG_MCAST) 281727ad0b0SHugo Santos return B_ERROR; 282bf48e753SHugo Santos 283bf48e753SHugo Santos return _DemuxUnicast(buffer); 284bf48e753SHugo Santos } 285bf48e753SHugo Santos 286bf48e753SHugo Santos 287bf48e753SHugo Santos status_t 288727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint, 289727ad0b0SHugo Santos const sockaddr *address) 290727ad0b0SHugo Santos { 291727ad0b0SHugo Santos BenaphoreLocker _(fLock); 292727ad0b0SHugo Santos 293727ad0b0SHugo Santos if (endpoint->IsActive()) 294727ad0b0SHugo Santos return EINVAL; 295727ad0b0SHugo Santos 296727ad0b0SHugo Santos return _BindEndpoint(endpoint, address); 297727ad0b0SHugo Santos } 298727ad0b0SHugo Santos 299727ad0b0SHugo Santos 300727ad0b0SHugo Santos status_t 301727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint, 302727ad0b0SHugo Santos const sockaddr *address) 303727ad0b0SHugo Santos { 304727ad0b0SHugo Santos BenaphoreLocker _(fLock); 305727ad0b0SHugo Santos 306727ad0b0SHugo Santos if (endpoint->IsActive()) { 307727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 308727ad0b0SHugo Santos endpoint->SetActive(false); 309727ad0b0SHugo Santos } 310727ad0b0SHugo Santos 311727ad0b0SHugo Santos if (address->sa_family == AF_UNSPEC) { 312727ad0b0SHugo Santos // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect", 313727ad0b0SHugo Santos // so we reset the peer address: 314727ad0b0SHugo Santos endpoint->PeerAddress().SetToEmpty(); 315727ad0b0SHugo Santos } else { 316727ad0b0SHugo Santos status_t status = endpoint->PeerAddress().SetTo(address); 317727ad0b0SHugo Santos if (status < B_OK) 318727ad0b0SHugo Santos return status; 319727ad0b0SHugo Santos } 320727ad0b0SHugo Santos 321727ad0b0SHugo Santos // we need to activate no matter whether or not we have just disconnected, 322727ad0b0SHugo Santos // as calling connect() always triggers an implicit bind(): 323727ad0b0SHugo Santos return _BindEndpoint(endpoint, *endpoint->LocalAddress()); 324727ad0b0SHugo Santos } 325727ad0b0SHugo Santos 326727ad0b0SHugo Santos 327727ad0b0SHugo Santos status_t 328727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint) 329727ad0b0SHugo Santos { 330727ad0b0SHugo Santos BenaphoreLocker _(fLock); 331727ad0b0SHugo Santos 332727ad0b0SHugo Santos if (endpoint->IsActive()) 333727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 334727ad0b0SHugo Santos 335727ad0b0SHugo Santos endpoint->SetActive(false); 336727ad0b0SHugo Santos 337727ad0b0SHugo Santos return B_OK; 338727ad0b0SHugo Santos } 339727ad0b0SHugo Santos 340727ad0b0SHugo Santos 341cf5d9f4bSHugo Santos void 342cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const 343cf5d9f4bSHugo Santos { 344cf5d9f4bSHugo Santos kprintf("-------- UDP Domain %p ---------\n", this); 345cf5d9f4bSHugo Santos kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q"); 346cf5d9f4bSHugo Santos 347cf5d9f4bSHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 348cf5d9f4bSHugo Santos 349cf5d9f4bSHugo Santos while (it.HasNext()) { 350cf5d9f4bSHugo Santos UdpEndpoint *endpoint = it.Next(); 351cf5d9f4bSHugo Santos 352cf5d9f4bSHugo Santos char localBuf[64], peerBuf[64]; 353cf5d9f4bSHugo Santos endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true); 354cf5d9f4bSHugo Santos endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true); 355cf5d9f4bSHugo Santos 356cf5d9f4bSHugo Santos kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf, 357cf5d9f4bSHugo Santos endpoint->AvailableData()); 358cf5d9f4bSHugo Santos } 359cf5d9f4bSHugo Santos } 360cf5d9f4bSHugo Santos 361cf5d9f4bSHugo Santos 362727ad0b0SHugo Santos status_t 363727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint, 364727ad0b0SHugo Santos const sockaddr *address) 365727ad0b0SHugo Santos { 366727ad0b0SHugo Santos if (AddressModule()->get_port(address) == 0) 367727ad0b0SHugo Santos return _BindToEphemeral(endpoint, address); 368727ad0b0SHugo Santos 369727ad0b0SHugo Santos return _Bind(endpoint, address); 370727ad0b0SHugo Santos } 371727ad0b0SHugo Santos 372727ad0b0SHugo Santos 373727ad0b0SHugo Santos status_t 374727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address) 375727ad0b0SHugo Santos { 376727ad0b0SHugo Santos int socketOptions = endpoint->Socket()->options; 37740bbf860SHugo Santos 37840bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 379bf48e753SHugo Santos 380bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind 381bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]): 382727ad0b0SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain, 383727ad0b0SHugo Santos address, true).Data()); 384727ad0b0SHugo Santos 38540bbf860SHugo Santos while (it.HasNext()) { 38640bbf860SHugo Santos UdpEndpoint *otherEndpoint = it.Next(); 38725a2744fSHugo Santos 388bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint, 3895084c839SHugo Santos ntohs(otherEndpoint->LocalAddress().Port())); 39025a2744fSHugo Santos 39125a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualPorts(address)) { 392bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required: 393727ad0b0SHugo Santos if (otherEndpoint->Socket()->options & (SO_REUSEADDR | SO_REUSEPORT) == 0 394727ad0b0SHugo Santos || socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0) 395727ad0b0SHugo Santos return EADDRINUSE; 39625a2744fSHugo Santos 397bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required: 39825a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualTo(address, false) 399727ad0b0SHugo Santos && (otherEndpoint->Socket()->options & SO_REUSEPORT == 0 400727ad0b0SHugo Santos || socketOptions & SO_REUSEPORT == 0)) 401727ad0b0SHugo Santos return EADDRINUSE; 402bf48e753SHugo Santos } 403bf48e753SHugo Santos } 404bf48e753SHugo Santos 405727ad0b0SHugo Santos return _FinishBind(endpoint, address); 406bf48e753SHugo Santos } 407bf48e753SHugo Santos 408bf48e753SHugo Santos 409bf48e753SHugo Santos status_t 410727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint, 411727ad0b0SHugo Santos const sockaddr *address) 412727ad0b0SHugo Santos { 413727ad0b0SHugo Santos SocketAddressStorage newAddress(AddressModule()); 414727ad0b0SHugo Santos status_t status = newAddress.SetTo(address); 415727ad0b0SHugo Santos if (status < B_OK) 416727ad0b0SHugo Santos return status; 417727ad0b0SHugo Santos 418727ad0b0SHugo Santos uint16 allocedPort = _GetNextEphemeral(); 419727ad0b0SHugo Santos if (allocedPort == 0) 420727ad0b0SHugo Santos return ENOBUFS; 421727ad0b0SHugo Santos 422727ad0b0SHugo Santos newAddress.SetPort(allocedPort); 423727ad0b0SHugo Santos 424727ad0b0SHugo Santos return _FinishBind(endpoint, *newAddress); 425727ad0b0SHugo Santos } 426727ad0b0SHugo Santos 427727ad0b0SHugo Santos 428727ad0b0SHugo Santos status_t 429727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address) 430727ad0b0SHugo Santos { 431727ad0b0SHugo Santos status_t status = endpoint->next->module->bind(endpoint->next, address); 432727ad0b0SHugo Santos if (status < B_OK) 433727ad0b0SHugo Santos return status; 43440bbf860SHugo Santos 43540bbf860SHugo Santos fActiveEndpoints.Insert(endpoint); 436727ad0b0SHugo Santos endpoint->SetActive(true); 437727ad0b0SHugo Santos 43840bbf860SHugo Santos return B_OK; 439bf48e753SHugo Santos } 440bf48e753SHugo Santos 441bf48e753SHugo Santos 442c22d69bfSAxel Dörfler UdpEndpoint * 44340bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress, 44440bbf860SHugo Santos const sockaddr *peerAddress) 445c22d69bfSAxel Dörfler { 446bf48e753SHugo Santos TRACE_DOMAIN("finding Endpoint for %s -> %s", 447bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(), 448bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data()); 449c3e054c8SHugo Santos 45040bbf860SHugo Santos return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress)); 451c22d69bfSAxel Dörfler } 452c22d69bfSAxel Dörfler 453c22d69bfSAxel Dörfler 454c22d69bfSAxel Dörfler status_t 455bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) 456c22d69bfSAxel Dörfler { 45779a0d252SHugo Santos sockaddr *peerAddr = buffer->source; 45879a0d252SHugo Santos sockaddr *broadcastAddr = buffer->destination; 459c22d69bfSAxel Dörfler sockaddr *mask = NULL; 460c22d69bfSAxel Dörfler if (buffer->interface) 461c22d69bfSAxel Dörfler mask = (sockaddr *)buffer->interface->mask; 462c22d69bfSAxel Dörfler 463bf48e753SHugo Santos TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); 464c22d69bfSAxel Dörfler 465bf48e753SHugo Santos uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 466c22d69bfSAxel Dörfler 46740bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 46840bbf860SHugo Santos 46940bbf860SHugo Santos while (it.HasNext()) { 47040bbf860SHugo Santos UdpEndpoint *endpoint = it.Next(); 471c22d69bfSAxel Dörfler 47225a2744fSHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", 47325a2744fSHugo Santos AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); 47425a2744fSHugo Santos 4755084c839SHugo Santos if (endpoint->LocalAddress().Port() != incomingPort) { 476c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint... 477c22d69bfSAxel Dörfler continue; 478c22d69bfSAxel Dörfler } 479c22d69bfSAxel Dörfler 48025a2744fSHugo Santos if (!endpoint->PeerAddress().IsEmpty(true)) { 481c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if 482c22d69bfSAxel Dörfler // this datagram is from there: 48325a2744fSHugo Santos if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) { 484c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to 485c22d69bfSAxel Dörfler // this endpoint... 486c22d69bfSAxel Dörfler continue; 487c22d69bfSAxel Dörfler } 488c22d69bfSAxel Dörfler } 489c22d69bfSAxel Dörfler 49025a2744fSHugo Santos if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) 49125a2744fSHugo Santos || endpoint->LocalAddress().IsEmpty(false)) { 492c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint: 493c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 494c22d69bfSAxel Dörfler } 495c22d69bfSAxel Dörfler } 49640bbf860SHugo Santos 497c22d69bfSAxel Dörfler return B_OK; 498c22d69bfSAxel Dörfler } 499c22d69bfSAxel Dörfler 500c22d69bfSAxel Dörfler 501c22d69bfSAxel Dörfler status_t 502bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer *buffer) 503c22d69bfSAxel Dörfler { 50479a0d252SHugo Santos struct sockaddr *peerAddr = buffer->source; 50579a0d252SHugo Santos struct sockaddr *localAddr = buffer->destination; 506c22d69bfSAxel Dörfler 507bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer); 508c22d69bfSAxel Dörfler 509c22d69bfSAxel Dörfler UdpEndpoint *endpoint; 510c22d69bfSAxel Dörfler // look for full (most special) match: 511bf48e753SHugo Santos endpoint = _FindActiveEndpoint(localAddr, peerAddr); 512c22d69bfSAxel Dörfler if (!endpoint) { 513c22d69bfSAxel Dörfler // look for endpoint matching local address & port: 514bf48e753SHugo Santos endpoint = _FindActiveEndpoint(localAddr, NULL); 515c22d69bfSAxel Dörfler if (!endpoint) { 516c22d69bfSAxel Dörfler // look for endpoint matching peer address & port and local port: 51725a2744fSHugo Santos SocketAddressStorage local(AddressModule()); 51825a2744fSHugo Santos local.SetToEmpty(); 51925a2744fSHugo Santos local.SetPort(AddressModule()->get_port(localAddr)); 52025a2744fSHugo Santos endpoint = _FindActiveEndpoint(*local, peerAddr); 521c22d69bfSAxel Dörfler if (!endpoint) { 522c22d69bfSAxel Dörfler // last chance: look for endpoint matching local port only: 52325a2744fSHugo Santos endpoint = _FindActiveEndpoint(*local, NULL); 524c22d69bfSAxel Dörfler } 525c22d69bfSAxel Dörfler } 526c22d69bfSAxel Dörfler } 527bf48e753SHugo Santos 528c22d69bfSAxel Dörfler if (!endpoint) 529c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND; 530c22d69bfSAxel Dörfler 531c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 532c22d69bfSAxel Dörfler return B_OK; 533c22d69bfSAxel Dörfler } 534c22d69bfSAxel Dörfler 535c22d69bfSAxel Dörfler 536bf48e753SHugo Santos uint16 537bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral() 538c22d69bfSAxel Dörfler { 53940bbf860SHugo Santos uint16 stop, curr; 540bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) { 541bf48e753SHugo Santos stop = fLastUsedEphemeral; 542bf48e753SHugo Santos curr = fLastUsedEphemeral + 1; 543bf48e753SHugo Santos } else { 544bf48e753SHugo Santos stop = kLast; 545bf48e753SHugo Santos curr = kFirst; 546bf48e753SHugo Santos } 547c22d69bfSAxel Dörfler 548bf48e753SHugo Santos // TODO: a free list could be used to avoid the impact of these 549bf48e753SHugo Santos // two nested loops most of the time... let's see how bad this really is 55040bbf860SHugo Santos 551727ad0b0SHugo Santos TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu", 552727ad0b0SHugo Santos fLastUsedEphemeral, curr, stop); 55340bbf860SHugo Santos 554727ad0b0SHugo Santos for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) { 555bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr); 55640bbf860SHugo Santos 557727ad0b0SHugo Santos if (_EndpointWithPort(htons(curr)) == NULL) { 558bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr); 559bf48e753SHugo Santos fLastUsedEphemeral = curr; 560bf48e753SHugo Santos return curr; 561bf48e753SHugo Santos } 562727ad0b0SHugo Santos } 563727ad0b0SHugo Santos 564727ad0b0SHugo Santos return 0; 565727ad0b0SHugo Santos } 566727ad0b0SHugo Santos 567727ad0b0SHugo Santos 568727ad0b0SHugo Santos UdpEndpoint * 569727ad0b0SHugo Santos UdpDomainSupport::_EndpointWithPort(uint16 port) const 570727ad0b0SHugo Santos { 571727ad0b0SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 572727ad0b0SHugo Santos 573727ad0b0SHugo Santos while (it.HasNext()) { 574727ad0b0SHugo Santos UdpEndpoint *endpoint = it.Next(); 575727ad0b0SHugo Santos if (endpoint->LocalAddress().Port() == port) 576727ad0b0SHugo Santos return endpoint; 577727ad0b0SHugo Santos } 578727ad0b0SHugo Santos 579727ad0b0SHugo Santos return NULL; 580727ad0b0SHugo Santos } 581c22d69bfSAxel Dörfler 582bf48e753SHugo Santos 583bf48e753SHugo Santos // #pragma mark - 584bf48e753SHugo Santos 585bf48e753SHugo Santos 586bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager() 587bf48e753SHugo Santos { 588bf48e753SHugo Santos fStatus = benaphore_init(&fLock, "UDP endpoints"); 589bf48e753SHugo Santos } 590bf48e753SHugo Santos 591bf48e753SHugo Santos 592bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 593bf48e753SHugo Santos { 594bf48e753SHugo Santos benaphore_destroy(&fLock); 595bf48e753SHugo Santos } 596bf48e753SHugo Santos 597bf48e753SHugo Santos 598bf48e753SHugo Santos status_t 599bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 600bf48e753SHugo Santos { 601bf48e753SHugo Santos return fStatus; 602bf48e753SHugo Santos } 603bf48e753SHugo Santos 604bf48e753SHugo Santos 605cf5d9f4bSHugo Santos int 606cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[]) 607cf5d9f4bSHugo Santos { 608cf5d9f4bSHugo Santos UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator(); 609cf5d9f4bSHugo Santos 610cf5d9f4bSHugo Santos while (it.HasNext()) 611cf5d9f4bSHugo Santos it.Next()->DumpEndpoints(); 612cf5d9f4bSHugo Santos 613cf5d9f4bSHugo Santos return 0; 614cf5d9f4bSHugo Santos } 615cf5d9f4bSHugo Santos 616cf5d9f4bSHugo Santos 617bf48e753SHugo Santos // #pragma mark - inbound 618bf48e753SHugo Santos 619bf48e753SHugo Santos 620bf48e753SHugo Santos status_t 621c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer) 622c22d69bfSAxel Dörfler { 6236a606180SHugo Santos status_t status = Deframe(buffer); 6246a606180SHugo Santos if (status < B_OK) 6256a606180SHugo Santos return status; 6266a606180SHugo Santos 627bf48e753SHugo Santos TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size); 628bf48e753SHugo Santos 6296a606180SHugo Santos net_domain *domain = buffer->interface->domain; 6306a606180SHugo Santos 631727ad0b0SHugo Santos UdpDomainSupport *domainSupport = NULL; 6326a606180SHugo Santos 633727ad0b0SHugo Santos { 634727ad0b0SHugo Santos BenaphoreLocker _(fLock); 635727ad0b0SHugo Santos domainSupport = _GetDomain(domain, false); 636727ad0b0SHugo Santos // TODO we don't want to hold to the manager's lock 637727ad0b0SHugo Santos // during the whole RX path, we may not hold an 638727ad0b0SHugo Santos // endpoint's lock with the manager lock held. 639727ad0b0SHugo Santos // But we should increase the domain's refcount 640727ad0b0SHugo Santos // here. 641727ad0b0SHugo Santos } 642727ad0b0SHugo Santos 6436a606180SHugo Santos if (domainSupport == NULL) { 6446a606180SHugo Santos // we don't instantiate domain supports in the 6456a606180SHugo Santos // RX path as we are only interested in delivering 6466a606180SHugo Santos // data to existing sockets. 6476a606180SHugo Santos return B_ERROR; 6486a606180SHugo Santos } 6496a606180SHugo Santos 6506a606180SHugo Santos status = domainSupport->DemuxIncomingBuffer(buffer); 6516a606180SHugo Santos if (status < B_OK) { 6526a606180SHugo Santos TRACE_EPM(" ReceiveData(): no endpoint."); 6536a606180SHugo Santos // TODO: send ICMP-error 6546a606180SHugo Santos return B_ERROR; 6556a606180SHugo Santos } 6566a606180SHugo Santos 657a1deb55eSHugo Santos gBufferModule->free(buffer); 658a1deb55eSHugo Santos return B_OK; 6596a606180SHugo Santos } 6606a606180SHugo Santos 6616a606180SHugo Santos 6626a606180SHugo Santos status_t 6636a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer) 6646a606180SHugo Santos { 6656a606180SHugo Santos TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); 6666a606180SHugo Santos 66787001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer); 668c22d69bfSAxel Dörfler if (bufferHeader.Status() < B_OK) 669c22d69bfSAxel Dörfler return bufferHeader.Status(); 670c22d69bfSAxel Dörfler 671c22d69bfSAxel Dörfler udp_header &header = bufferHeader.Data(); 672c22d69bfSAxel Dörfler 673bf48e753SHugo Santos if (buffer->interface == NULL || buffer->interface->domain == NULL) { 6746a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " 675bf48e753SHugo Santos "specified (interface %p).", buffer->interface); 676c22d69bfSAxel Dörfler return B_BAD_VALUE; 677c22d69bfSAxel Dörfler } 678bf48e753SHugo Santos 679bf48e753SHugo Santos net_domain *domain = buffer->interface->domain; 680bf48e753SHugo Santos net_address_module_info *addressModule = domain->address_module; 681bf48e753SHugo Santos 68279a0d252SHugo Santos SocketAddress source(addressModule, buffer->source); 68379a0d252SHugo Santos SocketAddress destination(addressModule, buffer->destination); 684bf48e753SHugo Santos 6854e8a1b33SHugo Santos source.SetPort(header.source_port); 6864e8a1b33SHugo Santos destination.SetPort(header.destination_port); 6874e8a1b33SHugo Santos 6884e8a1b33SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(), 6894e8a1b33SHugo Santos destination.AsString(true).Data()); 690c22d69bfSAxel Dörfler 691c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length); 692c22d69bfSAxel Dörfler if (udpLength > buffer->size) { 6936a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", 694bf48e753SHugo Santos udpLength); 695c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES; 696c22d69bfSAxel Dörfler } 697bf48e753SHugo Santos 698bf48e753SHugo Santos if (buffer->size > udpLength) 699c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength); 700c22d69bfSAxel Dörfler 701c22d69bfSAxel Dörfler if (header.udp_checksum != 0) { 702c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"): 703d5b5a2c2SHugo Santos uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule, 704d5b5a2c2SHugo Santos buffer, IPPROTO_UDP); 705c22d69bfSAxel Dörfler if (sum != 0) { 7066a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); 707c22d69bfSAxel Dörfler return B_BAD_VALUE; 708c22d69bfSAxel Dörfler } 709c22d69bfSAxel Dörfler } 710c22d69bfSAxel Dörfler 711c22d69bfSAxel Dörfler bufferHeader.Remove(); 712c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on 713c22d69bfSAxel Dörfler 7146a606180SHugo Santos return B_OK; 715c22d69bfSAxel Dörfler } 716c22d69bfSAxel Dörfler 717c22d69bfSAxel Dörfler 718bf48e753SHugo Santos UdpDomainSupport * 719c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) 720c22d69bfSAxel Dörfler { 721bf48e753SHugo Santos BenaphoreLocker _(fLock); 722bf48e753SHugo Santos 723bf48e753SHugo Santos UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); 724bf48e753SHugo Santos if (domain) 725bf48e753SHugo Santos domain->Ref(); 726bf48e753SHugo Santos return domain; 727bf48e753SHugo Santos } 728bf48e753SHugo Santos 729bf48e753SHugo Santos 730bf48e753SHugo Santos status_t 731bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) 732bf48e753SHugo Santos { 733bf48e753SHugo Santos BenaphoreLocker _(fLock); 734bf48e753SHugo Santos 735727ad0b0SHugo Santos if (domain->Put()) { 736bf48e753SHugo Santos fDomains.Remove(domain); 737bf48e753SHugo Santos delete domain; 738bf48e753SHugo Santos } 739bf48e753SHugo Santos 740bf48e753SHugo Santos return B_OK; 741bf48e753SHugo Santos } 742bf48e753SHugo Santos 743bf48e753SHugo Santos 744bf48e753SHugo Santos // #pragma mark - 745bf48e753SHugo Santos 746bf48e753SHugo Santos 747bf48e753SHugo Santos UdpDomainSupport * 748bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create) 749bf48e753SHugo Santos { 750bf48e753SHugo Santos UdpDomainList::Iterator it = fDomains.GetIterator(); 751bf48e753SHugo Santos 752bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain 753bf48e753SHugo Santos // receiver handlers that forward the requests to the 754bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while 755bf48e753SHugo Santos // being constructed UdpDomainSupport could call 756bf48e753SHugo Santos // register_domain_receiving_protocol() with the right 757bf48e753SHugo Santos // family. 758bf48e753SHugo Santos while (it.HasNext()) { 759bf48e753SHugo Santos UdpDomainSupport *domainSupport = it.Next(); 760bf48e753SHugo Santos if (domainSupport->Domain() == domain) 761bf48e753SHugo Santos return domainSupport; 762bf48e753SHugo Santos } 763bf48e753SHugo Santos 764bf48e753SHugo Santos if (!create) 765bf48e753SHugo Santos return NULL; 766bf48e753SHugo Santos 767bf48e753SHugo Santos UdpDomainSupport *domainSupport = 768bf48e753SHugo Santos new (std::nothrow) UdpDomainSupport(domain); 769bf48e753SHugo Santos if (domainSupport == NULL || domainSupport->InitCheck() < B_OK) { 770bf48e753SHugo Santos delete domainSupport; 771bf48e753SHugo Santos return NULL; 772bf48e753SHugo Santos } 773bf48e753SHugo Santos 774bf48e753SHugo Santos fDomains.Add(domainSupport); 775bf48e753SHugo Santos return domainSupport; 776c22d69bfSAxel Dörfler } 777c22d69bfSAxel Dörfler 778c22d69bfSAxel Dörfler 779c22d69bfSAxel Dörfler // #pragma mark - 780c22d69bfSAxel Dörfler 781c22d69bfSAxel Dörfler 782c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 783c72ab92dSHugo Santos : DatagramSocket<>("udp endpoint", socket), fActive(false) {} 784bf48e753SHugo Santos 785bf48e753SHugo Santos 786c22d69bfSAxel Dörfler // #pragma mark - activation 787c22d69bfSAxel Dörfler 788c22d69bfSAxel Dörfler 789c22d69bfSAxel Dörfler status_t 79053f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address) 791c22d69bfSAxel Dörfler { 792bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 793727ad0b0SHugo Santos return fManager->BindEndpoint(this, address); 794c22d69bfSAxel Dörfler } 795c22d69bfSAxel Dörfler 796c22d69bfSAxel Dörfler 797c22d69bfSAxel Dörfler status_t 798c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 799c22d69bfSAxel Dörfler { 800bf48e753SHugo Santos TRACE_EP("Unbind()"); 801727ad0b0SHugo Santos return fManager->UnbindEndpoint(this); 802c22d69bfSAxel Dörfler } 803c22d69bfSAxel Dörfler 804c22d69bfSAxel Dörfler 805c22d69bfSAxel Dörfler status_t 806c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 807c22d69bfSAxel Dörfler { 808bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 809727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address); 810c22d69bfSAxel Dörfler } 811c22d69bfSAxel Dörfler 812c22d69bfSAxel Dörfler 813c22d69bfSAxel Dörfler status_t 814c22d69bfSAxel Dörfler UdpEndpoint::Open() 815c22d69bfSAxel Dörfler { 816bf48e753SHugo Santos TRACE_EP("Open()"); 817bf48e753SHugo Santos 818*119c6cddSIngo Weinhold AutoLocker _(fLock); 819727ad0b0SHugo Santos 820c72ab92dSHugo Santos status_t status = ProtocolSocket::Open(); 821c72ab92dSHugo Santos if (status < B_OK) 822c72ab92dSHugo Santos return status; 823bf48e753SHugo Santos 824c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this); 825c72ab92dSHugo Santos if (fManager == NULL) 826bf48e753SHugo Santos return EAFNOSUPPORT; 827bf48e753SHugo Santos 828bf48e753SHugo Santos return B_OK; 829c22d69bfSAxel Dörfler } 830c22d69bfSAxel Dörfler 831c22d69bfSAxel Dörfler 832c22d69bfSAxel Dörfler status_t 833c22d69bfSAxel Dörfler UdpEndpoint::Close() 834c22d69bfSAxel Dörfler { 835bf48e753SHugo Santos TRACE_EP("Close()"); 836bf48e753SHugo Santos return B_OK; 837c22d69bfSAxel Dörfler } 838c22d69bfSAxel Dörfler 839c22d69bfSAxel Dörfler 840c22d69bfSAxel Dörfler status_t 841c22d69bfSAxel Dörfler UdpEndpoint::Free() 842c22d69bfSAxel Dörfler { 843bf48e753SHugo Santos TRACE_EP("Free()"); 8440086fe20SHugo Santos fManager->UnbindEndpoint(this); 845c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager); 846c22d69bfSAxel Dörfler } 847c22d69bfSAxel Dörfler 848c22d69bfSAxel Dörfler 849c22d69bfSAxel Dörfler // #pragma mark - outbound 850c22d69bfSAxel Dörfler 851c22d69bfSAxel Dörfler 852c22d69bfSAxel Dörfler status_t 853bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 854c22d69bfSAxel Dörfler { 855bf48e753SHugo Santos TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route); 856bf48e753SHugo Santos 857d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 858c22d69bfSAxel Dörfler return EMSGSIZE; 859c22d69bfSAxel Dörfler 860c22d69bfSAxel Dörfler buffer->protocol = IPPROTO_UDP; 861c22d69bfSAxel Dörfler 862c22d69bfSAxel Dörfler // add and fill UDP-specific header: 8636c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 8646c353509SHugo Santos if (header.Status() < B_OK) 8656c353509SHugo Santos return header.Status(); 866c22d69bfSAxel Dörfler 86779a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source); 86879a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination); 8696c353509SHugo Santos header->udp_length = htons(buffer->size); 870c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 8716c353509SHugo Santos header->udp_checksum = 0; 8726c353509SHugo Santos 8736c353509SHugo Santos header.Sync(); 874c22d69bfSAxel Dörfler 875d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(), 876d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP); 8776c353509SHugo Santos if (calculatedChecksum == 0) 8786c353509SHugo Santos calculatedChecksum = 0xffff; 8796c353509SHugo Santos 8806c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 881c22d69bfSAxel Dörfler 882c22d69bfSAxel Dörfler TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: ")); 8836c353509SHugo Santos 884c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 885c22d69bfSAxel Dörfler } 886c22d69bfSAxel Dörfler 887c22d69bfSAxel Dörfler 888bf48e753SHugo Santos status_t 889bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 890bf48e753SHugo Santos { 891bf48e753SHugo Santos TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size); 892bf48e753SHugo Santos 8931408d1f0SHugo Santos return gDatalinkModule->send_datagram(this, NULL, buffer); 894bf48e753SHugo Santos } 895bf48e753SHugo Santos 896bf48e753SHugo Santos 897c22d69bfSAxel Dörfler // #pragma mark - inbound 898c22d69bfSAxel Dörfler 899c22d69bfSAxel Dörfler 900c22d69bfSAxel Dörfler ssize_t 901c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 902c22d69bfSAxel Dörfler { 903bfb45f71SHugo Santos size_t bytes = AvailableData(); 904bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 905bfb45f71SHugo Santos return bytes; 906c22d69bfSAxel Dörfler } 907c22d69bfSAxel Dörfler 908c22d69bfSAxel Dörfler 909c22d69bfSAxel Dörfler status_t 910c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 911c22d69bfSAxel Dörfler { 912bf48e753SHugo Santos TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags); 913bf48e753SHugo Santos 914bfb45f71SHugo Santos status_t status = SocketDequeue(flags, _buffer); 915bf48e753SHugo Santos TRACE_EP(" FetchData(): returned from fifo status=0x%lx", status); 916c22d69bfSAxel Dörfler if (status < B_OK) 917c22d69bfSAxel Dörfler return status; 918c22d69bfSAxel Dörfler 919bfb45f71SHugo Santos TRACE_EP(" FetchData(): returns buffer with %ld bytes", (*_buffer)->size); 920c22d69bfSAxel Dörfler return B_OK; 921c22d69bfSAxel Dörfler } 922c22d69bfSAxel Dörfler 923c22d69bfSAxel Dörfler 924c22d69bfSAxel Dörfler status_t 925bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 926c22d69bfSAxel Dörfler { 927bf48e753SHugo Santos TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size); 928c22d69bfSAxel Dörfler 92949f3c71eSHugo Santos return SocketEnqueue(buffer); 930c22d69bfSAxel Dörfler } 931c22d69bfSAxel Dörfler 932c22d69bfSAxel Dörfler 9336a606180SHugo Santos status_t 9346a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 9356a606180SHugo Santos { 936f6cfc5afSHugo Santos TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size); 937f6cfc5afSHugo Santos 9386a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 9396a606180SHugo Santos if (buffer == NULL) 9406a606180SHugo Santos return B_NO_MEMORY; 9416a606180SHugo Santos 9426a606180SHugo Santos status_t status = sUdpEndpointManager->Deframe(buffer); 9436a606180SHugo Santos if (status < B_OK) { 9446a606180SHugo Santos gBufferModule->free(buffer); 9456a606180SHugo Santos return status; 9466a606180SHugo Santos } 9476a606180SHugo Santos 9486a606180SHugo Santos // we call Enqueue() instead of SocketEnqueue() as there is 9496a606180SHugo Santos // no need to clone the buffer again. 9506a606180SHugo Santos return Enqueue(buffer); 9516a606180SHugo Santos } 9526a606180SHugo Santos 9536a606180SHugo Santos 954c22d69bfSAxel Dörfler // #pragma mark - protocol interface 955c22d69bfSAxel Dörfler 956c22d69bfSAxel Dörfler 957c22d69bfSAxel Dörfler net_protocol * 958c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 959c22d69bfSAxel Dörfler { 960c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 961c22d69bfSAxel Dörfler 962c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 963bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 964bf48e753SHugo Santos delete endpoint; 965bf48e753SHugo Santos return NULL; 966bf48e753SHugo Santos } 967bf48e753SHugo Santos 968c22d69bfSAxel Dörfler return endpoint; 969c22d69bfSAxel Dörfler } 970c22d69bfSAxel Dörfler 971c22d69bfSAxel Dörfler 972c22d69bfSAxel Dörfler status_t 973c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 974c22d69bfSAxel Dörfler { 975bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 976c22d69bfSAxel Dörfler return B_OK; 977c22d69bfSAxel Dörfler } 978c22d69bfSAxel Dörfler 979c22d69bfSAxel Dörfler 980c22d69bfSAxel Dörfler status_t 981c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 982c22d69bfSAxel Dörfler { 983bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 984c22d69bfSAxel Dörfler } 985c22d69bfSAxel Dörfler 986c22d69bfSAxel Dörfler 987c22d69bfSAxel Dörfler status_t 988c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 989c22d69bfSAxel Dörfler { 990bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 991c22d69bfSAxel Dörfler } 992c22d69bfSAxel Dörfler 993c22d69bfSAxel Dörfler 994c22d69bfSAxel Dörfler status_t 995c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 996c22d69bfSAxel Dörfler { 997bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 998c22d69bfSAxel Dörfler } 999c22d69bfSAxel Dörfler 1000c22d69bfSAxel Dörfler 1001c22d69bfSAxel Dörfler status_t 1002c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1003c22d69bfSAxel Dörfler { 1004bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1005c22d69bfSAxel Dörfler } 1006c22d69bfSAxel Dörfler 1007c22d69bfSAxel Dörfler 1008c22d69bfSAxel Dörfler status_t 1009c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1010c22d69bfSAxel Dörfler { 1011c22d69bfSAxel Dörfler return EOPNOTSUPP; 1012c22d69bfSAxel Dörfler } 1013c22d69bfSAxel Dörfler 1014c22d69bfSAxel Dörfler 1015c22d69bfSAxel Dörfler status_t 1016c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1017c22d69bfSAxel Dörfler size_t *_length) 1018c22d69bfSAxel Dörfler { 1019c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1020c22d69bfSAxel Dörfler value, _length); 1021c22d69bfSAxel Dörfler } 1022c22d69bfSAxel Dörfler 1023c22d69bfSAxel Dörfler 1024c22d69bfSAxel Dörfler status_t 102545b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value, 102645b5203bSHugo Santos int *length) 102745b5203bSHugo Santos { 102845b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option, 102945b5203bSHugo Santos value, length); 103045b5203bSHugo Santos } 103145b5203bSHugo Santos 103245b5203bSHugo Santos 103345b5203bSHugo Santos status_t 103445b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option, 103545b5203bSHugo Santos const void *value, int length) 103645b5203bSHugo Santos { 103745b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option, 103845b5203bSHugo Santos value, length); 103945b5203bSHugo Santos } 104045b5203bSHugo Santos 104145b5203bSHugo Santos 104245b5203bSHugo Santos status_t 104353f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address) 1044c22d69bfSAxel Dörfler { 1045bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1046c22d69bfSAxel Dörfler } 1047c22d69bfSAxel Dörfler 1048c22d69bfSAxel Dörfler 1049c22d69bfSAxel Dörfler status_t 1050c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1051c22d69bfSAxel Dörfler { 1052bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1053c22d69bfSAxel Dörfler } 1054c22d69bfSAxel Dörfler 1055c22d69bfSAxel Dörfler 1056c22d69bfSAxel Dörfler status_t 1057c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1058c22d69bfSAxel Dörfler { 1059c22d69bfSAxel Dörfler return EOPNOTSUPP; 1060c22d69bfSAxel Dörfler } 1061c22d69bfSAxel Dörfler 1062c22d69bfSAxel Dörfler 1063c22d69bfSAxel Dörfler status_t 1064c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1065c22d69bfSAxel Dörfler { 1066c22d69bfSAxel Dörfler return EOPNOTSUPP; 1067c22d69bfSAxel Dörfler } 1068c22d69bfSAxel Dörfler 1069c22d69bfSAxel Dörfler 1070c22d69bfSAxel Dörfler status_t 1071c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1072c22d69bfSAxel Dörfler net_buffer *buffer) 1073c22d69bfSAxel Dörfler { 1074bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1075c22d69bfSAxel Dörfler } 1076c22d69bfSAxel Dörfler 1077c22d69bfSAxel Dörfler 1078c22d69bfSAxel Dörfler status_t 1079c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1080c22d69bfSAxel Dörfler { 1081bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1082c22d69bfSAxel Dörfler } 1083c22d69bfSAxel Dörfler 1084c22d69bfSAxel Dörfler 1085c22d69bfSAxel Dörfler ssize_t 1086c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1087c22d69bfSAxel Dörfler { 1088bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1089c22d69bfSAxel Dörfler } 1090c22d69bfSAxel Dörfler 1091c22d69bfSAxel Dörfler 1092c22d69bfSAxel Dörfler status_t 1093c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1094c22d69bfSAxel Dörfler net_buffer **_buffer) 1095c22d69bfSAxel Dörfler { 1096bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1097c22d69bfSAxel Dörfler } 1098c22d69bfSAxel Dörfler 1099c22d69bfSAxel Dörfler 1100c22d69bfSAxel Dörfler ssize_t 1101c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1102c22d69bfSAxel Dörfler { 1103bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1104c22d69bfSAxel Dörfler } 1105c22d69bfSAxel Dörfler 1106c22d69bfSAxel Dörfler 1107c22d69bfSAxel Dörfler struct net_domain * 1108c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1109c22d69bfSAxel Dörfler { 1110c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1111c22d69bfSAxel Dörfler } 1112c22d69bfSAxel Dörfler 1113c22d69bfSAxel Dörfler 1114c22d69bfSAxel Dörfler size_t 1115c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1116c22d69bfSAxel Dörfler { 1117c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1118c22d69bfSAxel Dörfler } 1119c22d69bfSAxel Dörfler 1120c22d69bfSAxel Dörfler 1121c22d69bfSAxel Dörfler status_t 1122c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1123c22d69bfSAxel Dörfler { 1124c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1125c22d69bfSAxel Dörfler } 1126c22d69bfSAxel Dörfler 1127c22d69bfSAxel Dörfler 1128c22d69bfSAxel Dörfler status_t 11296a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 11306a606180SHugo Santos { 11316a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 11326a606180SHugo Santos } 11336a606180SHugo Santos 11346a606180SHugo Santos 11356a606180SHugo Santos status_t 1136c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data) 1137c22d69bfSAxel Dörfler { 1138c22d69bfSAxel Dörfler return B_ERROR; 1139c22d69bfSAxel Dörfler } 1140c22d69bfSAxel Dörfler 1141c22d69bfSAxel Dörfler 1142c22d69bfSAxel Dörfler status_t 1143c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, 1144c22d69bfSAxel Dörfler void *errorData) 1145c22d69bfSAxel Dörfler { 1146c22d69bfSAxel Dörfler return B_ERROR; 1147c22d69bfSAxel Dörfler } 1148c22d69bfSAxel Dörfler 1149c22d69bfSAxel Dörfler 1150c22d69bfSAxel Dörfler // #pragma mark - module interface 1151c22d69bfSAxel Dörfler 1152c22d69bfSAxel Dörfler 1153c22d69bfSAxel Dörfler static status_t 1154c22d69bfSAxel Dörfler init_udp() 1155c22d69bfSAxel Dörfler { 1156c22d69bfSAxel Dörfler status_t status; 1157bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1158c22d69bfSAxel Dörfler 1159c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1160658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1161658a5506SHugo Santos return B_NO_MEMORY; 1162658a5506SHugo Santos 1163c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1164c22d69bfSAxel Dörfler if (status != B_OK) 1165d438fa4cSHugo Santos goto err1; 1166c22d69bfSAxel Dörfler 1167bfb45f71SHugo Santos status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP, 1168c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1169c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1170c22d69bfSAxel Dörfler NULL); 1171c22d69bfSAxel Dörfler if (status < B_OK) 1172658a5506SHugo Santos goto err1; 1173bfb45f71SHugo Santos status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 1174c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1175c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1176c22d69bfSAxel Dörfler NULL); 1177c22d69bfSAxel Dörfler if (status < B_OK) 1178658a5506SHugo Santos goto err1; 1179c22d69bfSAxel Dörfler 1180bfb45f71SHugo Santos status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP, 1181c22d69bfSAxel Dörfler "network/protocols/udp/v1"); 1182c22d69bfSAxel Dörfler if (status < B_OK) 1183658a5506SHugo Santos goto err1; 1184c22d69bfSAxel Dörfler 1185cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints, 1186cf5d9f4bSHugo Santos "lists all open UDP endpoints"); 1187cf5d9f4bSHugo Santos 1188c22d69bfSAxel Dörfler return B_OK; 1189c22d69bfSAxel Dörfler 1190c22d69bfSAxel Dörfler err1: 1191658a5506SHugo Santos delete sUdpEndpointManager; 1192c22d69bfSAxel Dörfler 1193bf48e753SHugo Santos TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status)); 1194c22d69bfSAxel Dörfler return status; 1195c22d69bfSAxel Dörfler } 1196c22d69bfSAxel Dörfler 1197c22d69bfSAxel Dörfler 1198c22d69bfSAxel Dörfler static status_t 1199c22d69bfSAxel Dörfler uninit_udp() 1200c22d69bfSAxel Dörfler { 1201bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1202cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints", 1203cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints); 1204c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1205c22d69bfSAxel Dörfler return B_OK; 1206c22d69bfSAxel Dörfler } 1207c22d69bfSAxel Dörfler 1208c22d69bfSAxel Dörfler 1209c22d69bfSAxel Dörfler static status_t 1210c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1211c22d69bfSAxel Dörfler { 1212c22d69bfSAxel Dörfler switch (op) { 1213c22d69bfSAxel Dörfler case B_MODULE_INIT: 1214c22d69bfSAxel Dörfler return init_udp(); 1215c22d69bfSAxel Dörfler 1216c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1217c22d69bfSAxel Dörfler return uninit_udp(); 1218c22d69bfSAxel Dörfler 1219c22d69bfSAxel Dörfler default: 1220c22d69bfSAxel Dörfler return B_ERROR; 1221c22d69bfSAxel Dörfler } 1222c22d69bfSAxel Dörfler } 1223c22d69bfSAxel Dörfler 1224c22d69bfSAxel Dörfler 1225c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1226c22d69bfSAxel Dörfler { 1227c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1228c22d69bfSAxel Dörfler 0, 1229c22d69bfSAxel Dörfler udp_std_ops 1230c22d69bfSAxel Dörfler }, 1231c22d69bfSAxel Dörfler udp_init_protocol, 1232c22d69bfSAxel Dörfler udp_uninit_protocol, 1233c22d69bfSAxel Dörfler udp_open, 1234c22d69bfSAxel Dörfler udp_close, 1235c22d69bfSAxel Dörfler udp_free, 1236c22d69bfSAxel Dörfler udp_connect, 1237c22d69bfSAxel Dörfler udp_accept, 1238c22d69bfSAxel Dörfler udp_control, 123945b5203bSHugo Santos udp_getsockopt, 124045b5203bSHugo Santos udp_setsockopt, 1241c22d69bfSAxel Dörfler udp_bind, 1242c22d69bfSAxel Dörfler udp_unbind, 1243c22d69bfSAxel Dörfler udp_listen, 1244c22d69bfSAxel Dörfler udp_shutdown, 1245c22d69bfSAxel Dörfler udp_send_data, 1246c22d69bfSAxel Dörfler udp_send_routed_data, 1247c22d69bfSAxel Dörfler udp_send_avail, 1248c22d69bfSAxel Dörfler udp_read_data, 1249c22d69bfSAxel Dörfler udp_read_avail, 1250c22d69bfSAxel Dörfler udp_get_domain, 1251c22d69bfSAxel Dörfler udp_get_mtu, 1252c22d69bfSAxel Dörfler udp_receive_data, 12536a606180SHugo Santos udp_deliver_data, 1254c22d69bfSAxel Dörfler udp_error, 1255c22d69bfSAxel Dörfler udp_error_reply, 1256c22d69bfSAxel Dörfler }; 1257c22d69bfSAxel Dörfler 1258658a5506SHugo Santos module_dependency module_dependencies[] = { 1259658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1260658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1261658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 1262658a5506SHugo Santos {} 1263658a5506SHugo Santos }; 1264658a5506SHugo Santos 1265c22d69bfSAxel Dörfler module_info *modules[] = { 1266c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1267c22d69bfSAxel Dörfler NULL 1268c22d69bfSAxel Dörfler }; 1269