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