2 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
7 #include <boot/net/UDP.h>
11 #include <KernelExport.h>
13 #include <boot/net/ChainBuffer.h>
14 #include <boot/net/NetStack.h>
19 # define TRACE(x) dprintf x
28 // #pragma mark - UDPPacket
31 UDPPacket::UDPPacket()
40 UDPPacket::~UDPPacket()
47 UDPPacket::SetTo(const void *data
, size_t size
, ip_addr_t sourceAddress
,
48 uint16 sourcePort
, ip_addr_t destinationAddress
, uint16 destinationPort
)
57 memcpy(fData
, data
, size
);
60 fSourceAddress
= sourceAddress
;
61 fDestinationAddress
= destinationAddress
;
62 fSourcePort
= sourcePort
;
63 fDestinationPort
= destinationPort
;
70 UDPPacket::Next() const
77 UDPPacket::SetNext(UDPPacket
*next
)
84 UDPPacket::Data() const
91 UDPPacket::DataSize() const
98 UDPPacket::SourceAddress() const
100 return fSourceAddress
;
105 UDPPacket::SourcePort() const
112 UDPPacket::DestinationAddress() const
114 return fDestinationAddress
;
119 UDPPacket::DestinationPort() const
121 return fDestinationPort
;
125 // #pragma mark - UDPSocket
128 UDPSocket::UDPSocket()
130 fUDPService(NetStack::Default()->GetUDPService()),
133 fAddress(INADDR_ANY
),
139 UDPSocket::~UDPSocket()
141 if (fPort
!= 0 && fUDPService
!= NULL
)
142 fUDPService
->UnbindSocket(this);
147 UDPSocket::Bind(ip_addr_t address
, uint16 port
)
149 if (fUDPService
== NULL
) {
150 printf("UDPSocket::Bind(): no UDP service\n");
154 if (address
== INADDR_BROADCAST
|| port
== 0) {
155 printf("UDPSocket::Bind(): broadcast IP or port 0\n");
160 printf("UDPSocket::Bind(): already bound\n");
165 status_t error
= fUDPService
->BindSocket(this, address
, port
);
167 printf("UDPSocket::Bind(): service BindSocket() failed\n");
182 // This will lead to subsequent methods returning B_NO_INIT
188 UDPSocket::Send(ip_addr_t destinationAddress
, uint16 destinationPort
,
191 if (fUDPService
== NULL
)
194 return fUDPService
->Send(fPort
, destinationAddress
, destinationPort
,
200 UDPSocket::Send(ip_addr_t destinationAddress
, uint16 destinationPort
,
201 const void *data
, size_t size
)
206 ChainBuffer
buffer((void*)data
, size
);
207 return Send(destinationAddress
, destinationPort
, &buffer
);
212 UDPSocket::Receive(UDPPacket
**_packet
, bigtime_t timeout
)
214 if (fUDPService
== NULL
)
220 bigtime_t startTime
= system_time();
222 fUDPService
->ProcessIncomingPackets();
223 *_packet
= PopPacket();
224 if (*_packet
!= NULL
)
227 if (system_time() - startTime
> timeout
)
228 return (timeout
== 0 ? B_WOULD_BLOCK
: B_TIMED_OUT
);
234 UDPSocket::PushPacket(UDPPacket
*packet
)
236 if (fLastPacket
!= NULL
)
237 fLastPacket
->SetNext(packet
);
239 fFirstPacket
= packet
;
241 fLastPacket
= packet
;
242 packet
->SetNext(NULL
);
247 UDPSocket::PopPacket()
249 if (fFirstPacket
== NULL
)
252 UDPPacket
*packet
= fFirstPacket
;
253 fFirstPacket
= packet
->Next();
255 if (fFirstPacket
== NULL
)
258 packet
->SetNext(NULL
);
263 // #pragma mark - UDPService
266 UDPService::UDPService(IPService
*ipService
)
268 IPSubService(kUDPServiceName
),
269 fIPService(ipService
)
274 UDPService::~UDPService()
276 int count
= fSockets
.Count();
277 for (int i
= 0; i
< count
; i
++) {
278 UDPSocket
*socket
= fSockets
.ElementAt(i
);
282 if (fIPService
!= NULL
)
283 fIPService
->UnregisterIPSubService(this);
290 if (fIPService
== NULL
)
292 if (!fIPService
->RegisterIPSubService(this))
299 UDPService::IPProtocol() const
306 UDPService::HandleIPPacket(IPService
*ipService
, ip_addr_t sourceIP
,
307 ip_addr_t destinationIP
, const void *data
, size_t size
)
309 TRACE(("UDPService::HandleIPPacket(): source: %08lx, destination: %08lx, "
310 "%lu - %lu bytes\n", sourceIP
, destinationIP
, size
,
311 sizeof(udp_header
)));
313 if (data
== NULL
|| size
< sizeof(udp_header
))
316 const udp_header
*header
= (const udp_header
*)data
;
317 uint16 source
= ntohs(header
->source
);
318 uint16 destination
= ntohs(header
->destination
);
319 uint16 length
= ntohs(header
->length
);
322 if (length
< sizeof(udp_header
) || length
> size
323 || (header
->checksum
!= 0 // 0 => checksum disabled
324 && _ChecksumData(data
, length
, sourceIP
, destinationIP
) != 0)) {
325 TRACE(("UDPService::HandleIPPacket(): dropping packet -- invalid size "
330 // find the target socket
331 UDPSocket
*socket
= _FindSocket(destinationIP
, destination
);
335 // create a UDPPacket and queue it in the socket
336 UDPPacket
*packet
= new(nothrow
) UDPPacket
;
339 status_t error
= packet
->SetTo((uint8
*)data
+ sizeof(udp_header
),
340 length
- sizeof(udp_header
), sourceIP
, source
, destinationIP
,
343 socket
->PushPacket(packet
);
350 UDPService::Send(uint16 sourcePort
, ip_addr_t destinationAddress
,
351 uint16 destinationPort
, ChainBuffer
*buffer
)
353 TRACE(("UDPService::Send(source port: %hu, to: %08lx:%hu, %lu bytes)\n",
354 sourcePort
, destinationAddress
, destinationPort
,
355 (buffer
!= NULL
? buffer
->TotalSize() : 0)));
357 if (fIPService
== NULL
)
363 // prepend the UDP header
365 ChainBuffer
headerBuffer(&header
, sizeof(header
), buffer
);
366 header
.source
= htons(sourcePort
);
367 header
.destination
= htons(destinationPort
);
368 header
.length
= htons(headerBuffer
.TotalSize());
370 // compute the checksum
372 header
.checksum
= htons(_ChecksumBuffer(&headerBuffer
,
373 fIPService
->IPAddress(), destinationAddress
,
374 headerBuffer
.TotalSize()));
375 // 0 means checksum disabled; 0xffff is equivalent in this case
376 if (header
.checksum
== 0)
377 header
.checksum
= 0xffff;
379 return fIPService
->Send(destinationAddress
, IPPROTO_UDP
, &headerBuffer
);
384 UDPService::ProcessIncomingPackets()
386 if (fIPService
!= NULL
)
387 fIPService
->ProcessIncomingPackets();
392 UDPService::BindSocket(UDPSocket
*socket
, ip_addr_t address
, uint16 port
)
397 if (_FindSocket(address
, port
) != NULL
) {
398 printf("UDPService::BindSocket(): address in use\n");
402 return fSockets
.Add(socket
);
407 UDPService::UnbindSocket(UDPSocket
*socket
)
409 fSockets
.Remove(socket
);
414 UDPService::_ChecksumBuffer(ChainBuffer
*buffer
, ip_addr_t source
,
415 ip_addr_t destination
, uint16 length
)
417 // The checksum is calculated over a pseudo-header plus the UDP packet.
418 // So we temporarily prepend the pseudo-header.
419 struct pseudo_header
{
421 ip_addr_t destination
;
425 } __attribute__ ((__packed__
));
426 pseudo_header header
= {
434 ChainBuffer
headerBuffer(&header
, sizeof(header
), buffer
);
435 uint16 checksum
= ip_checksum(&headerBuffer
);
436 headerBuffer
.DetachNext();
442 UDPService::_ChecksumData(const void *data
, uint16 length
, ip_addr_t source
,
443 ip_addr_t destination
)
445 ChainBuffer
buffer((void*)data
, length
);
446 return _ChecksumBuffer(&buffer
, source
, destination
, length
);
451 UDPService::_FindSocket(ip_addr_t address
, uint16 port
)
453 int count
= fSockets
.Count();
454 for (int i
= 0; i
< count
; i
++) {
455 UDPSocket
*socket
= fSockets
.ElementAt(i
);
456 if ((address
== INADDR_ANY
|| socket
->Address() == INADDR_ANY
457 || socket
->Address() == address
)
458 && port
== socket
->Port()) {