Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4331 → Rev 4332

/branches/network/uspace/srv/net/nil/eth/eth.c
54,6 → 54,7
#include "../../include/protocol_map.h"
#include "../../include/device.h"
#include "../../include/netif_interface.h"
#include "../../include/net_interface.h"
#include "../../include/nil_interface.h"
#include "../../include/il_interface.h"
 
69,9 → 70,31
#define ETH_SUFFIX sizeof( eth_fcs_t )
#define ETH_MAX_CONTENT 1500
#define ETH_MIN_CONTENT 46
#define ETH_MAX_TAGGED_CONTENT ( ETH_MAX_CONTENT - sizeof( eth_header_lsap_t ) - sizeof( eth_header_snap_t ))
#define ETH_MIN_TAGGED_CONTENT ( ETH_MIN_CONTENT - sizeof( eth_header_lsap_t ) - sizeof( eth_header_snap_t ))
#define ETH_MAX_TAGGED_CONTENT( flags ) ( ETH_MAX_CONTENT - (( IS_8023_2_LSAP( flags ) || IS_8023_2_SNAP( flags )) ? sizeof( eth_header_lsap_t ) : 0 ) - ( IS_8023_2_SNAP( flags ) ? sizeof( eth_header_snap_t ) : 0 ))
#define ETH_MIN_TAGGED_CONTENT( flags ) ( ETH_MIN_CONTENT - (( IS_8023_2_LSAP( flags ) || IS_8023_2_SNAP( flags )) ? sizeof( eth_header_lsap_t ) : 0 ) - ( IS_8023_2_SNAP( flags ) ? sizeof( eth_header_snap_t ) : 0 ))
 
#define ETH_DUMMY_SHIFT 0
#define ETH_MODE_SHIFT 1
 
/** Dummy device flag.
* Preamble and FCS are mandatory part of the packets.
*/
#define ETH_DUMMY ( 1 << ETH_DUMMY_SHIFT )
#define IS_DUMMY( flags ) (( flags ) & ETH_DUMMY )
 
/** Device mode flags.
* @see ETH_DIX
* @see ETH_8023_2_LSAP
* @see ETH_8023_2_SNAP
*/
#define ETH_MODE_MASK ( 3 << ETH_MODE_SHIFT )
#define ETH_DIX ( 1 << ETH_MODE_SHIFT )
#define IS_DIX( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_DIX )
#define ETH_8023_2_LSAP ( 2 << ETH_MODE_SHIFT )
#define IS_8023_2_LSAP( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_8023_2_LSAP )
#define ETH_8023_2_SNAP ( 3 << ETH_MODE_SHIFT )
#define IS_8023_2_SNAP( flags ) ((( flags ) & ETH_MODE_MASK ) == ETH_8023_2_SNAP )
 
typedef enum eth_addr_type eth_addr_type_t;
typedef eth_addr_type_t * eth_addr_type_ref;
 
100,8 → 123,8
int eth_packet_space_message( device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix );
int eth_addr_message( device_id_t device_id, eth_addr_type_t type, measured_string_ref * address );
int eth_send_message( device_id_t device_id, packet_t packet, services_t sender );
eth_proto_ref eth_process_packet( int dummy, packet_t packet );
int eth_prepare_packet( int dummy, packet_t packet, uint8_t * src_addr, int ethertype );
eth_proto_ref eth_process_packet( int flags, packet_t packet );
int eth_prepare_packet( int flags, packet_t packet, uint8_t * src_addr, int ethertype );
 
int nil_device_state_msg( int nil_phone, device_id_t device_id, int state ){
int index;
142,6 → 165,10
 
eth_device_ref device;
int index;
measured_string_t names[ 2 ] = {{ "ETH_MODE", 8 }, { "ETH_DUMMY", 9 }};
measured_string_ref configuration;
int count = 2;
char * data;
 
rwlock_write_lock( & eth_globals.devices_lock );
// an existing device?
162,9 → 189,29
if( ! device ) return ENOMEM;
device->device_id = device_id;
device->service = service;
device->mtu = (( mtu > 0 ) && ( mtu <= ETH_MAX_TAGGED_CONTENT )) ? mtu : ETH_MAX_TAGGED_CONTENT;
// TODO get dummy setting
device->dummy = 0;
device->flags = 0;
device->mtu = (( mtu > 0 ) && ( mtu <= ETH_MAX_TAGGED_CONTENT( device->flags ))) ? mtu : ETH_MAX_TAGGED_CONTENT( device->flags );
configuration = & names[ 0 ];
if( ERROR_OCCURRED( net_get_device_conf_req( eth_globals.net_phone, device->device_id, & configuration, count, & data ))){
rwlock_write_unlock( & eth_globals.devices_lock );
free( device );
return ERROR_CODE;
}
if( configuration ){
if( ! str_lcmp( configuration[ 0 ].value, "DIX", configuration[ 0 ].length )){
device->flags |= ETH_DIX;
}else if( ! str_lcmp( configuration[ 0 ].value, "8023_2_LSAP", configuration[ 0 ].length )){
// TODO 8023_2_LSAP
printf( "8023_2_LSAP is not supported (yet?), DIX used instead\n" );
device->flags |= ETH_DIX;
}else device->flags |= ETH_8023_2_SNAP;
if(( configuration[ 1 ].value ) && ( configuration[ 1 ].value[ 0 ] == 'y' )){
device->flags |= ETH_DUMMY;
}
net_free_settings( configuration, data );
}else{
device->flags |= ETH_8023_2_SNAP;
}
// bind the device driver
device->phone = netif_bind_service( device->service, device->device_id, SERVICE_ETHERNET, eth_receiver );
if( device->phone < 0 ){
187,13 → 234,13
free( device );
return index;
}
printf( "New device registered:\n\tid\t= %d\n\tservice\t= %d\n\tMTU\t= %d\n\taddress\t= %X:%X:%X:%X:%X:%X\n", device->device_id, device->service, device->mtu, device->addr_data[ 0 ], device->addr_data[ 1 ], device->addr_data[ 2 ], device->addr_data[ 3 ], device->addr_data[ 4 ], device->addr_data[ 5 ] );
printf( "New device registered:\n\tid\t= %d\n\tservice\t= %d\n\tMTU\t= %d\n\taddress\t= %X:%X:%X:%X:%X:%X\n\tflags\t= 0x%x\n", device->device_id, device->service, device->mtu, device->addr_data[ 0 ], device->addr_data[ 1 ], device->addr_data[ 2 ], device->addr_data[ 3 ], device->addr_data[ 4 ], device->addr_data[ 5 ], device->flags );
}
rwlock_write_unlock( & eth_globals.devices_lock );
return EOK;
}
 
eth_proto_ref eth_process_packet( int dummy, packet_t packet ){
eth_proto_ref eth_process_packet( int flags, packet_t packet ){
ERROR_DECLARE;
 
eth_header_ex_ref header;
204,17 → 251,17
eth_fcs_ref fcs;
 
length = packet_get_data_length( packet );
if( dummy ){
if( IS_DUMMY( flags )){
packet_trim( packet, sizeof( eth_preamble_t ), 0 );
}
if( length <= sizeof( eth_header_t ) + ETH_MIN_CONTENT + ETH_SUFFIX ) return NULL;
if( length < sizeof( eth_header_t ) + ETH_MIN_CONTENT + ( IS_DUMMY( flags ) ? ETH_SUFFIX : 0 )) return NULL;
header = ( eth_header_ex_ref ) packet_get_data( packet );
type = ntohs( header->header.ethertype );
if( type >= ETH_MIN_PROTO ){
// DIX Ethernet
prefix = sizeof( eth_header_t );
suffix = sizeof( eth_fcs_t );
fcs = (( void * ) header ) + length - suffix;
suffix = 0;
fcs = (( void * ) header ) + length - sizeof( eth_fcs_t );
}else if( type <= ETH_MAX_CONTENT ){
// translate "LSAP" values
if(( header->lsap.dsap == ETH_LSAP_GLSAP ) && ( header->lsap.ssap == ETH_LSAP_GLSAP )){
238,10 → 285,11
// invalid length/type, should not occurr
return NULL;
}
if( dummy ){
if( IS_DUMMY( flags )){
if(( ~ compute_crc32( ~ 0, & header->header.dest, ((( void * ) fcs ) - (( void * ) & header->header.dest )) * 8 )) != ntohl( * fcs )){
return NULL;
}
suffix += sizeof( eth_fcs_t );
}
if( ERROR_OCCURRED( packet_set_addr( packet, header->header.src, header->header.dest, ETH_ADDR ))
|| ERROR_OCCURRED( packet_trim( packet, prefix, suffix ))){
254,7 → 302,7
eth_proto_ref proto;
packet_t next;
eth_device_ref device;
int dummy;
int flags;
 
rwlock_read_lock( & eth_globals.devices_lock );
device = eth_devices_find( & eth_globals.devices, device_id );
262,12 → 310,12
rwlock_read_unlock( & eth_globals.devices_lock );
return ENOENT;
}
dummy = device->dummy;
flags = device->flags;
rwlock_read_unlock( & eth_globals.devices_lock );
rwlock_read_lock( & eth_globals.protos_lock );
do{
next = pq_detach( packet );
proto = eth_process_packet( dummy, packet );
proto = eth_process_packet( flags, packet );
if( proto ){
il_received_msg( proto->phone, device_id, packet, proto->service );
}else{
351,8 → 399,9
return EOK;
}
 
int eth_prepare_packet( int dummy, packet_t packet, uint8_t * src_addr, int ethertype ){
int eth_prepare_packet( int flags, packet_t packet, uint8_t * src_addr, int ethertype ){
eth_header_ex_ref header;
eth_header_ref header_dix;
eth_fcs_ref fcs;
uint8_t * src;
uint8_t * dest;
361,36 → 410,46
void * padding;
eth_preamble_ref preamble;
 
length = packet_get_addr( packet, & src, & dest );
if( length < 0 ) return length;
if( length < ETH_ADDR ) return EINVAL;
length = packet_get_data_length( packet );
if( length > ETH_MAX_TAGGED_CONTENT ) return EINVAL;
if( length < ETH_MIN_TAGGED_CONTENT ){
padding = packet_suffix( packet, ETH_MIN_TAGGED_CONTENT - length );
if( length > ETH_MAX_TAGGED_CONTENT( flags )) return EINVAL;
if( length < ETH_MIN_TAGGED_CONTENT( flags )){
padding = packet_suffix( packet, ETH_MIN_TAGGED_CONTENT( flags ) - length );
if( ! padding ) return ENOMEM;
bzero( padding, ETH_MIN_TAGGED_CONTENT - length );
bzero( padding, ETH_MIN_TAGGED_CONTENT( flags ) - length );
}
if( dummy ){
if( IS_DUMMY( flags )){
preamble = PACKET_PREFIX( packet, eth_preamble_t );
if( ! preamble ) return ENOMEM;
for( i = 0; i < 7; ++ i ) preamble->preamble[ i ] = ETH_PREAMBLE;
preamble->sfd = ETH_SFD;
}
header = PACKET_PREFIX( packet, eth_header_ex_t );
if( ! header ) return ENOMEM;
header->header.ethertype = htons( length + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ));
header->lsap.dsap = ( uint16_t ) ETH_LSAP_SNAP;
header->lsap.ssap = header->lsap.dsap;
header->lsap.ctrl = 0;
for( i = 0; i < 3; ++ i ) header->snap.proto[ i ] = 0;
header->snap.ethertype = ( uint16_t ) ethertype;
length = packet_get_addr( packet, & src, & dest );
if( length < 0 ) return length;
if( length < ETH_ADDR ) return EINVAL;
memcpy( header->header.src, src_addr, ETH_ADDR );
memcpy( header->header.dest, dest, ETH_ADDR );
if( dummy ){
// TODO LSAP only device
if( IS_DIX( flags ) || IS_8023_2_LSAP( flags )){
header_dix = PACKET_PREFIX( packet, eth_header_t );
header_dix->ethertype = ( uint16_t ) ethertype;
memcpy( header_dix->src, src_addr, ETH_ADDR );
memcpy( header_dix->dest, dest, ETH_ADDR );
src = & header_dix->dest[ 0 ];
}else if( IS_8023_2_SNAP( flags )){
header = PACKET_PREFIX( packet, eth_header_ex_t );
if( ! header ) return ENOMEM;
header->header.ethertype = htons( length + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ));
header->lsap.dsap = ( uint16_t ) ETH_LSAP_SNAP;
header->lsap.ssap = header->lsap.dsap;
header->lsap.ctrl = 0;
for( i = 0; i < 3; ++ i ) header->snap.proto[ i ] = 0;
header->snap.ethertype = ( uint16_t ) ethertype;
memcpy( header->header.src, src_addr, ETH_ADDR );
memcpy( header->header.dest, dest, ETH_ADDR );
src = & header->header.dest[ 0 ];
}
if( IS_DUMMY( flags )){
fcs = PACKET_SUFFIX( packet, eth_fcs_t );
if( ! fcs ) return ENOMEM;
* fcs = htonl( ~ compute_crc32( ~ 0, & header->header.dest, ((( void * ) fcs ) - (( void * ) & header->header.dest )) * 8 ));
* fcs = htonl( ~ compute_crc32( ~ 0, src, ((( void * ) fcs ) - (( void * ) src )) * 8 ));
}
return EOK;
}
417,7 → 476,7
// process packet queue
next = packet;
do{
if( ERROR_OCCURRED( eth_prepare_packet( device->dummy, next, ( uint8_t * ) device->addr->value, ethertype ))){
if( ERROR_OCCURRED( eth_prepare_packet( device->flags, next, ( uint8_t * ) device->addr->value, ethertype ))){
// release invalid packet
tmp = pq_detach( next );
pq_release( eth_globals.net_phone, packet_get_id( next ));
470,6 → 529,7
packet_t packet;
 
while( true ){
// printf( "message %d - %d\n", IPC_GET_METHOD( * icall ), NET_NIL_FIRST );
switch( IPC_GET_METHOD( * icall )){
case NET_NIL_DEVICE_STATE:
nil_device_state_msg( 0, IPC_GET_DEVICE( icall ), IPC_GET_STATE( icall ));