Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3990 → Rev 3991

/branches/network/uspace/srv/net/il/arp/arp.c
35,9 → 35,9
* @see arp.h
*/
 
#include <as.h>
#include <async.h>
#include <malloc.h>
#include <rwlock.h>
#include <stdio.h>
#include <string.h>
 
160,7 → 160,13
GENERIC_CHAR_MAP_IMPLEMENT( arp_addr, measured_string_t )
 
int arp_initialize( void ){
return arp_cache_initialize( & arp_globals.cache );
ERROR_DECLARE;
 
rwlock_initialize( & arp_globals.lock );
rwlock_write_lock( & arp_globals.lock );
ERROR_PROPAGATE( arp_cache_initialize( & arp_globals.cache ));
rwlock_write_unlock( & arp_globals.lock );
return EOK;
}
 
int arp_proto_create( arp_proto_ref * proto, services_t service, measured_string_ref address ){
187,10 → 193,14
ipcarg_t result;
arp_proto_ref proto;
 
rwlock_write_lock( & arp_globals.lock );
// an existing device?
device = arp_cache_find( & arp_globals.cache, device_id );
if( device ){
if( device->service != service ) return EEXIST;
if( device->service != service ){
rwlock_write_unlock( & arp_globals.lock );
return EEXIST;
}
proto = arp_protos_find( & device->protos, protocol );
if( proto ){
free( proto->addr );
198,8 → 208,12
proto->addr = address;
proto->addr_data = address->value;
}else{
ERROR_PROPAGATE( arp_proto_create( & proto, protocol, address ));
if( ERROR_OCCURRED( arp_proto_create( & proto, protocol, address ))){
rwlock_write_unlock( & arp_globals.lock );
return ERROR_CODE;
}
if( ERROR_OCCURRED( arp_protos_add( & device->protos, proto->service, proto ))){
rwlock_write_unlock( & arp_globals.lock );
free( proto );
return ERROR_CODE;
}
208,14 → 222,19
}else{
// create a new device
device = ( arp_device_ref ) malloc( sizeof( arp_device_t ));
if( ! device ) return ENOMEM;
if( ! device ){
rwlock_write_unlock( & arp_globals.lock );
return ENOMEM;
}
device->device_id = device_id;
if( ERROR_OCCURRED( arp_protos_initialize( & device->protos ))
|| ERROR_OCCURRED( arp_proto_create( & proto, protocol, address ))){
rwlock_write_unlock( & arp_globals.lock );
free( device );
return ERROR_CODE;
}
if( ERROR_OCCURRED( arp_protos_add( & device->protos, proto->service, proto ))){
rwlock_write_unlock( & arp_globals.lock );
arp_protos_destroy( & device->protos );
free( device );
return ERROR_CODE;
225,6 → 244,7
device->phone = bind_service( device->service, device->device_id, SERVICE_ARP, 0, arp_receiver );
// get packet dimensions
if( ERROR_OCCURRED( async_req_1_4( device->phone, NET_NIL_PACKET_SPACE, device_id, & device->addr_len, & device->prefix, & device->content, & device->suffix ))){
rwlock_write_unlock( & arp_globals.lock );
arp_protos_destroy( & device->protos );
free( device );
return ERROR_CODE;
232,6 → 252,7
// get hardware address
message = async_send_1( device->phone, NET_NIL_ADDR, device->device_id, & answer );
if( ERROR_OCCURRED( measured_strings_return( device->phone, & device->addr, & device->addr_data, 1 ))){
rwlock_write_unlock( & arp_globals.lock );
arp_protos_destroy( & device->protos );
free( device );
async_wait_for( message, NULL );
239,6 → 260,7
}
async_wait_for( message, & result );
if( ERROR_OCCURRED( result )){
rwlock_write_unlock( & arp_globals.lock );
free( device->addr );
free( device->addr_data );
arp_protos_destroy( & device->protos );
248,6 → 270,7
// get broadcast address
message = async_send_1( device->phone, NET_NIL_BROADCAST_ADDR, device->device_id, & answer );
if( ERROR_OCCURRED( measured_strings_return( device->phone, & device->broadcast_addr, & device->broadcast_data, 1 ))){
rwlock_write_unlock( & arp_globals.lock );
free( device->addr );
free( device->addr_data );
arp_protos_destroy( & device->protos );
259,6 → 282,7
// add to the cache
if( ERROR_OCCURRED( result )
|| ERROR_OCCURRED( arp_cache_add( & arp_globals.cache, device->device_id, device ))){
rwlock_write_unlock( & arp_globals.lock );
free( device->addr );
free( device->addr_data );
free( device->broadcast_addr );
268,6 → 292,7
return ERROR_CODE;
}
}
rwlock_write_unlock( & arp_globals.lock );
return EOK;
}
 
280,19 → 305,33
arp_header_ref header;
 
if( ! target ) return NULL;
rwlock_read_lock( & arp_globals.lock );
device = arp_cache_find( & arp_globals.cache, device_id );
if( ! device ) return NULL;
if( ! device ){
rwlock_read_unlock( & arp_globals.lock );
return NULL;
}
proto = arp_protos_find( & device->protos, protocol );
if(( ! proto ) || ( proto->addr->length != target->length )) return NULL;
if(( ! proto ) || ( proto->addr->length != target->length )){
rwlock_read_unlock( & arp_globals.lock );
return NULL;
}
addr = arp_addr_find( & proto->addresses, target->value, target->length );
if( addr ) return addr;
if( addr ){
rwlock_read_unlock( & arp_globals.lock );
return addr;
}
// ARP packet content size = header + ( address + translation ) * 2
length = 8 + ( CONVERT_SIZE( char, uint8_t, proto->addr->length ) + CONVERT_SIZE( char, uint8_t, device->addr->length )) * 2;
if( length > device->content ){
rwlock_read_unlock( & arp_globals.lock );
return NULL;
}
packet = packet_get_5( arp_globals.networking_phone, SERVICE_ARP, device->addr_len, device->prefix, length, device->suffix );
if( ! packet ) return NULL;
packet = packet_get_4( arp_globals.networking_phone, device->addr_len, device->prefix, length, device->suffix );
if( ! packet ){
rwlock_read_unlock( & arp_globals.lock );
return NULL;
}
header = ( arp_header_ref ) packet_suffix( packet, length );
header->hardware = device->hardware;
header->hardware_length = device->addr->length;
309,6 → 348,7
memcpy((( uint8_t * ) header ) + length, target->value, target->length );
packet_set_addr( packet, ( uint8_t * ) device->addr->value, ( uint8_t * ) device->broadcast_addr->value, CONVERT_SIZE( char, uint8_t, device->addr->length ));
async_msg_3( device->phone, NET_NETIF_SEND, device_id, SERVICE_ARP, packet_get_id( packet ));
rwlock_read_unlock( & arp_globals.lock );
return NULL;
}
 
319,14 → 359,8
arp_header_ref header;
arp_device_ref device;
arp_proto_ref proto;
// arp_addr_ref addr;
measured_string_ref hw_source;
/* measured_string_t proto_target;
aid_t message;
ipcarg_t result;
int index;
ipc_call_t answer;
*/ uint8_t * src_hw;
uint8_t * src_hw;
uint8_t * src_proto;
uint8_t * des_hw;
uint8_t * des_proto;
333,13 → 367,23
 
length = packet_get_data_length( packet );
if( length <= sizeof( arp_header_t )) return EINVAL;
rwlock_read_lock( & arp_globals.lock );
device = arp_cache_find( & arp_globals.cache, device_id );
if( ! device ) return ENOENT;
if( ! device ){
rwlock_read_unlock( & arp_globals.lock );
return ENOENT;
}
header = ( arp_header_ref ) packet_get_data( packet );
if( header->hardware != device->hardware ) return EINVAL;
if( length < sizeof( arp_header_t ) + ( header->hardware_length + header->protocol_length ) * 2 ) return EINVAL;
if(( header->hardware != device->hardware )
|| ( length < sizeof( arp_header_t ) + ( header->hardware_length + header->protocol_length ) * 2 )){
rwlock_read_unlock( & arp_globals.lock );
return EINVAL;
}
proto = arp_protos_find( & device->protos, protocol_unmap( device->service, header->protocol ));
if( ! proto ) return ENOENT;
if( ! proto ){
rwlock_read_unlock( & arp_globals.lock );
return ENOENT;
}
src_hw = (( uint8_t * ) header ) + sizeof( arp_header_t );
src_proto = src_hw + header->hardware_length;
des_hw = src_proto + header->protocol_length;
347,48 → 391,41
hw_source = arp_addr_find( & proto->addresses, ( char * ) src_proto, CONVERT_SIZE( uint8_t, char, header->protocol_length ));
// exists?
if( hw_source ){
if( hw_source->length != CONVERT_SIZE( uint8_t, char, header->hardware_length )) return EINVAL;
if( hw_source->length != CONVERT_SIZE( uint8_t, char, header->hardware_length )){
rwlock_read_unlock( & arp_globals.lock );
return EINVAL;
}
memcpy( hw_source->value, src_hw, hw_source->length );
}
// is my protocol address?
// TODO query protocol module?
/* proto_target.value = des_proto;
proto_target.length = header->protocol_length;
// TODO send necessary?
message = async_send_0( proto->phone, NET_IL_MY_ADDR, & answer );
if( ERROR_OCCURRED( measured_strings_send( device->phone, & proto_target, 1 ))){
async_wait_for( message, NULL );
return ERROR_CODE;
if( proto->addr->length != CONVERT_SIZE( uint8_t, char, header->hardware_length )){
rwlock_read_unlock( & arp_globals.lock );
return EINVAL;
}
async_wait_for( message, & result );
if( result == EOK ){
*/ if( proto->addr->length != CONVERT_SIZE( uint8_t, char, header->hardware_length )) return EINVAL;
if( ! strncmp( proto->addr->value, ( char * ) des_proto, proto->addr->length )){
// not already upadted?
if( ! hw_source ){
hw_source = measured_string_create_bulk(( char * ) src_hw, CONVERT_SIZE( uint8_t, char, header->hardware_length ));
if( ! hw_source ) return ENOMEM;
ERROR_PROPAGATE( arp_addr_add( & proto->addresses, ( char * ) src_proto, CONVERT_SIZE( uint8_t, char, header->protocol_length ), hw_source ));
if( ! hw_source ){
rwlock_read_unlock( & arp_globals.lock );
return ENOMEM;
}
if( ERROR_OCCURRED( arp_addr_add( & proto->addresses, ( char * ) src_proto, CONVERT_SIZE( uint8_t, char, header->protocol_length ), hw_source ))){
rwlock_read_unlock( & arp_globals.lock );
return ERROR_CODE;
}
}
if( header->operation == ARPOP_REQUEST ){
header->operation = ARPOP_REPLY;
/* for( index = 0; index + header->hardware_length < header->protocol_length; index += header->hardware_length ){
memcpy( src_hw, src_proto + index, header->hardware_length );
memcpy( src_proto + index, des_proto + index, header->hardware_length );
memcpy( des_proto + index, src_hw, header->hardware_length );
}
memcpy( src_hw, src_proto + index, header->hardware_length - header->protocol_length );
memcpy( src_proto + index, des_proto + index, header->hardware_length - header->protocol_length );
memcpy( des_proto + index, src_hw, header->hardware_length - header->protocol_length );
memcpy( src_hw, des_hw, header->hardware_length );
memcpy( des_hw, hw_source->value, hw_source->length );
*/ memcpy( des_proto, src_proto, header->protocol_length );
memcpy( des_proto, src_proto, header->protocol_length );
memcpy( src_proto, proto->addr->value, header->protocol_length );
memcpy( src_hw, des_hw, header->hardware_length );
memcpy( des_hw, hw_source->value, header->hardware_length );
packet_set_addr( packet, src_hw, des_hw, header->hardware_length );
async_msg_3( device->phone, NET_NETIF_SEND, device_id, SERVICE_ARP, packet_get_id( packet ));
rwlock_read_unlock( & arp_globals.lock );
}else{
rwlock_read_unlock( & arp_globals.lock );
packet_release( arp_globals.networking_phone, packet_get_id( packet ));
}
}
398,9 → 435,14
int arp_clear_device_message( device_id_t device_id ){
arp_device_ref device;
 
rwlock_write_lock( & arp_globals.lock );
device = arp_cache_find( & arp_globals.cache, device_id );
if( ! device ) return ENOENT;
if( ! device ){
rwlock_write_unlock( & arp_globals.lock );
return ENOENT;
}
clear_device( device );
rwlock_write_unlock( & arp_globals.lock );
return EOK;
}
 
423,6 → 465,7
int count;
arp_device_ref device;
 
rwlock_write_lock( & arp_globals.lock );
count = arp_cache_count( & arp_globals.cache );
while( count > 0 ){
device = arp_cache_get_index( & arp_globals.cache, count );
433,6 → 476,7
}
}
arp_cache_clear( & arp_globals.cache );
rwlock_write_lock( & arp_globals.lock );
return EOK;
}
 
477,7 → 521,8
while( true ){
switch( IPC_GET_METHOD( * icall )){
case NET_IL_DEVICE_STATE:
//TODO clear device if off?
// do nothing - keep the cache
ipc_answer_0( iid, EOK );
break;
case NET_IL_RECEIVED:
if( ! ERROR_OCCURRED( packet_translate( arp_globals.networking_phone, & packet, IPC_GET_PACKET( icall )))){