Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4710 → Rev 4711

/branches/network/uspace/srv/net/il/ip/ip.c
53,7 → 53,7
 
#include "../../include/net_interface.h"
#include "../../include/inet.h"
#include "../../include/socket.h"
#include "../../include/socket_codes.h"
#include "../../include/byteorder.h"
#include "../../include/crc.h"
#include "../../include/device.h"
131,11 → 131,6
*/
#define IP_HEADER_CHECKSUM( header ) ( htons( ip_checksum(( uint8_t * )( header ), IP_HEADER_LENGTH( header ))))
 
/** IP header checksum value for computed zero checksum.
* Zero is returned as 0xFFFF (not flipped)
*/
#define IP_HEADER_CHECKSUM_ZERO 0xFFFFu
 
/** IP global data.
*/
ip_globals_t ip_globals;
210,32 → 205,12
in_addr_t ip_get_destination( ip_header_ref header );
int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error );
 
/** Computes the ip header checksum.
* To compute the checksum of a new packet, the checksum header field must be zero.
* To check the checksum of a received packet, the checksum may be left set.
* The zero (0) value will returned in this case if valid.
* @param data The header data. Input parameter.
* @param length The header length in bytes. Input parameter.
* @returns The internet protocol header checksum.
* @returns 0xFFFF if the computed checksum is zero.
*/
uint16_t ip_checksum( uint8_t * data, size_t length );
 
int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header );
int ip_get_icmp_phone( void );
int ip_prepare_icmp( packet_t packet, ip_header_ref header );
 
static int release_and_return( packet_t packet, int result );
int ip_release_and_return( packet_t packet, int result );
 
uint16_t ip_checksum( uint8_t * data, size_t length ){
uint16_t checksum;
 
checksum = compact_checksum(compute_checksum( 0, data, length ));
 
// flip, zero is returned as 0xFFFF (not flipped)
return ( ~ checksum ) ? ( uint16_t ) ( ~ checksum ) : IP_HEADER_CHECKSUM_ZERO;
}
 
int ip_initialize( async_client_conn_t client_connection ){
ERROR_DECLARE;
 
541,11 → 516,11
// should be the next hop address or the target destination address
length = packet_get_addr( packet, NULL, ( uint8_t ** ) & dest );
if( length < 0 ){
return release_and_return( packet, length );
return ip_release_and_return( packet, length );
}
// TODO IPv6
if( length != IP_ADDR ){
return release_and_return( packet, EINVAL );
return ip_release_and_return( packet, EINVAL );
}
fibril_rwlock_read_lock( & ip_globals.netifs_lock );
// device specified?
572,7 → 547,7
|| ( !( ~ dest->s_addr ))
|| ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr )))
|| ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){
return release_and_return( packet, EINVAL );
return ip_release_and_return( packet, EINVAL );
}
}
// to me?
585,7 → 560,7
src = ip_netif_address( netif );
if( ! src ){
fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
return release_and_return( packet, ENOENT );
return ip_release_and_return( packet, ENOENT );
}
if( ERROR_OCCURRED( ip_send_route( packet, netif, route, src, * dest, error ))){
pq_release( ip_globals.net_phone, packet_get_id( packet ));
926,18 → 901,18
// allocate as much as originally
last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
if( ! last_header ){
return release_and_return( packet, ENOMEM );
return ip_release_and_return( packet, ENOMEM );
}
ip_create_last_header( last_header, header );
// trim the unused space
if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
return release_and_return( packet, ERROR_CODE );
return ip_release_and_return( packet, ERROR_CODE );
}
// biggest multiple of 8 lower than content
// TODO even fragmentation?
length = length & ( ~ 0x7 );// ( content / 8 ) * 8
if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, last_header, (( IP_TOTAL_LENGTH( header ) - length ) % ( length - IP_HEADER_LENGTH( last_header ))), src, dest, address_length ))){
return release_and_return( packet, ERROR_CODE );
return ip_release_and_return( packet, ERROR_CODE );
}
// mark the first as fragmented
header->flags |= IPFLAG_MORE_FRAGMENTS;
947,10 → 922,10
if( ! new_packet ) return ENOMEM;
middle_header = ip_create_middle_header( new_packet, last_header );
if( ! middle_header ){
return release_and_return( packet, ENOMEM );
return ip_release_and_return( packet, ENOMEM );
}
if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, length - IP_HEADER_LENGTH( middle_header ), src, dest, address_length ))){
return release_and_return( packet, ERROR_CODE );
return ip_release_and_return( packet, ERROR_CODE );
}
}
// finish the first fragment
1041,12 → 1016,12
 
header = ( ip_header_ref ) packet_get_data( packet );
if( ! header ){
return release_and_return( packet, ENOMEM );
return ip_release_and_return( packet, ENOMEM );
}
// checksum
if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
// TODO checksum error ICMP?
return release_and_return( packet, EINVAL );
return ip_release_and_return( packet, EINVAL );
}
if( header->ttl <= 1 ){
phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1101,7 → 1076,7
case SERVICE_ICMP:
offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
if( offset < 0 ){
return release_and_return( packet, ENOMEM );
return ip_release_and_return( packet, ENOMEM );
}
data = packet_get_data( packet );
header = ( ip_header_ref ) data + offset;
1123,7 → 1098,7
}
break;
default:
return release_and_return( packet, ENOTSUP );
return ip_release_and_return( packet, ENOTSUP );
}
return ip_deliver_local( device_id, packet, header, error );
}
1204,12 → 1179,12
 
phone = ip_get_icmp_phone();
if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){
return release_and_return( packet, EINVAL );
return ip_release_and_return( packet, EINVAL );
}
return phone;
}
 
static int release_and_return( packet_t packet, int result ){
int ip_release_and_return( packet_t packet, int result ){
pq_release( ip_globals.net_phone, packet_get_id( packet ));
return result;
}