Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4719 → Rev 4720

/branches/network/uspace/srv/net/il/ip/ip.c
51,21 → 51,24
#include "../../messages.h"
#include "../../modules.h"
 
#include "../../include/net_interface.h"
#include "../../include/inet.h"
#include "../../include/socket_codes.h"
#include "../../include/arp_interface.h"
#include "../../include/byteorder.h"
#include "../../include/crc.h"
#include "../../include/device.h"
#include "../../include/arp_interface.h"
#include "../../include/nil_interface.h"
#include "../../include/icmp_client.h"
#include "../../include/icmp_codes.h"
#include "../../include/icmp_interface.h"
#include "../../include/il_interface.h"
#include "../../include/in.h"
#include "../../include/in6.h"
#include "../../include/inet.h"
#include "../../include/ip_client.h"
#include "../../include/ip_interface.h"
#include "../../include/net_interface.h"
#include "../../include/nil_interface.h"
#include "../../include/tl_interface.h"
#include "../../include/icmp_codes.h"
#include "../../include/icmp_interface.h"
#include "../../include/icmp_client.h"
#include "../../include/socket_codes.h"
#include "../../include/socket_errno.h"
#include "../../structures/measured_strings.h"
#include "../../structures/module_map.h"
#include "../../structures/packet/packet_client.h"
97,7 → 100,7
 
/** IP packet address length.
*/
#define IP_ADDR sizeof( in_addr_t )
#define IP_ADDR sizeof( struct sockaddr_in6 )
 
/** IP packet prefix length.
*/
179,9 → 182,9
int ip_send_route( packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error );
int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination );
 
packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, size_t addr_len, services_t error );
int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, size_t addr_len );
int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, void * src, void * dest, size_t address_length );
packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error );
int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len );
int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen );
ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last );
void ip_create_last_header( ip_header_ref last, ip_header_ref first );
 
507,9 → 510,12
int ip_send_msg( int il_phone, device_id_t device_id, packet_t packet, services_t sender, services_t error ){
ERROR_DECLARE;
 
int length;
int addrlen;
ip_netif_ref netif;
ip_route_ref route;
struct sockaddr * addr;
struct sockaddr_in * address_in;
// struct sockaddr_in6 * address_in6;
in_addr_t * dest;
in_addr_t * src;
int phone;
516,14 → 522,29
 
// addresses in the host byte order
// 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 );
addrlen = packet_get_addr( packet, NULL, ( uint8_t ** ) & addr );
if( addrlen < 0 ){
return ip_release_and_return( packet, addrlen );
}
// TODO IPv6
if( length != IP_ADDR ){
if( addrlen < sizeof( struct sockaddr )){
return ip_release_and_return( packet, EINVAL );
}
switch( addr->sa_family ){
case AF_INET:
if( addrlen != sizeof( struct sockaddr_in )){
return ip_release_and_return( packet, EINVAL );
}
address_in = ( struct sockaddr_in * ) addr;
dest = & address_in->sin_addr;
break;
// TODO IPv6
/* case AF_INET6:
if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
address_in6 = ( struct sockaddr_in6 * ) dest;
address_in6.sin6_addr.s6_addr;
*/ default:
return ip_release_and_return( packet, EAFNOSUPPORT );
}
fibril_rwlock_read_lock( & ip_globals.netifs_lock );
// device specified?
if( device_id > 0 ){
530,7 → 551,6
netif = ip_netifs_find( & ip_globals.netifs, device_id );
route = ip_netif_find_route( netif, * dest );
}else{
// TODO IPv6
route = ip_find_route( * dest );
netif = route ? route->netif : NULL;
}
552,21 → 572,12
return ip_release_and_return( packet, EINVAL );
}
}
// to me?
if( route->address.s_addr == dest->s_addr ){
// TODO loopback deliver
fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
return ip_deliver_local( -1, packet, ( ip_header_ref ) packet_get_data( packet ), error );
}
 
src = ip_netif_address( netif );
if( ! src ){
fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
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 ));
}
ERROR_CODE = ip_send_route( packet, netif, route, src, * dest, error );
fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
return ERROR_CODE;
}
591,8 → 602,10
destination.value = route->gateway.s_addr ? ( char * ) & route->gateway.s_addr : ( char * ) & dest.s_addr;
destination.length = CONVERT_SIZE( dest.s_addr, char, 1 );
if( ERROR_OCCURRED( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ))){
sleep( 1 );
ERROR_PROPAGATE( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ));
// sleep( 1 );
// ERROR_PROPAGATE( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ));
pq_release( ip_globals.net_phone, packet_get_id( packet ));
return ERROR_CODE;
}
if( !( translation && translation->value )){
if( translation ){
835,7 → 848,7
return EOK;
}
 
packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, size_t addr_len, services_t error ){
packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error ){
size_t length;
packet_t next;
packet_t new_packet;
874,7 → 887,7
return packet;
}
 
int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, size_t addr_len ){
int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len ){
ERROR_DECLARE;
 
packet_t new_packet;
881,14 → 894,14
ip_header_ref header;
ip_header_ref middle_header;
ip_header_ref last_header;
uint8_t * src;
uint8_t * dest;
size_t address_length;
struct sockaddr * src;
struct sockaddr * dest;
socklen_t addrlen;
int result;
 
result = packet_get_addr( packet, & src, & dest );
result = packet_get_addr( packet, ( uint8_t ** ) & src, ( uint8_t ** ) & dest );
if( result <= 0 ) return EINVAL;
address_length = ( size_t ) result;
addrlen = ( socklen_t ) result;
if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
// get header
header = ( ip_header_ref ) packet_get_data( packet );
898,7 → 911,7
return EPERM;
}
// create the last fragment
new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, ((( size_t ) address_length > addr_len ) ? ( size_t ) address_length : addr_len ));
new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen > addr_len ) ? addrlen : addr_len ));
if( ! new_packet ) return ENOMEM;
// allocate as much as originally
last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
913,7 → 926,7
// 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 ))){
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, addrlen ))){
return ip_release_and_return( packet, ERROR_CODE );
}
// mark the first as fragmented
920,13 → 933,13
header->flags |= IPFLAG_MORE_FRAGMENTS;
// create middle framgents
while( IP_TOTAL_LENGTH( header ) > length ){
new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( address_length >= addr_len ) ? address_length : addr_len ));
new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen >= addr_len ) ? addrlen : addr_len ));
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 );
}
if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, length - IP_HEADER_LENGTH( middle_header ), src, dest, address_length ))){
if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, length - IP_HEADER_LENGTH( middle_header ), src, dest, addrlen ))){
return ip_release_and_return( packet, ERROR_CODE );
}
}
935,7 → 948,7
return EOK;
}
 
int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, void * src, void * dest, size_t address_length ){
int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen ){
ERROR_DECLARE;
 
void * data;
948,7 → 961,7
new_header->total_length = htons( IP_HEADER_LENGTH( new_header ) + length );
new_header->fragment_offset = header->fragment_offset + IP_HEADER_DATA_LENGTH( header ) / 8;
new_header->header_checksum = IP_HEADER_CHECKSUM( new_header );
ERROR_PROPAGATE( packet_set_addr( new_packet, src, dest, address_length ));
ERROR_PROPAGATE( packet_set_addr( new_packet, ( const uint8_t * ) src, ( const uint8_t * ) dest, addrlen ));
return pq_insert_after( packet, new_packet );
}
 
1015,6 → 1028,10
in_addr_t dest;
ip_route_ref route;
int phone;
struct sockaddr * addr;
struct sockaddr_in addr_in;
// struct sockaddr_in addr_in6;
socklen_t addrlen;
 
header = ( ip_header_ref ) packet_get_data( packet );
if( ! header ){
1035,7 → 1052,26
}
// process ipopt and get destination
dest = ip_get_destination( header );
ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) & dest.s_addr, IP_ADDR ));
// set the addrination address
switch( header->version ){
case IPVERSION:
addrlen = sizeof( addr_in );
bzero( & addr_in, addrlen );
addr_in.sin_family = AF_INET;
memcpy( & addr_in.sin_addr.s_addr, & dest, sizeof( dest ));
addr = ( struct sockaddr * ) & addr_in;
break;
/* case IPv6VERSION:
addrlen = sizeof( dest_in6 );
bzero( & dest_in6, addrlen );
dest_in6.sin6_family = AF_INET6;
memcpy( & dest_in6.sin6_addr.s6_addr, );
dest = ( struct sockaddr * ) & dest_in;
break;
*/ default:
return EAFNOSUPPORT;
}
ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) & addr, addrlen ));
route = ip_find_route( dest );
if( ! route ){
phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1081,7 → 1117,7
return ip_release_and_return( packet, ENOMEM );
}
data = packet_get_data( packet );
header = ( ip_header_ref ) data + offset;
header = ( ip_header_ref )( data + offset );
// destination host unreachable?
if(( type == ICMP_DEST_UNREACH ) && ( code == ICMP_HOST_UNREACH )){
fibril_rwlock_read_lock( & ip_globals.netifs_lock );
1110,12 → 1146,45
 
ip_proto_ref proto;
int phone;
services_t service;
tl_received_msg_t received_msg;
struct sockaddr * src;
struct sockaddr * dest;
struct sockaddr_in src_in;
struct sockaddr_in dest_in;
// struct sockaddr_in src_in6;
// struct sockaddr_in dest_in6;
socklen_t addrlen;
 
if(( header->flags & IPFLAG_MORE_FRAGMENTS ) || header->fragment_offset ){
// TODO fragmented
return ENOTSUP;
}else{
ERROR_PROPAGATE( packet_set_addr( packet, ( uint8_t * ) & header->source_address, ( uint8_t * ) & header->destination_address, IP_ADDR ));
switch( header->version ){
case IPVERSION:
addrlen = sizeof( src_in );
bzero( & src_in, addrlen );
src_in.sin_family = AF_INET;
memcpy( & dest_in, & src_in, addrlen );
memcpy( & src_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
memcpy( & dest_in.sin_addr.s_addr, & header->destination_address, sizeof( header->destination_address ));
src = ( struct sockaddr * ) & src_in;
dest = ( struct sockaddr * ) & dest_in;
break;
/* case IPv6VERSION:
addrlen = sizeof( src_in6 );
bzero( & src_in6, addrlen );
src_in6.sin6_family = AF_INET6;
memcpy( & dest_in6, & src_in6, addrlen );
memcpy( & src_in6.sin6_addr.s6_addr, );
memcpy( & dest_in6.sin6_addr.s6_addr, );
src = ( struct sockaddr * ) & src_in;
dest = ( struct sockaddr * ) & dest_in;
break;
*/ default:
return EAFNOSUPPORT;
}
ERROR_PROPAGATE( packet_set_addr( packet, ( uint8_t * ) src, ( uint8_t * ) dest, addrlen ));
fibril_rwlock_read_lock( & ip_globals.protos_lock );
proto = ip_protos_find( & ip_globals.protos, header->protocol );
if( ! proto ){
1128,11 → 1197,14
return ENOENT;
}
if( proto->received_msg ){
ERROR_CODE = proto->received_msg( device_id, packet, proto->service, error );
service = proto->service;
received_msg = proto->received_msg;
fibril_rwlock_read_unlock( & ip_globals.protos_lock );
ERROR_CODE = received_msg( device_id, packet, service, error );
}else{
ERROR_CODE = tl_received_msg( proto->phone, device_id, packet, proto->service, error );
fibril_rwlock_read_unlock( & ip_globals.protos_lock );
}
fibril_rwlock_read_unlock( & ip_globals.protos_lock );
return ERROR_CODE;
}
}
1147,6 → 1219,10
 
int ip_prepare_icmp( packet_t packet, ip_header_ref header ){
packet_t next;
struct sockaddr * dest;
struct sockaddr_in dest_in;
// struct sockaddr_in dest_in6;
socklen_t addrlen;
 
// detach the first packet and release the others
next = pq_detach( packet );
1162,7 → 1238,25
// only for the first fragment
if( header->fragment_offset ) return EINVAL;
// set the destination address
return packet_set_addr( packet, NULL, ( uint8_t * ) & header->source_address, sizeof( header->source_address ));
switch( header->version ){
case IPVERSION:
addrlen = sizeof( dest_in );
bzero( & dest_in, addrlen );
dest_in.sin_family = AF_INET;
memcpy( & dest_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
dest = ( struct sockaddr * ) & dest_in;
break;
/* case IPv6VERSION:
addrlen = sizeof( dest_in6 );
bzero( & dest_in6, addrlen );
dest_in6.sin6_family = AF_INET6;
memcpy( & dest_in6.sin6_addr.s6_addr, );
dest = ( struct sockaddr * ) & dest_in;
break;
*/ default:
return EAFNOSUPPORT;
}
return packet_set_addr( packet, NULL, ( uint8_t * ) dest, addrlen );
}
 
int ip_get_icmp_phone( void ){
/branches/network/uspace/srv/net/il/ip/Makefile
46,8 → 46,9
$(NET_BASE)il/arp/arp_remote.c \
$(NET_BASE)nil/nil_remote.c \
$(NET_BASE)net/net_remote.c \
$(NET_BASE)tl/icmp/icmp_client.c \
$(NET_BASE)tl/icmp/icmp_common.c \
$(NET_BASE)tl/icmp/icmp_remote.c \
$(NET_BASE)tl/icmp/icmp_client.c \
$(STRUCTURES)char_map.c \
$(STRUCTURES)measured_strings.c \
$(STRUCTURES)module_map.c \