Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4074 → Rev 4075

/branches/network/uspace/srv/net/nil/eth/eth.c
48,6 → 48,8
#include "../../modules.h"
 
#include "../../include/byteorder.h"
#include "../../include/crc.h"
#include "../../include/ethernet_lsap.h"
#include "../../include/ethernet_protocols.h"
#include "../../include/protocol_map.h"
#include "../../netif/device.h"
62,10 → 64,9
#include "eth_module.h"
 
#define ETH_PREFIX ( sizeof( eth_header_t ) + sizeof( eth_header_lsap_t ) + sizeof( eth_header_snap_t ))
#define ETH_SUFFIX 4
#define ETH_MAX_CONTENT ( ETH_MIN_PROTO - 1 )
#define ETH_SUFFIX sizeof( eth_fcs_t )
#define ETH_MAX_CONTENT 1500
#define ETH_MIN_CONTENT 46
#define ETH_PADDING ETH_SUFFIX
 
/** Returns the device identifier message parameter.
*/
122,6 → 123,8
int eth_send_message( device_id_t device_id, packet_t packet, services_t sender );
int eth_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count );
void eth_receiver( ipc_callid_t iid, ipc_call_t * icall );
eth_proto_ref eth_proccess_packet( packet_t packet );
int eth_prepare_packet( packet_t packet, uint8_t * src_addr, int ethertype );
 
int eth_initialize( void ){
ERROR_DECLARE;
201,55 → 204,76
return EOK;
}
 
int eth_receive_message( device_id_t device_id, packet_t packet ){
eth_proto_ref eth_proccess_packet( packet_t packet ){
ERROR_DECLARE;
 
eth_header_ex_ref header;
size_t length;
int type;
eth_proto_ref proto;
size_t size;
size_t prefix;
size_t suffix;
eth_fcs_ref fcs;
 
length = packet_get_data_length( packet );
if( length <= sizeof( eth_header_t ) + ETH_MIN_CONTENT + ETH_PADDING ) return EINVAL;
// TODO check CRC padding?
if( length <= sizeof( eth_header_t ) + ETH_MIN_CONTENT + ETH_SUFFIX ) return NULL;
header = ( eth_header_ex_ref ) packet_get_data( packet );
type = ntohs( header->header.ethertype );
if( type >= ETH_MIN_PROTO ){
// DIX Ethernet
size = sizeof( eth_header_t );
}else{
// TODO check length?
prefix = sizeof( eth_header_t );
suffix = sizeof( eth_fcs_t );
fcs = (( void * ) header ) + length - suffix;
}else if( type <= ETH_MAX_CONTENT ){
// translate "LSAP" values
if(( header->lsap.dsap == ETH_RAW ) && ( header->lsap.ssap == ETH_RAW )){
if(( header->lsap.dsap == ETH_LSAP_GLSAP ) && ( header->lsap.ssap == ETH_LSAP_GLSAP )){
// raw packet
// discard
return EINVAL;
return NULL;
}else if(( header->lsap.dsap == ETH_LSAP_SNAP ) && ( header->lsap.ssap == ETH_LSAP_SNAP )){
// IEEE 802.3 SNAP
// IEEE 802.3 + 802.2 + LSAP + SNAP
// organization code not supported
type = ntohs( header->snap.ethertype );
size = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t) + sizeof( eth_header_snap_t);
prefix = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t) + sizeof( eth_header_snap_t);
}else{
// IEEE 802.3 + 802.2 LSAP
// TODO lsap numbers
type = header->lsap.dsap;
size = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t);
type = lsap_map( header->lsap.dsap );
prefix = sizeof( eth_header_t ) + sizeof( eth_header_lsap_t);
}
suffix = ( type < ETH_MIN_CONTENT ) ? ETH_MIN_CONTENT - type : 0;
fcs = (( void * ) header ) + prefix + type + suffix;
suffix += length - prefix - type;
}else{
// invalid length/type, should not occurr
return NULL;
}
rwlock_write_lock( & eth_globals.protos_lock );
proto = eth_protos_find( & eth_globals.protos, type );
if( ! proto ){
rwlock_write_unlock( & eth_globals.protos_lock );
return ENOENT;
// TODO compute crc with fcs to erase?
if(( ~ compute_crc32( ~ 0, & header->header.dest, ((( void * ) fcs ) - (( void * ) & header->header.dest )) * 8 )) != ( * fcs )){
return NULL;
}
if( ERROR_OCCURRED( packet_set_addr( packet, header->header.src, header->header.dest, ETH_ADDR ))
|| ERROR_OCCURRED( packet_trim( packet, size, ETH_PADDING ))){
rwlock_write_unlock( & eth_globals.protos_lock );
return ERROR_CODE;
|| ERROR_OCCURRED( packet_trim( packet, prefix, suffix ))){
return NULL;
}
async_msg_2( proto->phone, NET_IL_RECEIVED, device_id, packet_get_id( packet ));
rwlock_write_unlock( & eth_globals.protos_lock );
return eth_protos_find( & eth_globals.protos, type );
}
 
int eth_receive_message( device_id_t device_id, packet_t packet ){
eth_proto_ref proto;
packet_t next;
 
rwlock_read_lock( & eth_globals.protos_lock );
do{
next = pq_detach( packet );
proto = eth_proccess_packet( packet );
if( proto ){
async_msg_2( proto->phone, NET_IL_RECEIVED, device_id, packet_get_id( packet ));
}else{
// drop invalid/unknown
packet_release( eth_globals.networking_phone, packet_get_id( packet ));
}
packet = next;
}while( packet );
rwlock_read_unlock( & eth_globals.protos_lock );
return EOK;
}
 
267,7 → 291,7
rwlock_write_unlock( & eth_globals.devices_lock );
* addr_len = ETH_ADDR;
* prefix = ETH_PREFIX;
* suffix = ETH_SUFFIX;
* suffix = ETH_MIN_CONTENT + ETH_SUFFIX;
return EOK;
}
 
323,15 → 347,14
return EOK;
}
 
int eth_send_message( device_id_t device_id, packet_t packet, services_t sender ){
ERROR_DECLARE;
 
eth_device_ref device;
int eth_prepare_packet( packet_t packet, uint8_t * src_addr, int ethertype ){
eth_header_ex_ref header;
eth_fcs_ref fcs;
uint8_t * src;
uint8_t * dest;
int length;
int i;
void * padding;
 
header = PACKET_PREFIX( packet, eth_header_ex_t );
if( ! header ) return ENOMEM;
340,12 → 363,14
length = packet_get_addr( packet, & src, & dest );
if( length < 0 ) return length;
if( length < ETH_ADDR ) return EINVAL;
// TODO src set?
// TODO set addresses
memcpy( header->header.src, src_addr, ETH_ADDR );
memcpy( & header->header.dest, dest, ETH_ADDR );
length = packet_get_data_length( packet );
if( length > ETH_MAX_CONTENT ) return EINVAL;
if( length < ETH_MIN_CONTENT ){
// TODO pad zeros
padding = packet_suffix( packet, ETH_MIN_CONTENT - length );
if( ! padding ) return ENOMEM;
memset( padding, 0, ETH_MIN_CONTENT - length );
}
header->header.ethertype = htons( length );
header->lsap.dsap = 0xAA;
352,15 → 377,47
header->lsap.ssap = header->lsap.dsap;
header->lsap.ctrl = 0;
for( i = 0; i < 3; ++ i ) header->snap.proto[ i ] = 0;
header->snap.ethertype = htons( protocol_map( SERVICE_ETHERNET, sender ));
if( ! header ) return ENOENT;
// TODO eth padding
if( ! packet_suffix( packet, ETH_PADDING )){
return ENOMEM;
header->snap.ethertype = ethertype;
fcs = PACKET_SUFFIX( packet, eth_fcs_t );
if( ! fcs ) return ENOMEM;
* fcs = ~ compute_crc32( ~ 0, & header->header.dest, ((( void * ) fcs ) - (( void * ) & header->header.dest )) * 8 );
return EOK;
}
 
int eth_send_message( device_id_t device_id, packet_t packet, services_t sender ){
ERROR_DECLARE;
 
eth_device_ref device;
packet_t next;
packet_t tmp;
int ethertype;
 
ethertype = htons( protocol_map( SERVICE_ETHERNET, sender ));
if( ! ethertype ){
packet_release( eth_globals.networking_phone, packet_get_id( packet ));
return EINVAL;
}
rwlock_write_lock( & eth_globals.devices_lock );
rwlock_write_unlock( & eth_globals.devices_lock );
rwlock_read_lock( & eth_globals.devices_lock );
device = eth_devices_find( & eth_globals.devices, device_id );
if( ! device ){
rwlock_read_unlock( & eth_globals.devices_lock );
return ENOENT;
}
// proccess packet queue
next = packet;
do{
if( ERROR_OCCURRED( eth_prepare_packet( next, ( uint8_t * ) device->addr->value, ethertype ))){
// release invalid packet
tmp = pq_detach( next );
packet_release( eth_globals.networking_phone, packet_get_id( next ));
next = tmp;
}else{
next = pq_next( next );
}
}while( next );
// send packet queue
async_msg_2( device->phone, NET_NETIF_SEND, device_id, packet_get_id( packet ));
rwlock_read_unlock( & eth_globals.devices_lock );
return EOK;
}