1 /**
2 * @file
3 * Ethernet Interface Skeleton
4 *
5 */
6
7 /*
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Adam Dunkels <adam@sics.se>
36 *
37 */
38
39 /*
40 * This file is a skeleton for developing Ethernet network interface
41 * drivers for lwIP. Add code to the low_level functions and do a
42 * search-and-replace for the word "ethernetif" to replace it with
43 * something that better describes your network interface.
44 */
45
46 #include <stdio.h>
47 #include <syscall.h>
48 #include <sys/nic.h>
49
50 #include <lwip/opt.h>
51
52 #include <lwip/def.h>
53 #include <lwip/mem.h>
54 #include <lwip/pbuf.h>
55 #include <lwip/sys.h>
56 #include <lwip/stats.h>
57 #include <lwip/snmp.h>
58 #include <netif/etharp.h>
59 #include <netif/ppp_oe.h>
60
61 /* NIC Number */
62 static int nicNo = 1;
63
64 /* Define those to better describe your network interface. */
65 #define IFNAME0 'e'
66 #define IFNAME1 'n'
67
68 /**
69 * Helper struct to hold private data used to operate your ethernet interface.
70 * Keeping the ethernet address of the MAC in this struct is not necessary
71 * as it is already kept in the struct netif.
72 * But this is only an example, anyway...
73 */
74 struct ethernetif {
75 struct eth_addr *ethaddr;
76 /* Add whatever per-interface state that is needed here. */
77 };
78
79 /* Forward declarations. */
80 static void ethernetif_input(struct netif *netif);
81 static void ethernetif_thread(void *arg);
82
83 /**
84 * In this function, the hardware should be initialized.
85 * Called from ethernetif_init().
86 *
87 * @param netif the already initialized lwip network interface structure
88 * for this ethernetif
89 */
90 static void
low_level_init(struct netif * netif)91 low_level_init(struct netif *netif)
92 {
93 //struct ethernetif *ethernetif = netif->state;
94
95 /* set MAC hardware address length */
96 netif->hwaddr_len = ETHARP_HWADDR_LEN;
97
98 /* set MAC hardware address */
99 netif->hwaddr[0] = 0x11;
100 netif->hwaddr[1] = 0x22;
101 netif->hwaddr[2] = 0x33;
102 netif->hwaddr[3] = 0x44;
103 netif->hwaddr[4] = 0x55;
104 netif->hwaddr[5] = 0x66;
105
106 /* maximum transfer unit */
107 netif->mtu = 1500;
108
109 /* device capabilities */
110 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
111 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
112
113 /* Do whatever else is needed to initialize interface. */
114 sys_thread_new("ethernetif_thread", ethernetif_thread, netif,
115 DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
116 }
117
118 /**
119 * This function should do the actual transmission of the packet. The packet is
120 * contained in the pbuf that is passed to the function. This pbuf
121 * might be chained.
122 *
123 * @param netif the lwip network interface structure for this ethernetif
124 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
125 * @return ERR_OK if the packet could be sent
126 * an err_t value if the packet couldn't be sent
127 *
128 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
129 * strange results. You might consider waiting for space in the DMA queue
130 * to become availale since the stack doesn't retry to send a packet
131 * dropped because of memory failure (except for the TCP timers).
132 */
133 static err_t
low_level_output(struct netif * netif,struct pbuf * p)134 low_level_output(struct netif *netif, struct pbuf *p)
135 {
136 struct MBuf mbuf;
137 struct pbuf *q;
138 char buf[1500];
139 char *bufptr;
140 int status;
141
142 /* initiate transfer(); */
143 bufptr = &buf[0];
144
145 for(q = p; q != NULL; q = q->next) {
146 /* Send the data from the pbuf to the interface, one pbuf at a
147 time. The size of the data in each pbuf is kept in the ->len
148 variable. */
149 /* send data from(q->payload, q->len); */
150 memcpy(bufptr, q->payload, q->len);
151 bufptr += q->len;
152 }
153
154 /* signal that packet should be sent(); */
155 mbuf.vaddr = (uint64_t)buf;
156 mbuf.maddr = 0;
157 mbuf.len = p->tot_len;
158 mbuf.type = MBUF_TYPE_NULL;
159 mbuf.flags = 0;
160 mbuf.status = MBUF_STATUS_NULL;
161
162 status = OSNICSend(nicNo, &mbuf);
163 if (status != 0) {
164 printf("OSNICSend failed!\n");
165 return ERR_IF;
166 }
167
168 if (mbuf.status == MBUF_STATUS_FAILED) {
169 printf("Failed to write packet!\n");
170 return ERR_IF;
171 }
172
173 return ERR_OK;
174 }
175
176 /**
177 * Should allocate a pbuf and transfer the bytes of the incoming
178 * packet from the interface into the pbuf.
179 *
180 * @param netif the lwip network interface structure for this ethernetif
181 * @return a pbuf filled with the received packet (including MAC header)
182 * NULL on memory error
183 */
184 static struct pbuf *
low_level_input(struct netif * netif)185 low_level_input(struct netif *netif)
186 {
187 struct MBuf mbuf;
188 struct pbuf *p, *q;
189 char buf[1500];
190 char *bufptr;
191 u16_t len;
192 int status;
193
194 /* Obtain the size of the packet and put it into the "len"
195 variable. */
196 mbuf.vaddr = (uint64_t)buf;
197 mbuf.maddr = 0;
198 mbuf.len = 1500;
199 mbuf.type = MBUF_TYPE_NULL;
200 mbuf.flags = 0;
201 mbuf.status = MBUF_STATUS_NULL;
202
203 status = OSNICRecv(nicNo, &mbuf);
204 if (status != 0) {
205 printf("OSNICSend failed!\n");
206 return NULL;
207 }
208
209 if (mbuf.status == MBUF_STATUS_FAILED) {
210 printf("Failed to write packet!\n");
211 return NULL;
212 }
213
214 len = mbuf.len;
215
216 #if ETH_PAD_SIZE
217 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
218 #endif
219
220 /* We allocate a pbuf chain of pbufs from the pool. */
221 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
222 if (p != NULL) {
223 /* We iterate over the pbuf chain until we have read the entire
224 packet into the pbuf. */
225 bufptr = &buf[0];
226 for(q = p; q != NULL; q = q->next) {
227 /* Read enough bytes to fill this pbuf in the chain. The
228 available data in the pbuf is given by the q->len
229 variable. */
230 /* read data into(q->payload, q->len); */
231 memcpy(q->payload, bufptr, q->len);
232 bufptr += q->len;
233 }
234
235 /* acknowledge that packet has been read(); */
236 LINK_STATS_INC(link.recv);
237 } else {
238 /* drop packet(); */
239 LINK_STATS_INC(link.memerr);
240 LINK_STATS_INC(link.drop);
241 }
242
243 return p;
244 }
245
246 /**
247 * This function should be called when a packet is ready to be read
248 * from the interface. It uses the function low_level_input() that
249 * should handle the actual reception of bytes from the network
250 * interface. Then the type of the received packet is determined and
251 * the appropriate input function is called.
252 *
253 * @param netif the lwip network interface structure for this ethernetif
254 */
255 static void
ethernetif_input(struct netif * netif)256 ethernetif_input(struct netif *netif)
257 {
258 struct eth_hdr *ethhdr;
259 struct pbuf *p;
260
261 /* move received packet into a new pbuf */
262 p = low_level_input(netif);
263 /* no packet could be read, silently ignore this */
264 if (p == NULL) return;
265 /* points to packet payload, which starts with an Ethernet header */
266 ethhdr = p->payload;
267
268 switch (htons(ethhdr->type)) {
269 /* IP or ARP packet? */
270 case ETHTYPE_IP:
271 case ETHTYPE_ARP:
272 #if PPPOE_SUPPORT
273 /* PPPoE packet? */
274 case ETHTYPE_PPPOEDISC:
275 case ETHTYPE_PPPOE:
276 #endif /* PPPOE_SUPPORT */
277 /* full packet send to tcpip_thread to process */
278 if (netif->input(p, netif)!=ERR_OK)
279 { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
280 pbuf_free(p);
281 p = NULL;
282 }
283 break;
284
285 default:
286 pbuf_free(p);
287 p = NULL;
288 break;
289 }
290 }
291
292 /*
293 * Input thread
294 */
295 static void
ethernetif_thread(void * arg)296 ethernetif_thread(void *arg)
297 {
298 struct netif *netif = (struct netif *)arg;
299
300 while (1) {
301 /* Wait for a packet to arrive. */
302 ethernetif_input(netif);
303 }
304 }
305
306 /**
307 * Should be called at the beginning of the program to set up the
308 * network interface. It calls the function low_level_init() to do the
309 * actual setup of the hardware.
310 *
311 * This function should be passed as a parameter to netif_add().
312 *
313 * @param netif the lwip network interface structure for this ethernetif
314 * @return ERR_OK if the loopif is initialized
315 * ERR_MEM if private data couldn't be allocated
316 * any other err_t on error
317 */
318 err_t
ethernetif_init(struct netif * netif)319 ethernetif_init(struct netif *netif)
320 {
321 struct ethernetif *ethernetif;
322
323 LWIP_ASSERT("netif != NULL", (netif != NULL));
324
325 ethernetif = mem_malloc(sizeof(struct ethernetif));
326 if (ethernetif == NULL) {
327 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
328 return ERR_MEM;
329 }
330
331 #if LWIP_NETIF_HOSTNAME
332 /* Initialize interface hostname */
333 netif->hostname = "lwip";
334 #endif /* LWIP_NETIF_HOSTNAME */
335
336 /*
337 * Initialize the snmp variables and counters inside the struct netif.
338 * The last argument should be replaced with your link speed, in units
339 * of bits per second.
340 */
341 NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
342
343 netif->state = ethernetif;
344 netif->name[0] = IFNAME0;
345 netif->name[1] = IFNAME1;
346 /* We directly use etharp_output() here to save a function call.
347 * You can instead declare your own function an call etharp_output()
348 * from it if you have to do some checks before sending (e.g. if link
349 * is available...) */
350 netif->output = etharp_output;
351 netif->linkoutput = low_level_output;
352
353 ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
354
355 /* initialize the hardware */
356 low_level_init(netif);
357
358 return ERR_OK;
359 }
360
361