]>
Commit | Line | Data |
---|---|---|
9d7164cf DK |
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 | ||
9d7164cf DK |
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 | ||
9d7164cf DK |
77 | #include <linux/module.h> |
78 | #include <linux/netdevice.h> | |
79 | #include <linux/etherdevice.h> | |
80 | #include <linux/kernel.h> | |
81 | #include <linux/init.h> | |
82 | #include <linux/if_arp.h> | |
83 | #include <net/arp.h> | |
84 | ||
85 | #include <net/protocol.h> | |
86 | #include <net/pkt_sched.h> | |
87 | #include <linux/if_ether.h> | |
88 | #include <linux/in.h> | |
89 | #include <linux/ip.h> | |
90 | #include <linux/udp.h> | |
91 | #include <linux/mm.h> | |
92 | #include <linux/types.h> | |
833dfbe7 | 93 | #include <linux/skbuff.h> /* for struct sk_buff */ |
9d7164cf DK |
94 | |
95 | #include "kernel/VirtualEthernet.h" | |
96 | #include "kernel/EplDllkCal.h" | |
97 | #include "kernel/EplDllk.h" | |
98 | ||
9d7164cf DK |
99 | #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0) |
100 | ||
101 | /***************************************************************************/ | |
102 | /* */ | |
103 | /* */ | |
104 | /* G L O B A L D E F I N I T I O N S */ | |
105 | /* */ | |
106 | /* */ | |
107 | /***************************************************************************/ | |
108 | ||
9d7164cf DK |
109 | //--------------------------------------------------------------------------- |
110 | // const defines | |
111 | //--------------------------------------------------------------------------- | |
112 | ||
113 | #ifndef EPL_VETH_TX_TIMEOUT | |
114 | //#define EPL_VETH_TX_TIMEOUT (2*HZ) | |
833dfbe7 | 115 | #define EPL_VETH_TX_TIMEOUT 0 // d.k.: we use no timeout |
9d7164cf DK |
116 | #endif |
117 | ||
9d7164cf DK |
118 | //--------------------------------------------------------------------------- |
119 | // local types | |
120 | //--------------------------------------------------------------------------- | |
121 | ||
9d7164cf DK |
122 | //--------------------------------------------------------------------------- |
123 | // modul globale vars | |
124 | //--------------------------------------------------------------------------- | |
125 | ||
833dfbe7 | 126 | static struct net_device *pVEthNetDevice_g = NULL; |
9d7164cf DK |
127 | |
128 | //--------------------------------------------------------------------------- | |
129 | // local function prototypes | |
130 | //--------------------------------------------------------------------------- | |
131 | ||
132 | static int VEthOpen(struct net_device *pNetDevice_p); | |
133 | static int VEthClose(struct net_device *pNetDevice_p); | |
134 | static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p); | |
833dfbe7 | 135 | static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p); |
9d7164cf DK |
136 | static void VEthTimeout(struct net_device *pNetDevice_p); |
137 | static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p); | |
138 | ||
9d7164cf DK |
139 | //=========================================================================// |
140 | // // | |
141 | // P U B L I C F U N C T I O N S // | |
142 | // // | |
143 | //=========================================================================// | |
144 | ||
145 | //--------------------------------------------------------------------------- | |
146 | // | |
147 | // Function: | |
148 | // | |
149 | // Description: | |
150 | // | |
151 | // | |
152 | // | |
153 | // Parameters: | |
154 | // | |
155 | // | |
156 | // Returns: | |
157 | // | |
158 | // | |
159 | // State: | |
160 | // | |
161 | //--------------------------------------------------------------------------- | |
162 | ||
163 | static int VEthOpen(struct net_device *pNetDevice_p) | |
164 | { | |
833dfbe7 | 165 | tEplKernel Ret = kEplSuccessful; |
9d7164cf | 166 | |
833dfbe7 | 167 | //open the device |
4cf7c4c6 | 168 | // struct net_device_stats* pStats = netdev_priv(pNetDevice_p); |
9d7164cf | 169 | |
833dfbe7 GKH |
170 | //start the interface queue for the network subsystem |
171 | netif_start_queue(pNetDevice_p); | |
9d7164cf | 172 | |
833dfbe7 GKH |
173 | // register callback function in DLL |
174 | Ret = EplDllkRegAsyncHandler(VEthRecvFrame); | |
9d7164cf | 175 | |
833dfbe7 GKH |
176 | EPL_DBGLVL_VETH_TRACE1 |
177 | ("VEthOpen: EplDllkRegAsyncHandler returned 0x%02X\n", Ret); | |
9d7164cf | 178 | |
833dfbe7 | 179 | return 0; |
9d7164cf DK |
180 | } |
181 | ||
182 | static int VEthClose(struct net_device *pNetDevice_p) | |
183 | { | |
833dfbe7 | 184 | tEplKernel Ret = kEplSuccessful; |
9d7164cf | 185 | |
833dfbe7 | 186 | EPL_DBGLVL_VETH_TRACE0("VEthClose\n"); |
9d7164cf | 187 | |
833dfbe7 | 188 | Ret = EplDllkDeregAsyncHandler(VEthRecvFrame); |
9d7164cf | 189 | |
833dfbe7 GKH |
190 | //stop the interface queue for the network subsystem |
191 | netif_stop_queue(pNetDevice_p); | |
192 | return 0; | |
9d7164cf DK |
193 | } |
194 | ||
9d7164cf DK |
195 | static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p) |
196 | { | |
833dfbe7 GKH |
197 | tEplKernel Ret = kEplSuccessful; |
198 | tEplFrameInfo FrameInfo; | |
199 | ||
200 | //transmit function | |
4cf7c4c6 | 201 | struct net_device_stats *pStats = netdev_priv(pNetDevice_p); |
833dfbe7 GKH |
202 | |
203 | //save timestemp | |
204 | pNetDevice_p->trans_start = jiffies; | |
205 | ||
206 | FrameInfo.m_pFrame = (tEplFrame *) pSkb_p->data; | |
207 | FrameInfo.m_uiFrameSize = pSkb_p->len; | |
208 | ||
209 | //call send fkt on DLL | |
210 | Ret = EplDllkCalAsyncSend(&FrameInfo, kEplDllAsyncReqPrioGeneric); | |
211 | if (Ret != kEplSuccessful) { | |
212 | EPL_DBGLVL_VETH_TRACE1 | |
213 | ("VEthXmit: EplDllkCalAsyncSend returned 0x%02X\n", Ret); | |
214 | netif_stop_queue(pNetDevice_p); | |
215 | goto Exit; | |
216 | } else { | |
217 | EPL_DBGLVL_VETH_TRACE0("VEthXmit: frame passed to DLL\n"); | |
218 | dev_kfree_skb(pSkb_p); | |
219 | ||
220 | //set stats for the device | |
221 | pStats->tx_packets++; | |
222 | pStats->tx_bytes += FrameInfo.m_uiFrameSize; | |
223 | } | |
224 | ||
225 | Exit: | |
6ed10654 | 226 | return NETDEV_TX_OK; |
9d7164cf DK |
227 | |
228 | } | |
229 | ||
833dfbe7 | 230 | static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p) |
9d7164cf | 231 | { |
833dfbe7 | 232 | EPL_DBGLVL_VETH_TRACE0("VEthGetStats\n"); |
9d7164cf | 233 | |
4cf7c4c6 | 234 | return netdev_priv(pNetDevice_p); |
9d7164cf DK |
235 | } |
236 | ||
9d7164cf DK |
237 | static void VEthTimeout(struct net_device *pNetDevice_p) |
238 | { | |
833dfbe7 | 239 | EPL_DBGLVL_VETH_TRACE0("VEthTimeout(\n"); |
9d7164cf | 240 | |
833dfbe7 GKH |
241 | // $$$ d.k.: move to extra function, which is called by DLL when new space is available in TxFifo |
242 | if (netif_queue_stopped(pNetDevice_p)) { | |
243 | netif_wake_queue(pNetDevice_p); | |
244 | } | |
9d7164cf DK |
245 | } |
246 | ||
9d7164cf DK |
247 | static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p) |
248 | { | |
833dfbe7 GKH |
249 | tEplKernel Ret = kEplSuccessful; |
250 | struct net_device *pNetDevice = pVEthNetDevice_g; | |
4cf7c4c6 | 251 | struct net_device_stats *pStats = netdev_priv(pNetDevice); |
833dfbe7 | 252 | struct sk_buff *pSkb; |
9d7164cf | 253 | |
833dfbe7 GKH |
254 | EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: FrameSize=%u\n", |
255 | pFrameInfo_p->m_uiFrameSize); | |
9d7164cf | 256 | |
833dfbe7 GKH |
257 | pSkb = dev_alloc_skb(pFrameInfo_p->m_uiFrameSize + 2); |
258 | if (pSkb == NULL) { | |
259 | pStats->rx_dropped++; | |
260 | goto Exit; | |
261 | } | |
262 | pSkb->dev = pNetDevice; | |
9d7164cf | 263 | |
833dfbe7 | 264 | skb_reserve(pSkb, 2); |
9d7164cf | 265 | |
833dfbe7 GKH |
266 | memcpy((void *)skb_put(pSkb, pFrameInfo_p->m_uiFrameSize), |
267 | pFrameInfo_p->m_pFrame, pFrameInfo_p->m_uiFrameSize); | |
9d7164cf | 268 | |
833dfbe7 GKH |
269 | pSkb->protocol = eth_type_trans(pSkb, pNetDevice); |
270 | pSkb->ip_summed = CHECKSUM_UNNECESSARY; | |
9d7164cf | 271 | |
833dfbe7 GKH |
272 | // call netif_rx with skb |
273 | netif_rx(pSkb); | |
9d7164cf | 274 | |
833dfbe7 GKH |
275 | EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: SrcMAC=0x%llx\n", |
276 | AmiGetQword48FromBe(pFrameInfo_p->m_pFrame-> | |
277 | m_be_abSrcMac)); | |
9d7164cf | 278 | |
833dfbe7 GKH |
279 | // update receive statistics |
280 | pStats->rx_packets++; | |
281 | pStats->rx_bytes += pFrameInfo_p->m_uiFrameSize; | |
9d7164cf | 282 | |
833dfbe7 GKH |
283 | Exit: |
284 | return Ret; | |
9d7164cf DK |
285 | } |
286 | ||
0e46ff33 AB |
287 | static const struct net_device_ops epl_netdev_ops = { |
288 | .ndo_open = VEthOpen, | |
289 | .ndo_stop = VEthClose, | |
290 | .ndo_get_stats = VEthGetStats, | |
291 | .ndo_start_xmit = VEthXmit, | |
292 | .ndo_tx_timeout = VEthTimeout, | |
293 | .ndo_change_mtu = eth_change_mtu, | |
294 | .ndo_set_mac_address = eth_mac_addr, | |
295 | .ndo_validate_addr = eth_validate_addr, | |
296 | }; | |
297 | ||
d10f4699 | 298 | tEplKernel VEthAddInstance(tEplDllkInitParam *pInitParam_p) |
9d7164cf | 299 | { |
833dfbe7 | 300 | tEplKernel Ret = kEplSuccessful; |
9d7164cf | 301 | |
833dfbe7 GKH |
302 | // allocate net device structure with priv pointing to stats structure |
303 | pVEthNetDevice_g = | |
304 | alloc_netdev(sizeof(struct net_device_stats), EPL_VETH_NAME, | |
305 | ether_setup); | |
9d7164cf DK |
306 | // pVEthNetDevice_g = alloc_etherdev(sizeof (struct net_device_stats)); |
307 | ||
833dfbe7 GKH |
308 | if (pVEthNetDevice_g == NULL) { |
309 | Ret = kEplNoResource; | |
310 | goto Exit; | |
311 | } | |
312 | ||
0e46ff33 | 313 | pVEthNetDevice_g->netdev_ops = &epl_netdev_ops; |
833dfbe7 GKH |
314 | pVEthNetDevice_g->watchdog_timeo = EPL_VETH_TX_TIMEOUT; |
315 | pVEthNetDevice_g->destructor = free_netdev; | |
316 | ||
317 | // copy own MAC address to net device structure | |
318 | memcpy(pVEthNetDevice_g->dev_addr, pInitParam_p->m_be_abSrcMac, 6); | |
319 | ||
320 | //register VEth to the network subsystem | |
321 | if (register_netdev(pVEthNetDevice_g)) { | |
322 | EPL_DBGLVL_VETH_TRACE0 | |
323 | ("VEthAddInstance: Could not register VEth...\n"); | |
324 | } else { | |
325 | EPL_DBGLVL_VETH_TRACE0 | |
326 | ("VEthAddInstance: Register VEth successfull...\n"); | |
327 | } | |
328 | ||
329 | Exit: | |
330 | return Ret; | |
9d7164cf DK |
331 | } |
332 | ||
d10f4699 | 333 | tEplKernel VEthDelInstance(void) |
9d7164cf | 334 | { |
833dfbe7 GKH |
335 | tEplKernel Ret = kEplSuccessful; |
336 | ||
337 | if (pVEthNetDevice_g != NULL) { | |
338 | //unregister VEth from the network subsystem | |
339 | unregister_netdev(pVEthNetDevice_g); | |
340 | // destructor was set to free_netdev, | |
341 | // so we do not need to call free_netdev here | |
342 | pVEthNetDevice_g = NULL; | |
343 | } | |
344 | ||
345 | return Ret; | |
9d7164cf DK |
346 | } |
347 | ||
348 | #endif // (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0) |