Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3911 → Rev 3912

/branches/network/uspace/srv/net/il/arp/arp.c
1,5 → 1,5
/*
* Copyright (c) 2008 Lukas Mejdrech
* Copyright (c) 2009 Lukas Mejdrech
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
31,6 → 31,8
*/
 
/** @file
* ARP module implementation.
* @see arp.h
*/
 
#include <as.h>
59,13 → 61,98
//#include "arp_messages.h"
#include "arp_module.h"
 
/** Returns the device identifier message parameter.
*/
#define IPC_GET_DEVICE( call ) ( device_id_t ) IPC_GET_ARG1( * call )
 
/** Returns the packet identifier message parameter.
*/
#define IPC_GET_PACKET( call ) ( packet_id_t ) IPC_GET_ARG2( * call )
 
/** Returns the protocol service message parameter.
*/
#define IPC_GET_PROTO( call ) ( services_t ) IPC_GET_ARG2( * call )
 
/** Returns the device driver service message parameter.
*/
#define IPC_GET_SERVICE( call ) ( services_t ) IPC_GET_ARG3( * call )
 
/** ARP global data.
*/
arp_globals_t arp_globals;
 
/** Creates new protocol specific data.
* @param proto Protocol specific data. Output parameter.
* @param service Protocol module service. Input parameter.
* @param address Actual protocol device address. Input parameter.
* @returns EOK on success.
* @returns ENOMEM if there is not enough memory left.
*/
int arp_proto_create( arp_proto_ref * proto, services_t service, measured_string_ref address );
 
/** Registers the device.
* Creates new device entry in the cache or updates the protocol address if the device with the device identifier and the driver service exists.
* @param device_id The device identifier. Input parameter.
* @param service The device driver service. Input parameter.
* @param protocol The protocol service. Input parameter.
* @param address The actual device protocol address.
* @returns EOK on success.
* @returns EEXIST if another device with the same device identifier and different driver service exists.
* @returns ENOMEM if there is not enough memory left.
* @returns Other error codes as defined for the measured_strings_return() function.
*/
int arp_device_message( device_id_t device_id, services_t service, services_t protocol, measured_string_ref address );
 
/** Returns the hardware address for the given protocol address.
* Sends the ARP request packet if the hardware address is not found in the cache.
* @param device_id The device identifier. Input parameter.
* @param protocol The protocol service. Input parameter.
* @param target The target protocol address. Input parameter.
* @returns The hardware address of the target.
* @returns NULL if the target parameter is NULL.
* @returns NULL if the device is not found.
* @returns NULL if the device packet is too small to send a&nbsp;request.
* @returns NULL if the hardware address is not found in the cache.
*/
measured_string_ref arp_translate_message( device_id_t device_id, services_t protocol, measured_string_ref target );
 
/** Processes the received ARP packet.
* Updates the source hardware address if the source entry exists or the packet is targeted to my protocol address.
* Responses to the ARP request if the packet is the ARP request and is targeted to my address.
* @param device_id The source device identifier. Input parameter.
* @param packet The received packet. Input/output parameter.
* @returns EOK on success.
* @returns EINVAL if the packet is too small to carry the ARP packet.
* @returns EINVAL if the received address lengths differs from the registered values.
* @returns ENOENT if the device is not found in the cache.
* @returns ENOENT if the protocol for the device is not found in the cache.
* @returns ENOMEM if there is not enough memory left.
*/
int arp_receive_message( device_id_t device_id, packet_t packet );
 
/** Clears the device specific data from the cache.
* @param device_id The device identifier. Input parameter.
* @returns EOK on success.
* @returns ENOENT if the device is not found in the cache.
*/
int arp_clear_device_message( device_id_t device_id );
 
/** Clears the device specific data.
* @param device The device specific data.
*/
void clear_device( arp_device_ref device );
 
/** Clears the whole cache.
* @returns EOK on success.
*/
int arp_clean_cache_message( void );
 
/** Processes IPC messages from the registered device driver modules in an infinite loop.
* @param iid The message identifier. Input parameter.
* @param icall The message parameters. Input/output parameter.
*/
void arp_receiver( ipc_callid_t iid, ipc_call_t * icall );
 
DEVICE_MAP_IMPLEMENT( arp_cache, arp_device_t )
 
INT_MAP_IMPLEMENT( arp_protos, arp_proto_t )
72,20 → 159,8
 
GENERIC_CHAR_MAP_IMPLEMENT( arp_addr, measured_string_t )
 
int arp_proto_create( arp_proto_ref * proto, services_t service, measured_string_ref address );
int arp_device_message( device_id_t device_id, services_t service, services_t protocol, measured_string_ref address );
measured_string_ref arp_translate_message( device_id_t device, services_t protocol, measured_string_ref target );
int arp_receive_message( device_id_t device_id, packet_t packet );
int arp_clear_device_message( device_id_t device_id );
void clear_device( arp_device_ref device );
int arp_clean_cache_message( void );
void arp_receiver( ipc_callid_t iid, ipc_call_t * icall );
 
/** Initializes the ARP module.
*/
int arp_initialize( void ){
arp_cache_initialize( & arp_globals.cache );
return EOK;
return arp_cache_initialize( & arp_globals.cache );
}
 
int arp_proto_create( arp_proto_ref * proto, services_t service, measured_string_ref address ){
96,7 → 171,7
( ** proto ).service = service;
( ** proto ).addr = address;
( ** proto ).addr_data = address->value;
if( ERROR_OCCURED( arp_addr_initialize( &( ** proto).addresses ))){
if( ERROR_OCCURRED( arp_addr_initialize( &( ** proto).addresses ))){
free( * proto );
return ERROR_CODE;
}
124,7 → 199,7
proto->addr_data = address->value;
}else{
ERROR_PROPAGATE( arp_proto_create( & proto, protocol, address ));
if( ERROR_OCCURED( arp_protos_add( & device->protos, proto->service, proto ))){
if( ERROR_OCCURRED( arp_protos_add( & device->protos, proto->service, proto ))){
free( proto );
return ERROR_CODE;
}
135,12 → 210,12
device = ( arp_device_ref ) malloc( sizeof( arp_device_t ));
if( ! device ) return ENOMEM;
device->device_id = device_id;
if( ERROR_OCCURED( arp_protos_initialize( & device->protos ))
|| ERROR_OCCURED( arp_proto_create( & proto, protocol, address ))){
if( ERROR_OCCURRED( arp_protos_initialize( & device->protos ))
|| ERROR_OCCURRED( arp_proto_create( & proto, protocol, address ))){
free( device );
return ERROR_CODE;
}
if( ERROR_OCCURED( arp_protos_add( & device->protos, proto->service, proto ))){
if( ERROR_OCCURRED( arp_protos_add( & device->protos, proto->service, proto ))){
arp_protos_destroy( & device->protos );
free( device );
return ERROR_CODE;
149,7 → 224,7
// bind the new one
device->phone = bind_service( device->service, device->device_id, SERVICE_ARP, 0, arp_receiver );
// get packet dimensions
if( ERROR_OCCURED( async_req_1_4( device->phone, NET_NIL_PACKET_SPACE, device_id, & device->addr_len, & device->prefix, & device->content, & device->sufix ))){
if( ERROR_OCCURRED( async_req_1_4( device->phone, NET_NIL_PACKET_SPACE, device_id, & device->addr_len, & device->prefix, & device->content, & device->suffix ))){
arp_protos_destroy( & device->protos );
free( device );
return ERROR_CODE;
156,7 → 231,7
}
// get hardware address
message = async_send_1( device->phone, NET_NIL_ADDR, device->device_id, & answer );
if( ERROR_OCCURED( measured_strings_return( device->phone, & device->addr, & device->addr_data, 1 ))){
if( ERROR_OCCURRED( measured_strings_return( device->phone, & device->addr, & device->addr_data, 1 ))){
arp_protos_destroy( & device->protos );
free( device );
async_wait_for( message, NULL );
163,7 → 238,7
return ERROR_CODE;
}
async_wait_for( message, & result );
if( ERROR_OCCURED( result )){
if( ERROR_OCCURRED( result )){
free( device->addr );
free( device->addr_data );
arp_protos_destroy( & device->protos );
172,7 → 247,7
}
// get broadcast address
message = async_send_1( device->phone, NET_NIL_BROADCAST_ADDR, device->device_id, & answer );
if( ERROR_OCCURED( measured_strings_return( device->phone, & device->broadcast_addr, & device->broadcast_data, 1 ))){
if( ERROR_OCCURRED( measured_strings_return( device->phone, & device->broadcast_addr, & device->broadcast_data, 1 ))){
free( device->addr );
free( device->addr_data );
arp_protos_destroy( & device->protos );
182,8 → 257,8
}
async_wait_for( message, & result );
// add to the cache
if( ERROR_OCCURED( result )
|| ERROR_OCCURED( arp_cache_add( & arp_globals.cache, device->device_id, device ))){
if( ERROR_OCCURRED( result )
|| ERROR_OCCURRED( arp_cache_add( & arp_globals.cache, device->device_id, device ))){
free( device->addr );
free( device->addr_data );
free( device->broadcast_addr );
197,8 → 272,6
}
 
measured_string_ref arp_translate_message( device_id_t device_id, services_t protocol, measured_string_ref target ){
// ERROR_DECLARE;
 
arp_device_ref device;
arp_proto_ref proto;
measured_string_ref addr;
218,9 → 291,9
if( length > device->content ){
return NULL;
}
packet = packet_get_5( arp_globals.networking_phone, SERVICE_ARP, device->addr_len, device->prefix, length, device->sufix );
packet = packet_get_5( arp_globals.networking_phone, SERVICE_ARP, device->addr_len, device->prefix, length, device->suffix );
if( ! packet ) return NULL;
header = ( arp_header_ref ) packet_append( packet, length );
header = ( arp_header_ref ) packet_suffix( packet, length );
header->hardware = device->hardware;
header->hardware_length = device->addr->length;
header->protocol = protocol_map( device->service, protocol );
234,7 → 307,7
memset((( uint8_t * ) header ) + length, 0, device->addr->length );
length += device->addr->length;
memcpy((( uint8_t * ) header ) + length, target->value, target->length );
// TODO send to the device->broadcast_addr as arp protocol
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 ));
return NULL;
}
253,10 → 326,10
ipcarg_t result;
int index;
ipc_call_t answer;
*/ int8_t * src_hw;
int8_t * src_proto;
int8_t * des_hw;
int8_t * des_proto;
*/ uint8_t * src_hw;
uint8_t * src_proto;
uint8_t * des_hw;
uint8_t * des_proto;
 
length = packet_get_data_length( packet );
if( length <= sizeof( arp_header_t )) return EINVAL;
267,34 → 340,35
if( length < sizeof( arp_header_t ) + ( header->hardware_length + header->protocol_length ) * 2 ) return EINVAL;
proto = arp_protos_find( & device->protos, protocol_unmap( device->service, header->protocol ));
if( ! proto ) return ENOENT;
src_hw = (( int8_t * ) header ) + sizeof( arp_header_t );
src_hw = (( uint8_t * ) header ) + sizeof( arp_header_t );
src_proto = src_hw + header->hardware_length;
des_hw = src_proto + header->protocol_length;
des_proto = des_hw + header->hardware_length;
hw_source = arp_addr_find( & proto->addresses, src_proto, header->protocol_length );
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 != header->hardware_length ) return EINVAL;
memcpy( hw_source->value, src_hw, header->hardware_length );
if( hw_source->length != CONVERT_SIZE( uint8_t, char, header->hardware_length )) 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_OCCURED( measured_strings_send( device->phone, & proto_target, 1 ))){
if( ERROR_OCCURRED( measured_strings_send( device->phone, & proto_target, 1 ))){
async_wait_for( message, NULL );
return ERROR_CODE;
}
async_wait_for( message, & result );
if( result == EOK ){
*/ if( proto->addr->length != header->hardware_length ) return EINVAL;
if( ! strncmp( proto->addr->value, des_proto, proto->addr->length )){
*/ 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( src_hw, header->hardware_length );
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, src_proto, header->protocol_length, hw_source ));
ERROR_PROPAGATE( arp_addr_add( & proto->addresses, ( char * ) src_proto, CONVERT_SIZE( uint8_t, char, header->protocol_length ), hw_source ));
}
if( header->operation == ARPOP_REQUEST ){
header->operation = ARPOP_REPLY;
311,8 → 385,8
*/ 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, hw_source->length );
// TODO send to the hw_source as arp protocol
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 ));
}else{
packet_release( arp_globals.networking_phone, packet_get_id( packet ));
354,7 → 428,7
device = arp_cache_get_index( & arp_globals.cache, count );
if( device ){
clear_device( device );
if( device->broadcast_addr ) free( device->broadcast_addr );
if( device->addr_data ) free( device->addr_data );
if( device->broadcast_data ) free( device->broadcast_data );
}
}
365,7 → 439,6
int arp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
ERROR_DECLARE;
 
// packet_t packet;
measured_string_ref address;
measured_string_ref translation;
char * data;
376,7 → 449,7
return EOK;
case NET_ARP_DEVICE:
ERROR_PROPAGATE( measured_strings_receive( & address, & data, 1 ));
if( ERROR_OCCURED( arp_device_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), IPC_GET_PROTO( call ), address ))){
if( ERROR_OCCURRED( arp_device_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), IPC_GET_PROTO( call ), address ))){
free( address );
free( data );
}
399,33 → 472,23
void arp_receiver( ipc_callid_t iid, ipc_call_t * icall ){
ERROR_DECLARE;
 
ipc_callid_t callid;
ipc_call_t call;
// int result;
packet_t packet;
 
/*
* Accept the connection
* - Answer the first IPC_M_CONNECT_ME_TO call.
*/
//TODO auto accept?
//ipc_answer_0( iid, EOK );
 
while( true ){
callid = async_get_call( & call );
switch( IPC_GET_METHOD( call )){
switch( IPC_GET_METHOD( * icall )){
case NET_IL_DEVICE_STATE:
//TODO clear device if off?
break;
case NET_IL_RECEIVED:
if( ! ERROR_OCCURED( packet_translate( arp_globals.networking_phone, & packet, IPC_GET_PACKET( & call )))){
ERROR_CODE = arp_receive_message( IPC_GET_DEVICE( & call ), packet );
if( ! ERROR_OCCURRED( packet_translate( arp_globals.networking_phone, & packet, IPC_GET_PACKET( icall )))){
ERROR_CODE = arp_receive_message( IPC_GET_DEVICE( icall ), packet );
}
ipc_answer_0( callid, ERROR_CODE );
ipc_answer_0( iid, ERROR_CODE );
break;
default:
ipc_answer_0( callid, ENOTSUP );
ipc_answer_0( iid, ENOTSUP );
}
iid = async_get_call( icall );
}
}