nxdrvlinux/libcifx/netx_tap/netx_tap.c

1382 lines
50 KiB
C
Raw Normal View History

// 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);
TAILQ_INSERT_TAIL( &s_DeviceList, internal_dev, lentry);
ret = internal_dev;
OS_LeaveLock( g_eth_list_lock);
return ret;
}
}
}
} 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);
}
} 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!");
}
}
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