2024-01-02 12:42:48 +03:00
// SPDX-License-Identifier: MIT
/**************************************************************************************
*
* Copyright ( c ) 2024 , Hilscher Gesellschaft fuer Systemautomation mbH . All Rights Reserved .
*
* Description : Implementation of the netX virtual network interface .
*
* Changes :
*
* Version Date Author Description
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 1 02.01 .24 SD changed licensing terms
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef CIFXETHERNET
# include <sys/ioctl.h>
# include <sys/select.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <string.h>
# include <malloc.h>
# include <pthread.h>
# include <unistd.h>
# include <stdlib.h>
# include <arpa/inet.h>
# include <errno.h>
# include <sys/socket.h>
# include <stdio.h>
# include <ctype.h>
# include <dirent.h>
# include <time.h>
# include <sys/queue.h>
# include <netlink/cli/utils.h>
# include <netlink/cli/link.h>
# include "Hil_Packet.h"
# include "Hil_Results.h"
# include "Hil_ApplicationCmd.h"
# include "DrvEth_GCI_API.h"
# include "cifXUser.h"
# include "cifXErrors.h"
# include "cifXHWFunctions.h"
# include "netx_tap.h"
# define TUNTAP_DEVICEPATH " / dev / net / tun"
# define SEND_RETRIES 0
# define LINK_STATE_POLL_INTERVAL 5 /* in seconds */
void * g_eth_list_lock ;
typedef struct NETX_ETH_DEV_Ttag
{
TAILQ_ENTRY ( NETX_ETH_DEV_Ttag ) lentry ;
int eth_fd ;
char cifxeth_name [ CIFX_MAX_FILE_NAME_LENGTH ] ;
char event_path [ CIFX_MAX_FILE_NAME_LENGTH ] ;
NETX_ETH_DEV_CFG_T config ;
CIFXHANDLE cifx_driver ;
CIFXHANDLE cifx_channel ;
PDEVICEINSTANCE devinst ;
uint32_t channel_no ;
pthread_t eth_to_cifx_thread ;
pthread_t cifx_to_eth_thread ;
int stop_to_eth ;
int stop_to_cifx ;
void * com_lock ;
void * send_event ;
uint32_t active_sends ;
uint32_t send_packets ;
uint32_t recv_packets ;
int link_up ;
void * link_event ;
} NETX_ETH_DEV_T ;
static TAILQ_HEAD ( , NETX_ETH_DEV_Ttag ) s_DeviceList = TAILQ_HEAD_INITIALIZER ( s_DeviceList ) ;
static int32_t cifxeth_search_eth_channel ( char * szDeviceName , uint32_t ulSearchIdx , uint32_t * pulChannelNumber ) ;
static int cifxeth_allocate_tap ( NETX_ETH_DEV_T * internal_dev , char * prefix ) ;
static void cifxeth_free_tap ( NETX_ETH_DEV_T * internal_dev , char * name ) ;
static void cifxeth_delete_device ( NETX_ETH_DEV_T * internal_dev ) ;
static int32_t cifxeth_register_app ( NETX_ETH_DEV_T * internal_dev , int fRegister ) ;
static int cifxeth_create_com_thread ( NETX_ETH_DEV_T * internal_dev ) ;
static int cifxeth_create_cifx_thread ( NETX_ETH_DEV_T * internal_dev ) ;
static int32_t cifxeth_update_device_config ( NETX_ETH_DEV_T * internal_dev ) ;
static int32_t cifxeth_update_link_state ( NETX_ETH_DEV_T * internal_dev ) ;
static int32_t cifxeth_get_extended_info ( NETX_ETH_DEV_T * internal_dev , uint32_t ulInformationRequest , void * pvBuffer , uint32_t ulBufLen ) ;
static void * eth_to_cifx_thread ( void * arg ) ;
static void * cifx_to_eth_thread ( void * arg ) ;
static NETX_ETH_DEV_T * find_device ( char * name ) ;
struct nl_link_arg {
struct rtnl_link * change ;
struct nl_sock * sock ;
NETX_ETH_DEV_T * priv ;
} ;
static void set_cb ( struct nl_object * obj , void * arg )
{
struct rtnl_link * link = nl_object_priv ( obj ) ;
struct nl_link_arg * link_arg = arg ;
if ( rtnl_link_change ( link_arg - > sock , link , link_arg - > change , 0 ) )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( link_arg - > priv - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Link-update failed for %s " , link_arg - > priv - > cifxeth_name ) ;
}
}
}
void nl_signal_link_change ( NETX_ETH_DEV_T * internal_dev , int state ) {
struct nl_sock * sock ;
struct nl_cache * link_cache ;
struct rtnl_link * link , * change ;
struct nl_link_arg link_arg ;
if ( NULL = = ( sock = nl_cli_alloc_socket ( ) ) )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Link-update failed - failed to allocate socket " , internal_dev - > cifxeth_name ) ;
}
return ;
}
if ( 0 = = nl_cli_connect ( sock , NETLINK_ROUTE ) )
{
link_cache = nl_cli_link_alloc_cache ( sock ) ;
link = nl_cli_link_alloc ( ) ;
change = nl_cli_link_alloc ( ) ;
nl_cli_link_parse_name ( link , internal_dev - > cifxeth_name ) ;
if ( state ! = 0 ) {
rtnl_link_set_flags ( change , IFF_UP ) ;
} else {
rtnl_link_unset_flags ( change , IFF_UP ) ;
}
link_arg . sock = sock ;
link_arg . change = change ;
link_arg . priv = internal_dev ;
nl_cache_foreach_filter ( link_cache , OBJ_CAST ( link ) , set_cb , & link_arg ) ;
} else
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Link-update failed - failed to connect socket " , internal_dev - > cifxeth_name ) ;
}
}
}
/*****************************************************************************/
/*! This function creates a netX based ethernet interface
* \ param config pointer to configuration structure
* \ return ! = NULL on success */
/*****************************************************************************/
void * cifxeth_create_device ( NETX_ETH_DEV_CFG_T * config )
{
NETX_ETH_DEV_T * internal_dev = NULL ;
void * ret = NULL ;
int32_t cifx_error = CIFX_NO_ERROR ;
int32_t search_error = CIFX_NO_ERROR ;
uint32_t channel_no = 0 ;
uint32_t eth_no = 0 ;
int err = 0 ;
if ( NULL = = config )
goto exit ;
if ( NULL ! = find_device ( config - > cifx_name ) )
return NULL ;
/* try to find a channel providing an ethernet interface */
while ( CIFX_NO_ERROR = = ( search_error = cifxeth_search_eth_channel ( config - > cifx_name , channel_no , & channel_no ) ) )
{
if ( NULL ! = ( internal_dev = ( NETX_ETH_DEV_T * ) OS_Memalloc ( sizeof ( * internal_dev ) ) ) )
{
OS_Memset ( internal_dev , 0 , sizeof ( NETX_ETH_DEV_T ) ) ;
if ( NULL = = ( internal_dev - > com_lock = OS_CreateLock ( ) ) )
{
OS_Memfree ( internal_dev ) ;
goto exit ;
} else if ( NULL = = ( internal_dev - > send_event = OS_CreateEvent ( ) ) )
{
OS_DeleteLock ( internal_dev - > com_lock ) ;
OS_Memfree ( internal_dev ) ;
goto exit ;
} else if ( NULL = = ( internal_dev - > link_event = OS_CreateEvent ( ) ) )
{
OS_DeleteEvent ( internal_dev - > send_event ) ;
OS_DeleteLock ( internal_dev - > com_lock ) ;
OS_Memfree ( internal_dev ) ;
goto exit ;
}
internal_dev - > channel_no = channel_no ;
if ( CIFX_NO_ERROR ! = ( cifx_error = xDriverOpen ( & internal_dev - > cifx_driver ) ) )
{
fprintf ( stderr , " Ethernet-IF Error: %s: Error opening cifX Device Driver (Ret=0x%08X) \n " , __TIME__ , cifx_error ) ;
} else if ( CIFX_NO_ERROR = = ( cifx_error = xChannelOpen ( internal_dev - > cifx_driver ,
config - > cifx_name ,
internal_dev - > channel_no ,
& internal_dev - > cifx_channel ) ) )
{
char prefix [ CIFX_MAX_FILE_NAME_LENGTH ] ;
CIFX_PACKET tDummy ;
uint32_t i = 0 ;
PCHANNELINSTANCE ptdevice = ( PCHANNELINSTANCE ) internal_dev - > cifx_channel ;
internal_dev - > devinst = ( PDEVICEINSTANCE ) ptdevice - > pvDeviceInstance ;
/* in case there are remaining packages try to empty mailbox */
for ( i = 0 ; i < 16 ; i + + ) {
if ( CIFX_NO_ERROR ! = xChannelGetPacket ( internal_dev - > cifx_channel , sizeof ( tDummy ) , & tDummy , 50 ) )
break ;
}
OS_Memcpy ( & internal_dev - > config , config , sizeof ( internal_dev - > config ) ) ;
strcpy ( internal_dev - > config . cifx_name , config - > cifx_name ) ;
strcpy ( prefix , config - > cifx_name ) ;
for ( i = 0 ; i < strlen ( config - > cifx_name ) ; i + + )
prefix [ i ] = tolower ( prefix [ i ] ) ;
internal_dev - > eth_fd = - 1 ;
if ( ( internal_dev - > eth_fd = cifxeth_allocate_tap ( internal_dev , prefix ) ) < 0 )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error allocating tap device for '%s'. Error=%d " , config - > cifx_name , internal_dev - > eth_fd ) ;
}
} else
{
/* signal link down since TAP device is up by default */
nl_signal_link_change ( internal_dev , 0 ) ;
eth_no + + ;
strcpy ( config - > eth_dev_name , internal_dev - > cifxeth_name ) ;
if ( g_ulTraceLevel & TRACE_LEVEL_INFO )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_INFO , " Ethernet-IF Info: Successfully created '%s' at channel %d on device '%s' " , internal_dev - > cifxeth_name , channel_no , config - > cifx_name ) ;
}
/* de-register application since may not be de-registered */
cifxeth_register_app ( internal_dev , 0 ) ;
/* Register for ethernet service on device */
if ( CIFX_NO_ERROR = = ( cifxeth_register_app ( internal_dev , 1 ) ) )
{
/* Create threads for packet exchange */
if ( cifxeth_create_cifx_thread ( internal_dev ) ! = 0 )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error creating cifX ethernet channel thread for %s. " , internal_dev - > cifxeth_name ) ;
}
} else
{
/* Set device MAC address from response packet */
//cifxeth_update_device_config( internal_dev);
/* Device successfully created */
OS_EnterLock ( g_eth_list_lock ) ;
2024-03-21 16:05:25 +03:00
TAILQ_INSERT_TAIL ( & s_DeviceList , internal_dev , lentry ) ;
ret = internal_dev ;
2024-01-02 12:42:48 +03:00
OS_LeaveLock ( g_eth_list_lock ) ;
2024-03-21 16:05:25 +03:00
return ret ;
2024-01-02 12:42:48 +03:00
}
}
}
} else
{
fprintf ( stderr , " Ethernet-IF Error: %s: Error opening cifX Ethernet Channel (Board=%s, Channel=%u, Errror=0x%08X) \n " , __TIME__ ,
config - > cifx_name , internal_dev - > channel_no , cifx_error ) ;
}
if ( NULL = = ret )
{
cifxeth_delete_device ( internal_dev ) ;
}
2024-03-21 16:05:25 +03:00
} else
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Not enough memory to create cifx virtual ethernet interface! " ) ;
}
2024-01-02 12:42:48 +03:00
}
channel_no + + ;
}
exit :
return ret ;
}
/*****************************************************************************/
/*! This removes a previously with cifxeth_create_device() created netX based ethernet interface
* The function requires either a handle or config structure containing the name of the cifX device
* \ param devicehandle pointer to handle returned by cifxeth_create_device ( )
* \ param config pointer to configuration structure
* \ return ! = NULL on success */
/*****************************************************************************/
void cifxeth_remove_device ( void * devicehandle , NETX_ETH_DEV_CFG_T * config )
{
NETX_ETH_DEV_T * internal_dev = ( NETX_ETH_DEV_T * ) devicehandle ;
if ( ( NULL = = internal_dev ) & & ( NULL = = config ) )
return ;
if ( ( NULL ! = internal_dev ) | | ( NULL ! = ( internal_dev = find_device ( config - > cifx_name ) ) ) )
{
cifxeth_delete_device ( internal_dev ) ;
}
}
/*****************************************************************************/
/*! This function empties mailbox
* \ param internal_dev pointer to internal netx - ethernet device */
/*****************************************************************************/
void empty_mailbox ( NETX_ETH_DEV_T * internal_dev ) {
uint32_t ulRecvPktCount = 0 ;
uint32_t ulSendPktCount = 0 ;
int32_t lRet = 0 ;
if ( ( internal_dev = = NULL ) | | ( internal_dev - > cifx_channel = = NULL ) )
return ;
lRet = xChannelGetMBXState ( internal_dev - > cifx_channel , & ulRecvPktCount , & ulSendPktCount ) ;
while ( ( lRet = = CIFX_NO_ERROR ) & & ( ulRecvPktCount > 0 ) ) {
CIFX_PACKET cifx_packet ;
lRet = xChannelGetPacket ( internal_dev - > cifx_channel , sizeof ( cifx_packet ) , & cifx_packet , CIFX_TO_CONT_PACKET ) ;
if ( lRet = = CIFX_NO_ERROR )
lRet = xChannelGetMBXState ( internal_dev - > cifx_channel , & ulRecvPktCount , & ulSendPktCount ) ;
}
}
/*****************************************************************************/
/*! This function deletes netX based ethernet interface
* \ param internal_dev pointer to internal netx - ethernet device
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
static void cifxeth_delete_device ( NETX_ETH_DEV_T * internal_dev )
{
if ( NULL ! = internal_dev )
{
if ( 0 ! = internal_dev - > eth_to_cifx_thread ) {
internal_dev - > stop_to_cifx = 1 ;
pthread_join ( internal_dev - > eth_to_cifx_thread , NULL ) ;
}
if ( 0 ! = internal_dev - > cifx_to_eth_thread ) {
internal_dev - > stop_to_eth = 1 ;
pthread_join ( internal_dev - > cifx_to_eth_thread , NULL ) ;
}
if ( internal_dev - > cifx_channel ! = NULL )
cifxeth_register_app ( internal_dev , 0 ) ;
/* remove any pending packets */
empty_mailbox ( internal_dev ) ;
cifxeth_free_tap ( internal_dev , internal_dev - > cifxeth_name ) ;
if ( NULL ! = internal_dev - > link_event )
OS_DeleteEvent ( internal_dev - > link_event ) ;
if ( NULL ! = internal_dev - > com_lock )
OS_DeleteLock ( internal_dev - > com_lock ) ;
if ( NULL ! = internal_dev - > send_event )
OS_DeleteEvent ( internal_dev - > send_event ) ;
if ( NULL ! = internal_dev - > cifx_channel )
xChannelClose ( internal_dev - > cifx_channel ) ;
if ( NULL ! = internal_dev - > cifx_driver )
xDriverClose ( internal_dev - > cifx_driver ) ;
OS_EnterLock ( g_eth_list_lock ) ;
if ( ! TAILQ_EMPTY ( & s_DeviceList ) ) {
TAILQ_REMOVE ( & s_DeviceList , internal_dev , lentry ) ;
OS_Memfree ( internal_dev ) ;
}
OS_LeaveLock ( g_eth_list_lock ) ;
}
}
/*****************************************************************************/
/*! removes all cifx tap devices reside in /sys/class/net */
/*****************************************************************************/
void cifxeth_sys_cleanup ( void ) {
struct dirent * * namelist ;
int num_virt_eth ;
num_virt_eth = scandir ( " /sys/class/net/ " , & namelist , 0 , alphasort ) ;
if ( num_virt_eth > 0 )
{
int currenteth ;
for ( currenteth = 0 ; currenteth < num_virt_eth ; + + currenteth )
{
if ( 0 = = strncmp ( " cifx " , namelist [ currenteth ] - > d_name , 4 ) ) {
cifxeth_free_tap ( NULL , namelist [ currenteth ] - > d_name ) ;
}
free ( namelist [ currenteth ] ) ;
}
free ( namelist ) ;
}
}
static int is_ethernet_channel ( HIL_DPM_CHANNEL_INFO_BLOCK_T * ptChannel ) {
int ret = 0 ;
if ( HIL_COMM_CLASS_MESSAGING = = ptChannel - > tCom . usCommunicationClass ) {
if ( HIL_PROT_CLASS_ETHERNET = = ptChannel - > tCom . usProtocolClass ) {
/* old identification */
ret = 1 ;
} else if ( ( HIL_PROT_CLASS_NETWORK_SERVICES = = ptChannel - > tCom . usProtocolClass ) & &
( ptChannel - > tCom . usProtocolConformanceClass & HIL_CONF_CLASS_FLAG_NDIS_AWARE ) ) {
/* new identification */
ret = 1 ;
}
}
return ret ;
}
/*****************************************************************************/
/*! This function searches a cifx device for an existing Ethernet channel
* \ param szDeviceName name of the cifX device
* \ param ulSearchIdx Start index for channel information search
* \ param ulSearchIdx pointer to channel providing ethernet interface
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
int32_t cifxeth_search_eth_channel ( char * szDeviceName ,
uint32_t ulSearchIdx ,
uint32_t * pulChannelNumber )
{
int32_t lRet = CIFX_NO_ERROR ;
CIFXHANDLE hSysdevice = NULL ;
CIFXHANDLE hDriver = NULL ;
PCHANNELINSTANCE ptdevice = NULL ;
PDEVICEINSTANCE ptDevInst = NULL ;
if ( ulSearchIdx > = CIFX_MAX_NUMBER_OF_CHANNELS )
return CIFX_INVALID_PARAMETER ;
if ( CIFX_NO_ERROR ! = xDriverOpen ( & hDriver ) )
{
fprintf ( stderr , " Ethernet-IF Error: %s: Error opening driver to for ethernet interface (lRet=0x%08X) \n " , __TIME__ , lRet ) ;
/* Check if we have a channel that might be used for Ethernet / NDIS */
} else if ( CIFX_NO_ERROR ! = ( lRet = xSysdeviceOpen ( hDriver ,
szDeviceName ,
& hSysdevice ) ) )
{
fprintf ( stderr , " Ethernet-IF Error: %s: Error opening system device to read channel info block to detect channels usable for ethernet interface (lRet=0x%08X). - %s \n " , __TIME__ , lRet , szDeviceName ) ;
} else
{
/* Read channel information block */
SYSTEM_CHANNEL_CHANNEL_INFO_BLOCK tChannelInfoBlock = { { { 0 } } } ;
ptdevice = ( PCHANNELINSTANCE ) hSysdevice ;
ptDevInst = ( PDEVICEINSTANCE ) ptdevice - > pvDeviceInstance ;
if ( CIFX_NO_ERROR ! = ( lRet = xSysdeviceInfo ( hSysdevice ,
CIFX_INFO_CMD_SYSTEM_CHANNEL_BLOCK ,
sizeof ( tChannelInfoBlock ) ,
& tChannelInfoBlock ) ) )
{
/* Error reading system info block */
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( ptDevInst ,
TRACE_LEVEL_ERROR ,
" Ethernet-IF Error: Error reading channel info block to detect channels usable for ethernet interface (lRet=0x%08X). " ,
lRet ) ;
}
} else
{
uint32_t ulStartIndex = 0 ;
int fComChannelFound = 0 ;
if ( ulSearchIdx > = ptDevInst - > ulCommChannelCount )
return CIFX_INVALID_PARAMETER ;
for ( ; ulStartIndex < CIFX_MAX_NUMBER_OF_CHANNELS ; + + ulStartIndex )
{
HIL_DPM_CHANNEL_INFO_BLOCK_T * ptChannel = ( HIL_DPM_CHANNEL_INFO_BLOCK_T * ) & tChannelInfoBlock . abInfoBlock [ ulStartIndex ] [ 0 ] ;
if ( ( HIL_CHANNEL_TYPE_COMMUNICATION = = ptChannel - > tHandshake . bChannelType ) )
{
if ( DEV_IsReady ( ptDevInst - > pptCommChannels [ ulSearchIdx ] ) )
{
fComChannelFound = 1 ;
lRet = CIFX_NO_ERROR ;
break ;
} else
{
lRet = CIFX_DEV_NOT_READY ;
}
}
}
lRet = CIFX_INVALID_BOARD ;
/* Check system info block entries */
for ( ; ( fComChannelFound & & ( ( ulSearchIdx + ulStartIndex ) < CIFX_MAX_NUMBER_OF_CHANNELS ) ) ; + + ulSearchIdx )
{
HIL_DPM_CHANNEL_INFO_BLOCK_T * ptChannel = ( HIL_DPM_CHANNEL_INFO_BLOCK_T * ) & tChannelInfoBlock . abInfoBlock [ ulSearchIdx + ulStartIndex ] [ 0 ] ;
if ( is_ethernet_channel ( ptChannel ) )
{
/* only create a NDIS interface if the interface is not created already */
if ( NULL ! = pulChannelNumber )
* pulChannelNumber = ulSearchIdx ;
lRet = CIFX_NO_ERROR ;
break ;
}
}
}
/* Close system device */
xSysdeviceClose ( hSysdevice ) ;
}
xDriverClose ( hDriver ) ;
return lRet ;
}
/*****************************************************************************/
/*! This function allocates and initializes a tap device
* \ param internal_dev pointer to internal netx - ethernet device
* \ param prefix prefix of the device ( e . g . " cifX " - > cifX [ x ] )
* \ param dev returns the name of created device ( - > cifX [ x ] )
* \ return a valid file descriptor to the device - on success ( > = 0 ) */
/*****************************************************************************/
static int cifxeth_allocate_tap ( NETX_ETH_DEV_T * internal_dev , char * prefix )
{
struct ifreq ifr ;
int ret ;
if ( ( ret = open ( TUNTAP_DEVICEPATH , O_RDWR ) ) > = 0 )
{
int err ;
memset ( & ifr , 0 , sizeof ( ifr ) ) ;
ifr . ifr_flags = ( IFF_TAP | IFF_NO_PI ) ;
if ( prefix )
strncpy ( ifr . ifr_name , prefix , IFNAMSIZ ) ;
if ( ( err = ioctl ( ret , TUNSETIFF , ( void * ) & ifr ) ) < 0 )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error creating tap device (TUNSETIFF) '%s'. Error=%d " , prefix , errno ) ;
}
close ( ret ) ;
ret = err ;
} else
{
strcpy ( internal_dev - > cifxeth_name , prefix ) ;
sprintf ( internal_dev - > event_path , " /sys/class/net/%s/uevent " , prefix ) ;
internal_dev - > eth_fd = ret ; /* set temp. since cifxeth_update_device_config() deals with that handle */
cifxeth_update_device_config ( internal_dev ) ;
}
} else
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error opening tun interface '%s'. Error=%d " , TUNTAP_DEVICEPATH , errno ) ;
}
ret = - errno ;
}
return ret ;
}
/*****************************************************************************/
/*! This function frees a tap device
* \ param internal_dev pointer to internal netx - ethernet device
* \ param name name of device in case device is already closed ( - > link down ) */
/*****************************************************************************/
void cifxeth_free_tap ( NETX_ETH_DEV_T * internal_dev , char * name ) {
if ( NULL ! = internal_dev ) {
if ( internal_dev - > eth_fd > = 0 ) {
ioctl ( internal_dev - > eth_fd , TUNSETPERSIST , 0 ) ;
close ( internal_dev - > eth_fd ) ;
internal_dev - > eth_fd = - 1 ;
}
}
/* we have also check the name, in case of link down the handle is '-1' */
if ( name ! = NULL ) {
struct ifreq ifr ;
int ret ;
if ( ( ret = open ( TUNTAP_DEVICEPATH , O_RDWR ) ) ) {
memset ( & ifr , 0 , sizeof ( ifr ) ) ;
ifr . ifr_flags = ( IFF_TAP | IFF_NO_PI ) ;
strncpy ( ifr . ifr_name , name , IFNAMSIZ ) ;
ioctl ( ret , TUNSETIFF , ( void * ) & ifr ) ;
ioctl ( ret , TUNSETPERSIST , 0 ) ;
close ( ret ) ;
}
}
}
/*****************************************************************************/
/*! This function creates send/receivce thread
* \ param internal_dev pointer to internal cifx eth channel
* \ return > 0 on success */
/*****************************************************************************/
static int cifxeth_create_cifx_thread ( NETX_ETH_DEV_T * internal_dev )
{
int ret = - 1 ;
pthread_attr_t attr ;
internal_dev - > stop_to_eth = 0 ;
if ( 0 = = ( ret = pthread_attr_init ( & attr ) ) )
{
ret = pthread_create ( & internal_dev - > cifx_to_eth_thread ,
& attr ,
cifx_to_eth_thread ,
internal_dev ) ;
}
return ret ;
}
/*****************************************************************************/
/*! This function creates send/receivce thread
* \ param internal_dev pointer to internal netx - ethernet device
* \ return > 0 on success */
/*****************************************************************************/
static int cifxeth_create_com_thread ( NETX_ETH_DEV_T * internal_dev )
{
int ret = - 1 ;
pthread_attr_t attr ;
internal_dev - > stop_to_cifx = 0 ;
if ( 0 = = ( ret = pthread_attr_init ( & attr ) ) )
{
ret = pthread_create ( & internal_dev - > eth_to_cifx_thread ,
& attr ,
eth_to_cifx_thread ,
internal_dev ) ;
}
return ret ;
}
/*****************************************************************************/
/*! Send thread: processes eth packets from tapX to cifX device
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
static void * eth_to_cifx_thread ( void * arg )
{
NETX_ETH_DEV_T * internal_dev = ( NETX_ETH_DEV_T * ) arg ;
int fd = internal_dev - > eth_fd ;
char buffer [ 1514 ] ;
DRVETH_GCI_SEND_ETH_FRAME_PCK_T cifx_packet ;
int select_ret = 0 ;
memset ( & cifx_packet . tReq . tHead , 0 , sizeof ( cifx_packet . tReq . tHead ) ) ;
cifx_packet . tReq . tHead . ulCmd = DRVETH_GCI_CMD_SEND_ETH_FRAME_REQ ;
cifx_packet . tReq . tHead . ulDest = HIL_PACKET_DEST_DEFAULT_CHANNEL ;
while ( 1 )
{
fd_set readfds , exceptfds ;
struct timeval timeout = { 0 } ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 500 * 1000 ; /* Default wait timeout = 500ms */
FD_ZERO ( & readfds ) ;
FD_ZERO ( & exceptfds ) ;
FD_SET ( fd , & readfds ) ;
FD_SET ( fd , & exceptfds ) ;
/* check link state */
while ( 0 = = internal_dev - > link_up )
{
OS_WaitEvent ( internal_dev - > link_event , 10 ) ;
if ( internal_dev - > stop_to_cifx = = 1 )
break ;
}
if ( ( select_ret = select ( fd + 1 , & readfds , NULL , & exceptfds , & timeout ) ) > 0 )
{
if ( FD_ISSET ( fd , & exceptfds ) )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Exception on Ethernet Device file descriptor, exiting thread " ) ;
}
break ;
}
if ( FD_ISSET ( fd , & readfds ) )
{
int32_t cifx_error ;
ssize_t recv_len ;
int retry = 0 ;
recv_len = read ( fd , buffer , sizeof ( buffer ) ) ;
while ( internal_dev - > active_sends > 0x08 )
{
OS_WaitEvent ( internal_dev - > send_event , 10 ) ;
if ( internal_dev - > stop_to_cifx = = 1 )
break ;
}
if ( internal_dev - > stop_to_cifx = = 1 )
break ;
if ( recv_len > 0 )
{
memcpy ( & cifx_packet . tReq . tData , buffer , recv_len ) ;
cifx_packet . tReq . tHead . ulLen = recv_len ;
if ( recv_len < 60 )
{
memset ( ( cifx_packet . tReq . tData . abData + recv_len ) , 0 , ( 60 - recv_len ) ) ;
cifx_packet . tReq . tHead . ulLen = 60 ;
}
retry = SEND_RETRIES ;
do {
cifx_error = xChannelPutPacket ( internal_dev - > cifx_channel , ( CIFX_PACKET * ) & cifx_packet , CIFX_TO_CONT_PACKET ) ;
if ( cifx_error = = CIFX_NO_ERROR ) {
OS_EnterLock ( internal_dev - > com_lock ) ;
internal_dev - > active_sends + + ;
OS_LeaveLock ( internal_dev - > com_lock ) ;
}
} while ( ( cifx_error = = CIFX_DEV_MAILBOX_FULL ) & & ( retry - - > 0 ) ) ;
if ( ( g_ulTraceLevel & TRACE_LEVEL_DEBUG ) & & ( ( SEND_RETRIES - retry ) ! = SEND_RETRIES ) )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_DEBUG , " Ethernet-IF Error: Sending a packet took %d-%dms)! " , ( SEND_RETRIES - retry + 1 ) * CIFX_TO_CONT_PACKET , ( SEND_RETRIES - retry ) * CIFX_TO_CONT_PACKET ) ;
}
if ( CIFX_NO_ERROR ! = cifx_error )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error sending packet to cifX Device. (Error=0x%08X) " , cifx_error ) ;
}
}
}
}
} else if ( 0 = = select_ret )
{
//continue;
} else
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error on select/or stop requested for Ethernet Device file descriptor, exiting thread " ) ;
}
break ;
}
if ( internal_dev - > stop_to_cifx = = 1 )
break ;
}
return NULL ;
}
/*****************************************************************************/
/*! send confirmation of the packet
* \ param internal_dev Pointer to internal device
* \ param ptPacket Pointer to packet to handle
* \ param ulTimeout timeout
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
int32_t send_confirmation ( NETX_ETH_DEV_T * internal_dev , CIFX_PACKET * ptPacket , uint32_t ulState , uint32_t ulTimeout ) {
int32_t ret = CIFX_NO_ERROR ;
if ( ptPacket = = NULL )
return CIFX_NO_ERROR ;
if ( ( ptPacket - > tHeader . ulCmd & CIFX_MSK_PACKET_ANSWER ) = = 0 ) {
uint8_t bRetry = 3 ;
ptPacket - > tHeader . ulCmd | = CIFX_MSK_PACKET_ANSWER ;
ptPacket - > tHeader . ulState = ulState ;
ptPacket - > tHeader . ulLen = 0 ;
do {
ret = xChannelPutPacket ( internal_dev - > cifx_channel , ptPacket , ulTimeout ) ;
} while ( ( ret ! = CIFX_NO_ERROR ) & & ( bRetry - - > 0 ) ) ;
if ( ( ret ! = CIFX_NO_ERROR ) & & ( g_ulTraceLevel & TRACE_LEVEL_ERROR ) ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Failed to send confirmation - Error=0x%X (ulCmd=0x%X / ulState=0x%X)! \n " ,
ret ,
ptPacket - > tHeader . ulCmd ,
ptPacket - > tHeader . ulState ) ;
}
}
return ret ;
}
/*****************************************************************************/
/*! handles incoming packets
* \ param internal_dev Pointer to internal device
* \ param ptPacket Pointer to packet to handle
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
void handle_incoming_packet ( NETX_ETH_DEV_T * internal_dev , CIFX_PACKET * ptPacket ) {
uint32_t ulState = 0 ;
switch ( ptPacket - > tHeader . ulCmd ) {
case DRVETH_GCI_CMD_SEND_ETH_FRAME_CNF :
/* Send response */
OS_EnterLock ( internal_dev - > com_lock ) ;
internal_dev - > active_sends - - ;
OS_SetEvent ( internal_dev - > send_event ) ;
OS_LeaveLock ( internal_dev - > com_lock ) ;
if ( ptPacket - > tHeader . ulState ! = CIFX_NO_ERROR ) {
if ( g_ulTraceLevel & TRACE_LEVEL_WARNING ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_WARNING , " Ethernet-IF Error: Error signaled by confirmation packet (0x%X) \n " , ptPacket - > tHeader . ulState ) ;
}
}
break ;
case DRVETH_GCI_CMD_RECV_ETH_FRAME_IND :
{
if ( internal_dev - > link_up ) {
uint32_t data_len = ptPacket - > tHeader . ulLen ;
ssize_t send_res = data_len ;
int ret = 0 ;
/* New RX packet */
if ( send_res ! = ( ret = write ( internal_dev - > eth_fd , ptPacket - > abData , data_len ) ) ) {
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error sending incoming data to ethernet device (%d) \n " , ret ) ;
}
}
}
}
break ;
case DRVETH_GCI_CMD_EVENT_IND :
{
/* ignore package since we poll the link state */
}
break ;
default :
{
ulState = ERR_HIL_UNKNOWN_COMMAND ;
if ( g_ulTraceLevel & TRACE_LEVEL_INFO ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_INFO , " Ethernet-IF Error: Error receiving unknown packet cmd=0x%X \n " , ptPacket - > tHeader . ulCmd ) ;
}
}
break ;
}
send_confirmation ( internal_dev , ptPacket , ulState , CIFX_TO_CONT_PACKET ) ;
}
/*****************************************************************************/
/*! Receiver thread: processes eth packets from cifX to tapX device
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
static void * cifx_to_eth_thread ( void * arg )
{
NETX_ETH_DEV_T * internal_dev = ( NETX_ETH_DEV_T * ) arg ;
CIFX_PACKET cifx_packet ;
uint32_t ulRecvPktCount = 0 ;
uint32_t ulSendPktCount = 0 ;
time_t last_update = 0 ;
int32_t lRet ;
while ( 1 )
{
if ( internal_dev - > stop_to_eth = = 1 )
break ;
ulRecvPktCount = 1 ;
while ( ulRecvPktCount > 0 ) {
if ( CIFX_NO_ERROR = = ( lRet = xChannelGetPacket ( internal_dev - > cifx_channel , sizeof ( cifx_packet ) , & cifx_packet , CIFX_TO_CONT_PACKET ) ) ) {
handle_incoming_packet ( internal_dev , & cifx_packet ) ;
}
if ( lRet = = CIFX_DEV_GET_NO_PACKET ) {
/* in some case the firmware may deliver wrong mailbox state. */
/* In case of false state, break here to update link state or */
/* to be able to interrupt/stop the running thread. */
break ;
}
if ( CIFX_NO_ERROR ! = ( lRet = xChannelGetMBXState ( internal_dev - > cifx_channel , & ulRecvPktCount , & ulSendPktCount ) ) ) {
break ;
}
}
if ( difftime ( time ( NULL ) , last_update ) > LINK_STATE_POLL_INTERVAL ) {
cifxeth_update_link_state ( internal_dev ) ;
last_update = time ( NULL ) ;
}
}
return NULL ;
}
/*! **************************************************************************
* Function retrieves the device link state and updates the corresponding
* tap device
* \ param internal_dev Pointer to internal device
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
static int32_t cifxeth_update_link_state ( NETX_ETH_DEV_T * internal_dev )
{
LINK_STATE_T tLinkState = { 0 } ;
int32_t lRet = CIFX_NO_ERROR ;
if ( CIFX_NO_ERROR = = ( lRet = cifxeth_get_extended_info ( internal_dev , EXT_INFO_LINKSTATE , & tLinkState , sizeof ( tLinkState ) ) ) )
{
int fSkipUpdate = 0 ;
if ( ( internal_dev - > link_up > 0 ) & & ( tLinkState . bLinkState ) ) {
/* device is already online */
fSkipUpdate = 1 ;
}
if ( ( internal_dev - > link_up < = 0 ) & & ( tLinkState . bLinkState = = 0 ) ) {
/* already offline... skip handling */
fSkipUpdate = 1 ;
}
if ( fSkipUpdate = = 0 ) {
if ( tLinkState . bLinkState )
{
if ( g_ulTraceLevel & TRACE_LEVEL_DEBUG ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_DEBUG , " Link up on '%s' " , internal_dev - > cifxeth_name ) ;
}
/* notify link state change */
internal_dev - > link_up = 1 ;
OS_SetEvent ( internal_dev - > link_event ) ;
if ( cifxeth_create_com_thread ( internal_dev ) ! = 0 ) {
lRet = CIFX_FUNCTION_FAILED ;
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error creating cifX Ethernet communication thread for %s. " , internal_dev - > cifxeth_name ) ;
}
} else {
FILE * file = NULL ;
nl_signal_link_change ( internal_dev , 1 ) ;
/* notify link up via uevent */
if ( NULL ! = ( file = fopen ( internal_dev - > event_path , " r+ " ) ) ) {
fprintf ( file , " online " ) ;
fclose ( file ) ;
} else {
lRet = CIFX_FUNCTION_FAILED ;
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error opening event path of cifX Ethernet IF %s (online event). " , internal_dev - > cifxeth_name ) ;
}
}
}
} else
{
FILE * file = NULL ;
internal_dev - > link_up = 0 ;
if ( g_ulTraceLevel & TRACE_LEVEL_DEBUG ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_DEBUG , " Link down on '%s' " , internal_dev - > cifxeth_name ) ;
}
/* stop eth-if to cifx communication since we we will remove the handle */
internal_dev - > stop_to_cifx = 1 ;
if ( internal_dev - > eth_to_cifx_thread ! = 0 ) {
pthread_join ( internal_dev - > eth_to_cifx_thread , 0 ) ;
internal_dev - > eth_to_cifx_thread = 0 ;
}
nl_signal_link_change ( internal_dev , 0 ) ;
/* notify link down via uevent */
if ( NULL ! = ( file = fopen ( internal_dev - > event_path , " r+ " ) ) ) {
fprintf ( file , " offline " ) ;
fclose ( file ) ;
} else {
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Error opening event path of cifX Ethernet IF %s (offline event). " , internal_dev - > cifxeth_name ) ;
}
lRet = CIFX_FUNCTION_FAILED ;
}
}
}
}
return lRet ;
}
/*! **************************************************************************
* Function retrieves the device configuration and initialize the corresponding
* tap device
* \ param internal_dev Pointer to internal device
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
static int32_t cifxeth_update_device_config ( NETX_ETH_DEV_T * internal_dev )
{
IFCONFIG_T tExtInfo = { 0 } ;
int32_t lRet = CIFX_NO_ERROR ;
if ( CIFX_NO_ERROR = = ( lRet = cifxeth_get_extended_info ( internal_dev , EXT_INFO_INTF_CONFIG , & tExtInfo , sizeof ( tExtInfo ) ) ) )
{
struct ifreq ifr ;
memset ( & ifr , 0 , sizeof ( ifr ) ) ;
memcpy ( ifr . ifr_hwaddr . sa_data , tExtInfo . abEthernetMACAddr , 6 ) ;
ifr . ifr_hwaddr . sa_family = 1 ;
if ( ( ioctl ( internal_dev - > eth_fd , SIOCSIFHWADDR , ( void * ) & ifr ) ) < 0 )
{
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Failed to set MAC address %02x:%02x:%02x:%02x:%02x:%02x of %s (%d) " ,
tExtInfo . abEthernetMACAddr [ 0 ] , tExtInfo . abEthernetMACAddr [ 1 ] , tExtInfo . abEthernetMACAddr [ 2 ] ,
tExtInfo . abEthernetMACAddr [ 3 ] , tExtInfo . abEthernetMACAddr [ 4 ] , tExtInfo . abEthernetMACAddr [ 5 ] ,
internal_dev - > cifxeth_name , errno ) ;
}
} else
{
if ( g_ulTraceLevel & TRACE_LEVEL_DEBUG )
{
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_DEBUG , " Ethernet-IF: Successfully set MAC address to %02x:%02x:%02x:%02x:%02x:%02x on %s " ,
tExtInfo . abEthernetMACAddr [ 0 ] , tExtInfo . abEthernetMACAddr [ 1 ] , tExtInfo . abEthernetMACAddr [ 2 ] ,
tExtInfo . abEthernetMACAddr [ 3 ] , tExtInfo . abEthernetMACAddr [ 4 ] , tExtInfo . abEthernetMACAddr [ 5 ] ,
internal_dev - > cifxeth_name ) ;
}
}
}
return lRet ;
}
/*! *************************************************************************
* Receive callback function . requried to handle incoming packets during admin
* communication
* \ param ptRecvPkt
* \ param pvUser */
/****************************************************************************/
void PacketRecvCallBack ( CIFX_PACKET * ptRecvPkt , void * pvUser )
{
NETX_ETH_DEV_T * internal_dev = ( NETX_ETH_DEV_T * ) pvUser ;
handle_incoming_packet ( internal_dev , ptRecvPkt ) ;
}
/*! *************************************************************************
* Register an application , so the Ethernet Stack will send indications
* \ param internal_dev Pointer to internal device
* \ param fRegister 1 = register , 0 = unregister application */
/****************************************************************************/
static int32_t cifxeth_register_app ( NETX_ETH_DEV_T * internal_dev , int fRegister )
{
uint32_t lRet = CIFX_NO_ERROR ;
CIFXHANDLE hChannel = internal_dev - > cifx_channel ;
HIL_REGISTER_APP_REQ_T tSendPkt = { { 0 } } ;
CIFX_PACKET tRecvPkt = { { 0 } } ;
tSendPkt . tHead . ulDest = HIL_PACKET_DEST_DEFAULT_CHANNEL ; /* Destination of packet, process queue */
tSendPkt . tHead . ulSrc = 0 ; /* Source of packet, process queue */
tSendPkt . tHead . ulLen = 0 ;
tSendPkt . tHead . ulId = 0x00 ; /* Identification handle of sender */
if ( fRegister )
{
tSendPkt . tHead . ulCmd = HIL_REGISTER_APP_REQ ; /* Packet command */
} else
{
tSendPkt . tHead . ulCmd = HIL_UNREGISTER_APP_REQ ; /* Packet command */
}
lRet = DEV_TransferPacket ( hChannel ,
( CIFX_PACKET * ) & tSendPkt ,
& tRecvPkt ,
sizeof ( tRecvPkt ) ,
CIFX_TO_SEND_PACKET ,
PacketRecvCallBack , internal_dev ) ;
if ( CIFX_NO_ERROR ! = lRet )
{
/* This is a transport error */
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR )
{
/* This is a transport error */
USER_Trace ( internal_dev - > devinst ,
TRACE_LEVEL_ERROR ,
" Ethernet-IF Error: Error in cifXEthTransferPacket()(lRet=0x%08X). " ,
lRet ) ;
}
} else
{
/* in case of de-register ignore return value since we might not be registered */
if ( fRegister ) {
/* Check if we have a state error from the stack */
if ( SUCCESS_HIL_OK ! = ( lRet = tRecvPkt . tHeader . ulState ) ) {
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR ) {
USER_Trace ( internal_dev - > devinst ,
TRACE_LEVEL_ERROR ,
" Ethernet-IF Error: Error sending Register-Application-Request (lRet=0x%08X). " ,
lRet ) ;
}
}
}
}
return lRet ;
}
/*! **************************************************************************
* Function reads extended status block an returns requested information
* \ param internal_dev Pointer to internal device
* \ param ulInformationRequest Command which information is retrieved
* \ param pvBuffer Pointer to information buffer
* \ param ulBufLen Size of pvBuffer
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
static int32_t cifxeth_get_extended_info ( NETX_ETH_DEV_T * internal_dev , uint32_t ulInformationRequest , void * pvBuffer , uint32_t ulBufLen )
{
int32_t lRet = CIFX_NO_ERROR ;
CIFXHANDLE hChannel = internal_dev - > cifx_channel ;
DRVETH_GCI_EXTENDED_STATE_T tExtStatusInfo ;
/* check parameter */
if ( ( pvBuffer = = NULL ) | | ( ulBufLen = = 0 ) )
return CIFX_INVALID_PARAMETER ;
lRet = xChannelExtendedStatusBlock ( hChannel , CIFX_CMD_READ_DATA , 0 , sizeof ( tExtStatusInfo ) , & tExtStatusInfo ) ;
if ( CIFX_NO_ERROR = = lRet )
{
/* check which information is requested */
switch ( ulInformationRequest )
{
/* return MAC address */
case EXT_INFO_INTF_CONFIG :
{
if ( sizeof ( IFCONFIG_T ) ! = ulBufLen ) {
lRet = CIFX_INVALID_BUFFERSIZE ;
} else {
PIFCONFIG_T ptIPconfig = ( PIFCONFIG_T ) pvBuffer ;
OS_Memcpy ( ( void * ) ptIPconfig - > abEthernetMACAddr , ( void * ) tExtStatusInfo . abMacAddress , DRVETH_GCI_ETH_ADDR_SIZE ) ;
lRet = CIFX_NO_ERROR ;
}
}
break ;
/* return Link State */
case EXT_INFO_LINKSTATE :
{
if ( sizeof ( LINK_STATE_T ) ! = ulBufLen ) {
lRet = CIFX_INVALID_BUFFERSIZE ;
} else {
PLINK_STATE_T ptLinkState = ( PLINK_STATE_T ) pvBuffer ;
ptLinkState - > bLinkState = tExtStatusInfo . bMautype ;
lRet = CIFX_NO_ERROR ;
}
}
break ;
case EXT_STATISTICS :
{
if ( sizeof ( STATISTIC_T ) ! = ulBufLen ) {
lRet = CIFX_INVALID_BUFFERSIZE ;
} else {
STATISTIC_T * ptStatistic = ( STATISTIC_T * ) pvBuffer ;
ptStatistic - > ullIfInPkts = tExtStatusInfo . ullIfInPkts ;
ptStatistic - > ullIfInDiscards = tExtStatusInfo . ullIfInDiscards ;
ptStatistic - > ullIfOutPkts = tExtStatusInfo . ullIfOutPkts ;
ptStatistic - > ullIfOutDiscards = tExtStatusInfo . ullIfOutDiscards ;
ptStatistic - > ullIfInBytes = tExtStatusInfo . ullIfInBytes ;
ptStatistic - > ullIfOutBytes = tExtStatusInfo . ullIfOutBytes ;
lRet = CIFX_NO_ERROR ;
}
}
break ;
case EXT_INFO_MACADDR :
case EXT_INFO_IPADDR :
case EXT_INFO_NETMASK :
case EXT_INFO_GATEWAY :
case EXT_INFO_NO_RECVPKT :
case EXT_INFO_NO_RCVPKT_DROP :
case EXT_INFO_NO_SENDPKT :
case EXT_INFO_NO_SENDPKT_DROP :
default :
lRet = CIFX_INVALID_COMMAND ;
break ;
}
}
if ( CIFX_NO_ERROR ! = lRet ) {
if ( g_ulTraceLevel & TRACE_LEVEL_ERROR ) {
USER_Trace ( internal_dev - > devinst , TRACE_LEVEL_ERROR , " Ethernet-IF Error: Failed to retrieve extended info of %s (0x%X) " , internal_dev - > cifxeth_name , lRet ) ;
}
}
return lRet ;
}
/*****************************************************************************/
/*! Searchs for internal device structure of the device given by name
* \ param name Name of the requested cifX device
* \ return pointer to internal device ( ! = NULL on success ) */
/*****************************************************************************/
static NETX_ETH_DEV_T * find_device ( char * name )
{
NETX_ETH_DEV_T * internal_dev = NULL ;
OS_EnterLock ( g_eth_list_lock ) ;
if ( ! TAILQ_EMPTY ( & s_DeviceList ) )
{
NETX_ETH_DEV_T * item ;
TAILQ_FOREACH ( item , & s_DeviceList , lentry ) {
if ( 0 = = strcmp ( item - > config . cifx_name , name ) )
{
internal_dev = item ;
break ;
}
}
}
OS_LeaveLock ( g_eth_list_lock ) ;
return internal_dev ;
}
/*****************************************************************************/
/*! NOTE: xSysdeviceReset() is a cifx toolkit function. In case of an ethernet
* interface a function wrapper is required since xSysdeviceReset ( ) will reset
* the whole device including the raw ethernet channel . So we need a wrap
* around to remove all previously registered ethernet interfaces . */
/*****************************************************************************/
extern int32_t APIENTRY xSysdeviceResetTK ( CIFXHANDLE hSysdevice , uint32_t ulTimeout ) ;
/*****************************************************************************/
/*! Hard resets a complete device via system channel
* \ param hSysdevice Handle to system device
* \ param ulTimeout Timeout to wait for card to finish reset
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
int32_t APIENTRY xSysdeviceReset ( CIFXHANDLE hSysdevice , uint32_t ulTimeout )
{
int32_t ret = CIFX_NO_ERROR ;
PCHANNELINSTANCE ptdevice = ( PCHANNELINSTANCE ) hSysdevice ;
PDEVICEINSTANCE ptDevInst = ( PDEVICEINSTANCE ) ptdevice - > pvDeviceInstance ;
NETX_ETH_DEV_T * internal_dev = find_device ( ptDevInst - > szName ) ;
NETX_ETH_DEV_CFG_T config = { { 0 } } ;
int ethdevice = 0 ;
if ( NULL ! = internal_dev )
{
ethdevice = 1 ;
strcpy ( config . cifx_name , internal_dev - > config . cifx_name ) ;
cifxeth_delete_device ( internal_dev ) ;
}
if ( CIFX_NO_ERROR = = ( ret = xSysdeviceResetTK ( hSysdevice , ulTimeout ) ) )
{
if ( 1 = = ethdevice )
cifxeth_create_device ( & config ) ;
}
return ret ;
}
extern int32_t APIENTRY xSysdeviceResetExTK ( CIFXHANDLE hSysdevice , uint32_t ulTimeout , uint32_t ulMode ) ;
/*****************************************************************************/
/*! Hard resets a complete device via system channel with reset parameter
* \ param hSysdevice Handle to system device
* \ param ulTimeout Timeout to wait for card to finish reset
* \ param ulMode Reset mode with parameter
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
int32_t APIENTRY xSysdeviceResetEx ( CIFXHANDLE hSysdevice , uint32_t ulTimeout , uint32_t ulMode )
{
int32_t ret = CIFX_NO_ERROR ;
PCHANNELINSTANCE ptdevice = ( PCHANNELINSTANCE ) hSysdevice ;
PDEVICEINSTANCE ptDevInst = ( PDEVICEINSTANCE ) ptdevice - > pvDeviceInstance ;
NETX_ETH_DEV_T * internal_dev = find_device ( ptDevInst - > szName ) ;
NETX_ETH_DEV_CFG_T config = { { 0 } } ;
int ethdevice = 0 ;
switch ( ulMode )
{
case CIFX_RESETEX_SYSTEMSTART :
case CIFX_RESETEX_BOOTSTART :
case CIFX_RESETEX_UPDATESTART :
{
if ( NULL ! = internal_dev )
{
ethdevice = 1 ;
strcpy ( config . cifx_name , internal_dev - > config . cifx_name ) ;
cifxeth_delete_device ( internal_dev ) ;
}
if ( CIFX_NO_ERROR = = ( ret = xSysdeviceResetExTK ( hSysdevice , ulTimeout , ulMode ) ) )
{
if ( ( 1 = = ethdevice ) & & ( ulMode ! = CIFX_RESETEX_BOOTSTART ) )
cifxeth_create_device ( & config ) ;
}
}
break ;
default :
{
ret = CIFX_INVALID_PARAMETER ;
}
break ;
}
return ret ;
}
extern int32_t APIENTRY xSysdeviceBootstartTK ( CIFXHANDLE hSysdevice , uint32_t ulTimeout ) ;
/*****************************************************************************/
/*! Boot start reset to via system channel
* \ param hSysdevice Handle to system device
* \ param ulTimeout Timeout to wait for card to finish reset
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
int32_t APIENTRY xSysdeviceBootstart ( CIFXHANDLE hSysdevice , uint32_t ulTimeout )
{
int32_t ret = CIFX_NO_ERROR ;
PCHANNELINSTANCE ptdevice = ( PCHANNELINSTANCE ) hSysdevice ;
PDEVICEINSTANCE ptDevInst = ( PDEVICEINSTANCE ) ptdevice - > pvDeviceInstance ;
NETX_ETH_DEV_T * internal_dev = find_device ( ptDevInst - > szName ) ;
NETX_ETH_DEV_CFG_T config = { { 0 } } ;
if ( NULL ! = internal_dev )
{
strcpy ( config . cifx_name , internal_dev - > config . cifx_name ) ;
cifxeth_delete_device ( internal_dev ) ;
}
return xSysdeviceBootstartTK ( hSysdevice , ulTimeout ) ;
}
/*****************************************************************************/
/*! NOTE: xChannelReset() is a cifx toolkit function. In case of an ethernet
* interface a function wrapper is required since xChannelReset ( ) ( with mode set
* to CIFX_SYSTEMSTART ) will reset the whole device including the raw ethernet
* channel . So we need a wrap around to remove all previously registered ethernet
* interfaces . */
/*****************************************************************************/
extern int32_t APIENTRY xChannelResetTK ( CIFXHANDLE hChannel , uint32_t ulResetMode , uint32_t ulTimeout ) ;
/*****************************************************************************/
/*! Hard resets a complete device via system channel
* \ param hChannel Handle to system device
* \ param ulResetMode Reset Mode
* \ param ulTimeout Timeout to wait for card to finish reset
* \ return CIFX_NO_ERROR on success */
/*****************************************************************************/
int32_t APIENTRY xChannelReset ( CIFXHANDLE hChannel , uint32_t ulResetMode , uint32_t ulTimeout )
{
int32_t ret = CIFX_NO_ERROR ;
PCHANNELINSTANCE ptdevice = ( PCHANNELINSTANCE ) hChannel ;
PDEVICEINSTANCE ptDevInst = ( PDEVICEINSTANCE ) ptdevice - > pvDeviceInstance ;
NETX_ETH_DEV_T * internal_dev = find_device ( ptDevInst - > szName ) ;
NETX_ETH_DEV_CFG_T config = { { 0 } } ;
int ethdevice = 0 ;
switch ( ulResetMode )
{
case CIFX_SYSTEMSTART :
{
if ( NULL ! = internal_dev )
{
ethdevice = 1 ;
strcpy ( config . cifx_name , internal_dev - > config . cifx_name ) ;
cifxeth_delete_device ( internal_dev ) ;
}
if ( CIFX_NO_ERROR = = ( ret = xChannelResetTK ( hChannel , ulResetMode , ulTimeout ) ) )
{
if ( 1 = = ethdevice )
cifxeth_create_device ( & config ) ;
}
}
break ;
default :
{
ret = xChannelResetTK ( hChannel , ulResetMode , ulTimeout ) ;
}
break ;
}
return ret ;
}
# endif //CIFXETHERNET