1c22d69bfSAxel Dörfler /* 26f58064fSAxel Dörfler * Copyright 2006-2008, 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 11884052230SAxel Dörfler UdpHashDefinition(net_address_module_info *_module) 11984052230SAxel Dörfler : module(_module) {} 12084052230SAxel Dörfler UdpHashDefinition(const UdpHashDefinition& definition) 12184052230SAxel Dörfler : module(definition.module) {} 12240bbf860SHugo Santos 12340bbf860SHugo Santos size_t HashKey(const KeyType &key) const 12440bbf860SHugo Santos { 12540bbf860SHugo Santos return _Mix(module->hash_address_pair(key.first, key.second)); 12640bbf860SHugo Santos } 12740bbf860SHugo Santos 12840bbf860SHugo Santos size_t Hash(UdpEndpoint *endpoint) const 12940bbf860SHugo Santos { 13040bbf860SHugo Santos return _Mix(endpoint->LocalAddress().HashPair(*endpoint->PeerAddress())); 13140bbf860SHugo Santos } 13240bbf860SHugo Santos 13340bbf860SHugo Santos static size_t _Mix(size_t hash) 13440bbf860SHugo Santos { 13540bbf860SHugo Santos // move the bits into the relevant range (as defined by kNumHashBuckets): 13640bbf860SHugo Santos return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11 13740bbf860SHugo Santos ^ (hash & 0xFFC00000UL) >> 22; 13840bbf860SHugo Santos } 13940bbf860SHugo Santos 14040bbf860SHugo Santos bool Compare(const KeyType &key, UdpEndpoint *endpoint) const 14140bbf860SHugo Santos { 14240bbf860SHugo Santos return endpoint->LocalAddress().EqualTo(key.first, true) 14340bbf860SHugo Santos && endpoint->PeerAddress().EqualTo(key.second, true); 14440bbf860SHugo Santos } 14540bbf860SHugo Santos 14640bbf860SHugo Santos HashTableLink<UdpEndpoint> *GetLink(UdpEndpoint *endpoint) const 14740bbf860SHugo Santos { 14840bbf860SHugo Santos return endpoint->HashTableLink(); 14940bbf860SHugo Santos } 15040bbf860SHugo Santos 15140bbf860SHugo Santos net_address_module_info *module; 152c22d69bfSAxel Dörfler }; 153c22d69bfSAxel Dörfler 154c22d69bfSAxel Dörfler 155bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> { 156c22d69bfSAxel Dörfler public: 157bf48e753SHugo Santos UdpDomainSupport(net_domain *domain); 158727ad0b0SHugo Santos ~UdpDomainSupport(); 159c22d69bfSAxel Dörfler 160276aa463SIngo Weinhold status_t Init(); 161bf48e753SHugo Santos 162bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 163bf48e753SHugo Santos 164bf48e753SHugo Santos void Ref() { fEndpointCount++; } 165727ad0b0SHugo Santos bool Put() { fEndpointCount--; return fEndpointCount == 0; } 166bf48e753SHugo Santos 167bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer *buffer); 168727ad0b0SHugo Santos 169727ad0b0SHugo Santos status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 170727ad0b0SHugo Santos status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 171727ad0b0SHugo Santos status_t UnbindEndpoint(UdpEndpoint *endpoint); 172727ad0b0SHugo Santos 173cf5d9f4bSHugo Santos void DumpEndpoints() const; 174bf48e753SHugo Santos 175c22d69bfSAxel Dörfler private: 176727ad0b0SHugo Santos status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address); 177727ad0b0SHugo Santos status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address); 178727ad0b0SHugo Santos status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address); 179727ad0b0SHugo Santos status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address); 180727ad0b0SHugo Santos 18140bbf860SHugo Santos UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress, 18240bbf860SHugo Santos const sockaddr *peerAddress); 183bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer); 184bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer); 185bf48e753SHugo Santos 186bf48e753SHugo Santos uint16 _GetNextEphemeral(); 187727ad0b0SHugo Santos UdpEndpoint *_EndpointWithPort(uint16 port) const; 188bf48e753SHugo Santos 189bf48e753SHugo Santos net_address_module_info *AddressModule() const 190727ad0b0SHugo Santos { return fDomain->address_module; } 191bf48e753SHugo Santos 19240bbf860SHugo Santos typedef OpenHashTable<UdpHashDefinition, false> EndpointTable; 19340bbf860SHugo Santos 1942b07b8e0SIngo Weinhold mutex fLock; 195bf48e753SHugo Santos net_domain *fDomain; 196bf48e753SHugo Santos uint16 fLastUsedEphemeral; 19740bbf860SHugo Santos EndpointTable fActiveEndpoints; 198bf48e753SHugo Santos uint32 fEndpointCount; 199bf48e753SHugo Santos 200bf48e753SHugo Santos static const uint16 kFirst = 49152; 201bf48e753SHugo Santos static const uint16 kLast = 65535; 202bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800; 203bf48e753SHugo Santos // if you change this, adjust the shifting in 204bf48e753SHugo Santos // Hash() accordingly! 205bf48e753SHugo Santos }; 206bf48e753SHugo Santos 207bf48e753SHugo Santos 208bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList; 209bf48e753SHugo Santos 210bf48e753SHugo Santos 211bf48e753SHugo Santos class UdpEndpointManager { 212c22d69bfSAxel Dörfler public: 213c22d69bfSAxel Dörfler UdpEndpointManager(); 214c22d69bfSAxel Dörfler ~UdpEndpointManager(); 215c22d69bfSAxel Dörfler 216c22d69bfSAxel Dörfler status_t ReceiveData(net_buffer *buffer); 2176a606180SHugo Santos status_t Deframe(net_buffer *buffer); 218c22d69bfSAxel Dörfler 219bf48e753SHugo Santos UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint); 220bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport *domain); 221c22d69bfSAxel Dörfler 222c22d69bfSAxel Dörfler status_t InitCheck() const; 223bf48e753SHugo Santos 224cf5d9f4bSHugo Santos static int DumpEndpoints(int argc, char *argv[]); 225cf5d9f4bSHugo Santos 226c22d69bfSAxel Dörfler private: 227bf48e753SHugo Santos UdpDomainSupport *_GetDomain(net_domain *domain, bool create); 228bf48e753SHugo Santos 2292b07b8e0SIngo Weinhold mutex fLock; 230c22d69bfSAxel Dörfler status_t fStatus; 231bf48e753SHugo Santos UdpDomainList fDomains; 232c22d69bfSAxel Dörfler }; 233c22d69bfSAxel Dörfler 234c22d69bfSAxel Dörfler 235c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager; 236c22d69bfSAxel Dörfler 237c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule; 238658a5506SHugo Santos net_datalink_module_info *gDatalinkModule; 239658a5506SHugo Santos net_stack_module_info *gStackModule; 240c22d69bfSAxel Dörfler 241c22d69bfSAxel Dörfler 242c22d69bfSAxel Dörfler // #pragma mark - 243c22d69bfSAxel Dörfler 244c22d69bfSAxel Dörfler 245bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain) 246c22d69bfSAxel Dörfler : 247bf48e753SHugo Santos fDomain(domain), 248276aa463SIngo Weinhold fActiveEndpoints(domain->address_module), 249bf48e753SHugo Santos fEndpointCount(0) 250c22d69bfSAxel Dörfler { 2512b07b8e0SIngo Weinhold mutex_init(&fLock, "udp domain"); 252727ad0b0SHugo Santos 253727ad0b0SHugo Santos fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst); 254727ad0b0SHugo Santos } 255727ad0b0SHugo Santos 256727ad0b0SHugo Santos 257727ad0b0SHugo Santos UdpDomainSupport::~UdpDomainSupport() 258727ad0b0SHugo Santos { 2592b07b8e0SIngo Weinhold mutex_destroy(&fLock); 260bf48e753SHugo Santos } 261bf48e753SHugo Santos 262bf48e753SHugo Santos 263bf48e753SHugo Santos status_t 264276aa463SIngo Weinhold UdpDomainSupport::Init() 265bf48e753SHugo Santos { 266276aa463SIngo Weinhold return fActiveEndpoints.Init(kNumHashBuckets); 267bf48e753SHugo Santos } 268bf48e753SHugo Santos 269bf48e753SHugo Santos 270bf48e753SHugo Santos status_t 271bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer) 272bf48e753SHugo Santos { 273727ad0b0SHugo Santos // NOTE multicast is delivered directly to the endpoint 274727ad0b0SHugo Santos 2752b07b8e0SIngo Weinhold MutexLocker _(fLock); 276727ad0b0SHugo Santos 277bf48e753SHugo Santos if (buffer->flags & MSG_BCAST) 278bf48e753SHugo Santos return _DemuxBroadcast(buffer); 279bf48e753SHugo Santos else if (buffer->flags & MSG_MCAST) 280727ad0b0SHugo Santos return B_ERROR; 281bf48e753SHugo Santos 282bf48e753SHugo Santos return _DemuxUnicast(buffer); 283bf48e753SHugo Santos } 284bf48e753SHugo Santos 285bf48e753SHugo Santos 286bf48e753SHugo Santos status_t 287727ad0b0SHugo Santos UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint, 288727ad0b0SHugo Santos const sockaddr *address) 289727ad0b0SHugo Santos { 2902b07b8e0SIngo Weinhold MutexLocker _(fLock); 291727ad0b0SHugo Santos 292727ad0b0SHugo Santos if (endpoint->IsActive()) 293727ad0b0SHugo Santos return EINVAL; 294727ad0b0SHugo Santos 295727ad0b0SHugo Santos return _BindEndpoint(endpoint, address); 296727ad0b0SHugo Santos } 297727ad0b0SHugo Santos 298727ad0b0SHugo Santos 299727ad0b0SHugo Santos status_t 300727ad0b0SHugo Santos UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint, 301727ad0b0SHugo Santos const sockaddr *address) 302727ad0b0SHugo Santos { 3032b07b8e0SIngo Weinhold MutexLocker _(fLock); 304727ad0b0SHugo Santos 305727ad0b0SHugo Santos if (endpoint->IsActive()) { 306727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 307727ad0b0SHugo Santos endpoint->SetActive(false); 308727ad0b0SHugo Santos } 309727ad0b0SHugo Santos 310727ad0b0SHugo Santos if (address->sa_family == AF_UNSPEC) { 311727ad0b0SHugo Santos // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect", 312727ad0b0SHugo Santos // so we reset the peer address: 313727ad0b0SHugo Santos endpoint->PeerAddress().SetToEmpty(); 314727ad0b0SHugo Santos } else { 315727ad0b0SHugo Santos status_t status = endpoint->PeerAddress().SetTo(address); 316727ad0b0SHugo Santos if (status < B_OK) 317727ad0b0SHugo Santos return status; 318727ad0b0SHugo Santos } 319727ad0b0SHugo Santos 320727ad0b0SHugo Santos // we need to activate no matter whether or not we have just disconnected, 321727ad0b0SHugo Santos // as calling connect() always triggers an implicit bind(): 322727ad0b0SHugo Santos return _BindEndpoint(endpoint, *endpoint->LocalAddress()); 323727ad0b0SHugo Santos } 324727ad0b0SHugo Santos 325727ad0b0SHugo Santos 326727ad0b0SHugo Santos status_t 327727ad0b0SHugo Santos UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint) 328727ad0b0SHugo Santos { 3292b07b8e0SIngo Weinhold MutexLocker _(fLock); 330727ad0b0SHugo Santos 331727ad0b0SHugo Santos if (endpoint->IsActive()) 332727ad0b0SHugo Santos fActiveEndpoints.Remove(endpoint); 333727ad0b0SHugo Santos 334727ad0b0SHugo Santos endpoint->SetActive(false); 335727ad0b0SHugo Santos 336727ad0b0SHugo Santos return B_OK; 337727ad0b0SHugo Santos } 338727ad0b0SHugo Santos 339727ad0b0SHugo Santos 340cf5d9f4bSHugo Santos void 341cf5d9f4bSHugo Santos UdpDomainSupport::DumpEndpoints() const 342cf5d9f4bSHugo Santos { 343cf5d9f4bSHugo Santos kprintf("-------- UDP Domain %p ---------\n", this); 344cf5d9f4bSHugo Santos kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q"); 345cf5d9f4bSHugo Santos 346cf5d9f4bSHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 347cf5d9f4bSHugo Santos 348cf5d9f4bSHugo Santos while (it.HasNext()) { 349cf5d9f4bSHugo Santos UdpEndpoint *endpoint = it.Next(); 350cf5d9f4bSHugo Santos 351cf5d9f4bSHugo Santos char localBuf[64], peerBuf[64]; 352cf5d9f4bSHugo Santos endpoint->LocalAddress().AsString(localBuf, sizeof(localBuf), true); 353cf5d9f4bSHugo Santos endpoint->PeerAddress().AsString(peerBuf, sizeof(peerBuf), true); 354cf5d9f4bSHugo Santos 355cf5d9f4bSHugo Santos kprintf("%p %20s %20s %8lu\n", endpoint, localBuf, peerBuf, 356cf5d9f4bSHugo Santos endpoint->AvailableData()); 357cf5d9f4bSHugo Santos } 358cf5d9f4bSHugo Santos } 359cf5d9f4bSHugo Santos 360cf5d9f4bSHugo Santos 361727ad0b0SHugo Santos status_t 362727ad0b0SHugo Santos UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint, 363727ad0b0SHugo Santos const sockaddr *address) 364727ad0b0SHugo Santos { 365727ad0b0SHugo Santos if (AddressModule()->get_port(address) == 0) 366727ad0b0SHugo Santos return _BindToEphemeral(endpoint, address); 367727ad0b0SHugo Santos 368727ad0b0SHugo Santos return _Bind(endpoint, address); 369727ad0b0SHugo Santos } 370727ad0b0SHugo Santos 371727ad0b0SHugo Santos 372727ad0b0SHugo Santos status_t 373727ad0b0SHugo Santos UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address) 374727ad0b0SHugo Santos { 375727ad0b0SHugo Santos int socketOptions = endpoint->Socket()->options; 37640bbf860SHugo Santos 37740bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 378bf48e753SHugo Santos 379bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind 380bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]): 381727ad0b0SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain, 382727ad0b0SHugo Santos address, true).Data()); 383727ad0b0SHugo Santos 38440bbf860SHugo Santos while (it.HasNext()) { 38540bbf860SHugo Santos UdpEndpoint *otherEndpoint = it.Next(); 38625a2744fSHugo Santos 387bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint, 3885084c839SHugo Santos ntohs(otherEndpoint->LocalAddress().Port())); 38925a2744fSHugo Santos 39025a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualPorts(address)) { 391bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required: 392727ad0b0SHugo Santos if (otherEndpoint->Socket()->options & (SO_REUSEADDR | SO_REUSEPORT) == 0 393727ad0b0SHugo Santos || socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0) 394727ad0b0SHugo Santos return EADDRINUSE; 39525a2744fSHugo Santos 396bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required: 39725a2744fSHugo Santos if (otherEndpoint->LocalAddress().EqualTo(address, false) 398727ad0b0SHugo Santos && (otherEndpoint->Socket()->options & SO_REUSEPORT == 0 399727ad0b0SHugo Santos || socketOptions & SO_REUSEPORT == 0)) 400727ad0b0SHugo Santos return EADDRINUSE; 401bf48e753SHugo Santos } 402bf48e753SHugo Santos } 403bf48e753SHugo Santos 404727ad0b0SHugo Santos return _FinishBind(endpoint, address); 405bf48e753SHugo Santos } 406bf48e753SHugo Santos 407bf48e753SHugo Santos 408bf48e753SHugo Santos status_t 409727ad0b0SHugo Santos UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint, 410727ad0b0SHugo Santos const sockaddr *address) 411727ad0b0SHugo Santos { 412727ad0b0SHugo Santos SocketAddressStorage newAddress(AddressModule()); 413727ad0b0SHugo Santos status_t status = newAddress.SetTo(address); 414727ad0b0SHugo Santos if (status < B_OK) 415727ad0b0SHugo Santos return status; 416727ad0b0SHugo Santos 417727ad0b0SHugo Santos uint16 allocedPort = _GetNextEphemeral(); 418727ad0b0SHugo Santos if (allocedPort == 0) 419727ad0b0SHugo Santos return ENOBUFS; 420727ad0b0SHugo Santos 421*9e051839SOliver Tappe newAddress.SetPort(htons(allocedPort)); 422727ad0b0SHugo Santos 423727ad0b0SHugo Santos return _FinishBind(endpoint, *newAddress); 424727ad0b0SHugo Santos } 425727ad0b0SHugo Santos 426727ad0b0SHugo Santos 427727ad0b0SHugo Santos status_t 428727ad0b0SHugo Santos UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address) 429727ad0b0SHugo Santos { 430727ad0b0SHugo Santos status_t status = endpoint->next->module->bind(endpoint->next, address); 431727ad0b0SHugo Santos if (status < B_OK) 432727ad0b0SHugo Santos return status; 43340bbf860SHugo Santos 43440bbf860SHugo Santos fActiveEndpoints.Insert(endpoint); 435727ad0b0SHugo Santos endpoint->SetActive(true); 436727ad0b0SHugo Santos 43740bbf860SHugo Santos return B_OK; 438bf48e753SHugo Santos } 439bf48e753SHugo Santos 440bf48e753SHugo Santos 441c22d69bfSAxel Dörfler UdpEndpoint * 44240bbf860SHugo Santos UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress, 44340bbf860SHugo Santos const sockaddr *peerAddress) 444c22d69bfSAxel Dörfler { 445*9e051839SOliver Tappe TRACE_DOMAIN("finding Endpoint for %s <- %s", 446bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(), 447bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data()); 448c3e054c8SHugo Santos 44940bbf860SHugo Santos return fActiveEndpoints.Lookup(std::make_pair(ourAddress, peerAddress)); 450c22d69bfSAxel Dörfler } 451c22d69bfSAxel Dörfler 452c22d69bfSAxel Dörfler 453c22d69bfSAxel Dörfler status_t 454bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) 455c22d69bfSAxel Dörfler { 45679a0d252SHugo Santos sockaddr *peerAddr = buffer->source; 45779a0d252SHugo Santos sockaddr *broadcastAddr = buffer->destination; 458c22d69bfSAxel Dörfler sockaddr *mask = NULL; 459c22d69bfSAxel Dörfler if (buffer->interface) 460c22d69bfSAxel Dörfler mask = (sockaddr *)buffer->interface->mask; 461c22d69bfSAxel Dörfler 462bf48e753SHugo Santos TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); 463c22d69bfSAxel Dörfler 464bf48e753SHugo Santos uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 465c22d69bfSAxel Dörfler 46640bbf860SHugo Santos EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); 46740bbf860SHugo Santos 46840bbf860SHugo Santos while (it.HasNext()) { 46940bbf860SHugo Santos UdpEndpoint *endpoint = it.Next(); 470c22d69bfSAxel Dörfler 47125a2744fSHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", 47225a2744fSHugo Santos AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); 47325a2744fSHugo Santos 4745084c839SHugo Santos if (endpoint->LocalAddress().Port() != incomingPort) { 475c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint... 476c22d69bfSAxel Dörfler continue; 477c22d69bfSAxel Dörfler } 478c22d69bfSAxel Dörfler 47925a2744fSHugo Santos if (!endpoint->PeerAddress().IsEmpty(true)) { 480c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if 481c22d69bfSAxel Dörfler // this datagram is from there: 48225a2744fSHugo Santos if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) { 483c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to 484c22d69bfSAxel Dörfler // this endpoint... 485c22d69bfSAxel Dörfler continue; 486c22d69bfSAxel Dörfler } 487c22d69bfSAxel Dörfler } 488c22d69bfSAxel Dörfler 48925a2744fSHugo Santos if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) 49025a2744fSHugo Santos || endpoint->LocalAddress().IsEmpty(false)) { 491c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint: 492c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 493c22d69bfSAxel Dörfler } 494c22d69bfSAxel Dörfler } 49540bbf860SHugo Santos 496c22d69bfSAxel Dörfler return B_OK; 497c22d69bfSAxel Dörfler } 498c22d69bfSAxel Dörfler 499c22d69bfSAxel Dörfler 500c22d69bfSAxel Dörfler status_t 501bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer *buffer) 502c22d69bfSAxel Dörfler { 50379a0d252SHugo Santos struct sockaddr *peerAddr = buffer->source; 50479a0d252SHugo Santos struct sockaddr *localAddr = buffer->destination; 505c22d69bfSAxel Dörfler 506bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer); 507c22d69bfSAxel Dörfler 508c22d69bfSAxel Dörfler UdpEndpoint *endpoint; 509c22d69bfSAxel Dörfler // look for full (most special) match: 510bf48e753SHugo Santos endpoint = _FindActiveEndpoint(localAddr, peerAddr); 511c22d69bfSAxel Dörfler if (!endpoint) { 512c22d69bfSAxel Dörfler // look for endpoint matching local address & port: 513bf48e753SHugo Santos endpoint = _FindActiveEndpoint(localAddr, NULL); 514c22d69bfSAxel Dörfler if (!endpoint) { 515c22d69bfSAxel Dörfler // look for endpoint matching peer address & port and local port: 51625a2744fSHugo Santos SocketAddressStorage local(AddressModule()); 51725a2744fSHugo Santos local.SetToEmpty(); 51825a2744fSHugo Santos local.SetPort(AddressModule()->get_port(localAddr)); 51925a2744fSHugo Santos endpoint = _FindActiveEndpoint(*local, peerAddr); 520c22d69bfSAxel Dörfler if (!endpoint) { 521c22d69bfSAxel Dörfler // last chance: look for endpoint matching local port only: 52225a2744fSHugo Santos endpoint = _FindActiveEndpoint(*local, NULL); 523c22d69bfSAxel Dörfler } 524c22d69bfSAxel Dörfler } 525c22d69bfSAxel Dörfler } 526bf48e753SHugo Santos 527*9e051839SOliver Tappe if (!endpoint) { 528*9e051839SOliver Tappe TRACE_DOMAIN("_DemuxBroadcast(%p) - no matching endpoint found!", buffer); 529c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND; 530*9e051839SOliver Tappe } 531c22d69bfSAxel Dörfler 532c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 533c22d69bfSAxel Dörfler return B_OK; 534c22d69bfSAxel Dörfler } 535c22d69bfSAxel Dörfler 536c22d69bfSAxel Dörfler 537bf48e753SHugo Santos uint16 538bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral() 539c22d69bfSAxel Dörfler { 54040bbf860SHugo Santos uint16 stop, curr; 541bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) { 542bf48e753SHugo Santos stop = fLastUsedEphemeral; 543bf48e753SHugo Santos curr = fLastUsedEphemeral + 1; 544bf48e753SHugo Santos } else { 545bf48e753SHugo Santos stop = kLast; 546bf48e753SHugo Santos curr = kFirst; 547bf48e753SHugo Santos } 548c22d69bfSAxel Dörfler 549727ad0b0SHugo Santos TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu", 550727ad0b0SHugo Santos fLastUsedEphemeral, curr, stop); 55140bbf860SHugo Santos 552*9e051839SOliver Tappe // TODO: a free list could be used to avoid the impact of these two 553*9e051839SOliver Tappe // nested loops most of the time... let's see how bad this really is 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 { 5882b07b8e0SIngo Weinhold mutex_init(&fLock, "UDP endpoints"); 5892b07b8e0SIngo Weinhold fStatus = B_OK; 590bf48e753SHugo Santos } 591bf48e753SHugo Santos 592bf48e753SHugo Santos 593bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 594bf48e753SHugo Santos { 5952b07b8e0SIngo Weinhold mutex_destroy(&fLock); 596bf48e753SHugo Santos } 597bf48e753SHugo Santos 598bf48e753SHugo Santos 599bf48e753SHugo Santos status_t 600bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 601bf48e753SHugo Santos { 602bf48e753SHugo Santos return fStatus; 603bf48e753SHugo Santos } 604bf48e753SHugo Santos 605bf48e753SHugo Santos 606cf5d9f4bSHugo Santos int 607cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints(int argc, char *argv[]) 608cf5d9f4bSHugo Santos { 609cf5d9f4bSHugo Santos UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator(); 610cf5d9f4bSHugo Santos 611cf5d9f4bSHugo Santos while (it.HasNext()) 612cf5d9f4bSHugo Santos it.Next()->DumpEndpoints(); 613cf5d9f4bSHugo Santos 614cf5d9f4bSHugo Santos return 0; 615cf5d9f4bSHugo Santos } 616cf5d9f4bSHugo Santos 617cf5d9f4bSHugo Santos 618bf48e753SHugo Santos // #pragma mark - inbound 619bf48e753SHugo Santos 620bf48e753SHugo Santos 621bf48e753SHugo Santos status_t 622c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer) 623c22d69bfSAxel Dörfler { 6246a606180SHugo Santos status_t status = Deframe(buffer); 6256a606180SHugo Santos if (status < B_OK) 6266a606180SHugo Santos return status; 6276a606180SHugo Santos 628bf48e753SHugo Santos TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size); 629bf48e753SHugo Santos 6306a606180SHugo Santos net_domain *domain = buffer->interface->domain; 6316a606180SHugo Santos 632727ad0b0SHugo Santos UdpDomainSupport *domainSupport = NULL; 6336a606180SHugo Santos 634727ad0b0SHugo Santos { 6352b07b8e0SIngo Weinhold MutexLocker _(fLock); 636727ad0b0SHugo Santos domainSupport = _GetDomain(domain, false); 637727ad0b0SHugo Santos // TODO we don't want to hold to the manager's lock 638727ad0b0SHugo Santos // during the whole RX path, we may not hold an 639727ad0b0SHugo Santos // endpoint's lock with the manager lock held. 640727ad0b0SHugo Santos // But we should increase the domain's refcount 641727ad0b0SHugo Santos // here. 642727ad0b0SHugo Santos } 643727ad0b0SHugo Santos 6446a606180SHugo Santos if (domainSupport == NULL) { 6456a606180SHugo Santos // we don't instantiate domain supports in the 6466a606180SHugo Santos // RX path as we are only interested in delivering 6476a606180SHugo Santos // data to existing sockets. 6486a606180SHugo Santos return B_ERROR; 6496a606180SHugo Santos } 6506a606180SHugo Santos 6516a606180SHugo Santos status = domainSupport->DemuxIncomingBuffer(buffer); 6526a606180SHugo Santos if (status < B_OK) { 6536a606180SHugo Santos TRACE_EPM(" ReceiveData(): no endpoint."); 6546a606180SHugo Santos // TODO: send ICMP-error 6556a606180SHugo Santos return B_ERROR; 6566a606180SHugo Santos } 6576a606180SHugo Santos 658a1deb55eSHugo Santos gBufferModule->free(buffer); 659a1deb55eSHugo Santos return B_OK; 6606a606180SHugo Santos } 6616a606180SHugo Santos 6626a606180SHugo Santos 6636a606180SHugo Santos status_t 6646a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer) 6656a606180SHugo Santos { 6666a606180SHugo Santos TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); 6676a606180SHugo Santos 66887001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer); 669c22d69bfSAxel Dörfler if (bufferHeader.Status() < B_OK) 670c22d69bfSAxel Dörfler return bufferHeader.Status(); 671c22d69bfSAxel Dörfler 672c22d69bfSAxel Dörfler udp_header &header = bufferHeader.Data(); 673c22d69bfSAxel Dörfler 674bf48e753SHugo Santos if (buffer->interface == NULL || buffer->interface->domain == NULL) { 6756a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " 676bf48e753SHugo Santos "specified (interface %p).", buffer->interface); 677c22d69bfSAxel Dörfler return B_BAD_VALUE; 678c22d69bfSAxel Dörfler } 679bf48e753SHugo Santos 680bf48e753SHugo Santos net_domain *domain = buffer->interface->domain; 681bf48e753SHugo Santos net_address_module_info *addressModule = domain->address_module; 682bf48e753SHugo Santos 68379a0d252SHugo Santos SocketAddress source(addressModule, buffer->source); 68479a0d252SHugo Santos SocketAddress destination(addressModule, buffer->destination); 685bf48e753SHugo Santos 6864e8a1b33SHugo Santos source.SetPort(header.source_port); 6874e8a1b33SHugo Santos destination.SetPort(header.destination_port); 6884e8a1b33SHugo Santos 6894e8a1b33SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(), 6904e8a1b33SHugo Santos destination.AsString(true).Data()); 691c22d69bfSAxel Dörfler 692c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length); 693c22d69bfSAxel Dörfler if (udpLength > buffer->size) { 6946a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", 695bf48e753SHugo Santos udpLength); 696c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES; 697c22d69bfSAxel Dörfler } 698bf48e753SHugo Santos 699bf48e753SHugo Santos if (buffer->size > udpLength) 700c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength); 701c22d69bfSAxel Dörfler 702c22d69bfSAxel Dörfler if (header.udp_checksum != 0) { 703c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"): 704d5b5a2c2SHugo Santos uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule, 705d5b5a2c2SHugo Santos buffer, IPPROTO_UDP); 706c22d69bfSAxel Dörfler if (sum != 0) { 7076a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); 708c22d69bfSAxel Dörfler return B_BAD_VALUE; 709c22d69bfSAxel Dörfler } 710c22d69bfSAxel Dörfler } 711c22d69bfSAxel Dörfler 712c22d69bfSAxel Dörfler bufferHeader.Remove(); 713c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on 714c22d69bfSAxel Dörfler 7156a606180SHugo Santos return B_OK; 716c22d69bfSAxel Dörfler } 717c22d69bfSAxel Dörfler 718c22d69bfSAxel Dörfler 719bf48e753SHugo Santos UdpDomainSupport * 720c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) 721c22d69bfSAxel Dörfler { 7222b07b8e0SIngo Weinhold MutexLocker _(fLock); 723bf48e753SHugo Santos 724bf48e753SHugo Santos UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); 725bf48e753SHugo Santos if (domain) 726bf48e753SHugo Santos domain->Ref(); 727bf48e753SHugo Santos return domain; 728bf48e753SHugo Santos } 729bf48e753SHugo Santos 730bf48e753SHugo Santos 731bf48e753SHugo Santos status_t 732bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) 733bf48e753SHugo Santos { 7342b07b8e0SIngo Weinhold MutexLocker _(fLock); 735bf48e753SHugo Santos 736727ad0b0SHugo Santos if (domain->Put()) { 737bf48e753SHugo Santos fDomains.Remove(domain); 738bf48e753SHugo Santos delete domain; 739bf48e753SHugo Santos } 740bf48e753SHugo Santos 741bf48e753SHugo Santos return B_OK; 742bf48e753SHugo Santos } 743bf48e753SHugo Santos 744bf48e753SHugo Santos 745bf48e753SHugo Santos // #pragma mark - 746bf48e753SHugo Santos 747bf48e753SHugo Santos 748bf48e753SHugo Santos UdpDomainSupport * 749bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create) 750bf48e753SHugo Santos { 751bf48e753SHugo Santos UdpDomainList::Iterator it = fDomains.GetIterator(); 752bf48e753SHugo Santos 753bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain 754bf48e753SHugo Santos // receiver handlers that forward the requests to the 755bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while 756bf48e753SHugo Santos // being constructed UdpDomainSupport could call 757bf48e753SHugo Santos // register_domain_receiving_protocol() with the right 758bf48e753SHugo Santos // family. 759bf48e753SHugo Santos while (it.HasNext()) { 760bf48e753SHugo Santos UdpDomainSupport *domainSupport = it.Next(); 761bf48e753SHugo Santos if (domainSupport->Domain() == domain) 762bf48e753SHugo Santos return domainSupport; 763bf48e753SHugo Santos } 764bf48e753SHugo Santos 765bf48e753SHugo Santos if (!create) 766bf48e753SHugo Santos return NULL; 767bf48e753SHugo Santos 768bf48e753SHugo Santos UdpDomainSupport *domainSupport = 769bf48e753SHugo Santos new (std::nothrow) UdpDomainSupport(domain); 770276aa463SIngo Weinhold if (domainSupport == NULL || domainSupport->Init() < B_OK) { 771bf48e753SHugo Santos delete domainSupport; 772bf48e753SHugo Santos return NULL; 773bf48e753SHugo Santos } 774bf48e753SHugo Santos 775bf48e753SHugo Santos fDomains.Add(domainSupport); 776bf48e753SHugo Santos return domainSupport; 777c22d69bfSAxel Dörfler } 778c22d69bfSAxel Dörfler 779c22d69bfSAxel Dörfler 780c22d69bfSAxel Dörfler // #pragma mark - 781c22d69bfSAxel Dörfler 782c22d69bfSAxel Dörfler 783c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 784c72ab92dSHugo Santos : DatagramSocket<>("udp endpoint", socket), fActive(false) {} 785bf48e753SHugo Santos 786bf48e753SHugo Santos 787c22d69bfSAxel Dörfler // #pragma mark - activation 788c22d69bfSAxel Dörfler 789c22d69bfSAxel Dörfler 790c22d69bfSAxel Dörfler status_t 79153f23f85SHugo Santos UdpEndpoint::Bind(const sockaddr *address) 792c22d69bfSAxel Dörfler { 793bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 794727ad0b0SHugo Santos return fManager->BindEndpoint(this, address); 795c22d69bfSAxel Dörfler } 796c22d69bfSAxel Dörfler 797c22d69bfSAxel Dörfler 798c22d69bfSAxel Dörfler status_t 799c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 800c22d69bfSAxel Dörfler { 801bf48e753SHugo Santos TRACE_EP("Unbind()"); 802727ad0b0SHugo Santos return fManager->UnbindEndpoint(this); 803c22d69bfSAxel Dörfler } 804c22d69bfSAxel Dörfler 805c22d69bfSAxel Dörfler 806c22d69bfSAxel Dörfler status_t 807c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 808c22d69bfSAxel Dörfler { 809bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 810727ad0b0SHugo Santos return fManager->ConnectEndpoint(this, address); 811c22d69bfSAxel Dörfler } 812c22d69bfSAxel Dörfler 813c22d69bfSAxel Dörfler 814c22d69bfSAxel Dörfler status_t 815c22d69bfSAxel Dörfler UdpEndpoint::Open() 816c22d69bfSAxel Dörfler { 817bf48e753SHugo Santos TRACE_EP("Open()"); 818bf48e753SHugo Santos 819119c6cddSIngo Weinhold AutoLocker _(fLock); 820727ad0b0SHugo Santos 821c72ab92dSHugo Santos status_t status = ProtocolSocket::Open(); 822c72ab92dSHugo Santos if (status < B_OK) 823c72ab92dSHugo Santos return status; 824bf48e753SHugo Santos 825c72ab92dSHugo Santos fManager = sUdpEndpointManager->OpenEndpoint(this); 826c72ab92dSHugo Santos if (fManager == NULL) 827bf48e753SHugo Santos return EAFNOSUPPORT; 828bf48e753SHugo Santos 829bf48e753SHugo Santos return B_OK; 830c22d69bfSAxel Dörfler } 831c22d69bfSAxel Dörfler 832c22d69bfSAxel Dörfler 833c22d69bfSAxel Dörfler status_t 834c22d69bfSAxel Dörfler UdpEndpoint::Close() 835c22d69bfSAxel Dörfler { 836bf48e753SHugo Santos TRACE_EP("Close()"); 837bf48e753SHugo Santos return B_OK; 838c22d69bfSAxel Dörfler } 839c22d69bfSAxel Dörfler 840c22d69bfSAxel Dörfler 841c22d69bfSAxel Dörfler status_t 842c22d69bfSAxel Dörfler UdpEndpoint::Free() 843c22d69bfSAxel Dörfler { 844bf48e753SHugo Santos TRACE_EP("Free()"); 8450086fe20SHugo Santos fManager->UnbindEndpoint(this); 846c72ab92dSHugo Santos return sUdpEndpointManager->FreeEndpoint(fManager); 847c22d69bfSAxel Dörfler } 848c22d69bfSAxel Dörfler 849c22d69bfSAxel Dörfler 850c22d69bfSAxel Dörfler // #pragma mark - outbound 851c22d69bfSAxel Dörfler 852c22d69bfSAxel Dörfler 853c22d69bfSAxel Dörfler status_t 854bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 855c22d69bfSAxel Dörfler { 856bf48e753SHugo Santos TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route); 857bf48e753SHugo Santos 858d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 859c22d69bfSAxel Dörfler return EMSGSIZE; 860c22d69bfSAxel Dörfler 861c22d69bfSAxel Dörfler buffer->protocol = IPPROTO_UDP; 862c22d69bfSAxel Dörfler 863c22d69bfSAxel Dörfler // add and fill UDP-specific header: 8646c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 8656c353509SHugo Santos if (header.Status() < B_OK) 8666c353509SHugo Santos return header.Status(); 867c22d69bfSAxel Dörfler 86879a0d252SHugo Santos header->source_port = AddressModule()->get_port(buffer->source); 86979a0d252SHugo Santos header->destination_port = AddressModule()->get_port(buffer->destination); 8706c353509SHugo Santos header->udp_length = htons(buffer->size); 871c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 8726c353509SHugo Santos header->udp_checksum = 0; 8736c353509SHugo Santos 8746c353509SHugo Santos header.Sync(); 875c22d69bfSAxel Dörfler 876d5b5a2c2SHugo Santos uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(), 877d5b5a2c2SHugo Santos gBufferModule, buffer, IPPROTO_UDP); 8786c353509SHugo Santos if (calculatedChecksum == 0) 8796c353509SHugo Santos calculatedChecksum = 0xffff; 8806c353509SHugo Santos 8816c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 882c22d69bfSAxel Dörfler 883c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 884c22d69bfSAxel Dörfler } 885c22d69bfSAxel Dörfler 886c22d69bfSAxel Dörfler 887bf48e753SHugo Santos status_t 888bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 889bf48e753SHugo Santos { 890bf48e753SHugo Santos TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size); 891bf48e753SHugo Santos 8921408d1f0SHugo Santos return gDatalinkModule->send_datagram(this, NULL, buffer); 893bf48e753SHugo Santos } 894bf48e753SHugo Santos 895bf48e753SHugo Santos 896c22d69bfSAxel Dörfler // #pragma mark - inbound 897c22d69bfSAxel Dörfler 898c22d69bfSAxel Dörfler 899c22d69bfSAxel Dörfler ssize_t 900c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 901c22d69bfSAxel Dörfler { 902bfb45f71SHugo Santos size_t bytes = AvailableData(); 903bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 904bfb45f71SHugo Santos return bytes; 905c22d69bfSAxel Dörfler } 906c22d69bfSAxel Dörfler 907c22d69bfSAxel Dörfler 908c22d69bfSAxel Dörfler status_t 909c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 910c22d69bfSAxel Dörfler { 911bf48e753SHugo Santos TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags); 912bf48e753SHugo Santos 913bfb45f71SHugo Santos status_t status = SocketDequeue(flags, _buffer); 914bf48e753SHugo Santos TRACE_EP(" FetchData(): returned from fifo status=0x%lx", status); 915c22d69bfSAxel Dörfler if (status < B_OK) 916c22d69bfSAxel Dörfler return status; 917c22d69bfSAxel Dörfler 918bfb45f71SHugo Santos TRACE_EP(" FetchData(): returns buffer with %ld bytes", (*_buffer)->size); 919c22d69bfSAxel Dörfler return B_OK; 920c22d69bfSAxel Dörfler } 921c22d69bfSAxel Dörfler 922c22d69bfSAxel Dörfler 923c22d69bfSAxel Dörfler status_t 924bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 925c22d69bfSAxel Dörfler { 926bf48e753SHugo Santos TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size); 927c22d69bfSAxel Dörfler 92849f3c71eSHugo Santos return SocketEnqueue(buffer); 929c22d69bfSAxel Dörfler } 930c22d69bfSAxel Dörfler 931c22d69bfSAxel Dörfler 9326a606180SHugo Santos status_t 9336a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 9346a606180SHugo Santos { 935f6cfc5afSHugo Santos TRACE_EP("DeliverData(%p [%ld bytes])", _buffer, _buffer->size); 936f6cfc5afSHugo Santos 9376a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 9386a606180SHugo Santos if (buffer == NULL) 9396a606180SHugo Santos return B_NO_MEMORY; 9406a606180SHugo Santos 9416a606180SHugo Santos status_t status = sUdpEndpointManager->Deframe(buffer); 9426a606180SHugo Santos if (status < B_OK) { 9436a606180SHugo Santos gBufferModule->free(buffer); 9446a606180SHugo Santos return status; 9456a606180SHugo Santos } 9466a606180SHugo Santos 9476a606180SHugo Santos // we call Enqueue() instead of SocketEnqueue() as there is 9486a606180SHugo Santos // no need to clone the buffer again. 9496a606180SHugo Santos return Enqueue(buffer); 9506a606180SHugo Santos } 9516a606180SHugo Santos 9526a606180SHugo Santos 953c22d69bfSAxel Dörfler // #pragma mark - protocol interface 954c22d69bfSAxel Dörfler 955c22d69bfSAxel Dörfler 956c22d69bfSAxel Dörfler net_protocol * 957c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 958c22d69bfSAxel Dörfler { 959c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 960c22d69bfSAxel Dörfler 961c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 962bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 963bf48e753SHugo Santos delete endpoint; 964bf48e753SHugo Santos return NULL; 965bf48e753SHugo Santos } 966bf48e753SHugo Santos 967c22d69bfSAxel Dörfler return endpoint; 968c22d69bfSAxel Dörfler } 969c22d69bfSAxel Dörfler 970c22d69bfSAxel Dörfler 971c22d69bfSAxel Dörfler status_t 972c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 973c22d69bfSAxel Dörfler { 974bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 975c22d69bfSAxel Dörfler return B_OK; 976c22d69bfSAxel Dörfler } 977c22d69bfSAxel Dörfler 978c22d69bfSAxel Dörfler 979c22d69bfSAxel Dörfler status_t 980c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 981c22d69bfSAxel Dörfler { 982bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 983c22d69bfSAxel Dörfler } 984c22d69bfSAxel Dörfler 985c22d69bfSAxel Dörfler 986c22d69bfSAxel Dörfler status_t 987c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 988c22d69bfSAxel Dörfler { 989bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 990c22d69bfSAxel Dörfler } 991c22d69bfSAxel Dörfler 992c22d69bfSAxel Dörfler 993c22d69bfSAxel Dörfler status_t 994c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 995c22d69bfSAxel Dörfler { 996bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 997c22d69bfSAxel Dörfler } 998c22d69bfSAxel Dörfler 999c22d69bfSAxel Dörfler 1000c22d69bfSAxel Dörfler status_t 1001c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1002c22d69bfSAxel Dörfler { 1003bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1004c22d69bfSAxel Dörfler } 1005c22d69bfSAxel Dörfler 1006c22d69bfSAxel Dörfler 1007c22d69bfSAxel Dörfler status_t 1008c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1009c22d69bfSAxel Dörfler { 1010c22d69bfSAxel Dörfler return EOPNOTSUPP; 1011c22d69bfSAxel Dörfler } 1012c22d69bfSAxel Dörfler 1013c22d69bfSAxel Dörfler 1014c22d69bfSAxel Dörfler status_t 1015c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1016c22d69bfSAxel Dörfler size_t *_length) 1017c22d69bfSAxel Dörfler { 1018c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1019c22d69bfSAxel Dörfler value, _length); 1020c22d69bfSAxel Dörfler } 1021c22d69bfSAxel Dörfler 1022c22d69bfSAxel Dörfler 1023c22d69bfSAxel Dörfler status_t 102445b5203bSHugo Santos udp_getsockopt(net_protocol *protocol, int level, int option, void *value, 102545b5203bSHugo Santos int *length) 102645b5203bSHugo Santos { 102745b5203bSHugo Santos return protocol->next->module->getsockopt(protocol->next, level, option, 102845b5203bSHugo Santos value, length); 102945b5203bSHugo Santos } 103045b5203bSHugo Santos 103145b5203bSHugo Santos 103245b5203bSHugo Santos status_t 103345b5203bSHugo Santos udp_setsockopt(net_protocol *protocol, int level, int option, 103445b5203bSHugo Santos const void *value, int length) 103545b5203bSHugo Santos { 103645b5203bSHugo Santos return protocol->next->module->setsockopt(protocol->next, level, option, 103745b5203bSHugo Santos value, length); 103845b5203bSHugo Santos } 103945b5203bSHugo Santos 104045b5203bSHugo Santos 104145b5203bSHugo Santos status_t 104253f23f85SHugo Santos udp_bind(net_protocol *protocol, const struct sockaddr *address) 1043c22d69bfSAxel Dörfler { 1044bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1045c22d69bfSAxel Dörfler } 1046c22d69bfSAxel Dörfler 1047c22d69bfSAxel Dörfler 1048c22d69bfSAxel Dörfler status_t 1049c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1050c22d69bfSAxel Dörfler { 1051bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1052c22d69bfSAxel Dörfler } 1053c22d69bfSAxel Dörfler 1054c22d69bfSAxel Dörfler 1055c22d69bfSAxel Dörfler status_t 1056c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1057c22d69bfSAxel Dörfler { 1058c22d69bfSAxel Dörfler return EOPNOTSUPP; 1059c22d69bfSAxel Dörfler } 1060c22d69bfSAxel Dörfler 1061c22d69bfSAxel Dörfler 1062c22d69bfSAxel Dörfler status_t 1063c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1064c22d69bfSAxel Dörfler { 1065c22d69bfSAxel Dörfler return EOPNOTSUPP; 1066c22d69bfSAxel Dörfler } 1067c22d69bfSAxel Dörfler 1068c22d69bfSAxel Dörfler 1069c22d69bfSAxel Dörfler status_t 1070c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1071c22d69bfSAxel Dörfler net_buffer *buffer) 1072c22d69bfSAxel Dörfler { 1073bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1074c22d69bfSAxel Dörfler } 1075c22d69bfSAxel Dörfler 1076c22d69bfSAxel Dörfler 1077c22d69bfSAxel Dörfler status_t 1078c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1079c22d69bfSAxel Dörfler { 1080bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1081c22d69bfSAxel Dörfler } 1082c22d69bfSAxel Dörfler 1083c22d69bfSAxel Dörfler 1084c22d69bfSAxel Dörfler ssize_t 1085c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1086c22d69bfSAxel Dörfler { 1087bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1088c22d69bfSAxel Dörfler } 1089c22d69bfSAxel Dörfler 1090c22d69bfSAxel Dörfler 1091c22d69bfSAxel Dörfler status_t 1092c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1093c22d69bfSAxel Dörfler net_buffer **_buffer) 1094c22d69bfSAxel Dörfler { 1095bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1096c22d69bfSAxel Dörfler } 1097c22d69bfSAxel Dörfler 1098c22d69bfSAxel Dörfler 1099c22d69bfSAxel Dörfler ssize_t 1100c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1101c22d69bfSAxel Dörfler { 1102bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1103c22d69bfSAxel Dörfler } 1104c22d69bfSAxel Dörfler 1105c22d69bfSAxel Dörfler 1106c22d69bfSAxel Dörfler struct net_domain * 1107c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1108c22d69bfSAxel Dörfler { 1109c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1110c22d69bfSAxel Dörfler } 1111c22d69bfSAxel Dörfler 1112c22d69bfSAxel Dörfler 1113c22d69bfSAxel Dörfler size_t 1114c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1115c22d69bfSAxel Dörfler { 1116c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1117c22d69bfSAxel Dörfler } 1118c22d69bfSAxel Dörfler 1119c22d69bfSAxel Dörfler 1120c22d69bfSAxel Dörfler status_t 1121c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1122c22d69bfSAxel Dörfler { 1123c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1124c22d69bfSAxel Dörfler } 1125c22d69bfSAxel Dörfler 1126c22d69bfSAxel Dörfler 1127c22d69bfSAxel Dörfler status_t 11286a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 11296a606180SHugo Santos { 11306a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 11316a606180SHugo Santos } 11326a606180SHugo Santos 11336a606180SHugo Santos 11346a606180SHugo Santos status_t 1135c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data) 1136c22d69bfSAxel Dörfler { 1137c22d69bfSAxel Dörfler return B_ERROR; 1138c22d69bfSAxel Dörfler } 1139c22d69bfSAxel Dörfler 1140c22d69bfSAxel Dörfler 1141c22d69bfSAxel Dörfler status_t 1142c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, 1143c22d69bfSAxel Dörfler void *errorData) 1144c22d69bfSAxel Dörfler { 1145c22d69bfSAxel Dörfler return B_ERROR; 1146c22d69bfSAxel Dörfler } 1147c22d69bfSAxel Dörfler 1148c22d69bfSAxel Dörfler 1149c22d69bfSAxel Dörfler // #pragma mark - module interface 1150c22d69bfSAxel Dörfler 1151c22d69bfSAxel Dörfler 1152c22d69bfSAxel Dörfler static status_t 1153c22d69bfSAxel Dörfler init_udp() 1154c22d69bfSAxel Dörfler { 1155c22d69bfSAxel Dörfler status_t status; 1156bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1157c22d69bfSAxel Dörfler 1158c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1159658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1160658a5506SHugo Santos return B_NO_MEMORY; 1161658a5506SHugo Santos 1162c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1163c22d69bfSAxel Dörfler if (status != B_OK) 1164d438fa4cSHugo Santos goto err1; 1165c22d69bfSAxel Dörfler 1166bfb45f71SHugo Santos status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP, 1167c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1168c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1169c22d69bfSAxel Dörfler NULL); 1170c22d69bfSAxel Dörfler if (status < B_OK) 1171658a5506SHugo Santos goto err1; 1172bfb45f71SHugo Santos status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 1173c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1174c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1175c22d69bfSAxel Dörfler NULL); 1176c22d69bfSAxel Dörfler if (status < B_OK) 1177658a5506SHugo Santos goto err1; 1178c22d69bfSAxel Dörfler 1179bfb45f71SHugo Santos status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP, 1180c22d69bfSAxel Dörfler "network/protocols/udp/v1"); 1181c22d69bfSAxel Dörfler if (status < B_OK) 1182658a5506SHugo Santos goto err1; 1183c22d69bfSAxel Dörfler 1184cf5d9f4bSHugo Santos add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints, 1185cf5d9f4bSHugo Santos "lists all open UDP endpoints"); 1186cf5d9f4bSHugo Santos 1187c22d69bfSAxel Dörfler return B_OK; 1188c22d69bfSAxel Dörfler 1189c22d69bfSAxel Dörfler err1: 1190658a5506SHugo Santos delete sUdpEndpointManager; 1191c22d69bfSAxel Dörfler 1192bf48e753SHugo Santos TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status)); 1193c22d69bfSAxel Dörfler return status; 1194c22d69bfSAxel Dörfler } 1195c22d69bfSAxel Dörfler 1196c22d69bfSAxel Dörfler 1197c22d69bfSAxel Dörfler static status_t 1198c22d69bfSAxel Dörfler uninit_udp() 1199c22d69bfSAxel Dörfler { 1200bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1201cf5d9f4bSHugo Santos remove_debugger_command("udp_endpoints", 1202cf5d9f4bSHugo Santos UdpEndpointManager::DumpEndpoints); 1203c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1204c22d69bfSAxel Dörfler return B_OK; 1205c22d69bfSAxel Dörfler } 1206c22d69bfSAxel Dörfler 1207c22d69bfSAxel Dörfler 1208c22d69bfSAxel Dörfler static status_t 1209c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1210c22d69bfSAxel Dörfler { 1211c22d69bfSAxel Dörfler switch (op) { 1212c22d69bfSAxel Dörfler case B_MODULE_INIT: 1213c22d69bfSAxel Dörfler return init_udp(); 1214c22d69bfSAxel Dörfler 1215c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1216c22d69bfSAxel Dörfler return uninit_udp(); 1217c22d69bfSAxel Dörfler 1218c22d69bfSAxel Dörfler default: 1219c22d69bfSAxel Dörfler return B_ERROR; 1220c22d69bfSAxel Dörfler } 1221c22d69bfSAxel Dörfler } 1222c22d69bfSAxel Dörfler 1223c22d69bfSAxel Dörfler 1224c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1225c22d69bfSAxel Dörfler { 1226c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1227c22d69bfSAxel Dörfler 0, 1228c22d69bfSAxel Dörfler udp_std_ops 1229c22d69bfSAxel Dörfler }, 12306f58064fSAxel Dörfler NET_PROTOCOL_ATOMIC_MESSAGES, 12316f58064fSAxel Dörfler 1232c22d69bfSAxel Dörfler udp_init_protocol, 1233c22d69bfSAxel Dörfler udp_uninit_protocol, 1234c22d69bfSAxel Dörfler udp_open, 1235c22d69bfSAxel Dörfler udp_close, 1236c22d69bfSAxel Dörfler udp_free, 1237c22d69bfSAxel Dörfler udp_connect, 1238c22d69bfSAxel Dörfler udp_accept, 1239c22d69bfSAxel Dörfler udp_control, 124045b5203bSHugo Santos udp_getsockopt, 124145b5203bSHugo Santos udp_setsockopt, 1242c22d69bfSAxel Dörfler udp_bind, 1243c22d69bfSAxel Dörfler udp_unbind, 1244c22d69bfSAxel Dörfler udp_listen, 1245c22d69bfSAxel Dörfler udp_shutdown, 1246c22d69bfSAxel Dörfler udp_send_data, 1247c22d69bfSAxel Dörfler udp_send_routed_data, 1248c22d69bfSAxel Dörfler udp_send_avail, 1249c22d69bfSAxel Dörfler udp_read_data, 1250c22d69bfSAxel Dörfler udp_read_avail, 1251c22d69bfSAxel Dörfler udp_get_domain, 1252c22d69bfSAxel Dörfler udp_get_mtu, 1253c22d69bfSAxel Dörfler udp_receive_data, 12546a606180SHugo Santos udp_deliver_data, 1255c22d69bfSAxel Dörfler udp_error, 1256c22d69bfSAxel Dörfler udp_error_reply, 1257c22d69bfSAxel Dörfler }; 1258c22d69bfSAxel Dörfler 1259658a5506SHugo Santos module_dependency module_dependencies[] = { 1260658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1261658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1262658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 1263658a5506SHugo Santos {} 1264658a5506SHugo Santos }; 1265658a5506SHugo Santos 1266c22d69bfSAxel Dörfler module_info *modules[] = { 1267c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1268c22d69bfSAxel Dörfler NULL 1269c22d69bfSAxel Dörfler }; 1270