38,7 → 38,6 |
#include <async.h> |
#include <fibril_sync.h> |
#include <malloc.h> |
#include <stdio.h> |
|
#include <ipc/ipc.h> |
#include <ipc/services.h> |
55,6 → 54,8 |
#include "../../include/ip_client.h" |
#include "../../include/ip_interface.h" |
#include "../../include/ip_protocols.h" |
#include "../../include/icmp_client.h" |
#include "../../include/icmp_interface.h" |
#include "../../include/socket.h" |
#include "../../include/socket_errno.h" |
|
79,21 → 80,15 |
*/ |
#define UDP_FREE_PORTS_END 65535 |
|
/** Processes the received UDP packet. |
/** Processes the received UDP packet queue. |
* Is used as an entry point from the underlying IP module. |
* Releases the packet on error. |
* Notifies the destination socket application. |
* Releases the packet on error or send an ICMP error notification.. |
* @param device_id The device identifier. Ignored parameter. |
* @param packet The received packet. Input/output 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 ); |
|
/** Processes the received UDP packet. |
* Notifies the destination socket application. |
* @param packet The received packet. Input/output 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. |
102,8 → 97,23 |
* @returns EADDRNOTAVAIL if the destination socket does not exist. |
* @returns Other error codes as defined for the ip_client_process_packet() function. |
*/ |
int udp_process_packet( packet_t packet ); |
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ); |
|
/** Releases the packet and returns the result. |
* @param packet The packet queue to be released. Input parameter. |
* @param result The result to be returned. Input parameter. |
* @return The result parameter. |
*/ |
static int release_and_return( packet_t packet, int result ); |
|
/** Sends the port unreachable ICMP notification. |
* Sends the first packet and releases all the others. |
* Releases the packet queu on error. |
* @param packet The packet to be send. Input parameter. |
* @param error The packet error reporting service. Prefixes the received packet. Input parameter. |
*/ |
void udp_send_icmp_port_unreachable( packet_t packet, services_t error ); |
|
/** @name Socket messages processing functions |
*/ |
/*@{*/ |
196,6 → 206,10 |
|
fibril_rwlock_initialize( & udp_globals.lock ); |
fibril_rwlock_write_lock( & udp_globals.lock ); |
udp_globals.icmp_phone = icmp_connect_module( SERVICE_ICMP ); |
if( udp_globals.icmp_phone < 0 ){ |
return udp_globals.icmp_phone; |
} |
udp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg ); |
if( udp_globals.ip_phone < 0 ){ |
return udp_globals.ip_phone; |
209,24 → 223,12 |
return EOK; |
} |
|
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver ){ |
int udp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){ |
ERROR_DECLARE; |
|
if( ERROR_OCCURRED( udp_process_packet( packet ))){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return ERROR_CODE; |
} |
|
return EOK; |
} |
|
int udp_process_packet( packet_t packet ){ |
ERROR_DECLARE; |
|
uint8_t * src; |
uint8_t * dest; |
int length; |
void * data; |
int offset; |
uint8_t * data; |
udp_header_ref header; |
socket_core_ref * socket; |
packet_t next_packet; |
234,23 → 236,55 |
// uint16_t checksum; |
int fragments; |
packet_t tmp_packet; |
icmp_type_t type; |
icmp_code_t code; |
|
// get packet data |
length = packet_get_addr( packet, & src, & dest ); |
if( length != sizeof( in_addr_t )) return EINVAL; |
if( error ){ |
switch( error ){ |
case SERVICE_ICMP: |
// process error |
// TODO remove debug dump |
// length = icmp_client_header_length( packet ); |
length = icmp_client_process_packet( packet, & type, & code, NULL, NULL ); |
if( length < 0 ){ |
return release_and_return( packet, length ); |
} |
printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) ); |
if( ERROR_OCCURRED( packet_trim( packet, length, 0 ))){ |
return release_and_return( packet, ERROR_CODE ); |
} |
break; |
default: |
return release_and_return( packet, ENOTSUP ); |
} |
} |
// TODO process received ipopts? |
ERROR_PROPAGATE( ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL )); |
offset = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL ); |
if( offset < 0 ){ |
return release_and_return( packet, offset ); |
} |
|
length = packet_get_data_length( packet ); |
if( length <= 0 ) return EINVAL; |
if( length < sizeof( udp_header_t )) return NO_DATA; |
if( length <= 0 ){ |
return release_and_return( packet, EINVAL ); |
} |
if( length < sizeof( udp_header_t ) + offset ){ |
return release_and_return( packet, NO_DATA ); |
} |
data = packet_get_data( packet ); |
if( ! data ) return NO_DATA; |
if( ! data ){ |
return release_and_return( packet, NO_DATA ); |
} |
// get udp header |
header = ( udp_header_ref ) data; |
header = ( udp_header_ref )( data + offset ); |
// find the destination socket |
socket = socket_ports_find( & udp_globals.sockets, ntohs( header->dest )); |
if( ! socket ) return EADDRNOTAVAIL; |
if( ! socket ){ |
udp_send_icmp_port_unreachable( 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; |
258,10 → 292,14 |
do{ |
++ fragments; |
length = packet_get_data_length( packet ); |
if( ! length ) return NO_DATA; |
if( ! length ){ |
return release_and_return( packet, NO_DATA ); |
} |
if( total_length < length ){ |
// cut of the suffix if too long |
ERROR_PROPAGATE( packet_trim( next_packet, 0, length - total_length )); |
if( ERROR_OCCURRED( packet_trim( next_packet, 0, length - total_length ))){ |
return release_and_return( packet, ERROR_CODE ); |
} |
// relese the rest of the packet fragments |
tmp_packet = pq_next( next_packet ); |
while( tmp_packet ){ |
277,7 → 315,9 |
*/ |
}while(( next_packet = pq_next( next_packet )) && ( total_length > 0 )); |
// queue the received packet |
ERROR_PROPAGATE( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE )); |
if( ERROR_OCCURRED( dyn_fifo_push( &( ** socket ).received, packet_get_id( packet ), SOCKET_MAX_RECEIVED_SIZE ))){ |
return release_and_return( packet, ERROR_CODE ); |
} |
|
// notify the destination socket |
async_msg_2(( ** socket ).phone, NET_SOCKET_RECEIVED, ( ** socket ).socket_id, fragments ); |
294,7 → 334,7 |
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 ); |
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; |
495,7 → 535,7 |
return ERROR_CODE; |
} |
// send the packet |
return ip_send_msg( udp_globals.ip_phone, socket->device_id, packet, SERVICE_UDP ); |
return ip_send_msg( udp_globals.ip_phone, socket->device_id, packet, SERVICE_UDP, 0 ); |
// TODO IPv6 |
default: |
return EAFNOSUPPORT; |
645,5 → 685,32 |
return length; |
} |
|
static int release_and_return( packet_t packet, int result ){ |
pq_release( udp_globals.net_phone, packet_get_id( packet )); |
return result; |
} |
|
void udp_send_icmp_port_unreachable( packet_t packet, services_t error ){ |
packet_t next; |
uint8_t * src; |
int length; |
|
// detach the first packet and release the others |
next = pq_detach( packet ); |
if( next ){ |
pq_release( udp_globals.net_phone, packet_get_id( next )); |
} |
length = packet_get_addr( packet, & src, NULL ); |
if(( length > 0 ) |
&& ( ! error ) |
&& ( udp_globals.icmp_phone >= 0 ) |
// set both addresses to the source one (avoids the source address deletion before setting the destination one) |
&& ( packet_set_addr( packet, src, src, length ) == EOK )){ |
icmp_destination_unreachable_msg( udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet ); |
}else{ |
return release_and_return( packet, EINVAL ); |
} |
} |
|
/** @} |
*/ |