at v2.6.29 342 lines 11 kB view raw
1/**************************************************************************** 2 3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 4 www.systec-electronic.com 5 6 Project: openPOWERLINK 7 8 Description: Virtual Ethernet Driver for Linux 9 10 License: 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in the 21 documentation and/or other materials provided with the distribution. 22 23 3. Neither the name of SYSTEC electronic GmbH nor the names of its 24 contributors may be used to endorse or promote products derived 25 from this software without prior written permission. For written 26 permission, please contact info@systec-electronic.com. 27 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 31 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 32 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 34 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 38 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 POSSIBILITY OF SUCH DAMAGE. 40 41 Severability Clause: 42 43 If a provision of this License is or becomes illegal, invalid or 44 unenforceable in any jurisdiction, that shall not affect: 45 1. the validity or enforceability in that jurisdiction of any other 46 provision of this License; or 47 2. the validity or enforceability in other jurisdictions of that or 48 any other provision of this License. 49 50 ------------------------------------------------------------------------- 51 52 $RCSfile: VirtualEthernetLinux.c,v $ 53 54 $Author: D.Krueger $ 55 56 $Revision: 1.8 $ $Date: 2008/11/20 17:06:51 $ 57 58 $State: Exp $ 59 60 Build Environment: 61 62 ------------------------------------------------------------------------- 63 64 Revision History: 65 66 2006/06/12 -ar: start of the implementation, version 1.00 67 68 2006/09/18 d.k.: integration into EPL DLLk module 69 70 ToDo: 71 72 void netif_carrier_off(struct net_device *dev); 73 void netif_carrier_on(struct net_device *dev); 74 75****************************************************************************/ 76 77#include <linux/version.h> 78#include <linux/module.h> 79#include <linux/netdevice.h> 80#include <linux/etherdevice.h> 81#include <linux/kernel.h> 82#include <linux/init.h> 83#include <linux/if_arp.h> 84#include <net/arp.h> 85 86#include <net/protocol.h> 87#include <net/pkt_sched.h> 88#include <linux/if_ether.h> 89#include <linux/in.h> 90#include <linux/ip.h> 91#include <linux/udp.h> 92#include <linux/mm.h> 93#include <linux/types.h> 94#include <linux/skbuff.h> /* for struct sk_buff */ 95 96#include "kernel/VirtualEthernet.h" 97#include "kernel/EplDllkCal.h" 98#include "kernel/EplDllk.h" 99 100#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0) 101 102/***************************************************************************/ 103/* */ 104/* */ 105/* G L O B A L D E F I N I T I O N S */ 106/* */ 107/* */ 108/***************************************************************************/ 109 110//--------------------------------------------------------------------------- 111// const defines 112//--------------------------------------------------------------------------- 113 114#ifndef EPL_VETH_TX_TIMEOUT 115//#define EPL_VETH_TX_TIMEOUT (2*HZ) 116#define EPL_VETH_TX_TIMEOUT 0 // d.k.: we use no timeout 117#endif 118 119//--------------------------------------------------------------------------- 120// local types 121//--------------------------------------------------------------------------- 122 123//--------------------------------------------------------------------------- 124// modul globale vars 125//--------------------------------------------------------------------------- 126 127static struct net_device *pVEthNetDevice_g = NULL; 128 129//--------------------------------------------------------------------------- 130// local function prototypes 131//--------------------------------------------------------------------------- 132 133static int VEthOpen(struct net_device *pNetDevice_p); 134static int VEthClose(struct net_device *pNetDevice_p); 135static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p); 136static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p); 137static void VEthTimeout(struct net_device *pNetDevice_p); 138static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p); 139 140//=========================================================================// 141// // 142// P U B L I C F U N C T I O N S // 143// // 144//=========================================================================// 145 146//--------------------------------------------------------------------------- 147// 148// Function: 149// 150// Description: 151// 152// 153// 154// Parameters: 155// 156// 157// Returns: 158// 159// 160// State: 161// 162//--------------------------------------------------------------------------- 163 164static int VEthOpen(struct net_device *pNetDevice_p) 165{ 166 tEplKernel Ret = kEplSuccessful; 167 168 //open the device 169// struct net_device_stats* pStats = netdev_priv(pNetDevice_p); 170 171 //start the interface queue for the network subsystem 172 netif_start_queue(pNetDevice_p); 173 174 // register callback function in DLL 175 Ret = EplDllkRegAsyncHandler(VEthRecvFrame); 176 177 EPL_DBGLVL_VETH_TRACE1 178 ("VEthOpen: EplDllkRegAsyncHandler returned 0x%02X\n", Ret); 179 180 return 0; 181} 182 183static int VEthClose(struct net_device *pNetDevice_p) 184{ 185 tEplKernel Ret = kEplSuccessful; 186 187 EPL_DBGLVL_VETH_TRACE0("VEthClose\n"); 188 189 Ret = EplDllkDeregAsyncHandler(VEthRecvFrame); 190 191 //stop the interface queue for the network subsystem 192 netif_stop_queue(pNetDevice_p); 193 return 0; 194} 195 196static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p) 197{ 198 tEplKernel Ret = kEplSuccessful; 199 tEplFrameInfo FrameInfo; 200 201 //transmit function 202 struct net_device_stats *pStats = netdev_priv(pNetDevice_p); 203 204 //save timestemp 205 pNetDevice_p->trans_start = jiffies; 206 207 FrameInfo.m_pFrame = (tEplFrame *) pSkb_p->data; 208 FrameInfo.m_uiFrameSize = pSkb_p->len; 209 210 //call send fkt on DLL 211 Ret = EplDllkCalAsyncSend(&FrameInfo, kEplDllAsyncReqPrioGeneric); 212 if (Ret != kEplSuccessful) { 213 EPL_DBGLVL_VETH_TRACE1 214 ("VEthXmit: EplDllkCalAsyncSend returned 0x%02X\n", Ret); 215 netif_stop_queue(pNetDevice_p); 216 goto Exit; 217 } else { 218 EPL_DBGLVL_VETH_TRACE0("VEthXmit: frame passed to DLL\n"); 219 dev_kfree_skb(pSkb_p); 220 221 //set stats for the device 222 pStats->tx_packets++; 223 pStats->tx_bytes += FrameInfo.m_uiFrameSize; 224 } 225 226 Exit: 227 return 0; 228 229} 230 231static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p) 232{ 233 EPL_DBGLVL_VETH_TRACE0("VEthGetStats\n"); 234 235 return netdev_priv(pNetDevice_p); 236} 237 238static void VEthTimeout(struct net_device *pNetDevice_p) 239{ 240 EPL_DBGLVL_VETH_TRACE0("VEthTimeout(\n"); 241 242 // $$$ d.k.: move to extra function, which is called by DLL when new space is available in TxFifo 243 if (netif_queue_stopped(pNetDevice_p)) { 244 netif_wake_queue(pNetDevice_p); 245 } 246} 247 248static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p) 249{ 250 tEplKernel Ret = kEplSuccessful; 251 struct net_device *pNetDevice = pVEthNetDevice_g; 252 struct net_device_stats *pStats = netdev_priv(pNetDevice); 253 struct sk_buff *pSkb; 254 255 EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: FrameSize=%u\n", 256 pFrameInfo_p->m_uiFrameSize); 257 258 pSkb = dev_alloc_skb(pFrameInfo_p->m_uiFrameSize + 2); 259 if (pSkb == NULL) { 260 pStats->rx_dropped++; 261 goto Exit; 262 } 263 pSkb->dev = pNetDevice; 264 265 skb_reserve(pSkb, 2); 266 267 memcpy((void *)skb_put(pSkb, pFrameInfo_p->m_uiFrameSize), 268 pFrameInfo_p->m_pFrame, pFrameInfo_p->m_uiFrameSize); 269 270 pSkb->protocol = eth_type_trans(pSkb, pNetDevice); 271 pSkb->ip_summed = CHECKSUM_UNNECESSARY; 272 273 // call netif_rx with skb 274 netif_rx(pSkb); 275 276 EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: SrcMAC=0x%llx\n", 277 AmiGetQword48FromBe(pFrameInfo_p->m_pFrame-> 278 m_be_abSrcMac)); 279 280 // update receive statistics 281 pStats->rx_packets++; 282 pStats->rx_bytes += pFrameInfo_p->m_uiFrameSize; 283 284 Exit: 285 return Ret; 286} 287 288tEplKernel PUBLIC VEthAddInstance(tEplDllkInitParam * pInitParam_p) 289{ 290 tEplKernel Ret = kEplSuccessful; 291 292 // allocate net device structure with priv pointing to stats structure 293 pVEthNetDevice_g = 294 alloc_netdev(sizeof(struct net_device_stats), EPL_VETH_NAME, 295 ether_setup); 296// pVEthNetDevice_g = alloc_etherdev(sizeof (struct net_device_stats)); 297 298 if (pVEthNetDevice_g == NULL) { 299 Ret = kEplNoResource; 300 goto Exit; 301 } 302 303 pVEthNetDevice_g->open = VEthOpen; 304 pVEthNetDevice_g->stop = VEthClose; 305 pVEthNetDevice_g->get_stats = VEthGetStats; 306 pVEthNetDevice_g->hard_start_xmit = VEthXmit; 307 pVEthNetDevice_g->tx_timeout = VEthTimeout; 308 pVEthNetDevice_g->watchdog_timeo = EPL_VETH_TX_TIMEOUT; 309 pVEthNetDevice_g->destructor = free_netdev; 310 311 // copy own MAC address to net device structure 312 memcpy(pVEthNetDevice_g->dev_addr, pInitParam_p->m_be_abSrcMac, 6); 313 314 //register VEth to the network subsystem 315 if (register_netdev(pVEthNetDevice_g)) { 316 EPL_DBGLVL_VETH_TRACE0 317 ("VEthAddInstance: Could not register VEth...\n"); 318 } else { 319 EPL_DBGLVL_VETH_TRACE0 320 ("VEthAddInstance: Register VEth successfull...\n"); 321 } 322 323 Exit: 324 return Ret; 325} 326 327tEplKernel PUBLIC VEthDelInstance(void) 328{ 329 tEplKernel Ret = kEplSuccessful; 330 331 if (pVEthNetDevice_g != NULL) { 332 //unregister VEth from the network subsystem 333 unregister_netdev(pVEthNetDevice_g); 334 // destructor was set to free_netdev, 335 // so we do not need to call free_netdev here 336 pVEthNetDevice_g = NULL; 337 } 338 339 return Ret; 340} 341 342#endif // (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)