76,6 → 76,10 |
*/ |
#define NET_DEFAULT_UDP_CHECKSUM_COMPUTING true |
|
/** Default UDP autobind when sending via unbound sockets. |
*/ |
#define NET_DEFAULT_UDP_AUTOBINDING true |
|
/** Maximum UDP fragment size. |
*/ |
#define MAX_UDP_FRAGMENT_SIZE 65535 |
90,13 → 94,22 |
|
/** Processes the received UDP packet queue. |
* Is used as an entry point from the underlying IP module. |
* Notifies the destination socket application. |
* Releases the packet on error or send an ICMP error notification.. |
* Locks the global lock and calls udp_process_packet() function. |
* @param device_id The device identifier. Ignored parameter. |
* @param packet The received packet queue. Input/output parameter. |
* @param receiver The target service. Ignored parameter. |
* @param error The packet error reporting service. Prefixes the received packet. Input parameter. |
* @returns EOK on success. |
* @returns Other error codes as defined for the udp_process_packet() function. |
*/ |
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ); |
|
/** Processes the received UDP packet queue. |
* Notifies the destination socket application. |
* Releases the packet on error or sends an ICMP error notification.. |
* @param packet The received packet queue. Input/output parameter. |
* @param error The packet error reporting service. Prefixes the received packet. Input parameter. |
* @returns EOK on success. |
* @returns EINVAL if the packet is not valid. |
* @returns EINVAL if the stored packet address is not the an_addr_t. |
* @returns EINVAL if the packet does not contain any data. |
105,7 → 118,7 |
* @returns EADDRNOTAVAIL if the destination socket does not exist. |
* @returns Other error codes as defined for the ip_client_process_packet() function. |
*/ |
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ); |
int udp_process_packet( packet_t packet, services_t error ); |
|
/** Releases the packet and returns the result. |
* @param packet The packet queue to be released. Input parameter. |
176,7 → 189,7 |
int udp_initialize( async_client_conn_t client_connection ){ |
ERROR_DECLARE; |
|
measured_string_t names[] = {{ "UDP_CHECKSUM_COMPUTING", 22 }}; |
measured_string_t names[] = {{ "UDP_CHECKSUM_COMPUTING", 22 }, { "UDP_AUTOBINDING", 15 }}; |
measured_string_ref configuration; |
size_t count = sizeof( names ) / sizeof( measured_string_t ); |
char * data; |
198,6 → 211,7 |
udp_globals.last_used_port = UDP_FREE_PORTS_START - 1; |
// get configuration |
udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING; |
udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING; |
configuration = & names[ 0 ]; |
ERROR_PROPAGATE( net_get_conf_req( udp_globals.net_phone, & configuration, count, & data )); |
if( configuration ){ |
204,6 → 218,9 |
if( configuration[ 0 ].value ){ |
udp_globals.checksum_computing = ( configuration[ 0 ].value[ 0 ] == 'y' ); |
} |
if( configuration[ 1 ].value ){ |
udp_globals.autobinding = ( configuration[ 1 ].value[ 0 ] == 'y' ); |
} |
net_free_settings( configuration, data ); |
} |
fibril_rwlock_write_unlock( & udp_globals.lock ); |
211,6 → 228,16 |
} |
|
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){ |
int result; |
|
fibril_rwlock_read_lock( & udp_globals.lock ); |
result = udp_process_packet( packet, error ); |
fibril_rwlock_read_unlock( & udp_globals.lock ); |
|
return result; |
} |
|
int udp_process_packet( packet_t packet, services_t error ){ |
ERROR_DECLARE; |
|
size_t length; |
276,8 → 303,10 |
tl_send_icmp_port_unreachable( udp_globals.net_phone, udp_globals.icmp_phone, packet, error ); |
return EADDRNOTAVAIL; |
} |
|
// trim after successful processing to be able to send an ICMP error message! |
ERROR_PROPAGATE( packet_trim( packet, offset, 0 )); |
|
// count the received packet fragments |
next_packet = packet; |
fragments = 0; |
299,6 → 328,7 |
header->checksum = 0; |
checksum = 0; |
} |
|
do{ |
++ fragments; |
length = packet_get_data_length( next_packet ); |
329,6 → 359,7 |
checksum = compute_checksum( checksum, packet_get_data( packet ), packet_get_data_length( packet )); |
} |
}while(( next_packet = pq_next( next_packet )) && ( total_length > 0 )); |
|
// check checksum |
if( header->checksum ){ |
if( flip_checksum( compact_checksum( checksum ))){ |
338,6 → 369,7 |
return udp_release_and_return( packet, EINVAL ); |
} |
} |
|
// queue the received packet |
if( ERROR_OCCURRED( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))){ |
return udp_release_and_return( packet, ERROR_CODE ); |
356,11 → 388,9 |
* answer_count = 0; |
switch( IPC_GET_METHOD( * call )){ |
case NET_TL_RECEIVED: |
fibril_rwlock_read_lock( & udp_globals.lock ); |
if( ! ERROR_OCCURRED( packet_translate( udp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){ |
ERROR_CODE = udp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_UDP, IPC_GET_ERROR( call )); |
} |
fibril_rwlock_read_unlock( & udp_globals.lock ); |
return ERROR_CODE; |
case IPC_M_CONNECT_TO_ME: |
return udp_process_client_messages( callid, * call ); |
491,18 → 521,22 |
socket = socket_cores_find( local_sockets, socket_id ); |
if( ! socket ) return ENOTSOCK; |
|
// bind the socket to a random free port if not bound |
while( socket->port <= 0 ){ |
// try to find a free port |
fibril_rwlock_read_unlock( & udp_globals.lock ); |
fibril_rwlock_write_lock( & udp_globals.lock ); |
if( socket->port <= 0 ){ |
ERROR_PROPAGATE( socket_bind_free_port( & udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port )); |
// set the next port as the search starting port number |
udp_globals.last_used_port = socket->port; |
} |
fibril_rwlock_write_unlock( & udp_globals.lock ); |
fibril_rwlock_read_lock( & udp_globals.lock ); |
if(( socket->port <= 0 ) && udp_globals.autobinding ){ |
// bind the socket to a random free port if not bound |
do{ |
// try to find a free port |
fibril_rwlock_read_unlock( & udp_globals.lock ); |
fibril_rwlock_write_lock( & udp_globals.lock ); |
// might be changed in the meantime |
if( socket->port <= 0 ){ |
ERROR_PROPAGATE( socket_bind_free_port( & udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port )); |
// set the next port as the search starting port number |
udp_globals.last_used_port = socket->port; |
} |
fibril_rwlock_write_unlock( & udp_globals.lock ); |
fibril_rwlock_read_lock( & udp_globals.lock ); |
// might be changed in the meantime |
}while( socket->port <= 0 ); |
} |
|
// TODO do not ask all the time |
536,9 → 570,9 |
} |
} |
// set the udp header |
header->source_port = htons( socket->port ); |
header->source_port = htons(( socket->port > 0 ) ? socket->port : 0 ); |
header->destination_port = htons( dest_port ); |
header->total_length = htons( total_length + sizeof( udp_header_t )); |
header->total_length = htons( total_length + sizeof( * header )); |
header->checksum = 0; |
if( udp_globals.checksum_computing ){ |
if( ERROR_OCCURRED( ip_get_route_req( udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, & device_id, & ip_header, & headerlen ))){ |