• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
127 static struct net_device *pVEthNetDevice_g = NULL;
128 
129 //---------------------------------------------------------------------------
130 // local function prototypes
131 //---------------------------------------------------------------------------
132 
133 static int VEthOpen(struct net_device *pNetDevice_p);
134 static int VEthClose(struct net_device *pNetDevice_p);
135 static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p);
136 static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p);
137 static void VEthTimeout(struct net_device *pNetDevice_p);
138 static 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 
VEthOpen(struct net_device * pNetDevice_p)164 static 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 
VEthClose(struct net_device * pNetDevice_p)183 static 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 
VEthXmit(struct sk_buff * pSkb_p,struct net_device * pNetDevice_p)196 static 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 
VEthGetStats(struct net_device * pNetDevice_p)231 static 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 
VEthTimeout(struct net_device * pNetDevice_p)238 static 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 
VEthRecvFrame(tEplFrameInfo * pFrameInfo_p)248 static 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 
VEthAddInstance(tEplDllkInitParam * pInitParam_p)288 tEplKernel 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 
VEthDelInstance(void)327 tEplKernel 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)
343