source: mainline/uspace/srv/net/tl/udp/udp.c@ 918e9910

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 918e9910 was 918e9910, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago
  • zero IP checksum flip fix
  • Property mode set to 100644
File size: 25.1 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup udp
30 * @{
31 */
32
33/** @file
34 * UDP module implementation.
35 * @see udp.h
36 */
37
38#include <async.h>
39#include <fibril_synch.h>
40#include <malloc.h>
41#include <stdio.h>
42
43#include <ipc/ipc.h>
44#include <ipc/services.h>
45
46#include "../../err.h"
47#include "../../messages.h"
48#include "../../modules.h"
49
50#include "../../structures/dynamic_fifo.h"
51#include "../../structures/packet/packet_client.h"
52
53#include "../../include/checksum.h"
54#include "../../include/in.h"
55#include "../../include/in6.h"
56#include "../../include/inet.h"
57#include "../../include/ip_client.h"
58#include "../../include/ip_interface.h"
59#include "../../include/ip_protocols.h"
60#include "../../include/icmp_client.h"
61#include "../../include/icmp_interface.h"
62#include "../../include/net_interface.h"
63#include "../../include/socket_codes.h"
64#include "../../include/socket_errno.h"
65
66#include "../../socket/socket_core.h"
67#include "../../socket/socket_messages.h"
68
69#include "../tl_common.h"
70#include "../tl_messages.h"
71
72#include "udp.h"
73#include "udp_header.h"
74#include "udp_module.h"
75
76/** Default UDP checksum computing.
77 */
78#define NET_DEFAULT_UDP_CHECKSUM_COMPUTING true
79
80/** Default UDP autobind when sending via unbound sockets.
81 */
82#define NET_DEFAULT_UDP_AUTOBINDING true
83
84/** Maximum UDP fragment size.
85 */
86#define MAX_UDP_FRAGMENT_SIZE 65535
87
88/** Free ports pool start.
89 */
90#define UDP_FREE_PORTS_START 1025
91
92/** Free ports pool end.
93 */
94#define UDP_FREE_PORTS_END 65535
95
96/** Processes the received UDP packet queue.
97 * Is used as an entry point from the underlying IP module.
98 * Locks the global lock and calls udp_process_packet() function.
[ede63e4]99 * @param[in] device_id The receiving device identifier.
[21580dd]100 * @param[in,out] packet The received packet queue.
101 * @param receiver The target service. Ignored parameter.
102 * @param[in] error The packet error reporting service. Prefixes the received packet.
103 * @returns EOK on success.
104 * @returns Other error codes as defined for the udp_process_packet() function.
105 */
106int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
107
108/** Processes the received UDP packet queue.
109 * Notifies the destination socket application.
110 * Releases the packet on error or sends an ICMP error notification..
[ede63e4]111 * @param[in] device_id The receiving device identifier.
[21580dd]112 * @param[in,out] packet The received packet queue.
113 * @param[in] error The packet error reporting service. Prefixes the received packet.
114 * @returns EOK on success.
115 * @returns EINVAL if the packet is not valid.
116 * @returns EINVAL if the stored packet address is not the an_addr_t.
117 * @returns EINVAL if the packet does not contain any data.
118 * @returns NO_DATA if the packet content is shorter than the user datagram header.
119 * @returns ENOMEM if there is not enough memory left.
120 * @returns EADDRNOTAVAIL if the destination socket does not exist.
121 * @returns Other error codes as defined for the ip_client_process_packet() function.
122 */
[ede63e4]123int udp_process_packet( device_id_t device_id, packet_t packet, services_t error );
[21580dd]124
125/** Releases the packet and returns the result.
126 * @param[in] packet The packet queue to be released.
127 * @param[in] result The result to be returned.
128 * @return The result parameter.
129 */
130int udp_release_and_return( packet_t packet, int result );
131
132/** @name Socket messages processing functions
133 */
134/*@{*/
135
136/** Processes the socket client messages.
137 * Runs until the client module disconnects.
138 * @param[in] callid The message identifier.
139 * @param[in] call The message parameters.
140 * @returns EOK on success.
141 * @see socket.h
142 */
143int udp_process_client_messages( ipc_callid_t callid, ipc_call_t call );
144
145/** Sends data from the socket to the remote address.
146 * Binds the socket to a free port if not already connected/bound.
147 * Handles the NET_SOCKET_SENDTO message.
148 * Supports AF_INET and AF_INET6 address families.
149 * @param[in,out] local_sockets The application local sockets.
150 * @param[in] socket_id Socket identifier.
151 * @param[in] addr The destination address.
152 * @param[in] addrlen The address length.
153 * @param[in] fragments The number of data fragments.
[ede63e4]154 * @param[out] data_fragment_size The data fragment size in bytes.
[21580dd]155 * @param[in] flags Various send flags.
156 * @returns EOK on success.
157 * @returns EAFNOTSUPPORT if the address family is not supported.
158 * @returns ENOTSOCK if the socket is not found.
159 * @returns EINVAL if the address is invalid.
160 * @returns ENOTCONN if the sending socket is not and cannot be bound.
161 * @returns ENOMEM if there is not enough memory left.
162 * @returns Other error codes as defined for the socket_read_packet_data() function.
163 * @returns Other error codes as defined for the ip_client_prepare_packet() function.
164 * @returns Other error codes as defined for the ip_send_msg() function.
165 */
[ede63e4]166int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags );
[21580dd]167
168/** Receives data to the socket.
169 * Handles the NET_SOCKET_RECVFROM message.
170 * Replies the source address as well.
171 * @param[in] local_sockets The application local sockets.
172 * @param[in] socket_id Socket identifier.
173 * @param[in] flags Various receive flags.
174 * @param[out] addrlen The source address length.
175 * @returns The number of bytes received.
176 * @returns ENOTSOCK if the socket is not found.
177 * @returns NO_DATA if there are no received packets or data.
178 * @returns ENOMEM if there is not enough memory left.
179 * @returns EINVAL if the received address is not an IP address.
180 * @returns Other error codes as defined for the packet_translate() function.
181 * @returns Other error codes as defined for the data_reply() function.
182 */
183int udp_recvfrom_message( socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen );
184
185/*@}*/
186
187/** UDP global data.
188 */
189udp_globals_t udp_globals;
190
191int udp_initialize( async_client_conn_t client_connection ){
192 ERROR_DECLARE;
193
194 measured_string_t names[] = {{ "UDP_CHECKSUM_COMPUTING", 22 }, { "UDP_AUTOBINDING", 15 }};
195 measured_string_ref configuration;
196 size_t count = sizeof( names ) / sizeof( measured_string_t );
197 char * data;
198
199 fibril_rwlock_initialize( & udp_globals.lock );
200 fibril_rwlock_write_lock( & udp_globals.lock );
[1a0fb3f8]201 udp_globals.icmp_phone = icmp_connect_module( SERVICE_ICMP, ICMP_CONNECT_TIMEOUT );
[21580dd]202 udp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg );
203 if( udp_globals.ip_phone < 0 ){
204 return udp_globals.ip_phone;
205 }
206 // read default packet dimensions
207 ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.packet_dimension.addr_len, & udp_globals.packet_dimension.prefix, & udp_globals.packet_dimension.content, & udp_globals.packet_dimension.suffix ));
208 ERROR_PROPAGATE( socket_ports_initialize( & udp_globals.sockets ));
209 if( ERROR_OCCURRED( packet_dimensions_initialize( & udp_globals.dimensions ))){
210 socket_ports_destroy( & udp_globals.sockets );
211 return ERROR_CODE;
212 }
213 udp_globals.packet_dimension.prefix += sizeof( udp_header_t );
214 udp_globals.packet_dimension.content -= sizeof( udp_header_t );
215 udp_globals.last_used_port = UDP_FREE_PORTS_START - 1;
216 // get configuration
217 udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING;
218 udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING;
219 configuration = & names[ 0 ];
220 ERROR_PROPAGATE( net_get_conf_req( udp_globals.net_phone, & configuration, count, & data ));
221 if( configuration ){
222 if( configuration[ 0 ].value ){
223 udp_globals.checksum_computing = ( configuration[ 0 ].value[ 0 ] == 'y' );
224 }
225 if( configuration[ 1 ].value ){
226 udp_globals.autobinding = ( configuration[ 1 ].value[ 0 ] == 'y' );
227 }
228 net_free_settings( configuration, data );
229 }
230 fibril_rwlock_write_unlock( & udp_globals.lock );
231 return EOK;
232}
233
234int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
235 int result;
236
237 fibril_rwlock_write_lock( & udp_globals.lock );
[ede63e4]238 result = udp_process_packet( device_id, packet, error );
[21580dd]239 if( result != EOK ){
240 fibril_rwlock_write_unlock( & udp_globals.lock );
241 }
242
243 return result;
244}
245
[ede63e4]246int udp_process_packet( device_id_t device_id, packet_t packet, services_t error ){
[21580dd]247 ERROR_DECLARE;
248
249 size_t length;
250 size_t offset;
251 int result;
252 udp_header_ref header;
253 socket_core_ref socket;
254 packet_t next_packet;
255 size_t total_length;
256 uint32_t checksum;
257 int fragments;
258 packet_t tmp_packet;
259 icmp_type_t type;
260 icmp_code_t code;
261 ip_pseudo_header_ref ip_header;
262 struct sockaddr * src;
263 struct sockaddr * dest;
[ede63e4]264 packet_dimension_ref packet_dimension;
[21580dd]265
266 if( error ){
267 switch( error ){
268 case SERVICE_ICMP:
269 // ignore error
270 // length = icmp_client_header_length( packet );
271 // process error
272 result = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
273 if( result < 0 ){
274 return udp_release_and_return( packet, result );
275 }
276 length = ( size_t ) result;
277 if( ERROR_OCCURRED( packet_trim( packet, length, 0 ))){
278 return udp_release_and_return( packet, ERROR_CODE );
279 }
280 break;
281 default:
282 return udp_release_and_return( packet, ENOTSUP );
283 }
284 }
285 // TODO process received ipopts?
286 result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
287 if( result < 0 ){
288 return udp_release_and_return( packet, result );
289 }
290 offset = ( size_t ) result;
291
292 length = packet_get_data_length( packet );
293 if( length <= 0 ){
294 return udp_release_and_return( packet, EINVAL );
295 }
[ede63e4]296 if( length < UDP_HEADER_SIZE + offset ){
[21580dd]297 return udp_release_and_return( packet, NO_DATA );
298 }
299
300 // trim all but UDP header
301 if( ERROR_OCCURRED( packet_trim( packet, offset, 0 ))){
302 return udp_release_and_return( packet, ERROR_CODE );
303 }
304
305 // get udp header
306 header = ( udp_header_ref ) packet_get_data( packet );
307 if( ! header ){
308 return udp_release_and_return( packet, NO_DATA );
309 }
310 // find the destination socket
311 socket = socket_port_find( & udp_globals.sockets, ntohs( header->destination_port ), SOCKET_MAP_KEY_LISTENING, 0 );
312 if( ! socket ){
313 if( tl_prepare_icmp_packet( udp_globals.net_phone, udp_globals.icmp_phone, packet, error ) == EOK ){
314 icmp_destination_unreachable_msg( udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet );
315 }
316 return EADDRNOTAVAIL;
317 }
318
319 // count the received packet fragments
320 next_packet = packet;
321 fragments = 0;
322 total_length = ntohs( header->total_length );
323 // compute header checksum if set
324 if( header->checksum && ( ! error )){
325 result = packet_get_addr( packet, ( uint8_t ** ) & src, ( uint8_t ** ) & dest );
326 if( result <= 0 ){
327 return udp_release_and_return( packet, result );
328 }
329 if( ERROR_OCCURRED( ip_client_get_pseudo_header( IPPROTO_UDP, src, result, dest, result, total_length, & ip_header, & length ))){
330 return udp_release_and_return( packet, ERROR_CODE );
331 }else{
332 checksum = compute_checksum( 0, ip_header, length );
333 // the udp header checksum will be added with the first fragment later
334 free( ip_header );
335 }
336 }else{
337 header->checksum = 0;
338 checksum = 0;
339 }
340
341 do{
342 ++ fragments;
343 length = packet_get_data_length( next_packet );
344 if( length <= 0 ){
345 return udp_release_and_return( packet, NO_DATA );
346 }
347 if( total_length < length ){
348 if( ERROR_OCCURRED( packet_trim( next_packet, 0, length - total_length ))){
349 return udp_release_and_return( packet, ERROR_CODE );
350 }
351 // add partial checksum if set
352 if( header->checksum ){
353 checksum = compute_checksum( checksum, packet_get_data( packet ), packet_get_data_length( packet ));
354 }
355 // relese the rest of the packet fragments
356 tmp_packet = pq_next( next_packet );
357 while( tmp_packet ){
358 next_packet = pq_detach( tmp_packet );
359 pq_release( udp_globals.net_phone, packet_get_id( tmp_packet ));
360 tmp_packet = next_packet;
361 }
362 // exit the loop
363 break;
364 }
365 total_length -= length;
366 // add partial checksum if set
367 if( header->checksum ){
368 checksum = compute_checksum( checksum, packet_get_data( packet ), packet_get_data_length( packet ));
369 }
370 }while(( next_packet = pq_next( next_packet )) && ( total_length > 0 ));
371
372 // check checksum
373 if( header->checksum ){
[918e9910]374 if( flip_checksum( compact_checksum( checksum )) != IP_CHECKSUM_ZERO ){
[21580dd]375 if( tl_prepare_icmp_packet( udp_globals.net_phone, udp_globals.icmp_phone, packet, error ) == EOK ){
376 // checksum error ICMP
377 icmp_parameter_problem_msg( udp_globals.icmp_phone, ICMP_PARAM_POINTER, (( size_t ) (( void * ) & header->checksum )) - (( size_t ) (( void * ) header )), packet );
378 }
379 return EINVAL;
380 }
381 }
382
383 // queue the received packet
[ede63e4]384 if( ERROR_OCCURRED( dyn_fifo_push( & socket->received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))
385 || ERROR_OCCURRED( tl_get_ip_packet_dimension( udp_globals.ip_phone, & udp_globals.dimensions, device_id, & packet_dimension ))){
[21580dd]386 return udp_release_and_return( packet, ERROR_CODE );
387 }
388
389 // notify the destination socket
390 fibril_rwlock_write_unlock( & udp_globals.lock );
[ede63e4]391 async_msg_5( socket->phone, NET_SOCKET_RECEIVED, ( ipcarg_t ) socket->socket_id, packet_dimension->content, 0, 0, ( ipcarg_t ) fragments );
392/* fibril_rwlock_write_unlock( & udp_globals.lock );
[21580dd]393 async_msg_5( socket->phone, NET_SOCKET_RECEIVED, ( ipcarg_t ) socket->socket_id, 0, 0, 0, ( ipcarg_t ) fragments );
[ede63e4]394*/ return EOK;
[21580dd]395}
396
397int udp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
398 ERROR_DECLARE;
399
400 packet_t packet;
401
402 * answer_count = 0;
403 switch( IPC_GET_METHOD( * call )){
404 case NET_TL_RECEIVED:
405 if( ! ERROR_OCCURRED( packet_translate( udp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
406 ERROR_CODE = udp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_UDP, IPC_GET_ERROR( call ));
407 }
408 return ERROR_CODE;
409 case IPC_M_CONNECT_TO_ME:
410 return udp_process_client_messages( callid, * call );
411 }
412 return ENOTSUP;
413}
414
415int udp_process_client_messages( ipc_callid_t callid, ipc_call_t call ){
416 int res;
417 bool keep_on_going = true;
418 socket_cores_t local_sockets;
419 int app_phone = IPC_GET_PHONE( & call );
420 struct sockaddr * addr;
421 size_t addrlen;
422 fibril_rwlock_t lock;
423 ipc_call_t answer;
424 int answer_count;
[ede63e4]425 packet_dimension_ref packet_dimension;
[21580dd]426
427 /*
428 * Accept the connection
429 * - Answer the first IPC_M_CONNECT_TO_ME call.
430 */
431 ipc_answer_0( callid, EOK );
432
433 // The client connection is only in one fibril and therefore no additional locks are needed.
434
435 socket_cores_initialize( & local_sockets );
436 fibril_rwlock_initialize( & lock );
437
438 while( keep_on_going ){
439 // refresh data
440 refresh_answer( & answer, & answer_count );
441
442 callid = async_get_call( & call );
443// printf( "message %d\n", IPC_GET_METHOD( * call ));
444
445 switch( IPC_GET_METHOD( call )){
446 case IPC_M_PHONE_HUNGUP:
447 keep_on_going = false;
448 res = EOK;
449 break;
450 case NET_SOCKET:
451 fibril_rwlock_write_lock( & lock );
[ede63e4]452 * SOCKET_SET_SOCKET_ID( answer ) = SOCKET_GET_SOCKET_ID( call );
[21580dd]453 res = socket_create( & local_sockets, app_phone, NULL, SOCKET_SET_SOCKET_ID( answer ));
454 fibril_rwlock_write_unlock( & lock );
[ede63e4]455 if( res == EOK ){
456 if( tl_get_ip_packet_dimension( udp_globals.ip_phone, & udp_globals.dimensions, DEVICE_INVALID_ID, & packet_dimension ) == EOK ){
457 * SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = packet_dimension->content;
458 }
459// * SOCKET_SET_DATA_FRAGMENT_SIZE( answer ) = MAX_UDP_FRAGMENT_SIZE;
460 * SOCKET_SET_HEADER_SIZE( answer ) = UDP_HEADER_SIZE;
461 answer_count = 3;
462 }
[21580dd]463 break;
464 case NET_SOCKET_BIND:
465 res = data_receive(( void ** ) & addr, & addrlen );
466 if( res == EOK ){
467 fibril_rwlock_read_lock( & lock );
468 fibril_rwlock_write_lock( & udp_globals.lock );
469 res = socket_bind( & local_sockets, & udp_globals.sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port );
470 fibril_rwlock_write_unlock( & udp_globals.lock );
471 fibril_rwlock_read_unlock( & lock );
472 free( addr );
473 }
474 break;
475 case NET_SOCKET_SENDTO:
476 res = data_receive(( void ** ) & addr, & addrlen );
477 if( res == EOK ){
478 fibril_rwlock_read_lock( & lock );
479 fibril_rwlock_write_lock( & udp_globals.lock );
[ede63e4]480 res = udp_sendto_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS( call ), SOCKET_SET_DATA_FRAGMENT_SIZE( answer ), SOCKET_GET_FLAGS( call ));
[21580dd]481 if( res != EOK ){
482 fibril_rwlock_write_unlock( & udp_globals.lock );
[ede63e4]483 }else{
484 answer_count = 2;
[21580dd]485 }
486 fibril_rwlock_read_unlock( & lock );
487 free( addr );
488 }
489 break;
490 case NET_SOCKET_RECVFROM:
491 fibril_rwlock_read_lock( & lock );
492 fibril_rwlock_write_lock( & udp_globals.lock );
493 res = udp_recvfrom_message( & local_sockets, SOCKET_GET_SOCKET_ID( call ), SOCKET_GET_FLAGS( call ), & addrlen );
494 fibril_rwlock_write_unlock( & udp_globals.lock );
495 fibril_rwlock_read_unlock( & lock );
496 if( res > 0 ){
497 * SOCKET_SET_READ_DATA_LENGTH( answer ) = res;
498 * SOCKET_SET_ADDRESS_LENGTH( answer ) = addrlen;
[ede63e4]499 answer_count = 3;
[21580dd]500 res = EOK;
501 }
502 break;
503 case NET_SOCKET_CLOSE:
504 fibril_rwlock_write_lock( & lock );
505 fibril_rwlock_write_lock( & udp_globals.lock );
506 res = socket_destroy( udp_globals.net_phone, SOCKET_GET_SOCKET_ID( call ), & local_sockets, & udp_globals.sockets, NULL );
507 fibril_rwlock_write_unlock( & udp_globals.lock );
508 fibril_rwlock_write_unlock( & lock );
509 break;
510 case NET_SOCKET_GETSOCKOPT:
511 case NET_SOCKET_SETSOCKOPT:
512 default:
513 res = ENOTSUP;
514 break;
515 }
516
517// printf( "res = %d\n", res );
518
519 answer_call( callid, res, & answer, answer_count );
520 }
521
522 // release all local sockets
523 socket_cores_release( udp_globals.net_phone, & local_sockets, & udp_globals.sockets, NULL );
524
525 return EOK;
526}
527
[ede63e4]528int udp_sendto_message( socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags ){
[21580dd]529 ERROR_DECLARE;
530
531 socket_core_ref socket;
532 packet_t packet;
533 packet_t next_packet;
534 udp_header_ref header;
535 int index;
536 size_t total_length;
537 int result;
538 uint16_t dest_port;
539 uint32_t checksum;
540 ip_pseudo_header_ref ip_header;
541 size_t headerlen;
542 device_id_t device_id;
543 packet_dimension_ref packet_dimension;
544
545 ERROR_PROPAGATE( tl_get_address_port( addr, addrlen, & dest_port ));
546
547 socket = socket_cores_find( local_sockets, socket_id );
548 if( ! socket ) return ENOTSOCK;
549
550 if(( socket->port <= 0 ) && udp_globals.autobinding ){
551 // bind the socket to a random free port if not bound
552// do{
553 // try to find a free port
554// fibril_rwlock_read_unlock( & udp_globals.lock );
555// fibril_rwlock_write_lock( & udp_globals.lock );
556 // might be changed in the meantime
557// if( socket->port <= 0 ){
558 if( ERROR_OCCURRED( socket_bind_free_port( & udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port ))){
559// fibril_rwlock_write_unlock( & udp_globals.lock );
560// fibril_rwlock_read_lock( & udp_globals.lock );
561 return ERROR_CODE;
562 }
563 // set the next port as the search starting port number
564 udp_globals.last_used_port = socket->port;
565// }
566// fibril_rwlock_write_unlock( & udp_globals.lock );
567// fibril_rwlock_read_lock( & udp_globals.lock );
568 // might be changed in the meantime
569// }while( socket->port <= 0 );
570 }
571
572 if( udp_globals.checksum_computing ){
573 if( ERROR_OCCURRED( ip_get_route_req( udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, & device_id, & ip_header, & headerlen ))){
574 return udp_release_and_return( packet, ERROR_CODE );
575 }
576 // get the device packet dimension
577// ERROR_PROPAGATE( tl_get_ip_packet_dimension( udp_globals.ip_phone, & udp_globals.dimensions, device_id, & packet_dimension ));
578 }
579// }else{
580 // do not ask all the time
581 ERROR_PROPAGATE( ip_packet_size_req( udp_globals.ip_phone, -1, & udp_globals.packet_dimension.addr_len, & udp_globals.packet_dimension.prefix, & udp_globals.packet_dimension.content, & udp_globals.packet_dimension.suffix ));
582 packet_dimension = & udp_globals.packet_dimension;
583// }
584
585 // read the first packet fragment
[ede63e4]586 result = tl_socket_read_packet_data( udp_globals.net_phone, & packet, UDP_HEADER_SIZE, packet_dimension, addr, addrlen );
[21580dd]587 if( result < 0 ) return result;
588 total_length = ( size_t ) result;
589 if( udp_globals.checksum_computing ){
590 checksum = compute_checksum( 0, packet_get_data( packet ), packet_get_data_length( packet ));
591 }else{
592 checksum = 0;
593 }
594 // prefix the udp header
595 header = PACKET_PREFIX( packet, udp_header_t );
596 if( ! header ){
597 return udp_release_and_return( packet, ENOMEM );
598 }
599 bzero( header, sizeof( * header ));
600 // read the rest of the packet fragments
601 for( index = 1; index < fragments; ++ index ){
602 result = tl_socket_read_packet_data( udp_globals.net_phone, & next_packet, 0, packet_dimension, addr, addrlen );
603 if( result < 0 ){
604 return udp_release_and_return( packet, result );
605 }
606 packet = pq_add( packet, next_packet, index, 0 );
607 total_length += ( size_t ) result;
608 if( udp_globals.checksum_computing ){
609 checksum = compute_checksum( checksum, packet_get_data( next_packet ), packet_get_data_length( next_packet ));
610 }
611 }
612 // set the udp header
613 header->source_port = htons(( socket->port > 0 ) ? socket->port : 0 );
614 header->destination_port = htons( dest_port );
615 header->total_length = htons( total_length + sizeof( * header ));
616 header->checksum = 0;
617 if( udp_globals.checksum_computing ){
618// if( ERROR_OCCURRED( ip_get_route_req( udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, & device_id, & ip_header, & headerlen ))){
619// return udp_release_and_return( packet, ERROR_CODE );
620// }
[ede63e4]621 if( ERROR_OCCURRED( ip_client_set_pseudo_header_data_length( ip_header, headerlen, total_length + UDP_HEADER_SIZE))){
[21580dd]622 free( ip_header );
623 return udp_release_and_return( packet, ERROR_CODE );
624 }
625 checksum = compute_checksum( checksum, ip_header, headerlen );
626 checksum = compute_checksum( checksum, ( uint8_t * ) header, sizeof( * header ));
627 header->checksum = htons( flip_checksum( compact_checksum( checksum )));
628 free( ip_header );
629 }else{
[ede63e4]630 device_id = DEVICE_INVALID_ID;
[21580dd]631 }
632 // prepare the first packet fragment
633 if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_UDP, 0, 0, 0, 0 ))){
634 return udp_release_and_return( packet, ERROR_CODE );
635 }
636 // send the packet
637 fibril_rwlock_write_unlock( & udp_globals.lock );
638 ip_send_msg( udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0 );
639 return EOK;
640}
641
642int udp_recvfrom_message( socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen ){
643 ERROR_DECLARE;
644
645 socket_core_ref socket;
646 int packet_id;
647 packet_t packet;
648 udp_header_ref header;
649 struct sockaddr * addr;
650 size_t length;
651 uint8_t * data;
652 int result;
653
654 // find the socket
655 socket = socket_cores_find( local_sockets, socket_id );
656 if( ! socket ) return ENOTSOCK;
657 // get the next received packet
658 packet_id = dyn_fifo_value( & socket->received );
659 if( packet_id < 0 ) return NO_DATA;
660 ERROR_PROPAGATE( packet_translate( udp_globals.net_phone, & packet, packet_id ));
661 // get udp header
662 data = packet_get_data( packet );
663 if( ! data ){
664 pq_release( udp_globals.net_phone, packet_id );
665 return NO_DATA;
666 }
667 header = ( udp_header_ref ) data;
668
669 // set the source address port
670 result = packet_get_addr( packet, ( uint8_t ** ) & addr, NULL );
671 if( ERROR_OCCURRED( tl_set_address_port( addr, result, ntohs( header->source_port )))){
672 pq_release( udp_globals.net_phone, packet_id );
673 return ERROR_CODE;
674 }
675 * addrlen = ( size_t ) result;
676 // send the source address
677 ERROR_PROPAGATE( data_reply( addr, * addrlen ));
678
679 // trim the header
[ede63e4]680 ERROR_PROPAGATE( packet_trim( packet, UDP_HEADER_SIZE, 0 ));
[21580dd]681
682 // reply the packets
683 ERROR_PROPAGATE( socket_reply_packets( packet, & length ));
684
685 // release the packet
686 dyn_fifo_pop( & socket->received );
687 pq_release( udp_globals.net_phone, packet_get_id( packet ));
688 // return the total length
689 return ( int ) length;
690}
691
692int udp_release_and_return( packet_t packet, int result ){
693 pq_release( udp_globals.net_phone, packet_get_id( packet ));
694 return result;
695}
696
697/** @}
698 */
Note: See TracBrowser for help on using the repository browser.