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> 19c22d69bfSAxel Dörfler #include <util/khash.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 33af3a31f7SAxel Dörfler //#define TRACE_UDP 34c22d69bfSAxel Dörfler #ifdef TRACE_UDP 35c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) dump_block x 36bf48e753SHugo Santos // do not remove the space before ', ##args' if you want this 37bf48e753SHugo Santos // to compile with gcc 2.95 38bf48e753SHugo Santos # define TRACE_EP(format, args...) dprintf("UDP [%llu] %p " format "\n", \ 39bf48e753SHugo Santos system_time(), this , ##args) 40bf48e753SHugo Santos # define TRACE_EPM(format, args...) dprintf("UDP [%llu] " format "\n", \ 41bf48e753SHugo Santos system_time() , ##args) 42bf48e753SHugo Santos # define TRACE_DOMAIN(format, args...) dprintf("UDP [%llu] (%d) " format \ 43bf48e753SHugo Santos "\n", system_time(), Domain()->family , ##args) 44c22d69bfSAxel Dörfler #else 45c22d69bfSAxel Dörfler # define TRACE_BLOCK(x) 46bf48e753SHugo Santos # define TRACE_EP(args...) do { } while (0) 47bf48e753SHugo Santos # define TRACE_EPM(args...) do { } while (0) 48bf48e753SHugo Santos # define TRACE_DOMAIN(args...) do { } while (0) 49c22d69bfSAxel Dörfler #endif 50c22d69bfSAxel Dörfler 51c22d69bfSAxel Dörfler 52c22d69bfSAxel Dörfler struct udp_header { 53c22d69bfSAxel Dörfler uint16 source_port; 54c22d69bfSAxel Dörfler uint16 destination_port; 55c22d69bfSAxel Dörfler uint16 udp_length; 56c22d69bfSAxel Dörfler uint16 udp_checksum; 57c22d69bfSAxel Dörfler } _PACKED; 58c22d69bfSAxel Dörfler 59c22d69bfSAxel Dörfler 606c353509SHugo Santos typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)> 616c353509SHugo Santos UDPChecksumField; 626c353509SHugo Santos 63bf48e753SHugo Santos class UdpDomainSupport; 646c353509SHugo Santos 65bfb45f71SHugo Santos class UdpEndpoint : public net_protocol, public DatagramSocket<> { 66c22d69bfSAxel Dörfler public: 67c22d69bfSAxel Dörfler UdpEndpoint(net_socket *socket); 68bf48e753SHugo Santos 69c22d69bfSAxel Dörfler status_t Bind(sockaddr *newAddr); 70c22d69bfSAxel Dörfler status_t Unbind(sockaddr *newAddr); 71c22d69bfSAxel Dörfler status_t Connect(const sockaddr *newAddr); 72c22d69bfSAxel Dörfler 73c22d69bfSAxel Dörfler status_t Open(); 74c22d69bfSAxel Dörfler status_t Close(); 75c22d69bfSAxel Dörfler status_t Free(); 76c22d69bfSAxel Dörfler 77bf48e753SHugo Santos status_t SendRoutedData(net_buffer *buffer, net_route *route); 78bf48e753SHugo Santos status_t SendData(net_buffer *buffer); 79c22d69bfSAxel Dörfler 80c22d69bfSAxel Dörfler ssize_t BytesAvailable(); 81c22d69bfSAxel Dörfler status_t FetchData(size_t numBytes, uint32 flags, 82c22d69bfSAxel Dörfler net_buffer **_buffer); 83c22d69bfSAxel Dörfler 84c22d69bfSAxel Dörfler status_t StoreData(net_buffer *buffer); 856a606180SHugo Santos status_t DeliverData(net_buffer *buffer); 86c22d69bfSAxel Dörfler 87bf48e753SHugo Santos net_domain * Domain() const 88bf48e753SHugo Santos { 89bf48e753SHugo Santos return socket->first_protocol->module->get_domain(socket->first_protocol); 90bf48e753SHugo Santos } 91bf48e753SHugo Santos 92bf48e753SHugo Santos net_address_module_info *AddressModule() const 93bf48e753SHugo Santos { 94bf48e753SHugo Santos return Domain()->address_module; 95bf48e753SHugo Santos } 96bf48e753SHugo Santos 97bf48e753SHugo Santos UdpDomainSupport *DomainSupport() const { return fDomain; } 98bf48e753SHugo Santos 99c22d69bfSAxel Dörfler UdpEndpoint *hash_link; 100c22d69bfSAxel Dörfler // link required by hash_table (see khash.h) 101c22d69bfSAxel Dörfler private: 102c22d69bfSAxel Dörfler status_t _Activate(); 103c22d69bfSAxel Dörfler status_t _Deactivate(); 104c22d69bfSAxel Dörfler 105bf48e753SHugo Santos UdpDomainSupport *fDomain; 106c22d69bfSAxel Dörfler bool fActive; 107c22d69bfSAxel Dörfler // an active UdpEndpoint is part of the endpoint 108c22d69bfSAxel Dörfler // hash (and it is bound and optionally connected) 109c22d69bfSAxel Dörfler }; 110c22d69bfSAxel Dörfler 111c22d69bfSAxel Dörfler 112bf48e753SHugo Santos class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> { 113c22d69bfSAxel Dörfler public: 114bf48e753SHugo Santos UdpDomainSupport(net_domain *domain); 115bf48e753SHugo Santos ~UdpDomainSupport(); 116c22d69bfSAxel Dörfler 117bf48e753SHugo Santos status_t InitCheck() const; 118bf48e753SHugo Santos 119bf48e753SHugo Santos net_domain *Domain() const { return fDomain; } 120bf48e753SHugo Santos 121bf48e753SHugo Santos void Ref() { fEndpointCount++; } 122bf48e753SHugo Santos void Put() { fEndpointCount--; } 123bf48e753SHugo Santos 124bf48e753SHugo Santos bool IsEmpty() const { return fEndpointCount == 0; } 125bf48e753SHugo Santos 126bf48e753SHugo Santos status_t DemuxIncomingBuffer(net_buffer *buffer); 127bf48e753SHugo Santos status_t CheckBindRequest(sockaddr *address, int socketOptions); 128bf48e753SHugo Santos status_t ActivateEndpoint(UdpEndpoint *endpoint); 129bf48e753SHugo Santos status_t DeactivateEndpoint(UdpEndpoint *endpoint); 130bf48e753SHugo Santos 131bf48e753SHugo Santos uint16 GetEphemeralPort(); 132bf48e753SHugo Santos 133c22d69bfSAxel Dörfler private: 134bf48e753SHugo Santos struct HashKey { 135bf48e753SHugo Santos HashKey() {} 136bf48e753SHugo Santos HashKey(net_address_module_info *module, const sockaddr *_local, 137bf48e753SHugo Santos const sockaddr *_peer) 138bf48e753SHugo Santos : address_module(module), local(_local), peer(_peer) {} 139bf48e753SHugo Santos 140bf48e753SHugo Santos net_address_module_info *address_module; 141bf48e753SHugo Santos const sockaddr *local; 142bf48e753SHugo Santos const sockaddr *peer; 143c22d69bfSAxel Dörfler }; 144c22d69bfSAxel Dörfler 145bf48e753SHugo Santos UdpEndpoint *_FindActiveEndpoint(sockaddr *ourAddress, 146bf48e753SHugo Santos sockaddr *peerAddress); 147bf48e753SHugo Santos status_t _DemuxBroadcast(net_buffer *buffer); 148bf48e753SHugo Santos status_t _DemuxMulticast(net_buffer *buffer); 149bf48e753SHugo Santos status_t _DemuxUnicast(net_buffer *buffer); 150bf48e753SHugo Santos 151bf48e753SHugo Santos uint16 _GetNextEphemeral(); 152bf48e753SHugo Santos 153bf48e753SHugo Santos static int _Compare(void *udpEndpoint, const void *_key); 154bf48e753SHugo Santos static uint32 _Hash(void *udpEndpoint, const void *key, uint32 range); 155bf48e753SHugo Santos 156bf48e753SHugo Santos net_address_module_info *AddressModule() const 157bf48e753SHugo Santos { 158bf48e753SHugo Santos return fDomain->address_module; 159bf48e753SHugo Santos } 160bf48e753SHugo Santos 161bf48e753SHugo Santos net_domain *fDomain; 162bf48e753SHugo Santos uint16 fLastUsedEphemeral; 163bf48e753SHugo Santos hash_table *fActiveEndpoints; 164bf48e753SHugo Santos uint32 fEndpointCount; 165bf48e753SHugo Santos 166bf48e753SHugo Santos static const uint16 kFirst = 49152; 167bf48e753SHugo Santos static const uint16 kLast = 65535; 168bf48e753SHugo Santos static const uint32 kNumHashBuckets = 0x800; 169bf48e753SHugo Santos // if you change this, adjust the shifting in 170bf48e753SHugo Santos // Hash() accordingly! 171bf48e753SHugo Santos }; 172bf48e753SHugo Santos 173bf48e753SHugo Santos 174bf48e753SHugo Santos typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList; 175bf48e753SHugo Santos 176bf48e753SHugo Santos 177bf48e753SHugo Santos class UdpEndpointManager { 178c22d69bfSAxel Dörfler public: 179c22d69bfSAxel Dörfler UdpEndpointManager(); 180c22d69bfSAxel Dörfler ~UdpEndpointManager(); 181c22d69bfSAxel Dörfler 182c22d69bfSAxel Dörfler status_t ReceiveData(net_buffer *buffer); 1836a606180SHugo Santos status_t Deframe(net_buffer *buffer); 184c22d69bfSAxel Dörfler 185bf48e753SHugo Santos UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint); 186bf48e753SHugo Santos status_t FreeEndpoint(UdpDomainSupport *domain); 187c22d69bfSAxel Dörfler 188c22d69bfSAxel Dörfler uint16 GetEphemeralPort(); 189c22d69bfSAxel Dörfler 190bf48e753SHugo Santos benaphore *Locker() { return &fLock; } 191c22d69bfSAxel Dörfler status_t InitCheck() const; 192bf48e753SHugo Santos 193c22d69bfSAxel Dörfler private: 194bf48e753SHugo Santos UdpDomainSupport *_GetDomain(net_domain *domain, bool create); 195bf48e753SHugo Santos 196c22d69bfSAxel Dörfler benaphore fLock; 197c22d69bfSAxel Dörfler status_t fStatus; 198bf48e753SHugo Santos UdpDomainList fDomains; 199c22d69bfSAxel Dörfler }; 200c22d69bfSAxel Dörfler 201c22d69bfSAxel Dörfler 202c22d69bfSAxel Dörfler static UdpEndpointManager *sUdpEndpointManager; 203c22d69bfSAxel Dörfler 204c35b04deSAxel Dörfler net_buffer_module_info *gBufferModule; 205658a5506SHugo Santos net_datalink_module_info *gDatalinkModule; 206658a5506SHugo Santos net_stack_module_info *gStackModule; 207c22d69bfSAxel Dörfler 208c22d69bfSAxel Dörfler 209c22d69bfSAxel Dörfler // #pragma mark - 210c22d69bfSAxel Dörfler 211c22d69bfSAxel Dörfler 212bf48e753SHugo Santos UdpDomainSupport::UdpDomainSupport(net_domain *domain) 213c22d69bfSAxel Dörfler : 214bf48e753SHugo Santos fDomain(domain), 215bf48e753SHugo Santos fLastUsedEphemeral(kLast), 216bf48e753SHugo Santos fEndpointCount(0) 217c22d69bfSAxel Dörfler { 218bf48e753SHugo Santos fActiveEndpoints = hash_init(kNumHashBuckets, offsetof(UdpEndpoint, hash_link), 219bf48e753SHugo Santos &_Compare, &_Hash); 220c22d69bfSAxel Dörfler } 221c22d69bfSAxel Dörfler 222c22d69bfSAxel Dörfler 223bf48e753SHugo Santos UdpDomainSupport::~UdpDomainSupport() 224c22d69bfSAxel Dörfler { 225bf48e753SHugo Santos if (fActiveEndpoints) 226bf48e753SHugo Santos hash_uninit(fActiveEndpoints); 227bf48e753SHugo Santos } 228bf48e753SHugo Santos 229bf48e753SHugo Santos 230bf48e753SHugo Santos status_t 231bf48e753SHugo Santos UdpDomainSupport::InitCheck() const 232bf48e753SHugo Santos { 233bf48e753SHugo Santos return fActiveEndpoints ? B_OK : B_NO_MEMORY; 234bf48e753SHugo Santos } 235bf48e753SHugo Santos 236bf48e753SHugo Santos 237bf48e753SHugo Santos status_t 238bf48e753SHugo Santos UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer) 239bf48e753SHugo Santos { 240bf48e753SHugo Santos if (buffer->flags & MSG_BCAST) 241bf48e753SHugo Santos return _DemuxBroadcast(buffer); 242bf48e753SHugo Santos else if (buffer->flags & MSG_MCAST) 243bf48e753SHugo Santos return _DemuxMulticast(buffer); 244bf48e753SHugo Santos 245bf48e753SHugo Santos return _DemuxUnicast(buffer); 246bf48e753SHugo Santos } 247bf48e753SHugo Santos 248bf48e753SHugo Santos 249bf48e753SHugo Santos status_t 250bf48e753SHugo Santos UdpDomainSupport::CheckBindRequest(sockaddr *address, int socketOptions) 251bf48e753SHugo Santos { // sUdpEndpointManager->Locker() must be locked! 252bf48e753SHugo Santos status_t status = B_OK; 253bf48e753SHugo Santos UdpEndpoint *otherEndpoint; 254bf48e753SHugo Santos sockaddr *otherAddr; 255bf48e753SHugo Santos struct hash_iterator endpointIterator; 256bf48e753SHugo Santos 257bf48e753SHugo Santos // Iterate over all active UDP-endpoints and check if the requested bind 258bf48e753SHugo Santos // is allowed (see figure 22.24 in [Stevens - TCP2, p735]): 259bf48e753SHugo Santos hash_open(fActiveEndpoints, &endpointIterator); 260bf48e753SHugo Santos TRACE_DOMAIN("CheckBindRequest() for %s...", 261bf48e753SHugo Santos AddressString(fDomain, address, true).Data()); 262bf48e753SHugo Santos while(1) { 263bf48e753SHugo Santos otherEndpoint = (UdpEndpoint *)hash_next(fActiveEndpoints, &endpointIterator); 264bf48e753SHugo Santos if (!otherEndpoint) 265bf48e753SHugo Santos break; 266bf48e753SHugo Santos otherAddr = (sockaddr *)&otherEndpoint->socket->address; 267bf48e753SHugo Santos TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint, 268bf48e753SHugo Santos ntohs(AddressModule()->get_port(otherAddr))); 269bf48e753SHugo Santos if (AddressModule()->equal_ports(otherAddr, address)) { 270bf48e753SHugo Santos // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required: 271bf48e753SHugo Santos if (otherEndpoint->socket->options & (SO_REUSEADDR | SO_REUSEPORT) == 0 272bf48e753SHugo Santos || socketOptions & (SO_REUSEADDR | SO_REUSEPORT) == 0) { 273bf48e753SHugo Santos status = EADDRINUSE; 274bf48e753SHugo Santos break; 275bf48e753SHugo Santos } 276bf48e753SHugo Santos // if both addresses are the same, SO_REUSEPORT is required: 277bf48e753SHugo Santos if (AddressModule()->equal_addresses(otherAddr, address) 278bf48e753SHugo Santos && (otherEndpoint->socket->options & SO_REUSEPORT == 0 279bf48e753SHugo Santos || socketOptions & SO_REUSEPORT == 0)) { 280bf48e753SHugo Santos status = EADDRINUSE; 281bf48e753SHugo Santos break; 282bf48e753SHugo Santos } 283bf48e753SHugo Santos } 284bf48e753SHugo Santos } 285bf48e753SHugo Santos hash_close(fActiveEndpoints, &endpointIterator, false); 286bf48e753SHugo Santos 287bf48e753SHugo Santos TRACE_DOMAIN(" CheckBindRequest done (status=%lx)", status); 288bf48e753SHugo Santos return status; 289bf48e753SHugo Santos } 290bf48e753SHugo Santos 291bf48e753SHugo Santos 292bf48e753SHugo Santos status_t 293bf48e753SHugo Santos UdpDomainSupport::ActivateEndpoint(UdpEndpoint *endpoint) 294bf48e753SHugo Santos { // sUdpEndpointManager->Locker() must be locked! 295bf48e753SHugo Santos TRACE_DOMAIN("Endpoint(%s) was activated", 296bf48e753SHugo Santos AddressString(fDomain, (sockaddr *)&endpoint->socket->address, true).Data()); 297bf48e753SHugo Santos return hash_insert(fActiveEndpoints, endpoint); 298bf48e753SHugo Santos } 299bf48e753SHugo Santos 300bf48e753SHugo Santos 301bf48e753SHugo Santos status_t 302bf48e753SHugo Santos UdpDomainSupport::DeactivateEndpoint(UdpEndpoint *endpoint) 303bf48e753SHugo Santos { // sUdpEndpointManager->Locker() must be locked! 304bf48e753SHugo Santos TRACE_DOMAIN("Endpoint(%s) was deactivated", 305bf48e753SHugo Santos AddressString(fDomain, (sockaddr *)&endpoint->socket->address, true).Data()); 306bf48e753SHugo Santos return hash_remove(fActiveEndpoints, endpoint); 307c22d69bfSAxel Dörfler } 308c22d69bfSAxel Dörfler 309c22d69bfSAxel Dörfler 310c22d69bfSAxel Dörfler uint16 311bf48e753SHugo Santos UdpDomainSupport::GetEphemeralPort() 312c22d69bfSAxel Dörfler { 313bf48e753SHugo Santos return _GetNextEphemeral(); 314c22d69bfSAxel Dörfler } 315c22d69bfSAxel Dörfler 316c22d69bfSAxel Dörfler 317c22d69bfSAxel Dörfler UdpEndpoint * 318bf48e753SHugo Santos UdpDomainSupport::_FindActiveEndpoint(sockaddr *ourAddress, 319c22d69bfSAxel Dörfler sockaddr *peerAddress) 320c22d69bfSAxel Dörfler { 321bf48e753SHugo Santos TRACE_DOMAIN("finding Endpoint for %s -> %s", 322bf48e753SHugo Santos AddressString(fDomain, ourAddress, true).Data(), 323bf48e753SHugo Santos AddressString(fDomain, peerAddress, true).Data()); 324c3e054c8SHugo Santos 325bf48e753SHugo Santos HashKey key(AddressModule(), ourAddress, peerAddress); 326c3e054c8SHugo Santos return (UdpEndpoint *)hash_lookup(fActiveEndpoints, &key); 327c22d69bfSAxel Dörfler } 328c22d69bfSAxel Dörfler 329c22d69bfSAxel Dörfler 330c22d69bfSAxel Dörfler status_t 331bf48e753SHugo Santos UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) 332c22d69bfSAxel Dörfler { 333c22d69bfSAxel Dörfler sockaddr *peerAddr = (sockaddr *)&buffer->source; 334c22d69bfSAxel Dörfler sockaddr *broadcastAddr = (sockaddr *)&buffer->destination; 335c22d69bfSAxel Dörfler sockaddr *mask = NULL; 336c22d69bfSAxel Dörfler if (buffer->interface) 337c22d69bfSAxel Dörfler mask = (sockaddr *)buffer->interface->mask; 338c22d69bfSAxel Dörfler 339bf48e753SHugo Santos TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); 340c22d69bfSAxel Dörfler 341bf48e753SHugo Santos uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 342c22d69bfSAxel Dörfler 343c22d69bfSAxel Dörfler UdpEndpoint *endpoint; 344bf48e753SHugo Santos hash_iterator endpointIterator; 345bf48e753SHugo Santos hash_open(fActiveEndpoints, &endpointIterator); 346bf48e753SHugo Santos while ((endpoint = (UdpEndpoint *)hash_next(fActiveEndpoints, 347bf48e753SHugo Santos &endpointIterator)) != NULL) { 348bf48e753SHugo Santos sockaddr *addr = (sockaddr *)&endpoint->socket->address; 349bf48e753SHugo Santos TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", 350bf48e753SHugo Santos AddressString(fDomain, addr, true).Data()); 351c22d69bfSAxel Dörfler 352bf48e753SHugo Santos if (incomingPort != AddressModule()->get_port(addr)) { 353c22d69bfSAxel Dörfler // ports don't match, so we do not dispatch to this endpoint... 354c22d69bfSAxel Dörfler continue; 355c22d69bfSAxel Dörfler } 356c22d69bfSAxel Dörfler 357bf48e753SHugo Santos sockaddr *connectAddr = (sockaddr *)&endpoint->socket->peer; 358bf48e753SHugo Santos if (!AddressModule()->is_empty_address(connectAddr, true)) { 359c22d69bfSAxel Dörfler // endpoint is connected to a specific destination, we check if 360c22d69bfSAxel Dörfler // this datagram is from there: 361bf48e753SHugo Santos if (!AddressModule()->equal_addresses_and_ports(connectAddr, peerAddr)) { 362c22d69bfSAxel Dörfler // no, datagram is from another peer, so we do not dispatch to 363c22d69bfSAxel Dörfler // this endpoint... 364c22d69bfSAxel Dörfler continue; 365c22d69bfSAxel Dörfler } 366c22d69bfSAxel Dörfler } 367c22d69bfSAxel Dörfler 368bf48e753SHugo Santos if (AddressModule()->equal_masked_addresses(addr, broadcastAddr, mask) 369bf48e753SHugo Santos || AddressModule()->is_empty_address(addr, false)) { 370c22d69bfSAxel Dörfler // address matches, dispatch to this endpoint: 371c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 372c22d69bfSAxel Dörfler } 373c22d69bfSAxel Dörfler } 374c22d69bfSAxel Dörfler hash_close(fActiveEndpoints, &endpointIterator, false); 375c22d69bfSAxel Dörfler return B_OK; 376c22d69bfSAxel Dörfler } 377c22d69bfSAxel Dörfler 378c22d69bfSAxel Dörfler 379c22d69bfSAxel Dörfler status_t 380bf48e753SHugo Santos UdpDomainSupport::_DemuxMulticast(net_buffer *buffer) 381c22d69bfSAxel Dörfler { // TODO: implement! 382bf48e753SHugo Santos TRACE_DOMAIN("_DemuxMulticast(%p)", buffer); 383bf48e753SHugo Santos 384c22d69bfSAxel Dörfler return B_ERROR; 385c22d69bfSAxel Dörfler } 386c22d69bfSAxel Dörfler 387c22d69bfSAxel Dörfler 388c22d69bfSAxel Dörfler status_t 389bf48e753SHugo Santos UdpDomainSupport::_DemuxUnicast(net_buffer *buffer) 390c22d69bfSAxel Dörfler { 391c22d69bfSAxel Dörfler struct sockaddr *peerAddr = (struct sockaddr *)&buffer->source; 392c22d69bfSAxel Dörfler struct sockaddr *localAddr = (struct sockaddr *)&buffer->destination; 393c22d69bfSAxel Dörfler 394bf48e753SHugo Santos TRACE_DOMAIN("_DemuxUnicast(%p)", buffer); 395c22d69bfSAxel Dörfler 396c22d69bfSAxel Dörfler UdpEndpoint *endpoint; 397c22d69bfSAxel Dörfler // look for full (most special) match: 398bf48e753SHugo Santos endpoint = _FindActiveEndpoint(localAddr, peerAddr); 399c22d69bfSAxel Dörfler if (!endpoint) { 400c22d69bfSAxel Dörfler // look for endpoint matching local address & port: 401bf48e753SHugo Santos endpoint = _FindActiveEndpoint(localAddr, NULL); 402c22d69bfSAxel Dörfler if (!endpoint) { 403c22d69bfSAxel Dörfler // look for endpoint matching peer address & port and local port: 404c22d69bfSAxel Dörfler sockaddr localPortAddr; 405bf48e753SHugo Santos AddressModule()->set_to_empty_address(&localPortAddr); 406bf48e753SHugo Santos uint16 localPort = AddressModule()->get_port(localAddr); 407bf48e753SHugo Santos AddressModule()->set_port(&localPortAddr, localPort); 408bf48e753SHugo Santos endpoint = _FindActiveEndpoint(&localPortAddr, peerAddr); 409c22d69bfSAxel Dörfler if (!endpoint) { 410c22d69bfSAxel Dörfler // last chance: look for endpoint matching local port only: 411bf48e753SHugo Santos endpoint = _FindActiveEndpoint(&localPortAddr, NULL); 412c22d69bfSAxel Dörfler } 413c22d69bfSAxel Dörfler } 414c22d69bfSAxel Dörfler } 415bf48e753SHugo Santos 416c22d69bfSAxel Dörfler if (!endpoint) 417c22d69bfSAxel Dörfler return B_NAME_NOT_FOUND; 418c22d69bfSAxel Dörfler 419c22d69bfSAxel Dörfler endpoint->StoreData(buffer); 420c22d69bfSAxel Dörfler return B_OK; 421c22d69bfSAxel Dörfler } 422c22d69bfSAxel Dörfler 423c22d69bfSAxel Dörfler 424bf48e753SHugo Santos uint16 425bf48e753SHugo Santos UdpDomainSupport::_GetNextEphemeral() 426c22d69bfSAxel Dörfler { 427bf48e753SHugo Santos uint16 stop, curr, ncurr; 428bf48e753SHugo Santos if (fLastUsedEphemeral < kLast) { 429bf48e753SHugo Santos stop = fLastUsedEphemeral; 430bf48e753SHugo Santos curr = fLastUsedEphemeral + 1; 431bf48e753SHugo Santos } else { 432bf48e753SHugo Santos stop = kLast; 433bf48e753SHugo Santos curr = kFirst; 434bf48e753SHugo Santos } 435c22d69bfSAxel Dörfler 436bf48e753SHugo Santos TRACE_DOMAIN("_GetNextEphemeral()"); 437bf48e753SHugo Santos // TODO: a free list could be used to avoid the impact of these 438bf48e753SHugo Santos // two nested loops most of the time... let's see how bad this really is 439bf48e753SHugo Santos bool found = false; 440bf48e753SHugo Santos uint16 endpointPort; 441bf48e753SHugo Santos hash_iterator endpointIterator; 442bf48e753SHugo Santos hash_open(fActiveEndpoints, &endpointIterator); 443bf48e753SHugo Santos while(!found && curr != stop) { 444bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr); 445bf48e753SHugo Santos ncurr = htons(curr); 446bf48e753SHugo Santos hash_rewind(fActiveEndpoints, &endpointIterator); 447bf48e753SHugo Santos while (!found) { 448bf48e753SHugo Santos UdpEndpoint *endpoint = (UdpEndpoint *)hash_next(fActiveEndpoints, 449bf48e753SHugo Santos &endpointIterator); 450bf48e753SHugo Santos if (!endpoint) { 451bf48e753SHugo Santos found = true; 452bf48e753SHugo Santos break; 453bf48e753SHugo Santos } 454bf48e753SHugo Santos endpointPort = AddressModule()->get_port( 455bf48e753SHugo Santos (sockaddr *)&endpoint->socket->address); 456bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): checking endpoint %p (port %hu)...", 457bf48e753SHugo Santos endpoint, ntohs(endpointPort)); 458bf48e753SHugo Santos if (endpointPort == ncurr) 459bf48e753SHugo Santos break; 460bf48e753SHugo Santos } 461bf48e753SHugo Santos if (!found) { 462bf48e753SHugo Santos if (curr < kLast) 463bf48e753SHugo Santos curr++; 464c22d69bfSAxel Dörfler else 465bf48e753SHugo Santos curr = kFirst; 466bf48e753SHugo Santos } 467bf48e753SHugo Santos } 468bf48e753SHugo Santos hash_close(fActiveEndpoints, &endpointIterator, false); 469bf48e753SHugo Santos if (!found) 470bf48e753SHugo Santos return 0; 471bf48e753SHugo Santos TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr); 472bf48e753SHugo Santos fLastUsedEphemeral = curr; 473bf48e753SHugo Santos return curr; 474bf48e753SHugo Santos } 475c22d69bfSAxel Dörfler 476bf48e753SHugo Santos 477bf48e753SHugo Santos int 478bf48e753SHugo Santos UdpDomainSupport::_Compare(void *_udpEndpoint, const void *_key) 479bf48e753SHugo Santos { 480bf48e753SHugo Santos struct UdpEndpoint *udpEndpoint = (UdpEndpoint*)_udpEndpoint; 481bf48e753SHugo Santos const HashKey *key = (const HashKey *)_key; 482bf48e753SHugo Santos 483bf48e753SHugo Santos sockaddr *ourAddr = (sockaddr *)&udpEndpoint->socket->address; 484bf48e753SHugo Santos sockaddr *peerAddr = (sockaddr *)&udpEndpoint->socket->peer; 485bf48e753SHugo Santos 486bf48e753SHugo Santos net_address_module_info *addressModule = key->address_module; 487bf48e753SHugo Santos 488bf48e753SHugo Santos if (addressModule->equal_addresses_and_ports(ourAddr, key->local) 489bf48e753SHugo Santos && addressModule->equal_addresses_and_ports(peerAddr, key->peer)) 490bf48e753SHugo Santos return 0; 491bf48e753SHugo Santos 492bf48e753SHugo Santos return 1; 493bf48e753SHugo Santos } 494bf48e753SHugo Santos 495bf48e753SHugo Santos 496bf48e753SHugo Santos uint32 497bf48e753SHugo Santos UdpDomainSupport::_Hash(void *_udpEndpoint, const void *_key, uint32 range) 498bf48e753SHugo Santos { 499bf48e753SHugo Santos const HashKey *key = (const HashKey *)_key; 500bf48e753SHugo Santos HashKey key_storage; 501bf48e753SHugo Santos uint32 hash; 502bf48e753SHugo Santos 503bf48e753SHugo Santos if (_udpEndpoint) { 504bf48e753SHugo Santos const UdpEndpoint *udpEndpoint = (const UdpEndpoint *)_udpEndpoint; 505bf48e753SHugo Santos key_storage = HashKey(udpEndpoint->DomainSupport()->AddressModule(), 506bf48e753SHugo Santos (const sockaddr *)&udpEndpoint->socket->address, 507bf48e753SHugo Santos (const sockaddr *)&udpEndpoint->socket->peer); 508bf48e753SHugo Santos key = &key_storage; 509bf48e753SHugo Santos } 510bf48e753SHugo Santos 511bf48e753SHugo Santos hash = key->address_module->hash_address_pair(key->local, key->peer); 512bf48e753SHugo Santos 513bf48e753SHugo Santos // move the bits into the relevant range (as defined by kNumHashBuckets): 514bf48e753SHugo Santos hash = (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11 515bf48e753SHugo Santos ^ (hash & 0xFFC00000UL) >> 22; 516bf48e753SHugo Santos 517bf48e753SHugo Santos return hash % range; 518bf48e753SHugo Santos } 519bf48e753SHugo Santos 520bf48e753SHugo Santos 521bf48e753SHugo Santos // #pragma mark - 522bf48e753SHugo Santos 523bf48e753SHugo Santos 524bf48e753SHugo Santos UdpEndpointManager::UdpEndpointManager() 525bf48e753SHugo Santos { 526bf48e753SHugo Santos fStatus = benaphore_init(&fLock, "UDP endpoints"); 527bf48e753SHugo Santos } 528bf48e753SHugo Santos 529bf48e753SHugo Santos 530bf48e753SHugo Santos UdpEndpointManager::~UdpEndpointManager() 531bf48e753SHugo Santos { 532bf48e753SHugo Santos benaphore_destroy(&fLock); 533bf48e753SHugo Santos } 534bf48e753SHugo Santos 535bf48e753SHugo Santos 536bf48e753SHugo Santos status_t 537bf48e753SHugo Santos UdpEndpointManager::InitCheck() const 538bf48e753SHugo Santos { 539bf48e753SHugo Santos return fStatus; 540bf48e753SHugo Santos } 541bf48e753SHugo Santos 542bf48e753SHugo Santos 543bf48e753SHugo Santos // #pragma mark - inbound 544bf48e753SHugo Santos 545bf48e753SHugo Santos 546bf48e753SHugo Santos status_t 547c22d69bfSAxel Dörfler UdpEndpointManager::ReceiveData(net_buffer *buffer) 548c22d69bfSAxel Dörfler { 5496a606180SHugo Santos status_t status = Deframe(buffer); 5506a606180SHugo Santos if (status < B_OK) 5516a606180SHugo Santos return status; 5526a606180SHugo Santos 553bf48e753SHugo Santos TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size); 554bf48e753SHugo Santos 5556a606180SHugo Santos net_domain *domain = buffer->interface->domain; 5566a606180SHugo Santos 5576a606180SHugo Santos BenaphoreLocker _(fLock); 5586a606180SHugo Santos 5596a606180SHugo Santos UdpDomainSupport *domainSupport = _GetDomain(domain, false); 5606a606180SHugo Santos if (domainSupport == NULL) { 5616a606180SHugo Santos // we don't instantiate domain supports in the 5626a606180SHugo Santos // RX path as we are only interested in delivering 5636a606180SHugo Santos // data to existing sockets. 5646a606180SHugo Santos return B_ERROR; 5656a606180SHugo Santos } 5666a606180SHugo Santos 5676a606180SHugo Santos status = domainSupport->DemuxIncomingBuffer(buffer); 5686a606180SHugo Santos if (status < B_OK) { 5696a606180SHugo Santos TRACE_EPM(" ReceiveData(): no endpoint."); 5706a606180SHugo Santos // TODO: send ICMP-error 5716a606180SHugo Santos return B_ERROR; 5726a606180SHugo Santos } 5736a606180SHugo Santos 5746a606180SHugo Santos return B_ERROR; 5756a606180SHugo Santos } 5766a606180SHugo Santos 5776a606180SHugo Santos 5786a606180SHugo Santos status_t 5796a606180SHugo Santos UdpEndpointManager::Deframe(net_buffer *buffer) 5806a606180SHugo Santos { 5816a606180SHugo Santos TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); 5826a606180SHugo Santos 58387001e05SHugo Santos NetBufferHeaderReader<udp_header> bufferHeader(buffer); 584c22d69bfSAxel Dörfler if (bufferHeader.Status() < B_OK) 585c22d69bfSAxel Dörfler return bufferHeader.Status(); 586c22d69bfSAxel Dörfler 587c22d69bfSAxel Dörfler udp_header &header = bufferHeader.Data(); 588c22d69bfSAxel Dörfler 589c22d69bfSAxel Dörfler struct sockaddr *source = (struct sockaddr *)&buffer->source; 590c22d69bfSAxel Dörfler struct sockaddr *destination = (struct sockaddr *)&buffer->destination; 591c22d69bfSAxel Dörfler 592bf48e753SHugo Santos if (buffer->interface == NULL || buffer->interface->domain == NULL) { 5936a606180SHugo Santos TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " 594bf48e753SHugo Santos "specified (interface %p).", buffer->interface); 595c22d69bfSAxel Dörfler return B_BAD_VALUE; 596c22d69bfSAxel Dörfler } 597bf48e753SHugo Santos 598bf48e753SHugo Santos net_domain *domain = buffer->interface->domain; 599bf48e753SHugo Santos net_address_module_info *addressModule = domain->address_module; 600bf48e753SHugo Santos 601bf48e753SHugo Santos addressModule->set_port(source, header.source_port); 602bf48e753SHugo Santos addressModule->set_port(destination, header.destination_port); 603bf48e753SHugo Santos 6046a606180SHugo Santos TRACE_EPM(" Deframe(): data from %s to %s", 605bf48e753SHugo Santos AddressString(domain, source, true).Data(), 606bf48e753SHugo Santos AddressString(domain, destination, true).Data()); 607c22d69bfSAxel Dörfler 608c22d69bfSAxel Dörfler uint16 udpLength = ntohs(header.udp_length); 609c22d69bfSAxel Dörfler if (udpLength > buffer->size) { 6106a606180SHugo Santos TRACE_EPM(" Deframe(): buffer is too short, expected %hu.", 611bf48e753SHugo Santos udpLength); 612c22d69bfSAxel Dörfler return B_MISMATCHED_VALUES; 613c22d69bfSAxel Dörfler } 614bf48e753SHugo Santos 615bf48e753SHugo Santos if (buffer->size > udpLength) 616c35b04deSAxel Dörfler gBufferModule->trim(buffer, udpLength); 617c22d69bfSAxel Dörfler 618c22d69bfSAxel Dörfler if (header.udp_checksum != 0) { 619c22d69bfSAxel Dörfler // check UDP-checksum (simulating a so-called "pseudo-header"): 620c22d69bfSAxel Dörfler Checksum udpChecksum; 621bf48e753SHugo Santos addressModule->checksum_address(&udpChecksum, source); 622bf48e753SHugo Santos addressModule->checksum_address(&udpChecksum, destination); 623c22d69bfSAxel Dörfler udpChecksum 624c22d69bfSAxel Dörfler << (uint16)htons(IPPROTO_UDP) 625c22d69bfSAxel Dörfler << header.udp_length 626c22d69bfSAxel Dörfler // peculiar but correct: UDP-len is used twice for checksum 627c22d69bfSAxel Dörfler // (as it is already contained in udp_header) 628c35b04deSAxel Dörfler << Checksum::BufferHelper(buffer, gBufferModule); 629c22d69bfSAxel Dörfler uint16 sum = udpChecksum; 630c22d69bfSAxel Dörfler if (sum != 0) { 6316a606180SHugo Santos TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum); 632c22d69bfSAxel Dörfler return B_BAD_VALUE; 633c22d69bfSAxel Dörfler } 634c22d69bfSAxel Dörfler } 635c22d69bfSAxel Dörfler 636c22d69bfSAxel Dörfler bufferHeader.Remove(); 637c22d69bfSAxel Dörfler // remove UDP-header from buffer before passing it on 638c22d69bfSAxel Dörfler 6396a606180SHugo Santos return B_OK; 640c22d69bfSAxel Dörfler } 641c22d69bfSAxel Dörfler 642c22d69bfSAxel Dörfler 643bf48e753SHugo Santos UdpDomainSupport * 644c22d69bfSAxel Dörfler UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) 645c22d69bfSAxel Dörfler { 646bf48e753SHugo Santos BenaphoreLocker _(fLock); 647bf48e753SHugo Santos 648bf48e753SHugo Santos UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); 649bf48e753SHugo Santos if (domain) 650bf48e753SHugo Santos domain->Ref(); 651bf48e753SHugo Santos return domain; 652bf48e753SHugo Santos } 653bf48e753SHugo Santos 654bf48e753SHugo Santos 655bf48e753SHugo Santos status_t 656bf48e753SHugo Santos UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) 657bf48e753SHugo Santos { 658bf48e753SHugo Santos BenaphoreLocker _(fLock); 659bf48e753SHugo Santos 660bf48e753SHugo Santos domain->Put(); 661bf48e753SHugo Santos 662bf48e753SHugo Santos if (domain->IsEmpty()) { 663bf48e753SHugo Santos fDomains.Remove(domain); 664bf48e753SHugo Santos delete domain; 665bf48e753SHugo Santos } 666bf48e753SHugo Santos 667bf48e753SHugo Santos return B_OK; 668bf48e753SHugo Santos } 669bf48e753SHugo Santos 670bf48e753SHugo Santos 671bf48e753SHugo Santos // #pragma mark - 672bf48e753SHugo Santos 673bf48e753SHugo Santos 674bf48e753SHugo Santos UdpDomainSupport * 675bf48e753SHugo Santos UdpEndpointManager::_GetDomain(net_domain *domain, bool create) 676bf48e753SHugo Santos { 677bf48e753SHugo Santos UdpDomainList::Iterator it = fDomains.GetIterator(); 678bf48e753SHugo Santos 679bf48e753SHugo Santos // TODO convert this into a Hashtable or install per-domain 680bf48e753SHugo Santos // receiver handlers that forward the requests to the 681bf48e753SHugo Santos // appropriate DemuxIncomingBuffer(). For instance, while 682bf48e753SHugo Santos // being constructed UdpDomainSupport could call 683bf48e753SHugo Santos // register_domain_receiving_protocol() with the right 684bf48e753SHugo Santos // family. 685bf48e753SHugo Santos while (it.HasNext()) { 686bf48e753SHugo Santos UdpDomainSupport *domainSupport = it.Next(); 687bf48e753SHugo Santos if (domainSupport->Domain() == domain) 688bf48e753SHugo Santos return domainSupport; 689bf48e753SHugo Santos } 690bf48e753SHugo Santos 691bf48e753SHugo Santos if (!create) 692bf48e753SHugo Santos return NULL; 693bf48e753SHugo Santos 694bf48e753SHugo Santos UdpDomainSupport *domainSupport = 695bf48e753SHugo Santos new (std::nothrow) UdpDomainSupport(domain); 696bf48e753SHugo Santos if (domainSupport == NULL || domainSupport->InitCheck() < B_OK) { 697bf48e753SHugo Santos delete domainSupport; 698bf48e753SHugo Santos return NULL; 699bf48e753SHugo Santos } 700bf48e753SHugo Santos 701bf48e753SHugo Santos fDomains.Add(domainSupport); 702bf48e753SHugo Santos return domainSupport; 703c22d69bfSAxel Dörfler } 704c22d69bfSAxel Dörfler 705c22d69bfSAxel Dörfler 706c22d69bfSAxel Dörfler // #pragma mark - 707c22d69bfSAxel Dörfler 708c22d69bfSAxel Dörfler 709c22d69bfSAxel Dörfler UdpEndpoint::UdpEndpoint(net_socket *socket) 710c22d69bfSAxel Dörfler : 711bfb45f71SHugo Santos DatagramSocket<>("udp endpoint", socket), 712bf48e753SHugo Santos fDomain(NULL), 713c22d69bfSAxel Dörfler fActive(false) 714c22d69bfSAxel Dörfler { 715bf48e753SHugo Santos } 716bf48e753SHugo Santos 717bf48e753SHugo Santos 718c22d69bfSAxel Dörfler // #pragma mark - activation 719c22d69bfSAxel Dörfler 720c22d69bfSAxel Dörfler 721c22d69bfSAxel Dörfler status_t 722c22d69bfSAxel Dörfler UdpEndpoint::Bind(sockaddr *address) 723c22d69bfSAxel Dörfler { 724bf48e753SHugo Santos TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data()); 725c22d69bfSAxel Dörfler 726bf48e753SHugo Santos // let the underlying protocol check whether there is an interface that 727bf48e753SHugo Santos // supports the given address 728c22d69bfSAxel Dörfler status_t status = next->module->bind(next, address); 729c22d69bfSAxel Dörfler if (status < B_OK) 730c22d69bfSAxel Dörfler return status; 731c22d69bfSAxel Dörfler 732c22d69bfSAxel Dörfler BenaphoreLocker locker(sUdpEndpointManager->Locker()); 733c22d69bfSAxel Dörfler 734c22d69bfSAxel Dörfler if (fActive) { 735c22d69bfSAxel Dörfler // socket module should have called unbind() before! 736c22d69bfSAxel Dörfler return EINVAL; 737c22d69bfSAxel Dörfler } 738c22d69bfSAxel Dörfler 739bf48e753SHugo Santos if (AddressModule()->get_port(address) == 0) { 740bf48e753SHugo Santos uint16 port = htons(fDomain->GetEphemeralPort()); 741c22d69bfSAxel Dörfler if (port == 0) 742c22d69bfSAxel Dörfler return ENOBUFS; 743c22d69bfSAxel Dörfler // whoa, no more ephemeral port available!?! 744bf48e753SHugo Santos AddressModule()->set_port((sockaddr *)&socket->address, port); 745c22d69bfSAxel Dörfler } else { 746bf48e753SHugo Santos status = fDomain->CheckBindRequest((sockaddr *)&socket->address, 747c22d69bfSAxel Dörfler socket->options); 748c22d69bfSAxel Dörfler if (status < B_OK) 749c22d69bfSAxel Dörfler return status; 750c22d69bfSAxel Dörfler } 751c22d69bfSAxel Dörfler 752c22d69bfSAxel Dörfler return _Activate(); 753c22d69bfSAxel Dörfler } 754c22d69bfSAxel Dörfler 755c22d69bfSAxel Dörfler 756c22d69bfSAxel Dörfler status_t 757c22d69bfSAxel Dörfler UdpEndpoint::Unbind(sockaddr *address) 758c22d69bfSAxel Dörfler { 759bf48e753SHugo Santos TRACE_EP("Unbind()"); 760c22d69bfSAxel Dörfler 761c22d69bfSAxel Dörfler BenaphoreLocker locker(sUdpEndpointManager->Locker()); 762c22d69bfSAxel Dörfler 763c22d69bfSAxel Dörfler return _Deactivate(); 764c22d69bfSAxel Dörfler } 765c22d69bfSAxel Dörfler 766c22d69bfSAxel Dörfler 767c22d69bfSAxel Dörfler status_t 768c22d69bfSAxel Dörfler UdpEndpoint::Connect(const sockaddr *address) 769c22d69bfSAxel Dörfler { 770bf48e753SHugo Santos TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data()); 771c22d69bfSAxel Dörfler 772c22d69bfSAxel Dörfler BenaphoreLocker locker(sUdpEndpointManager->Locker()); 773c22d69bfSAxel Dörfler 774c22d69bfSAxel Dörfler if (fActive) 775c22d69bfSAxel Dörfler _Deactivate(); 776c22d69bfSAxel Dörfler 777c22d69bfSAxel Dörfler if (address->sa_family == AF_UNSPEC) { 778c22d69bfSAxel Dörfler // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect", 779c22d69bfSAxel Dörfler // so we reset the peer address: 780bf48e753SHugo Santos AddressModule()->set_to_empty_address((sockaddr *)&socket->peer); 781bf48e753SHugo Santos } else { 782bf48e753SHugo Santos // TODO check if `address' is compatible with AddressModule() 783bf48e753SHugo Santos AddressModule()->set_to((sockaddr *)&socket->peer, address); 784bf48e753SHugo Santos } 785c22d69bfSAxel Dörfler 786c22d69bfSAxel Dörfler // we need to activate no matter whether or not we have just disconnected, 787c22d69bfSAxel Dörfler // as calling connect() always triggers an implicit bind(): 788c22d69bfSAxel Dörfler return _Activate(); 789c22d69bfSAxel Dörfler } 790c22d69bfSAxel Dörfler 791c22d69bfSAxel Dörfler 792c22d69bfSAxel Dörfler status_t 793c22d69bfSAxel Dörfler UdpEndpoint::Open() 794c22d69bfSAxel Dörfler { 795bf48e753SHugo Santos TRACE_EP("Open()"); 796bf48e753SHugo Santos 797bf48e753SHugo Santos // we can't be the first protocol, there must an underlying 798bf48e753SHugo Santos // network protocol that supplies us with an address module. 799bf48e753SHugo Santos if (socket->first_protocol == NULL) 800bf48e753SHugo Santos return EAFNOSUPPORT; 801bf48e753SHugo Santos 802bf48e753SHugo Santos if (Domain() == NULL || Domain()->address_module == NULL) 803bf48e753SHugo Santos return EAFNOSUPPORT; 804bf48e753SHugo Santos 805bf48e753SHugo Santos fDomain = sUdpEndpointManager->OpenEndpoint(this); 806bf48e753SHugo Santos 807bf48e753SHugo Santos if (fDomain == NULL) 808bf48e753SHugo Santos return EAFNOSUPPORT; 809bf48e753SHugo Santos 810bf48e753SHugo Santos return B_OK; 811c22d69bfSAxel Dörfler } 812c22d69bfSAxel Dörfler 813c22d69bfSAxel Dörfler 814c22d69bfSAxel Dörfler status_t 815c22d69bfSAxel Dörfler UdpEndpoint::Close() 816c22d69bfSAxel Dörfler { 817bf48e753SHugo Santos TRACE_EP("Close()"); 818bf48e753SHugo Santos 819bf48e753SHugo Santos BenaphoreLocker _(sUdpEndpointManager->Locker()); 820c22d69bfSAxel Dörfler if (fActive) 821c22d69bfSAxel Dörfler _Deactivate(); 822bf48e753SHugo Santos 823bf48e753SHugo Santos return B_OK; 824c22d69bfSAxel Dörfler } 825c22d69bfSAxel Dörfler 826c22d69bfSAxel Dörfler 827c22d69bfSAxel Dörfler status_t 828c22d69bfSAxel Dörfler UdpEndpoint::Free() 829c22d69bfSAxel Dörfler { 830bf48e753SHugo Santos TRACE_EP("Free()"); 831bf48e753SHugo Santos 832bf48e753SHugo Santos return sUdpEndpointManager->FreeEndpoint(fDomain); 833c22d69bfSAxel Dörfler } 834c22d69bfSAxel Dörfler 835c22d69bfSAxel Dörfler 836c22d69bfSAxel Dörfler status_t 837c22d69bfSAxel Dörfler UdpEndpoint::_Activate() 838c22d69bfSAxel Dörfler { 839c22d69bfSAxel Dörfler if (fActive) 840c22d69bfSAxel Dörfler return B_ERROR; 841bf48e753SHugo Santos status_t status = fDomain->ActivateEndpoint(this); 842c22d69bfSAxel Dörfler fActive = (status == B_OK); 843c22d69bfSAxel Dörfler return status; 844c22d69bfSAxel Dörfler } 845c22d69bfSAxel Dörfler 846c22d69bfSAxel Dörfler 847c22d69bfSAxel Dörfler status_t 848c22d69bfSAxel Dörfler UdpEndpoint::_Deactivate() 849c22d69bfSAxel Dörfler { 850c22d69bfSAxel Dörfler if (!fActive) 851c22d69bfSAxel Dörfler return B_ERROR; 852c22d69bfSAxel Dörfler fActive = false; 853bf48e753SHugo Santos return fDomain->DeactivateEndpoint(this); 854c22d69bfSAxel Dörfler } 855c22d69bfSAxel Dörfler 856c22d69bfSAxel Dörfler 857c22d69bfSAxel Dörfler // #pragma mark - outbound 858c22d69bfSAxel Dörfler 859c22d69bfSAxel Dörfler 860c22d69bfSAxel Dörfler status_t 861bf48e753SHugo Santos UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route) 862c22d69bfSAxel Dörfler { 863bf48e753SHugo Santos TRACE_EP("SendRoutedData(%p [%lu bytes], %p)", buffer, buffer->size, route); 864bf48e753SHugo Santos 865d86f48f3SHugo Santos if (buffer->size > (0xffff - sizeof(udp_header))) 866c22d69bfSAxel Dörfler return EMSGSIZE; 867c22d69bfSAxel Dörfler 868c22d69bfSAxel Dörfler buffer->protocol = IPPROTO_UDP; 869c22d69bfSAxel Dörfler 870c22d69bfSAxel Dörfler // add and fill UDP-specific header: 8716c353509SHugo Santos NetBufferPrepend<udp_header> header(buffer); 8726c353509SHugo Santos if (header.Status() < B_OK) 8736c353509SHugo Santos return header.Status(); 874c22d69bfSAxel Dörfler 875bf48e753SHugo Santos header->source_port = AddressModule()->get_port((sockaddr *)&buffer->source); 876bf48e753SHugo Santos header->destination_port = AddressModule()->get_port( 877c22d69bfSAxel Dörfler (sockaddr *)&buffer->destination); 8786c353509SHugo Santos header->udp_length = htons(buffer->size); 879c22d69bfSAxel Dörfler // the udp-header is already included in the buffer-size 8806c353509SHugo Santos header->udp_checksum = 0; 8816c353509SHugo Santos 8826c353509SHugo Santos header.Sync(); 883c22d69bfSAxel Dörfler 884c22d69bfSAxel Dörfler // generate UDP-checksum (simulating a so-called "pseudo-header"): 885c22d69bfSAxel Dörfler Checksum udpChecksum; 886bf48e753SHugo Santos AddressModule()->checksum_address(&udpChecksum, 887c22d69bfSAxel Dörfler (sockaddr *)route->interface->address); 888bf48e753SHugo Santos AddressModule()->checksum_address(&udpChecksum, 889c22d69bfSAxel Dörfler (sockaddr *)&buffer->destination); 890c22d69bfSAxel Dörfler udpChecksum 891c22d69bfSAxel Dörfler << (uint16)htons(IPPROTO_UDP) 892c22d69bfSAxel Dörfler << (uint16)htons(buffer->size) 893c22d69bfSAxel Dörfler // peculiar but correct: UDP-len is used twice for checksum 894c22d69bfSAxel Dörfler // (as it is already contained in udp_header) 895c35b04deSAxel Dörfler << Checksum::BufferHelper(buffer, gBufferModule); 8966c353509SHugo Santos 8976c353509SHugo Santos uint16 calculatedChecksum = udpChecksum; 8986c353509SHugo Santos if (calculatedChecksum == 0) 8996c353509SHugo Santos calculatedChecksum = 0xffff; 9006c353509SHugo Santos 9016c353509SHugo Santos *UDPChecksumField(buffer) = calculatedChecksum; 902c22d69bfSAxel Dörfler 903c22d69bfSAxel Dörfler TRACE_BLOCK(((char*)&header, sizeof(udp_header), "udp-hdr: ")); 9046c353509SHugo Santos 905c22d69bfSAxel Dörfler return next->module->send_routed_data(next, route, buffer); 906c22d69bfSAxel Dörfler } 907c22d69bfSAxel Dörfler 908c22d69bfSAxel Dörfler 909bf48e753SHugo Santos status_t 910bf48e753SHugo Santos UdpEndpoint::SendData(net_buffer *buffer) 911bf48e753SHugo Santos { 912bf48e753SHugo Santos TRACE_EP("SendData(%p [%lu bytes])", buffer, buffer->size); 913bf48e753SHugo Santos 914*1408d1f0SHugo Santos return gDatalinkModule->send_datagram(this, NULL, buffer); 915bf48e753SHugo Santos } 916bf48e753SHugo Santos 917bf48e753SHugo Santos 918c22d69bfSAxel Dörfler // #pragma mark - inbound 919c22d69bfSAxel Dörfler 920c22d69bfSAxel Dörfler 921c22d69bfSAxel Dörfler ssize_t 922c22d69bfSAxel Dörfler UdpEndpoint::BytesAvailable() 923c22d69bfSAxel Dörfler { 924bfb45f71SHugo Santos size_t bytes = AvailableData(); 925bfb45f71SHugo Santos TRACE_EP("BytesAvailable(): %lu", bytes); 926bfb45f71SHugo Santos return bytes; 927c22d69bfSAxel Dörfler } 928c22d69bfSAxel Dörfler 929c22d69bfSAxel Dörfler 930c22d69bfSAxel Dörfler status_t 931c22d69bfSAxel Dörfler UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer) 932c22d69bfSAxel Dörfler { 933bf48e753SHugo Santos TRACE_EP("FetchData(%ld, 0x%lx)", numBytes, flags); 934bf48e753SHugo Santos 935bfb45f71SHugo Santos status_t status = SocketDequeue(flags, _buffer); 936bf48e753SHugo Santos TRACE_EP(" FetchData(): returned from fifo status=0x%lx", status); 937c22d69bfSAxel Dörfler if (status < B_OK) 938c22d69bfSAxel Dörfler return status; 939c22d69bfSAxel Dörfler 940bfb45f71SHugo Santos TRACE_EP(" FetchData(): returns buffer with %ld bytes", (*_buffer)->size); 941c22d69bfSAxel Dörfler return B_OK; 942c22d69bfSAxel Dörfler } 943c22d69bfSAxel Dörfler 944c22d69bfSAxel Dörfler 945c22d69bfSAxel Dörfler status_t 946bf48e753SHugo Santos UdpEndpoint::StoreData(net_buffer *buffer) 947c22d69bfSAxel Dörfler { 948bf48e753SHugo Santos TRACE_EP("StoreData(%p [%ld bytes])", buffer, buffer->size); 949c22d69bfSAxel Dörfler 95049f3c71eSHugo Santos return SocketEnqueue(buffer); 951c22d69bfSAxel Dörfler } 952c22d69bfSAxel Dörfler 953c22d69bfSAxel Dörfler 9546a606180SHugo Santos status_t 9556a606180SHugo Santos UdpEndpoint::DeliverData(net_buffer *_buffer) 9566a606180SHugo Santos { 9576a606180SHugo Santos net_buffer *buffer = gBufferModule->clone(_buffer, false); 9586a606180SHugo Santos if (buffer == NULL) 9596a606180SHugo Santos return B_NO_MEMORY; 9606a606180SHugo Santos 9616a606180SHugo Santos status_t status = sUdpEndpointManager->Deframe(buffer); 9626a606180SHugo Santos if (status < B_OK) { 9636a606180SHugo Santos gBufferModule->free(buffer); 9646a606180SHugo Santos return status; 9656a606180SHugo Santos } 9666a606180SHugo Santos 9676a606180SHugo Santos // we call Enqueue() instead of SocketEnqueue() as there is 9686a606180SHugo Santos // no need to clone the buffer again. 9696a606180SHugo Santos return Enqueue(buffer); 9706a606180SHugo Santos } 9716a606180SHugo Santos 9726a606180SHugo Santos 973c22d69bfSAxel Dörfler // #pragma mark - protocol interface 974c22d69bfSAxel Dörfler 975c22d69bfSAxel Dörfler 976c22d69bfSAxel Dörfler net_protocol * 977c22d69bfSAxel Dörfler udp_init_protocol(net_socket *socket) 978c22d69bfSAxel Dörfler { 979c22d69bfSAxel Dörfler socket->protocol = IPPROTO_UDP; 980c22d69bfSAxel Dörfler 981c22d69bfSAxel Dörfler UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket); 982bf48e753SHugo Santos if (endpoint == NULL || endpoint->InitCheck() < B_OK) { 983bf48e753SHugo Santos delete endpoint; 984bf48e753SHugo Santos return NULL; 985bf48e753SHugo Santos } 986bf48e753SHugo Santos 987c22d69bfSAxel Dörfler return endpoint; 988c22d69bfSAxel Dörfler } 989c22d69bfSAxel Dörfler 990c22d69bfSAxel Dörfler 991c22d69bfSAxel Dörfler status_t 992c22d69bfSAxel Dörfler udp_uninit_protocol(net_protocol *protocol) 993c22d69bfSAxel Dörfler { 994bf48e753SHugo Santos delete (UdpEndpoint *)protocol; 995c22d69bfSAxel Dörfler return B_OK; 996c22d69bfSAxel Dörfler } 997c22d69bfSAxel Dörfler 998c22d69bfSAxel Dörfler 999c22d69bfSAxel Dörfler status_t 1000c22d69bfSAxel Dörfler udp_open(net_protocol *protocol) 1001c22d69bfSAxel Dörfler { 1002bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Open(); 1003c22d69bfSAxel Dörfler } 1004c22d69bfSAxel Dörfler 1005c22d69bfSAxel Dörfler 1006c22d69bfSAxel Dörfler status_t 1007c22d69bfSAxel Dörfler udp_close(net_protocol *protocol) 1008c22d69bfSAxel Dörfler { 1009bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Close(); 1010c22d69bfSAxel Dörfler } 1011c22d69bfSAxel Dörfler 1012c22d69bfSAxel Dörfler 1013c22d69bfSAxel Dörfler status_t 1014c22d69bfSAxel Dörfler udp_free(net_protocol *protocol) 1015c22d69bfSAxel Dörfler { 1016bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Free(); 1017c22d69bfSAxel Dörfler } 1018c22d69bfSAxel Dörfler 1019c22d69bfSAxel Dörfler 1020c22d69bfSAxel Dörfler status_t 1021c22d69bfSAxel Dörfler udp_connect(net_protocol *protocol, const struct sockaddr *address) 1022c22d69bfSAxel Dörfler { 1023bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Connect(address); 1024c22d69bfSAxel Dörfler } 1025c22d69bfSAxel Dörfler 1026c22d69bfSAxel Dörfler 1027c22d69bfSAxel Dörfler status_t 1028c22d69bfSAxel Dörfler udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket) 1029c22d69bfSAxel Dörfler { 1030c22d69bfSAxel Dörfler return EOPNOTSUPP; 1031c22d69bfSAxel Dörfler } 1032c22d69bfSAxel Dörfler 1033c22d69bfSAxel Dörfler 1034c22d69bfSAxel Dörfler status_t 1035c22d69bfSAxel Dörfler udp_control(net_protocol *protocol, int level, int option, void *value, 1036c22d69bfSAxel Dörfler size_t *_length) 1037c22d69bfSAxel Dörfler { 1038c22d69bfSAxel Dörfler return protocol->next->module->control(protocol->next, level, option, 1039c22d69bfSAxel Dörfler value, _length); 1040c22d69bfSAxel Dörfler } 1041c22d69bfSAxel Dörfler 1042c22d69bfSAxel Dörfler 1043c22d69bfSAxel Dörfler status_t 1044c22d69bfSAxel Dörfler udp_bind(net_protocol *protocol, struct sockaddr *address) 1045c22d69bfSAxel Dörfler { 1046bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Bind(address); 1047c22d69bfSAxel Dörfler } 1048c22d69bfSAxel Dörfler 1049c22d69bfSAxel Dörfler 1050c22d69bfSAxel Dörfler status_t 1051c22d69bfSAxel Dörfler udp_unbind(net_protocol *protocol, struct sockaddr *address) 1052c22d69bfSAxel Dörfler { 1053bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->Unbind(address); 1054c22d69bfSAxel Dörfler } 1055c22d69bfSAxel Dörfler 1056c22d69bfSAxel Dörfler 1057c22d69bfSAxel Dörfler status_t 1058c22d69bfSAxel Dörfler udp_listen(net_protocol *protocol, int count) 1059c22d69bfSAxel Dörfler { 1060c22d69bfSAxel Dörfler return EOPNOTSUPP; 1061c22d69bfSAxel Dörfler } 1062c22d69bfSAxel Dörfler 1063c22d69bfSAxel Dörfler 1064c22d69bfSAxel Dörfler status_t 1065c22d69bfSAxel Dörfler udp_shutdown(net_protocol *protocol, int direction) 1066c22d69bfSAxel Dörfler { 1067c22d69bfSAxel Dörfler return EOPNOTSUPP; 1068c22d69bfSAxel Dörfler } 1069c22d69bfSAxel Dörfler 1070c22d69bfSAxel Dörfler 1071c22d69bfSAxel Dörfler status_t 1072c22d69bfSAxel Dörfler udp_send_routed_data(net_protocol *protocol, struct net_route *route, 1073c22d69bfSAxel Dörfler net_buffer *buffer) 1074c22d69bfSAxel Dörfler { 1075bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route); 1076c22d69bfSAxel Dörfler } 1077c22d69bfSAxel Dörfler 1078c22d69bfSAxel Dörfler 1079c22d69bfSAxel Dörfler status_t 1080c22d69bfSAxel Dörfler udp_send_data(net_protocol *protocol, net_buffer *buffer) 1081c22d69bfSAxel Dörfler { 1082bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->SendData(buffer); 1083c22d69bfSAxel Dörfler } 1084c22d69bfSAxel Dörfler 1085c22d69bfSAxel Dörfler 1086c22d69bfSAxel Dörfler ssize_t 1087c22d69bfSAxel Dörfler udp_send_avail(net_protocol *protocol) 1088c22d69bfSAxel Dörfler { 1089bf48e753SHugo Santos return protocol->socket->send.buffer_size; 1090c22d69bfSAxel Dörfler } 1091c22d69bfSAxel Dörfler 1092c22d69bfSAxel Dörfler 1093c22d69bfSAxel Dörfler status_t 1094c22d69bfSAxel Dörfler udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags, 1095c22d69bfSAxel Dörfler net_buffer **_buffer) 1096c22d69bfSAxel Dörfler { 1097bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer); 1098c22d69bfSAxel Dörfler } 1099c22d69bfSAxel Dörfler 1100c22d69bfSAxel Dörfler 1101c22d69bfSAxel Dörfler ssize_t 1102c22d69bfSAxel Dörfler udp_read_avail(net_protocol *protocol) 1103c22d69bfSAxel Dörfler { 1104bf48e753SHugo Santos return ((UdpEndpoint *)protocol)->BytesAvailable(); 1105c22d69bfSAxel Dörfler } 1106c22d69bfSAxel Dörfler 1107c22d69bfSAxel Dörfler 1108c22d69bfSAxel Dörfler struct net_domain * 1109c22d69bfSAxel Dörfler udp_get_domain(net_protocol *protocol) 1110c22d69bfSAxel Dörfler { 1111c22d69bfSAxel Dörfler return protocol->next->module->get_domain(protocol->next); 1112c22d69bfSAxel Dörfler } 1113c22d69bfSAxel Dörfler 1114c22d69bfSAxel Dörfler 1115c22d69bfSAxel Dörfler size_t 1116c22d69bfSAxel Dörfler udp_get_mtu(net_protocol *protocol, const struct sockaddr *address) 1117c22d69bfSAxel Dörfler { 1118c22d69bfSAxel Dörfler return protocol->next->module->get_mtu(protocol->next, address); 1119c22d69bfSAxel Dörfler } 1120c22d69bfSAxel Dörfler 1121c22d69bfSAxel Dörfler 1122c22d69bfSAxel Dörfler status_t 1123c22d69bfSAxel Dörfler udp_receive_data(net_buffer *buffer) 1124c22d69bfSAxel Dörfler { 1125c22d69bfSAxel Dörfler return sUdpEndpointManager->ReceiveData(buffer); 1126c22d69bfSAxel Dörfler } 1127c22d69bfSAxel Dörfler 1128c22d69bfSAxel Dörfler 1129c22d69bfSAxel Dörfler status_t 11306a606180SHugo Santos udp_deliver_data(net_protocol *protocol, net_buffer *buffer) 11316a606180SHugo Santos { 11326a606180SHugo Santos return ((UdpEndpoint *)protocol)->DeliverData(buffer); 11336a606180SHugo Santos } 11346a606180SHugo Santos 11356a606180SHugo Santos 11366a606180SHugo Santos status_t 1137c22d69bfSAxel Dörfler udp_error(uint32 code, net_buffer *data) 1138c22d69bfSAxel Dörfler { 1139c22d69bfSAxel Dörfler return B_ERROR; 1140c22d69bfSAxel Dörfler } 1141c22d69bfSAxel Dörfler 1142c22d69bfSAxel Dörfler 1143c22d69bfSAxel Dörfler status_t 1144c22d69bfSAxel Dörfler udp_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, 1145c22d69bfSAxel Dörfler void *errorData) 1146c22d69bfSAxel Dörfler { 1147c22d69bfSAxel Dörfler return B_ERROR; 1148c22d69bfSAxel Dörfler } 1149c22d69bfSAxel Dörfler 1150c22d69bfSAxel Dörfler 1151c22d69bfSAxel Dörfler // #pragma mark - module interface 1152c22d69bfSAxel Dörfler 1153c22d69bfSAxel Dörfler 1154c22d69bfSAxel Dörfler static status_t 1155c22d69bfSAxel Dörfler init_udp() 1156c22d69bfSAxel Dörfler { 1157c22d69bfSAxel Dörfler status_t status; 1158bf48e753SHugo Santos TRACE_EPM("init_udp()"); 1159c22d69bfSAxel Dörfler 1160c22d69bfSAxel Dörfler sUdpEndpointManager = new (std::nothrow) UdpEndpointManager; 1161658a5506SHugo Santos if (sUdpEndpointManager == NULL) 1162658a5506SHugo Santos return B_NO_MEMORY; 1163658a5506SHugo Santos 1164c22d69bfSAxel Dörfler status = sUdpEndpointManager->InitCheck(); 1165c22d69bfSAxel Dörfler if (status != B_OK) 1166d438fa4cSHugo Santos goto err1; 1167c22d69bfSAxel Dörfler 1168bfb45f71SHugo Santos status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_IP, 1169c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1170c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1171c22d69bfSAxel Dörfler NULL); 1172c22d69bfSAxel Dörfler if (status < B_OK) 1173658a5506SHugo Santos goto err1; 1174bfb45f71SHugo Santos status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 1175c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1176c22d69bfSAxel Dörfler "network/protocols/ipv4/v1", 1177c22d69bfSAxel Dörfler NULL); 1178c22d69bfSAxel Dörfler if (status < B_OK) 1179658a5506SHugo Santos goto err1; 1180c22d69bfSAxel Dörfler 1181bfb45f71SHugo Santos status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP, 1182c22d69bfSAxel Dörfler "network/protocols/udp/v1"); 1183c22d69bfSAxel Dörfler if (status < B_OK) 1184658a5506SHugo Santos goto err1; 1185c22d69bfSAxel Dörfler 1186c22d69bfSAxel Dörfler return B_OK; 1187c22d69bfSAxel Dörfler 1188c22d69bfSAxel Dörfler err1: 1189658a5506SHugo Santos delete sUdpEndpointManager; 1190c22d69bfSAxel Dörfler 1191bf48e753SHugo Santos TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status)); 1192c22d69bfSAxel Dörfler return status; 1193c22d69bfSAxel Dörfler } 1194c22d69bfSAxel Dörfler 1195c22d69bfSAxel Dörfler 1196c22d69bfSAxel Dörfler static status_t 1197c22d69bfSAxel Dörfler uninit_udp() 1198c22d69bfSAxel Dörfler { 1199bf48e753SHugo Santos TRACE_EPM("uninit_udp()"); 1200c22d69bfSAxel Dörfler delete sUdpEndpointManager; 1201c22d69bfSAxel Dörfler return B_OK; 1202c22d69bfSAxel Dörfler } 1203c22d69bfSAxel Dörfler 1204c22d69bfSAxel Dörfler 1205c22d69bfSAxel Dörfler static status_t 1206c22d69bfSAxel Dörfler udp_std_ops(int32 op, ...) 1207c22d69bfSAxel Dörfler { 1208c22d69bfSAxel Dörfler switch (op) { 1209c22d69bfSAxel Dörfler case B_MODULE_INIT: 1210c22d69bfSAxel Dörfler return init_udp(); 1211c22d69bfSAxel Dörfler 1212c22d69bfSAxel Dörfler case B_MODULE_UNINIT: 1213c22d69bfSAxel Dörfler return uninit_udp(); 1214c22d69bfSAxel Dörfler 1215c22d69bfSAxel Dörfler default: 1216c22d69bfSAxel Dörfler return B_ERROR; 1217c22d69bfSAxel Dörfler } 1218c22d69bfSAxel Dörfler } 1219c22d69bfSAxel Dörfler 1220c22d69bfSAxel Dörfler 1221c22d69bfSAxel Dörfler net_protocol_module_info sUDPModule = { 1222c22d69bfSAxel Dörfler { 1223c22d69bfSAxel Dörfler "network/protocols/udp/v1", 1224c22d69bfSAxel Dörfler 0, 1225c22d69bfSAxel Dörfler udp_std_ops 1226c22d69bfSAxel Dörfler }, 1227c22d69bfSAxel Dörfler udp_init_protocol, 1228c22d69bfSAxel Dörfler udp_uninit_protocol, 1229c22d69bfSAxel Dörfler udp_open, 1230c22d69bfSAxel Dörfler udp_close, 1231c22d69bfSAxel Dörfler udp_free, 1232c22d69bfSAxel Dörfler udp_connect, 1233c22d69bfSAxel Dörfler udp_accept, 1234c22d69bfSAxel Dörfler udp_control, 1235c22d69bfSAxel Dörfler udp_bind, 1236c22d69bfSAxel Dörfler udp_unbind, 1237c22d69bfSAxel Dörfler udp_listen, 1238c22d69bfSAxel Dörfler udp_shutdown, 1239c22d69bfSAxel Dörfler udp_send_data, 1240c22d69bfSAxel Dörfler udp_send_routed_data, 1241c22d69bfSAxel Dörfler udp_send_avail, 1242c22d69bfSAxel Dörfler udp_read_data, 1243c22d69bfSAxel Dörfler udp_read_avail, 1244c22d69bfSAxel Dörfler udp_get_domain, 1245c22d69bfSAxel Dörfler udp_get_mtu, 1246c22d69bfSAxel Dörfler udp_receive_data, 12476a606180SHugo Santos udp_deliver_data, 1248c22d69bfSAxel Dörfler udp_error, 1249c22d69bfSAxel Dörfler udp_error_reply, 1250c22d69bfSAxel Dörfler }; 1251c22d69bfSAxel Dörfler 1252658a5506SHugo Santos module_dependency module_dependencies[] = { 1253658a5506SHugo Santos {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 1254658a5506SHugo Santos {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 1255658a5506SHugo Santos {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule}, 1256658a5506SHugo Santos {} 1257658a5506SHugo Santos }; 1258658a5506SHugo Santos 1259c22d69bfSAxel Dörfler module_info *modules[] = { 1260c22d69bfSAxel Dörfler (module_info *)&sUDPModule, 1261c22d69bfSAxel Dörfler NULL 1262c22d69bfSAxel Dörfler }; 1263