53,7 → 53,7 |
|
#include "../../include/net_interface.h" |
#include "../../include/inet.h" |
#include "../../include/socket_codes.h" |
#include "../../include/socket.h" |
#include "../../include/byteorder.h" |
#include "../../include/crc.h" |
#include "../../include/device.h" |
131,6 → 131,11 |
*/ |
#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; |
205,12 → 210,32 |
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 ); |
|
int ip_release_and_return( packet_t packet, int result ); |
static int 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; |
|
516,11 → 541,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 ip_release_and_return( packet, length ); |
return release_and_return( packet, length ); |
} |
// TODO IPv6 |
if( length != IP_ADDR ){ |
return ip_release_and_return( packet, EINVAL ); |
return release_and_return( packet, EINVAL ); |
} |
fibril_rwlock_read_lock( & ip_globals.netifs_lock ); |
// device specified? |
547,7 → 572,7 |
|| ( !( ~ dest->s_addr )) |
|| ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr ))) |
|| ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){ |
return ip_release_and_return( packet, EINVAL ); |
return release_and_return( packet, EINVAL ); |
} |
} |
// to me? |
560,7 → 585,7 |
src = ip_netif_address( netif ); |
if( ! src ){ |
fibril_rwlock_read_unlock( & ip_globals.netifs_lock ); |
return ip_release_and_return( packet, ENOENT ); |
return 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 )); |
901,18 → 926,18 |
// allocate as much as originally |
last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header )); |
if( ! last_header ){ |
return ip_release_and_return( packet, ENOMEM ); |
return 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 ip_release_and_return( packet, ERROR_CODE ); |
return 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 ip_release_and_return( packet, ERROR_CODE ); |
return release_and_return( packet, ERROR_CODE ); |
} |
// mark the first as fragmented |
header->flags |= IPFLAG_MORE_FRAGMENTS; |
922,10 → 947,10 |
if( ! new_packet ) return ENOMEM; |
middle_header = ip_create_middle_header( new_packet, last_header ); |
if( ! middle_header ){ |
return ip_release_and_return( packet, ENOMEM ); |
return 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 ip_release_and_return( packet, ERROR_CODE ); |
return release_and_return( packet, ERROR_CODE ); |
} |
} |
// finish the first fragment |
1016,12 → 1041,12 |
|
header = ( ip_header_ref ) packet_get_data( packet ); |
if( ! header ){ |
return ip_release_and_return( packet, ENOMEM ); |
return release_and_return( packet, ENOMEM ); |
} |
// checksum |
if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){ |
// TODO checksum error ICMP? |
return ip_release_and_return( packet, EINVAL ); |
return release_and_return( packet, EINVAL ); |
} |
if( header->ttl <= 1 ){ |
phone = ip_prepare_icmp_and_get_phone( 0, packet, header ); |
1076,7 → 1101,7 |
case SERVICE_ICMP: |
offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL ); |
if( offset < 0 ){ |
return ip_release_and_return( packet, ENOMEM ); |
return release_and_return( packet, ENOMEM ); |
} |
data = packet_get_data( packet ); |
header = ( ip_header_ref ) data + offset; |
1098,7 → 1123,7 |
} |
break; |
default: |
return ip_release_and_return( packet, ENOTSUP ); |
return release_and_return( packet, ENOTSUP ); |
} |
return ip_deliver_local( device_id, packet, header, error ); |
} |
1179,12 → 1204,12 |
|
phone = ip_get_icmp_phone(); |
if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){ |
return ip_release_and_return( packet, EINVAL ); |
return release_and_return( packet, EINVAL ); |
} |
return phone; |
} |
|
int ip_release_and_return( packet_t packet, int result ){ |
static int release_and_return( packet_t packet, int result ){ |
pq_release( ip_globals.net_phone, packet_get_id( packet )); |
return result; |
} |