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; |
} |
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 )); |
rwlock_write_unlock( & eth_globals.protos_lock ); |
}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; |
} |
|
rwlock_write_lock( & eth_globals.devices_lock ); |
rwlock_write_unlock( & eth_globals.devices_lock ); |
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_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; |
} |
|