1 /*
2 * Copyright 2006-2021, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Oliver Tappe, zooey@hirschkaefer.de
7 * Hugo Santos, hugosantos@gmail.com
8 */
9
10
11 #include <net_buffer.h>
12 #include <net_datalink.h>
13 #include <net_protocol.h>
14 #include <net_stack.h>
15
16 #include <lock.h>
17 #include <util/AutoLock.h>
18 #include <util/DoublyLinkedList.h>
19 #include <util/OpenHashTable.h>
20
21 #include <AutoDeleter.h>
22 #include <KernelExport.h>
23
24 #include <NetBufferUtilities.h>
25 #include <NetUtilities.h>
26 #include <ProtocolUtilities.h>
27
28 #include <algorithm>
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
31 #include <new>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <utility>
35
36
37 // NOTE the locking protocol dictates that we must hold UdpDomainSupport's
38 // lock before holding a child UdpEndpoint's lock. This restriction
39 // is dictated by the receive path as blind access to the endpoint
40 // hash is required when holding the DomainSupport's lock.
41
42
43 //#define TRACE_UDP
44 #ifdef TRACE_UDP
45 # define TRACE_BLOCK(x) dump_block x
46 // do not remove the space before ', ##args' if you want this
47 // to compile with gcc 2.95
48 # define TRACE_EP(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \
49 B_PRIu32 "] %p " format "\n", system_time(), \
50 thread_get_current_thread_id(), this , ##args)
51 # define TRACE_EPM(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \
52 B_PRIu32 "] " format "\n", system_time() , \
53 thread_get_current_thread_id() , ##args)
54 # define TRACE_DOMAIN(format, args...) dprintf("UDP [%" B_PRIu64 ",%" \
55 B_PRIu32 "] (%d) " format "\n", system_time(), \
56 thread_get_current_thread_id(), Domain()->family , ##args)
57 #else
58 # define TRACE_BLOCK(x)
59 # define TRACE_EP(args...) do { } while (0)
60 # define TRACE_EPM(args...) do { } while (0)
61 # define TRACE_DOMAIN(args...) do { } while (0)
62 #endif
63
64
65 struct udp_header {
66 uint16 source_port;
67 uint16 destination_port;
68 uint16 udp_length;
69 uint16 udp_checksum;
70 } _PACKED;
71
72
73 typedef NetBufferField<uint16, offsetof(udp_header, udp_checksum)>
74 UDPChecksumField;
75
76 class UdpDomainSupport;
77
78 class UdpEndpoint : public net_protocol, public DatagramSocket<> {
79 public:
80 UdpEndpoint(net_socket* socket);
81
82 status_t Bind(const sockaddr* newAddr);
83 status_t Unbind(sockaddr* newAddr);
84 status_t Connect(const sockaddr* newAddr);
85
86 status_t Open();
87 status_t Close();
88 status_t Free();
89
90 status_t SendRoutedData(net_buffer* buffer,
91 net_route* route);
92 status_t SendData(net_buffer* buffer);
93
94 ssize_t BytesAvailable();
95 status_t FetchData(size_t numBytes, uint32 flags,
96 net_buffer** _buffer);
97
98 status_t StoreData(net_buffer* buffer);
99 status_t DeliverData(net_buffer* buffer);
100
101 // only the domain support will change/check the Active flag so
102 // we don't really need to protect it with the socket lock.
IsActive() const103 bool IsActive() const { return fActive; }
SetActive(bool newValue)104 void SetActive(bool newValue) { fActive = newValue; }
105
HashTableLink()106 UdpEndpoint*& HashTableLink() { return fLink; }
107
108 void Dump() const;
109
110 private:
111 UdpDomainSupport* fManager;
112 bool fActive;
113 // an active UdpEndpoint is part of the
114 // endpoint hash (and it is bound and
115 // optionally connected)
116
117 UdpEndpoint* fLink;
118 };
119
120
121 class UdpDomainSupport;
122
123 struct UdpHashDefinition {
124 typedef net_address_module_info ParentType;
125 typedef std::pair<const sockaddr *, const sockaddr *> KeyType;
126 typedef UdpEndpoint ValueType;
127
UdpHashDefinitionUdpHashDefinition128 UdpHashDefinition(net_address_module_info *_module)
129 : module(_module) {}
UdpHashDefinitionUdpHashDefinition130 UdpHashDefinition(const UdpHashDefinition& definition)
131 : module(definition.module) {}
132
HashKeyUdpHashDefinition133 size_t HashKey(const KeyType &key) const
134 {
135 return _Mix(module->hash_address_pair(key.first, key.second));
136 }
137
HashUdpHashDefinition138 size_t Hash(UdpEndpoint *endpoint) const
139 {
140 return _Mix(endpoint->LocalAddress().HashPair(
141 *endpoint->PeerAddress()));
142 }
143
_MixUdpHashDefinition144 static size_t _Mix(size_t hash)
145 {
146 // move the bits into the relevant range (as defined by kNumHashBuckets)
147 return (hash & 0x000007FF) ^ (hash & 0x003FF800) >> 11
148 ^ (hash & 0xFFC00000UL) >> 22;
149 }
150
CompareUdpHashDefinition151 bool Compare(const KeyType &key, UdpEndpoint *endpoint) const
152 {
153 return endpoint->LocalAddress().EqualTo(key.first, true)
154 && endpoint->PeerAddress().EqualTo(key.second, true);
155 }
156
GetLinkUdpHashDefinition157 UdpEndpoint *&GetLink(UdpEndpoint *endpoint) const
158 {
159 return endpoint->HashTableLink();
160 }
161
162 net_address_module_info *module;
163 };
164
165
166 class UdpDomainSupport : public DoublyLinkedListLinkImpl<UdpDomainSupport> {
167 public:
168 UdpDomainSupport(net_domain *domain);
169 ~UdpDomainSupport();
170
171 status_t Init();
172
Domain() const173 net_domain *Domain() const { return fDomain; }
174
Ref()175 void Ref() { fEndpointCount++; }
Put()176 bool Put() { fEndpointCount--; return fEndpointCount == 0; }
177
178 status_t DemuxIncomingBuffer(net_buffer* buffer);
179 status_t DeliverError(status_t error, net_buffer* buffer);
180
181 status_t BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
182 status_t ConnectEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
183 status_t UnbindEndpoint(UdpEndpoint *endpoint);
184
185 void DumpEndpoints() const;
186
187 private:
188 status_t _BindEndpoint(UdpEndpoint *endpoint, const sockaddr *address);
189 status_t _Bind(UdpEndpoint *endpoint, const sockaddr *address);
190 status_t _BindToEphemeral(UdpEndpoint *endpoint, const sockaddr *address);
191 status_t _FinishBind(UdpEndpoint *endpoint, const sockaddr *address);
192
193 UdpEndpoint *_FindActiveEndpoint(const sockaddr *ourAddress,
194 const sockaddr *peerAddress, uint32 index = 0);
195 status_t _DemuxBroadcast(net_buffer *buffer);
196 status_t _DemuxUnicast(net_buffer *buffer);
197
198 uint16 _GetNextEphemeral();
199 UdpEndpoint *_EndpointWithPort(uint16 port) const;
200
AddressModule() const201 net_address_module_info *AddressModule() const
202 { return fDomain->address_module; }
203
204 typedef BOpenHashTable<UdpHashDefinition, false> EndpointTable;
205
206 mutex fLock;
207 net_domain *fDomain;
208 uint16 fLastUsedEphemeral;
209 EndpointTable fActiveEndpoints;
210 uint32 fEndpointCount;
211
212 static const uint16 kFirst = 49152;
213 static const uint16 kLast = 65535;
214 static const uint32 kNumHashBuckets = 0x800;
215 // if you change this, adjust the shifting in
216 // Hash() accordingly!
217 };
218
219
220 typedef DoublyLinkedList<UdpDomainSupport> UdpDomainList;
221
222
223 class UdpEndpointManager {
224 public:
225 UdpEndpointManager();
226 ~UdpEndpointManager();
227
228 status_t InitCheck() const;
229
230 status_t ReceiveData(net_buffer* buffer);
231 status_t ReceiveError(status_t error,
232 net_buffer* buffer);
233 status_t Deframe(net_buffer* buffer);
234
235 UdpDomainSupport* OpenEndpoint(UdpEndpoint* endpoint);
236 status_t FreeEndpoint(UdpDomainSupport* domain);
237
238 static int DumpEndpoints(int argc, char *argv[]);
239
240 private:
241 inline net_domain* _GetDomain(net_buffer* buffer);
242 UdpDomainSupport* _GetDomainSupport(net_domain* domain,
243 bool create);
244 UdpDomainSupport* _GetDomainSupport(net_buffer* buffer);
245
246 mutex fLock;
247 status_t fStatus;
248 UdpDomainList fDomains;
249 };
250
251
252 static UdpEndpointManager *sUdpEndpointManager;
253
254 net_buffer_module_info *gBufferModule;
255 net_datalink_module_info *gDatalinkModule;
256 net_stack_module_info *gStackModule;
257 net_socket_module_info *gSocketModule;
258
259
260 // #pragma mark -
261
262
UdpDomainSupport(net_domain * domain)263 UdpDomainSupport::UdpDomainSupport(net_domain *domain)
264 :
265 fDomain(domain),
266 fActiveEndpoints(domain->address_module),
267 fEndpointCount(0)
268 {
269 mutex_init(&fLock, "udp domain");
270
271 fLastUsedEphemeral = kFirst + rand() % (kLast - kFirst);
272 }
273
274
~UdpDomainSupport()275 UdpDomainSupport::~UdpDomainSupport()
276 {
277 mutex_destroy(&fLock);
278 }
279
280
281 status_t
Init()282 UdpDomainSupport::Init()
283 {
284 return fActiveEndpoints.Init(kNumHashBuckets);
285 }
286
287
288 status_t
DemuxIncomingBuffer(net_buffer * buffer)289 UdpDomainSupport::DemuxIncomingBuffer(net_buffer *buffer)
290 {
291 // NOTE: multicast is delivered directly to the endpoint
292 MutexLocker _(fLock);
293
294 if ((buffer->msg_flags & MSG_BCAST) != 0)
295 return _DemuxBroadcast(buffer);
296 if ((buffer->msg_flags & MSG_MCAST) != 0)
297 return B_ERROR;
298
299 return _DemuxUnicast(buffer);
300 }
301
302
303 status_t
DeliverError(status_t error,net_buffer * buffer)304 UdpDomainSupport::DeliverError(status_t error, net_buffer* buffer)
305 {
306 if ((buffer->msg_flags & (MSG_BCAST | MSG_MCAST)) != 0)
307 return B_ERROR;
308
309 MutexLocker _(fLock);
310
311 // Forward the error to the socket
312 UdpEndpoint* endpoint = _FindActiveEndpoint(buffer->source,
313 buffer->destination);
314 if (endpoint != NULL) {
315 gSocketModule->notify(endpoint->Socket(), B_SELECT_ERROR, error);
316 endpoint->NotifyOne();
317 }
318
319 gBufferModule->free(buffer);
320 return B_OK;
321 }
322
323
324 status_t
BindEndpoint(UdpEndpoint * endpoint,const sockaddr * address)325 UdpDomainSupport::BindEndpoint(UdpEndpoint *endpoint,
326 const sockaddr *address)
327 {
328 if (!AddressModule()->is_same_family(address))
329 return EAFNOSUPPORT;
330
331 MutexLocker _(fLock);
332
333 if (endpoint->IsActive())
334 return EINVAL;
335
336 return _BindEndpoint(endpoint, address);
337 }
338
339
340 status_t
ConnectEndpoint(UdpEndpoint * endpoint,const sockaddr * address)341 UdpDomainSupport::ConnectEndpoint(UdpEndpoint *endpoint,
342 const sockaddr *address)
343 {
344 MutexLocker _(fLock);
345
346 if (endpoint->IsActive()) {
347 fActiveEndpoints.Remove(endpoint);
348 endpoint->SetActive(false);
349 }
350
351 if (address->sa_family == AF_UNSPEC) {
352 // [Stevens-UNP1, p226]: specifying AF_UNSPEC requests a "disconnect",
353 // so we reset the peer address:
354 endpoint->PeerAddress().SetToEmpty();
355 } else {
356 if (!AddressModule()->is_same_family(address))
357 return EAFNOSUPPORT;
358
359 // consider destination address INADDR_ANY as INADDR_LOOPBACK
360 sockaddr_storage _address;
361 if (AddressModule()->is_empty_address(address, false)) {
362 AddressModule()->get_loopback_address((sockaddr *)&_address);
363 // for IPv4 and IPv6 the port is at the same offset
364 ((sockaddr_in&)_address).sin_port
365 = ((sockaddr_in *)address)->sin_port;
366 address = (sockaddr *)&_address;
367 }
368
369 status_t status = endpoint->PeerAddress().SetTo(address);
370 if (status < B_OK)
371 return status;
372 struct net_route *routeToDestination
373 = gDatalinkModule->get_route(fDomain, address);
374 if (routeToDestination) {
375 // stay bound to current local port, if any.
376 uint16 port = endpoint->LocalAddress().Port();
377 status = endpoint->LocalAddress().SetTo(
378 routeToDestination->interface_address->local);
379 endpoint->LocalAddress().SetPort(port);
380 gDatalinkModule->put_route(fDomain, routeToDestination);
381 if (status < B_OK)
382 return status;
383 }
384 }
385
386 // we need to activate no matter whether or not we have just disconnected,
387 // as calling connect() always triggers an implicit bind():
388 status_t status = _BindEndpoint(endpoint, *endpoint->LocalAddress());
389 if (status == B_OK)
390 gSocketModule->set_connected(endpoint->Socket());
391 return status;
392 }
393
394
395 status_t
UnbindEndpoint(UdpEndpoint * endpoint)396 UdpDomainSupport::UnbindEndpoint(UdpEndpoint *endpoint)
397 {
398 MutexLocker _(fLock);
399
400 if (endpoint->IsActive())
401 fActiveEndpoints.Remove(endpoint);
402
403 endpoint->SetActive(false);
404
405 return B_OK;
406 }
407
408
409 void
DumpEndpoints() const410 UdpDomainSupport::DumpEndpoints() const
411 {
412 kprintf("-------- UDP Domain %p ---------\n", this);
413 kprintf("%10s %20s %20s %8s\n", "address", "local", "peer", "recv-q");
414
415 EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
416
417 while (UdpEndpoint* endpoint = it.Next()) {
418 endpoint->Dump();
419 }
420 }
421
422
423 status_t
_BindEndpoint(UdpEndpoint * endpoint,const sockaddr * address)424 UdpDomainSupport::_BindEndpoint(UdpEndpoint *endpoint,
425 const sockaddr *address)
426 {
427 if (AddressModule()->get_port(address) == 0)
428 return _BindToEphemeral(endpoint, address);
429
430 return _Bind(endpoint, address);
431 }
432
433
434 status_t
_Bind(UdpEndpoint * endpoint,const sockaddr * address)435 UdpDomainSupport::_Bind(UdpEndpoint *endpoint, const sockaddr *address)
436 {
437 int socketOptions = endpoint->Socket()->options;
438
439 EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
440
441 // Iterate over all active UDP-endpoints and check if the requested bind
442 // is allowed (see figure 22.24 in [Stevens - TCP2, p735]):
443 TRACE_DOMAIN("CheckBindRequest() for %s...", AddressString(fDomain,
444 address, true).Data());
445
446 while (it.HasNext()) {
447 UdpEndpoint *otherEndpoint = it.Next();
448
449 TRACE_DOMAIN(" ...checking endpoint %p (port=%u)...", otherEndpoint,
450 ntohs(otherEndpoint->LocalAddress().Port()));
451
452 if (otherEndpoint->LocalAddress().EqualPorts(address)) {
453 // port is already bound, SO_REUSEADDR or SO_REUSEPORT is required:
454 if ((otherEndpoint->Socket()->options
455 & (SO_REUSEADDR | SO_REUSEPORT)) == 0
456 || (socketOptions & (SO_REUSEADDR | SO_REUSEPORT)) == 0)
457 return EADDRINUSE;
458
459 // if both addresses are the same, SO_REUSEPORT is required:
460 if (otherEndpoint->LocalAddress().EqualTo(address, false)
461 && ((otherEndpoint->Socket()->options & SO_REUSEPORT) == 0
462 || (socketOptions & SO_REUSEPORT) == 0))
463 return EADDRINUSE;
464 }
465 }
466
467 return _FinishBind(endpoint, address);
468 }
469
470
471 status_t
_BindToEphemeral(UdpEndpoint * endpoint,const sockaddr * address)472 UdpDomainSupport::_BindToEphemeral(UdpEndpoint *endpoint,
473 const sockaddr *address)
474 {
475 SocketAddressStorage newAddress(AddressModule());
476 status_t status = newAddress.SetTo(address);
477 if (status < B_OK)
478 return status;
479
480 uint16 allocedPort = _GetNextEphemeral();
481 if (allocedPort == 0)
482 return ENOBUFS;
483
484 newAddress.SetPort(htons(allocedPort));
485
486 return _FinishBind(endpoint, *newAddress);
487 }
488
489
490 status_t
_FinishBind(UdpEndpoint * endpoint,const sockaddr * address)491 UdpDomainSupport::_FinishBind(UdpEndpoint *endpoint, const sockaddr *address)
492 {
493 status_t status = endpoint->next->module->bind(endpoint->next, address);
494 if (status < B_OK)
495 return status;
496
497 fActiveEndpoints.Insert(endpoint);
498 endpoint->SetActive(true);
499
500 return B_OK;
501 }
502
503
504 UdpEndpoint *
_FindActiveEndpoint(const sockaddr * ourAddress,const sockaddr * peerAddress,uint32 index)505 UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
506 const sockaddr *peerAddress, uint32 index)
507 {
508 ASSERT_LOCKED_MUTEX(&fLock);
509
510 TRACE_DOMAIN("finding Endpoint for %s <- %s",
511 AddressString(fDomain, ourAddress, true).Data(),
512 AddressString(fDomain, peerAddress, true).Data());
513
514 UdpEndpoint* endpoint = fActiveEndpoints.Lookup(
515 std::make_pair(ourAddress, peerAddress));
516
517 // Make sure the bound_to_device constraint is fulfilled
518 while (endpoint != NULL && endpoint->socket->bound_to_device != 0
519 && index != 0 && endpoint->socket->bound_to_device != index) {
520 endpoint = endpoint->HashTableLink();
521 if (endpoint != NULL
522 && (!endpoint->LocalAddress().EqualTo(ourAddress, true)
523 || !endpoint->PeerAddress().EqualTo(peerAddress, true)))
524 return NULL;
525 }
526
527 return endpoint;
528 }
529
530
531 status_t
_DemuxBroadcast(net_buffer * buffer)532 UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
533 {
534 sockaddr* peerAddr = buffer->source;
535 sockaddr* broadcastAddr = buffer->destination;
536 uint16 incomingPort = AddressModule()->get_port(broadcastAddr);
537
538 sockaddr* mask = NULL;
539 if (buffer->interface_address != NULL)
540 mask = (sockaddr*)buffer->interface_address->mask;
541
542 TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
543
544 EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
545
546 while (UdpEndpoint* endpoint = iterator.Next()) {
547 TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...",
548 AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
549
550 if (endpoint->socket->bound_to_device != 0
551 && buffer->index != endpoint->socket->bound_to_device)
552 continue;
553
554 if (endpoint->LocalAddress().Port() != incomingPort) {
555 // ports don't match, so we do not dispatch to this endpoint...
556 continue;
557 }
558
559 if (!endpoint->PeerAddress().IsEmpty(true)) {
560 // endpoint is connected to a specific destination, we check if
561 // this datagram is from there:
562 if (!endpoint->PeerAddress().EqualTo(peerAddr, true)) {
563 // no, datagram is from another peer, so we do not dispatch to
564 // this endpoint...
565 continue;
566 }
567 }
568
569 if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
570 || mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
571 // address matches, dispatch to this endpoint:
572 endpoint->StoreData(buffer);
573 }
574 }
575
576 return B_OK;
577 }
578
579
580 status_t
_DemuxUnicast(net_buffer * buffer)581 UdpDomainSupport::_DemuxUnicast(net_buffer* buffer)
582 {
583 TRACE_DOMAIN("_DemuxUnicast(%p)", buffer);
584
585 const sockaddr* localAddress = buffer->destination;
586 const sockaddr* peerAddress = buffer->source;
587
588 // look for full (most special) match:
589 UdpEndpoint* endpoint = _FindActiveEndpoint(localAddress, peerAddress,
590 buffer->index);
591 if (endpoint == NULL) {
592 // look for endpoint matching local address & port:
593 endpoint = _FindActiveEndpoint(localAddress, NULL, buffer->index);
594 if (endpoint == NULL) {
595 // look for endpoint matching peer address & port and local port:
596 SocketAddressStorage local(AddressModule());
597 local.SetToEmpty();
598 local.SetPort(AddressModule()->get_port(localAddress));
599 endpoint = _FindActiveEndpoint(*local, peerAddress, buffer->index);
600 if (endpoint == NULL) {
601 // last chance: look for endpoint matching local port only:
602 endpoint = _FindActiveEndpoint(*local, NULL, buffer->index);
603 }
604 }
605 }
606
607 if (endpoint == NULL) {
608 TRACE_DOMAIN("_DemuxUnicast(%p) - no matching endpoint found!", buffer);
609 return B_NAME_NOT_FOUND;
610 }
611
612 endpoint->StoreData(buffer);
613 return B_OK;
614 }
615
616
617 uint16
_GetNextEphemeral()618 UdpDomainSupport::_GetNextEphemeral()
619 {
620 uint16 stop, curr;
621 if (fLastUsedEphemeral < kLast) {
622 stop = fLastUsedEphemeral;
623 curr = fLastUsedEphemeral + 1;
624 } else {
625 stop = kLast;
626 curr = kFirst;
627 }
628
629 TRACE_DOMAIN("_GetNextEphemeral(), last %hu, curr %hu, stop %hu",
630 fLastUsedEphemeral, curr, stop);
631
632 // TODO: a free list could be used to avoid the impact of these two
633 // nested loops most of the time... let's see how bad this really is
634 for (; curr != stop; curr = (curr < kLast) ? (curr + 1) : kFirst) {
635 TRACE_DOMAIN(" _GetNextEphemeral(): trying port %hu...", curr);
636
637 if (_EndpointWithPort(htons(curr)) == NULL) {
638 TRACE_DOMAIN(" _GetNextEphemeral(): ...using port %hu", curr);
639 fLastUsedEphemeral = curr;
640 return curr;
641 }
642 }
643
644 return 0;
645 }
646
647
648 UdpEndpoint *
_EndpointWithPort(uint16 port) const649 UdpDomainSupport::_EndpointWithPort(uint16 port) const
650 {
651 EndpointTable::Iterator it = fActiveEndpoints.GetIterator();
652
653 while (it.HasNext()) {
654 UdpEndpoint *endpoint = it.Next();
655 if (endpoint->LocalAddress().Port() == port)
656 return endpoint;
657 }
658
659 return NULL;
660 }
661
662
663 // #pragma mark -
664
665
UdpEndpointManager()666 UdpEndpointManager::UdpEndpointManager()
667 {
668 mutex_init(&fLock, "UDP endpoints");
669 fStatus = B_OK;
670 }
671
672
~UdpEndpointManager()673 UdpEndpointManager::~UdpEndpointManager()
674 {
675 mutex_destroy(&fLock);
676 }
677
678
679 status_t
InitCheck() const680 UdpEndpointManager::InitCheck() const
681 {
682 return fStatus;
683 }
684
685
686 int
DumpEndpoints(int argc,char * argv[])687 UdpEndpointManager::DumpEndpoints(int argc, char *argv[])
688 {
689 UdpDomainList::Iterator it = sUdpEndpointManager->fDomains.GetIterator();
690
691 kprintf("===== UDP domain manager %p =====\n", sUdpEndpointManager);
692
693 while (it.HasNext())
694 it.Next()->DumpEndpoints();
695
696 return 0;
697 }
698
699
700 // #pragma mark - inbound
701
702
703 struct DomainSupportDelete
704 {
operator ()DomainSupportDelete705 inline void operator()(UdpDomainSupport* object)
706 {
707 sUdpEndpointManager->FreeEndpoint(object);
708 }
709 };
710
711
712 struct DomainSupportDeleter
713 : BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>
714 {
DomainSupportDeleterDomainSupportDeleter715 DomainSupportDeleter(UdpDomainSupport* object)
716 : BPrivate::AutoDeleter<UdpDomainSupport, DomainSupportDelete>(object)
717 {}
718 };
719
720
721 status_t
ReceiveData(net_buffer * buffer)722 UdpEndpointManager::ReceiveData(net_buffer *buffer)
723 {
724 TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
725
726 UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
727 if (domainSupport == NULL) {
728 // we don't instantiate domain supports in the receiving path, as
729 // we are only interested in delivering data to existing sockets.
730 return B_ERROR;
731 }
732 DomainSupportDeleter deleter(domainSupport);
733
734 status_t status = Deframe(buffer);
735 if (status != B_OK) {
736 return status;
737 }
738
739 status = domainSupport->DemuxIncomingBuffer(buffer);
740 if (status != B_OK) {
741 TRACE_EPM(" ReceiveData(): no endpoint.");
742 // Send port unreachable error
743 domainSupport->Domain()->module->error_reply(NULL, buffer,
744 B_NET_ERROR_UNREACH_PORT, NULL);
745 return B_ERROR;
746 }
747
748 gBufferModule->free(buffer);
749 return B_OK;
750 }
751
752
753 status_t
ReceiveError(status_t error,net_buffer * buffer)754 UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
755 {
756 TRACE_EPM("ReceiveError(code %" B_PRId32 " %p [%" B_PRIu32 " bytes])",
757 error, buffer, buffer->size);
758
759 // We only really need the port information
760 if (buffer->size < 4)
761 return B_BAD_VALUE;
762
763 UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
764 if (domainSupport == NULL) {
765 // we don't instantiate domain supports in the receiving path, as
766 // we are only interested in delivering data to existing sockets.
767 return B_ERROR;
768 }
769 DomainSupportDeleter deleter(domainSupport);
770
771 // Deframe the buffer manually, as we usually only get 8 bytes from the
772 // original packet
773 udp_header header;
774 if (gBufferModule->read(buffer, 0, &header,
775 std::min((size_t)buffer->size, sizeof(udp_header))) != B_OK) {
776 return B_BAD_VALUE;
777 }
778
779 net_domain* domain = buffer->interface_address->domain;
780 net_address_module_info* addressModule = domain->address_module;
781
782 SocketAddress source(addressModule, buffer->source);
783 SocketAddress destination(addressModule, buffer->destination);
784
785 source.SetPort(header.source_port);
786 destination.SetPort(header.destination_port);
787
788 error = domainSupport->DeliverError(error, buffer);
789 return error;
790 }
791
792
793 status_t
Deframe(net_buffer * buffer)794 UdpEndpointManager::Deframe(net_buffer* buffer)
795 {
796 TRACE_EPM("Deframe(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
797
798 NetBufferHeaderReader<udp_header> bufferHeader(buffer);
799 if (bufferHeader.Status() != B_OK)
800 return bufferHeader.Status();
801
802 udp_header& header = bufferHeader.Data();
803
804 net_domain* domain = _GetDomain(buffer);
805 if (domain == NULL) {
806 TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain "
807 "specified (interface address %p).", buffer->interface_address);
808 return B_BAD_VALUE;
809 }
810 net_address_module_info* addressModule = domain->address_module;
811
812 SocketAddress source(addressModule, buffer->source);
813 SocketAddress destination(addressModule, buffer->destination);
814
815 source.SetPort(header.source_port);
816 destination.SetPort(header.destination_port);
817
818 TRACE_EPM(" Deframe(): data from %s to %s", source.AsString(true).Data(),
819 destination.AsString(true).Data());
820
821 uint16 udpLength = ntohs(header.udp_length);
822 if (udpLength > buffer->size) {
823 TRACE_EPM(" Deframe(): buffer is too short, expected %hu.",
824 udpLength);
825 return B_MISMATCHED_VALUES;
826 }
827
828 if (buffer->size > udpLength)
829 gBufferModule->trim(buffer, udpLength);
830
831 if (header.udp_checksum != 0 && (buffer->buffer_flags & NET_BUFFER_L4_CHECKSUM_VALID) == 0) {
832 // check UDP-checksum (simulating a so-called "pseudo-header"):
833 uint16 sum = Checksum::PseudoHeader(addressModule, gBufferModule,
834 buffer, IPPROTO_UDP);
835 if (sum != 0) {
836 TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum);
837 return B_BAD_VALUE;
838 }
839 }
840
841 bufferHeader.Remove();
842 // remove UDP-header from buffer before passing it on
843
844 return B_OK;
845 }
846
847
848 UdpDomainSupport *
OpenEndpoint(UdpEndpoint * endpoint)849 UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
850 {
851 MutexLocker _(fLock);
852
853 UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
854 return domain;
855 }
856
857
858 status_t
FreeEndpoint(UdpDomainSupport * domain)859 UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
860 {
861 MutexLocker _(fLock);
862
863 if (domain->Put()) {
864 fDomains.Remove(domain);
865 delete domain;
866 }
867
868 return B_OK;
869 }
870
871
872 // #pragma mark -
873
874
875 inline net_domain*
_GetDomain(net_buffer * buffer)876 UdpEndpointManager::_GetDomain(net_buffer* buffer)
877 {
878 if (buffer->interface_address != NULL)
879 return buffer->interface_address->domain;
880
881 return gStackModule->get_domain(buffer->destination->sa_family);
882 }
883
884
885 UdpDomainSupport*
_GetDomainSupport(net_domain * domain,bool create)886 UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create)
887 {
888 ASSERT_LOCKED_MUTEX(&fLock);
889
890 if (domain == NULL)
891 return NULL;
892
893 // TODO convert this into a Hashtable or install per-domain
894 // receiver handlers that forward the requests to the
895 // appropriate DemuxIncomingBuffer(). For instance, while
896 // being constructed UdpDomainSupport could call
897 // register_domain_receiving_protocol() with the right
898 // family.
899 UdpDomainList::Iterator iterator = fDomains.GetIterator();
900 while (UdpDomainSupport* domainSupport = iterator.Next()) {
901 if (domainSupport->Domain() == domain) {
902 domainSupport->Ref();
903 return domainSupport;
904 }
905 }
906
907 if (!create)
908 return NULL;
909
910 UdpDomainSupport* domainSupport
911 = new (std::nothrow) UdpDomainSupport(domain);
912 if (domainSupport == NULL || domainSupport->Init() < B_OK) {
913 delete domainSupport;
914 return NULL;
915 }
916
917 fDomains.Add(domainSupport);
918 domainSupport->Ref();
919 return domainSupport;
920 }
921
922
923 /*! Retrieves the UdpDomainSupport object responsible for this buffer, if the
924 domain can be determined. This is only successful if the domain support is
925 already existing, ie. there must already be an endpoint for the domain.
926 */
927 UdpDomainSupport*
_GetDomainSupport(net_buffer * buffer)928 UdpEndpointManager::_GetDomainSupport(net_buffer* buffer)
929 {
930 MutexLocker _(fLock);
931
932 return _GetDomainSupport(_GetDomain(buffer), false);
933 }
934
935
936 // #pragma mark -
937
938
UdpEndpoint(net_socket * socket)939 UdpEndpoint::UdpEndpoint(net_socket *socket)
940 :
941 DatagramSocket<>("udp endpoint", socket),
942 fActive(false)
943 {
944 }
945
946
947 // #pragma mark - activation
948
949
950 status_t
Bind(const sockaddr * address)951 UdpEndpoint::Bind(const sockaddr *address)
952 {
953 TRACE_EP("Bind(%s)", AddressString(Domain(), address, true).Data());
954 return fManager->BindEndpoint(this, address);
955 }
956
957
958 status_t
Unbind(sockaddr * address)959 UdpEndpoint::Unbind(sockaddr *address)
960 {
961 TRACE_EP("Unbind()");
962 return fManager->UnbindEndpoint(this);
963 }
964
965
966 status_t
Connect(const sockaddr * address)967 UdpEndpoint::Connect(const sockaddr *address)
968 {
969 TRACE_EP("Connect(%s)", AddressString(Domain(), address, true).Data());
970 return fManager->ConnectEndpoint(this, address);
971 }
972
973
974 status_t
Open()975 UdpEndpoint::Open()
976 {
977 TRACE_EP("Open()");
978
979 AutoLocker _(fLock);
980
981 status_t status = ProtocolSocket::Open();
982 if (status < B_OK)
983 return status;
984
985 fManager = sUdpEndpointManager->OpenEndpoint(this);
986 if (fManager == NULL)
987 return EAFNOSUPPORT;
988
989 return B_OK;
990 }
991
992
993 status_t
Close()994 UdpEndpoint::Close()
995 {
996 TRACE_EP("Close()");
997 fSocket->error = EBADF;
998 WakeAll();
999 return B_OK;
1000 }
1001
1002
1003 status_t
Free()1004 UdpEndpoint::Free()
1005 {
1006 TRACE_EP("Free()");
1007 fManager->UnbindEndpoint(this);
1008 return sUdpEndpointManager->FreeEndpoint(fManager);
1009 }
1010
1011
1012 // #pragma mark - outbound
1013
1014
1015 status_t
SendRoutedData(net_buffer * buffer,net_route * route)1016 UdpEndpoint::SendRoutedData(net_buffer *buffer, net_route *route)
1017 {
1018 TRACE_EP("SendRoutedData(%p [%" B_PRIu32 " bytes], %p)", buffer,
1019 buffer->size, route);
1020
1021 if (buffer->size > (0xffff - sizeof(udp_header)))
1022 return EMSGSIZE;
1023
1024 buffer->protocol = IPPROTO_UDP;
1025
1026 // add and fill UDP-specific header:
1027 NetBufferPrepend<udp_header> header(buffer);
1028 if (header.Status() < B_OK)
1029 return header.Status();
1030
1031 header->source_port = AddressModule()->get_port(buffer->source);
1032 header->destination_port = AddressModule()->get_port(buffer->destination);
1033 header->udp_length = htons(buffer->size);
1034 // the udp-header is already included in the buffer-size
1035 header->udp_checksum = 0;
1036
1037 header.Sync();
1038
1039 uint16 calculatedChecksum = Checksum::PseudoHeader(AddressModule(),
1040 gBufferModule, buffer, IPPROTO_UDP);
1041 if (calculatedChecksum == 0)
1042 calculatedChecksum = 0xffff;
1043
1044 *UDPChecksumField(buffer) = calculatedChecksum;
1045 buffer->buffer_flags |= NET_BUFFER_L4_CHECKSUM_VALID;
1046
1047 return next->module->send_routed_data(next, route, buffer);
1048 }
1049
1050
1051 status_t
SendData(net_buffer * buffer)1052 UdpEndpoint::SendData(net_buffer *buffer)
1053 {
1054 TRACE_EP("SendData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1055
1056 return gDatalinkModule->send_data(this, NULL, buffer);
1057 }
1058
1059
1060 // #pragma mark - inbound
1061
1062
1063 ssize_t
BytesAvailable()1064 UdpEndpoint::BytesAvailable()
1065 {
1066 size_t bytes = AvailableData();
1067 TRACE_EP("BytesAvailable(): %lu", bytes);
1068 return bytes;
1069 }
1070
1071
1072 status_t
FetchData(size_t numBytes,uint32 flags,net_buffer ** _buffer)1073 UdpEndpoint::FetchData(size_t numBytes, uint32 flags, net_buffer **_buffer)
1074 {
1075 TRACE_EP("FetchData(%" B_PRIuSIZE ", 0x%" B_PRIx32 ")", numBytes, flags);
1076
1077 status_t status = Dequeue(flags, _buffer);
1078 TRACE_EP(" FetchData(): returned from fifo status: %s", strerror(status));
1079 if (status != B_OK)
1080 return status;
1081
1082 TRACE_EP(" FetchData(): returns buffer with %" B_PRIu32 " bytes",
1083 (*_buffer)->size);
1084 return B_OK;
1085 }
1086
1087
1088 status_t
StoreData(net_buffer * buffer)1089 UdpEndpoint::StoreData(net_buffer *buffer)
1090 {
1091 TRACE_EP("StoreData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
1092
1093 return EnqueueClone(buffer);
1094 }
1095
1096
1097 status_t
DeliverData(net_buffer * _buffer)1098 UdpEndpoint::DeliverData(net_buffer *_buffer)
1099 {
1100 TRACE_EP("DeliverData(%p [%" B_PRIu32 " bytes])", _buffer, _buffer->size);
1101
1102 net_buffer *buffer = gBufferModule->clone(_buffer, false);
1103 if (buffer == NULL)
1104 return B_NO_MEMORY;
1105
1106 status_t status = sUdpEndpointManager->Deframe(buffer);
1107 if (status < B_OK) {
1108 gBufferModule->free(buffer);
1109 return status;
1110 }
1111
1112 return Enqueue(buffer);
1113 }
1114
1115
1116 void
Dump() const1117 UdpEndpoint::Dump() const
1118 {
1119 char local[64];
1120 LocalAddress().AsString(local, sizeof(local), true);
1121 char peer[64];
1122 PeerAddress().AsString(peer, sizeof(peer), true);
1123
1124 kprintf("%p %20s %20s %8lu\n", this, local, peer, fCurrentBytes);
1125 }
1126
1127
1128 // #pragma mark - protocol interface
1129
1130
1131 net_protocol *
udp_init_protocol(net_socket * socket)1132 udp_init_protocol(net_socket *socket)
1133 {
1134 socket->protocol = IPPROTO_UDP;
1135
1136 UdpEndpoint *endpoint = new (std::nothrow) UdpEndpoint(socket);
1137 if (endpoint == NULL || endpoint->InitCheck() < B_OK) {
1138 delete endpoint;
1139 return NULL;
1140 }
1141
1142 return endpoint;
1143 }
1144
1145
1146 status_t
udp_uninit_protocol(net_protocol * protocol)1147 udp_uninit_protocol(net_protocol *protocol)
1148 {
1149 delete (UdpEndpoint *)protocol;
1150 return B_OK;
1151 }
1152
1153
1154 status_t
udp_open(net_protocol * protocol)1155 udp_open(net_protocol *protocol)
1156 {
1157 return ((UdpEndpoint *)protocol)->Open();
1158 }
1159
1160
1161 status_t
udp_close(net_protocol * protocol)1162 udp_close(net_protocol *protocol)
1163 {
1164 return ((UdpEndpoint *)protocol)->Close();
1165 }
1166
1167
1168 status_t
udp_free(net_protocol * protocol)1169 udp_free(net_protocol *protocol)
1170 {
1171 return ((UdpEndpoint *)protocol)->Free();
1172 }
1173
1174
1175 status_t
udp_connect(net_protocol * protocol,const struct sockaddr * address)1176 udp_connect(net_protocol *protocol, const struct sockaddr *address)
1177 {
1178 return ((UdpEndpoint *)protocol)->Connect(address);
1179 }
1180
1181
1182 status_t
udp_accept(net_protocol * protocol,struct net_socket ** _acceptedSocket)1183 udp_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
1184 {
1185 return B_NOT_SUPPORTED;
1186 }
1187
1188
1189 status_t
udp_control(net_protocol * protocol,int level,int option,void * value,size_t * _length)1190 udp_control(net_protocol *protocol, int level, int option, void *value,
1191 size_t *_length)
1192 {
1193 return protocol->next->module->control(protocol->next, level, option,
1194 value, _length);
1195 }
1196
1197
1198 status_t
udp_getsockopt(net_protocol * protocol,int level,int option,void * value,int * length)1199 udp_getsockopt(net_protocol *protocol, int level, int option, void *value,
1200 int *length)
1201 {
1202 return protocol->next->module->getsockopt(protocol->next, level, option,
1203 value, length);
1204 }
1205
1206
1207 status_t
udp_setsockopt(net_protocol * protocol,int level,int option,const void * value,int length)1208 udp_setsockopt(net_protocol *protocol, int level, int option,
1209 const void *value, int length)
1210 {
1211 return protocol->next->module->setsockopt(protocol->next, level, option,
1212 value, length);
1213 }
1214
1215
1216 status_t
udp_bind(net_protocol * protocol,const struct sockaddr * address)1217 udp_bind(net_protocol *protocol, const struct sockaddr *address)
1218 {
1219 return ((UdpEndpoint *)protocol)->Bind(address);
1220 }
1221
1222
1223 status_t
udp_unbind(net_protocol * protocol,struct sockaddr * address)1224 udp_unbind(net_protocol *protocol, struct sockaddr *address)
1225 {
1226 return ((UdpEndpoint *)protocol)->Unbind(address);
1227 }
1228
1229
1230 status_t
udp_listen(net_protocol * protocol,int count)1231 udp_listen(net_protocol *protocol, int count)
1232 {
1233 return B_NOT_SUPPORTED;
1234 }
1235
1236
1237 status_t
udp_shutdown(net_protocol * protocol,int direction)1238 udp_shutdown(net_protocol *protocol, int direction)
1239 {
1240 return B_NOT_SUPPORTED;
1241 }
1242
1243
1244 status_t
udp_send_routed_data(net_protocol * protocol,struct net_route * route,net_buffer * buffer)1245 udp_send_routed_data(net_protocol *protocol, struct net_route *route,
1246 net_buffer *buffer)
1247 {
1248 return ((UdpEndpoint *)protocol)->SendRoutedData(buffer, route);
1249 }
1250
1251
1252 status_t
udp_send_data(net_protocol * protocol,net_buffer * buffer)1253 udp_send_data(net_protocol *protocol, net_buffer *buffer)
1254 {
1255 return ((UdpEndpoint *)protocol)->SendData(buffer);
1256 }
1257
1258
1259 ssize_t
udp_send_avail(net_protocol * protocol)1260 udp_send_avail(net_protocol *protocol)
1261 {
1262 return protocol->socket->send.buffer_size;
1263 }
1264
1265
1266 status_t
udp_read_data(net_protocol * protocol,size_t numBytes,uint32 flags,net_buffer ** _buffer)1267 udp_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
1268 net_buffer **_buffer)
1269 {
1270 return ((UdpEndpoint *)protocol)->FetchData(numBytes, flags, _buffer);
1271 }
1272
1273
1274 ssize_t
udp_read_avail(net_protocol * protocol)1275 udp_read_avail(net_protocol *protocol)
1276 {
1277 return ((UdpEndpoint *)protocol)->BytesAvailable();
1278 }
1279
1280
1281 struct net_domain *
udp_get_domain(net_protocol * protocol)1282 udp_get_domain(net_protocol *protocol)
1283 {
1284 return protocol->next->module->get_domain(protocol->next);
1285 }
1286
1287
1288 size_t
udp_get_mtu(net_protocol * protocol,const struct sockaddr * address)1289 udp_get_mtu(net_protocol *protocol, const struct sockaddr *address)
1290 {
1291 return protocol->next->module->get_mtu(protocol->next, address);
1292 }
1293
1294
1295 status_t
udp_receive_data(net_buffer * buffer)1296 udp_receive_data(net_buffer *buffer)
1297 {
1298 return sUdpEndpointManager->ReceiveData(buffer);
1299 }
1300
1301
1302 status_t
udp_deliver_data(net_protocol * protocol,net_buffer * buffer)1303 udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
1304 {
1305 return ((UdpEndpoint *)protocol)->DeliverData(buffer);
1306 }
1307
1308
1309 status_t
udp_error_received(net_error error,net_buffer * buffer)1310 udp_error_received(net_error error, net_buffer* buffer)
1311 {
1312 status_t notifyError = B_OK;
1313
1314 switch (error) {
1315 case B_NET_ERROR_UNREACH_NET:
1316 notifyError = ENETUNREACH;
1317 break;
1318 case B_NET_ERROR_UNREACH_HOST:
1319 case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
1320 notifyError = EHOSTUNREACH;
1321 break;
1322 case B_NET_ERROR_UNREACH_PROTOCOL:
1323 case B_NET_ERROR_UNREACH_PORT:
1324 notifyError = ECONNREFUSED;
1325 break;
1326 case B_NET_ERROR_MESSAGE_SIZE:
1327 notifyError = EMSGSIZE;
1328 break;
1329 case B_NET_ERROR_PARAMETER_PROBLEM:
1330 notifyError = ENOPROTOOPT;
1331 break;
1332
1333 case B_NET_ERROR_QUENCH:
1334 default:
1335 // ignore them
1336 gBufferModule->free(buffer);
1337 return B_OK;
1338 }
1339
1340 ASSERT(notifyError != B_OK);
1341
1342 return sUdpEndpointManager->ReceiveError(notifyError, buffer);
1343 }
1344
1345
1346 status_t
udp_error_reply(net_protocol * protocol,net_buffer * cause,net_error error,net_error_data * errorData)1347 udp_error_reply(net_protocol *protocol, net_buffer *cause, net_error error,
1348 net_error_data *errorData)
1349 {
1350 return B_ERROR;
1351 }
1352
1353
1354 ssize_t
udp_process_ancillary_data_no_container(net_protocol * protocol,net_buffer * buffer,void * data,size_t dataSize)1355 udp_process_ancillary_data_no_container(net_protocol *protocol,
1356 net_buffer* buffer, void *data, size_t dataSize)
1357 {
1358 return protocol->next->module->process_ancillary_data_no_container(
1359 protocol, buffer, data, dataSize);
1360 }
1361
1362
1363 // #pragma mark - module interface
1364
1365
1366 static status_t
init_udp()1367 init_udp()
1368 {
1369 status_t status;
1370 TRACE_EPM("init_udp()");
1371
1372 sUdpEndpointManager = new (std::nothrow) UdpEndpointManager;
1373 if (sUdpEndpointManager == NULL)
1374 return B_NO_MEMORY;
1375
1376 status = sUdpEndpointManager->InitCheck();
1377 if (status != B_OK)
1378 goto err1;
1379
1380 status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
1381 IPPROTO_IP,
1382 "network/protocols/udp/v1",
1383 "network/protocols/ipv4/v1",
1384 NULL);
1385 if (status < B_OK)
1386 goto err1;
1387 status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
1388 IPPROTO_IP,
1389 "network/protocols/udp/v1",
1390 "network/protocols/ipv6/v1",
1391 NULL);
1392 if (status < B_OK)
1393 goto err1;
1394
1395 status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
1396 IPPROTO_UDP,
1397 "network/protocols/udp/v1",
1398 "network/protocols/ipv4/v1",
1399 NULL);
1400 if (status < B_OK)
1401 goto err1;
1402 status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM,
1403 IPPROTO_UDP,
1404 "network/protocols/udp/v1",
1405 "network/protocols/ipv6/v1",
1406 NULL);
1407 if (status < B_OK)
1408 goto err1;
1409
1410 status = gStackModule->register_domain_receiving_protocol(AF_INET,
1411 IPPROTO_UDP, "network/protocols/udp/v1");
1412 if (status < B_OK)
1413 goto err1;
1414 status = gStackModule->register_domain_receiving_protocol(AF_INET6,
1415 IPPROTO_UDP, "network/protocols/udp/v1");
1416 if (status < B_OK)
1417 goto err1;
1418
1419 add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
1420 "lists all open UDP endpoints");
1421
1422 return B_OK;
1423
1424 err1:
1425 // TODO: shouldn't unregister the protocols here?
1426 delete sUdpEndpointManager;
1427
1428 TRACE_EPM("init_udp() fails with %" B_PRIx32 " (%s)", status,
1429 strerror(status));
1430 return status;
1431 }
1432
1433
1434 static status_t
uninit_udp()1435 uninit_udp()
1436 {
1437 TRACE_EPM("uninit_udp()");
1438 remove_debugger_command("udp_endpoints",
1439 UdpEndpointManager::DumpEndpoints);
1440 delete sUdpEndpointManager;
1441 return B_OK;
1442 }
1443
1444
1445 static status_t
udp_std_ops(int32 op,...)1446 udp_std_ops(int32 op, ...)
1447 {
1448 switch (op) {
1449 case B_MODULE_INIT:
1450 return init_udp();
1451
1452 case B_MODULE_UNINIT:
1453 return uninit_udp();
1454
1455 default:
1456 return B_ERROR;
1457 }
1458 }
1459
1460
1461 net_protocol_module_info sUDPModule = {
1462 {
1463 "network/protocols/udp/v1",
1464 0,
1465 udp_std_ops
1466 },
1467 NET_PROTOCOL_ATOMIC_MESSAGES,
1468
1469 udp_init_protocol,
1470 udp_uninit_protocol,
1471 udp_open,
1472 udp_close,
1473 udp_free,
1474 udp_connect,
1475 udp_accept,
1476 udp_control,
1477 udp_getsockopt,
1478 udp_setsockopt,
1479 udp_bind,
1480 udp_unbind,
1481 udp_listen,
1482 udp_shutdown,
1483 udp_send_data,
1484 udp_send_routed_data,
1485 udp_send_avail,
1486 udp_read_data,
1487 udp_read_avail,
1488 udp_get_domain,
1489 udp_get_mtu,
1490 udp_receive_data,
1491 udp_deliver_data,
1492 udp_error_received,
1493 udp_error_reply,
1494 NULL, // add_ancillary_data()
1495 NULL, // process_ancillary_data()
1496 udp_process_ancillary_data_no_container,
1497 NULL, // send_data_no_buffer()
1498 NULL // read_data_no_buffer()
1499 };
1500
1501 module_dependency module_dependencies[] = {
1502 {NET_STACK_MODULE_NAME, (module_info **)&gStackModule},
1503 {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
1504 {NET_DATALINK_MODULE_NAME, (module_info **)&gDatalinkModule},
1505 {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule},
1506 {}
1507 };
1508
1509 module_info *modules[] = {
1510 (module_info *)&sUDPModule,
1511 NULL
1512 };
1513