6ed106549d
This patch is the result of an automatic spatch transformation to convert all ndo_start_xmit() return values of 0 to NETDEV_TX_OK. Some occurences are missed by the automatic conversion, those will be handled in a seperate patch. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
349 lines
11 KiB
C
349 lines
11 KiB
C
/****************************************************************************
|
|
|
|
(c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
|
|
www.systec-electronic.com
|
|
|
|
Project: openPOWERLINK
|
|
|
|
Description: Virtual Ethernet Driver for Linux
|
|
|
|
License:
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
3. Neither the name of SYSTEC electronic GmbH nor the names of its
|
|
contributors may be used to endorse or promote products derived
|
|
from this software without prior written permission. For written
|
|
permission, please contact info@systec-electronic.com.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
Severability Clause:
|
|
|
|
If a provision of this License is or becomes illegal, invalid or
|
|
unenforceable in any jurisdiction, that shall not affect:
|
|
1. the validity or enforceability in that jurisdiction of any other
|
|
provision of this License; or
|
|
2. the validity or enforceability in other jurisdictions of that or
|
|
any other provision of this License.
|
|
|
|
-------------------------------------------------------------------------
|
|
|
|
$RCSfile: VirtualEthernetLinux.c,v $
|
|
|
|
$Author: D.Krueger $
|
|
|
|
$Revision: 1.8 $ $Date: 2008/11/20 17:06:51 $
|
|
|
|
$State: Exp $
|
|
|
|
Build Environment:
|
|
|
|
-------------------------------------------------------------------------
|
|
|
|
Revision History:
|
|
|
|
2006/06/12 -ar: start of the implementation, version 1.00
|
|
|
|
2006/09/18 d.k.: integration into EPL DLLk module
|
|
|
|
ToDo:
|
|
|
|
void netif_carrier_off(struct net_device *dev);
|
|
void netif_carrier_on(struct net_device *dev);
|
|
|
|
****************************************************************************/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/if_arp.h>
|
|
#include <net/arp.h>
|
|
|
|
#include <net/protocol.h>
|
|
#include <net/pkt_sched.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/in.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/udp.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/types.h>
|
|
#include <linux/skbuff.h> /* for struct sk_buff */
|
|
|
|
#include "kernel/VirtualEthernet.h"
|
|
#include "kernel/EplDllkCal.h"
|
|
#include "kernel/EplDllk.h"
|
|
|
|
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)
|
|
|
|
/***************************************************************************/
|
|
/* */
|
|
/* */
|
|
/* G L O B A L D E F I N I T I O N S */
|
|
/* */
|
|
/* */
|
|
/***************************************************************************/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// const defines
|
|
//---------------------------------------------------------------------------
|
|
|
|
#ifndef EPL_VETH_TX_TIMEOUT
|
|
//#define EPL_VETH_TX_TIMEOUT (2*HZ)
|
|
#define EPL_VETH_TX_TIMEOUT 0 // d.k.: we use no timeout
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------------
|
|
// local types
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
// modul globale vars
|
|
//---------------------------------------------------------------------------
|
|
|
|
static struct net_device *pVEthNetDevice_g = NULL;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// local function prototypes
|
|
//---------------------------------------------------------------------------
|
|
|
|
static int VEthOpen(struct net_device *pNetDevice_p);
|
|
static int VEthClose(struct net_device *pNetDevice_p);
|
|
static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p);
|
|
static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p);
|
|
static void VEthTimeout(struct net_device *pNetDevice_p);
|
|
static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p);
|
|
|
|
//=========================================================================//
|
|
// //
|
|
// P U B L I C F U N C T I O N S //
|
|
// //
|
|
//=========================================================================//
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
//
|
|
// Parameters:
|
|
//
|
|
//
|
|
// Returns:
|
|
//
|
|
//
|
|
// State:
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static int VEthOpen(struct net_device *pNetDevice_p)
|
|
{
|
|
tEplKernel Ret = kEplSuccessful;
|
|
|
|
//open the device
|
|
// struct net_device_stats* pStats = netdev_priv(pNetDevice_p);
|
|
|
|
//start the interface queue for the network subsystem
|
|
netif_start_queue(pNetDevice_p);
|
|
|
|
// register callback function in DLL
|
|
Ret = EplDllkRegAsyncHandler(VEthRecvFrame);
|
|
|
|
EPL_DBGLVL_VETH_TRACE1
|
|
("VEthOpen: EplDllkRegAsyncHandler returned 0x%02X\n", Ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int VEthClose(struct net_device *pNetDevice_p)
|
|
{
|
|
tEplKernel Ret = kEplSuccessful;
|
|
|
|
EPL_DBGLVL_VETH_TRACE0("VEthClose\n");
|
|
|
|
Ret = EplDllkDeregAsyncHandler(VEthRecvFrame);
|
|
|
|
//stop the interface queue for the network subsystem
|
|
netif_stop_queue(pNetDevice_p);
|
|
return 0;
|
|
}
|
|
|
|
static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p)
|
|
{
|
|
tEplKernel Ret = kEplSuccessful;
|
|
tEplFrameInfo FrameInfo;
|
|
|
|
//transmit function
|
|
struct net_device_stats *pStats = netdev_priv(pNetDevice_p);
|
|
|
|
//save timestemp
|
|
pNetDevice_p->trans_start = jiffies;
|
|
|
|
FrameInfo.m_pFrame = (tEplFrame *) pSkb_p->data;
|
|
FrameInfo.m_uiFrameSize = pSkb_p->len;
|
|
|
|
//call send fkt on DLL
|
|
Ret = EplDllkCalAsyncSend(&FrameInfo, kEplDllAsyncReqPrioGeneric);
|
|
if (Ret != kEplSuccessful) {
|
|
EPL_DBGLVL_VETH_TRACE1
|
|
("VEthXmit: EplDllkCalAsyncSend returned 0x%02X\n", Ret);
|
|
netif_stop_queue(pNetDevice_p);
|
|
goto Exit;
|
|
} else {
|
|
EPL_DBGLVL_VETH_TRACE0("VEthXmit: frame passed to DLL\n");
|
|
dev_kfree_skb(pSkb_p);
|
|
|
|
//set stats for the device
|
|
pStats->tx_packets++;
|
|
pStats->tx_bytes += FrameInfo.m_uiFrameSize;
|
|
}
|
|
|
|
Exit:
|
|
return NETDEV_TX_OK;
|
|
|
|
}
|
|
|
|
static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p)
|
|
{
|
|
EPL_DBGLVL_VETH_TRACE0("VEthGetStats\n");
|
|
|
|
return netdev_priv(pNetDevice_p);
|
|
}
|
|
|
|
static void VEthTimeout(struct net_device *pNetDevice_p)
|
|
{
|
|
EPL_DBGLVL_VETH_TRACE0("VEthTimeout(\n");
|
|
|
|
// $$$ d.k.: move to extra function, which is called by DLL when new space is available in TxFifo
|
|
if (netif_queue_stopped(pNetDevice_p)) {
|
|
netif_wake_queue(pNetDevice_p);
|
|
}
|
|
}
|
|
|
|
static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p)
|
|
{
|
|
tEplKernel Ret = kEplSuccessful;
|
|
struct net_device *pNetDevice = pVEthNetDevice_g;
|
|
struct net_device_stats *pStats = netdev_priv(pNetDevice);
|
|
struct sk_buff *pSkb;
|
|
|
|
EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: FrameSize=%u\n",
|
|
pFrameInfo_p->m_uiFrameSize);
|
|
|
|
pSkb = dev_alloc_skb(pFrameInfo_p->m_uiFrameSize + 2);
|
|
if (pSkb == NULL) {
|
|
pStats->rx_dropped++;
|
|
goto Exit;
|
|
}
|
|
pSkb->dev = pNetDevice;
|
|
|
|
skb_reserve(pSkb, 2);
|
|
|
|
memcpy((void *)skb_put(pSkb, pFrameInfo_p->m_uiFrameSize),
|
|
pFrameInfo_p->m_pFrame, pFrameInfo_p->m_uiFrameSize);
|
|
|
|
pSkb->protocol = eth_type_trans(pSkb, pNetDevice);
|
|
pSkb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
// call netif_rx with skb
|
|
netif_rx(pSkb);
|
|
|
|
EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: SrcMAC=0x%llx\n",
|
|
AmiGetQword48FromBe(pFrameInfo_p->m_pFrame->
|
|
m_be_abSrcMac));
|
|
|
|
// update receive statistics
|
|
pStats->rx_packets++;
|
|
pStats->rx_bytes += pFrameInfo_p->m_uiFrameSize;
|
|
|
|
Exit:
|
|
return Ret;
|
|
}
|
|
|
|
static const struct net_device_ops epl_netdev_ops = {
|
|
.ndo_open = VEthOpen,
|
|
.ndo_stop = VEthClose,
|
|
.ndo_get_stats = VEthGetStats,
|
|
.ndo_start_xmit = VEthXmit,
|
|
.ndo_tx_timeout = VEthTimeout,
|
|
.ndo_change_mtu = eth_change_mtu,
|
|
.ndo_set_mac_address = eth_mac_addr,
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
};
|
|
|
|
tEplKernel VEthAddInstance(tEplDllkInitParam *pInitParam_p)
|
|
{
|
|
tEplKernel Ret = kEplSuccessful;
|
|
|
|
// allocate net device structure with priv pointing to stats structure
|
|
pVEthNetDevice_g =
|
|
alloc_netdev(sizeof(struct net_device_stats), EPL_VETH_NAME,
|
|
ether_setup);
|
|
// pVEthNetDevice_g = alloc_etherdev(sizeof (struct net_device_stats));
|
|
|
|
if (pVEthNetDevice_g == NULL) {
|
|
Ret = kEplNoResource;
|
|
goto Exit;
|
|
}
|
|
|
|
pVEthNetDevice_g->netdev_ops = &epl_netdev_ops;
|
|
pVEthNetDevice_g->watchdog_timeo = EPL_VETH_TX_TIMEOUT;
|
|
pVEthNetDevice_g->destructor = free_netdev;
|
|
|
|
// copy own MAC address to net device structure
|
|
memcpy(pVEthNetDevice_g->dev_addr, pInitParam_p->m_be_abSrcMac, 6);
|
|
|
|
//register VEth to the network subsystem
|
|
if (register_netdev(pVEthNetDevice_g)) {
|
|
EPL_DBGLVL_VETH_TRACE0
|
|
("VEthAddInstance: Could not register VEth...\n");
|
|
} else {
|
|
EPL_DBGLVL_VETH_TRACE0
|
|
("VEthAddInstance: Register VEth successfull...\n");
|
|
}
|
|
|
|
Exit:
|
|
return Ret;
|
|
}
|
|
|
|
tEplKernel VEthDelInstance(void)
|
|
{
|
|
tEplKernel Ret = kEplSuccessful;
|
|
|
|
if (pVEthNetDevice_g != NULL) {
|
|
//unregister VEth from the network subsystem
|
|
unregister_netdev(pVEthNetDevice_g);
|
|
// destructor was set to free_netdev,
|
|
// so we do not need to call free_netdev here
|
|
pVEthNetDevice_g = NULL;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
#endif // (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)
|