]> git.sur5r.net Git - freertos/blob - Demo/lwIP_Demo_Rowley_ARM7/lwip-1.1.0/src/netif/ethernetif.c
First version under SVN is V4.0.1
[freertos] / Demo / lwIP_Demo_Rowley_ARM7 / lwip-1.1.0 / src / netif / ethernetif.c
1 /*\r
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without modification,\r
6  * are permitted provided that the following conditions are met:\r
7  *\r
8  * 1. Redistributions of source code must retain the above copyright notice,\r
9  *    this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
11  *    this list of conditions and the following disclaimer in the documentation\r
12  *    and/or other materials provided with the distribution.\r
13  * 3. The name of the author may not be used to endorse or promote products\r
14  *    derived from this software without specific prior written permission.\r
15  *\r
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
25  * OF SUCH DAMAGE.\r
26  *\r
27  * This file is part of the lwIP TCP/IP stack.\r
28  *\r
29  * Author: Adam Dunkels <adam@sics.se>\r
30  *\r
31  */\r
32 \r
33 /* lwIP includes. */\r
34 #include <string.h>\r
35 #include "lwip/opt.h"\r
36 #include "lwip/def.h"\r
37 #include "lwip/mem.h"\r
38 #include "lwip/pbuf.h"\r
39 #include "lwip/sys.h"\r
40 #include <lwip/stats.h>\r
41 #include "netif/etharp.h"\r
42 \r
43 /* FreeRTOS includes. */\r
44 #include "FreeRTOS.h"\r
45 #include "SAM7_EMAC.h"\r
46 #include "Emac.h"\r
47 \r
48 #define netifMTU                                                        ( 1500 )\r
49 #define netifINTERFACE_TASK_STACK_SIZE          ( 350 )\r
50 #define netifINTERFACE_TASK_PRIORITY            ( configMAX_PRIORITIES - 1 )\r
51 #define netifGUARD_BLOCK_TIME                           ( 250 )\r
52 #define IFNAME0 'e'\r
53 #define IFNAME1 'm'\r
54 \r
55 /* lwIP definitions. */\r
56 struct ethernetif\r
57 {\r
58         struct eth_addr *ethaddr;\r
59 };\r
60 static const struct eth_addr    ethbroadcast = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };\r
61 static struct netif *xNetIf = NULL;\r
62 \r
63 /* Forward declarations. */\r
64 static void ethernetif_input( void * );\r
65 static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr );\r
66 err_t ethernetif_init( struct netif *netif );\r
67 \r
68 \r
69 /*-----------------------------------------------------------*/\r
70 \r
71 static void low_level_init( struct netif *netif )\r
72 {\r
73 unsigned portBASE_TYPE uxPriority;\r
74 \r
75         /* set MAC hardware address length */\r
76         netif->hwaddr_len = 6;\r
77 \r
78         /* set MAC hardware address */\r
79         netif->hwaddr[0] = emacETHADDR0;\r
80         netif->hwaddr[1] = emacETHADDR1;\r
81         netif->hwaddr[2] = emacETHADDR2;\r
82         netif->hwaddr[3] = emacETHADDR3;\r
83         netif->hwaddr[4] = emacETHADDR4;\r
84         netif->hwaddr[5] = emacETHADDR5;\r
85 \r
86         /* maximum transfer unit */\r
87         netif->mtu = netifMTU;\r
88 \r
89         /* broadcast capability */\r
90         netif->flags = NETIF_FLAG_BROADCAST;\r
91 \r
92         xNetIf = netif;\r
93 \r
94         /* Initialise the EMAC.  This routine contains code that polls status bits.  \r
95         If the Ethernet cable is not plugged in then this can take a considerable \r
96         time.  To prevent this starving lower priority tasks of processing time we\r
97         lower our priority prior to the call, then raise it back again once the\r
98         initialisation is complete. */\r
99         uxPriority = uxTaskPriorityGet( NULL );\r
100         vTaskPrioritySet( NULL, tskIDLE_PRIORITY );\r
101         while( xEMACInit() == NULL )\r
102         {\r
103                 __asm( "NOP" );\r
104         }\r
105         vTaskPrioritySet( NULL, uxPriority );\r
106 \r
107         /* Create the task that handles the EMAC. */\r
108         xTaskCreate( ethernetif_input, ( signed portCHAR * ) "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL );\r
109 }\r
110 /*-----------------------------------------------------------*/\r
111 \r
112 /*\r
113  * low_level_output(): Should do the actual transmission of the packet. The \r
114  * packet is contained in the pbuf that is passed to the function. This pbuf \r
115  * might be chained.\r
116  */\r
117 static err_t low_level_output( struct netif *netif, struct pbuf *p )\r
118 {\r
119 struct pbuf *q;\r
120 static xSemaphoreHandle xTxSemaphore = NULL;\r
121 err_t xReturn = ERR_OK;\r
122 \r
123         /* Parameter not used. */\r
124         ( void ) netif;\r
125 \r
126         if( xTxSemaphore == NULL )\r
127         {\r
128                 vSemaphoreCreateBinary( xTxSemaphore );\r
129         }\r
130 \r
131         #if ETH_PAD_SIZE\r
132                 pbuf_header( p, -ETH_PAD_SIZE );    /* drop the padding word */\r
133         #endif\r
134 \r
135         /* Access to the EMAC is guarded using a semaphore. */\r
136         if( xSemaphoreTake( xTxSemaphore, netifGUARD_BLOCK_TIME ) )\r
137         {\r
138                 for( q = p; q != NULL; q = q->next )\r
139                 {\r
140                         /* Send the data from the pbuf to the interface, one pbuf at a \r
141                         time. The size of the data in each pbuf is kept in the ->len \r
142                         variable.  if q->next == NULL then this is the last pbuf in the\r
143                         chain. */\r
144                         if( !lEMACSend( q->payload, q->len, ( q->next == NULL ) ) )\r
145                         {\r
146                                 xReturn = ~ERR_OK;\r
147                         }\r
148                 }\r
149 \r
150         xSemaphoreGive( xTxSemaphore );\r
151         }\r
152         \r
153 \r
154         #if ETH_PAD_SIZE\r
155                 pbuf_header( p, ETH_PAD_SIZE );     /* reclaim the padding word */\r
156         #endif\r
157 \r
158         #if LINK_STATS\r
159                 lwip_stats.link.xmit++;\r
160         #endif /* LINK_STATS */\r
161 \r
162     return xReturn;\r
163 }\r
164 /*-----------------------------------------------------------*/\r
165 \r
166 /*\r
167  * low_level_input(): Should allocate a pbuf and transfer the bytes of the \r
168  * incoming packet from the interface into the pbuf. \r
169  */\r
170 static struct pbuf *low_level_input( struct netif *netif )\r
171 {\r
172 struct pbuf         *p = NULL, *q;\r
173 u16_t               len = 0;\r
174 static xSemaphoreHandle xRxSemaphore = NULL;\r
175 \r
176         /* Parameter not used. */\r
177         ( void ) netif;\r
178 \r
179         if( xRxSemaphore == NULL )\r
180         {\r
181                 vSemaphoreCreateBinary( xRxSemaphore );\r
182         }\r
183 \r
184         /* Access to the emac is guarded using a semaphore. */\r
185         if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )\r
186         {\r
187                 /* Obtain the size of the packet. */\r
188                 len = ulEMACInputLength();\r
189         \r
190                 if( len )\r
191                 {\r
192                         #if ETH_PAD_SIZE\r
193                                 len += ETH_PAD_SIZE;    /* allow room for Ethernet padding */\r
194                         #endif\r
195         \r
196                         /* We allocate a pbuf chain of pbufs from the pool. */\r
197                         p = pbuf_alloc( PBUF_RAW, len, PBUF_POOL );\r
198                 \r
199                         if( p != NULL )\r
200                         {\r
201                                 #if ETH_PAD_SIZE\r
202                                         pbuf_header( p, -ETH_PAD_SIZE );    /* drop the padding word */\r
203                                 #endif\r
204                 \r
205                                 /* Let the driver know we are going to read a new packet. */\r
206                                 vEMACRead( NULL, 0, len );\r
207                                         \r
208                                 /* We iterate over the pbuf chain until we have read the entire\r
209                                 packet into the pbuf. */                                \r
210                                 for( q = p; q != NULL; q = q->next )\r
211                                 {\r
212                                         /* Read enough bytes to fill this pbuf in the chain. The \r
213                                         available data in the pbuf is given by the q->len variable. */\r
214                                         vEMACRead( q->payload, q->len, len );\r
215                                 }\r
216                 \r
217                                 #if ETH_PAD_SIZE\r
218                                         pbuf_header( p, ETH_PAD_SIZE );     /* reclaim the padding word */\r
219                                 #endif\r
220                                 #if LINK_STATS\r
221                                         lwip_stats.link.recv++;\r
222                                 #endif /* LINK_STATS */\r
223                         }\r
224                         else\r
225                         {\r
226                                 #if LINK_STATS\r
227                                         lwip_stats.link.memerr++;\r
228                                         lwip_stats.link.drop++;\r
229                                 #endif /* LINK_STATS */\r
230                         }\r
231                 }\r
232 \r
233                 xSemaphoreGive( xRxSemaphore );\r
234         }\r
235 \r
236         return p;\r
237 }\r
238 /*-----------------------------------------------------------*/\r
239 \r
240 /*\r
241  * ethernetif_output(): This function is called by the TCP/IP stack when an \r
242  * IP packet should be sent. It calls the function called low_level_output() \r
243  * to do the actual transmission of the packet.\r
244  */\r
245 static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr )\r
246 {\r
247     /* resolve hardware address, then send (or queue) packet */\r
248     return etharp_output( netif, ipaddr, p );\r
249 }\r
250 /*-----------------------------------------------------------*/\r
251 \r
252 /*\r
253  * ethernetif_input(): This function should be called when a packet is ready to \r
254  * be read from the interface. It uses the function low_level_input() that \r
255  * should handle the actual reception of bytes from the network interface.\r
256  */\r
257 static void ethernetif_input( void * pvParameters )\r
258 {\r
259 struct ethernetif   *ethernetif;\r
260 struct eth_hdr      *ethhdr;\r
261 struct pbuf         *p;\r
262 \r
263         ( void ) pvParameters;\r
264 \r
265         for( ;; )\r
266         {\r
267                 do\r
268                 {\r
269                         ethernetif = xNetIf->state;\r
270 \r
271                         /* move received packet into a new pbuf */\r
272                         p = low_level_input( xNetIf );\r
273 \r
274                         if( p == NULL )\r
275                         {\r
276                                 /* No packet could be read.  Wait a for an interrupt to tell us \r
277                                 there is more data available. */\r
278                                 vEMACWaitForInput();\r
279                         }\r
280 \r
281                 } while( p == NULL );\r
282         \r
283                 /* points to packet payload, which starts with an Ethernet header */\r
284                 ethhdr = p->payload;\r
285         \r
286                 #if LINK_STATS\r
287                         lwip_stats.link.recv++;\r
288                 #endif /* LINK_STATS */\r
289         \r
290                 ethhdr = p->payload;\r
291         \r
292                 switch( htons( ethhdr->type ) )\r
293                 {\r
294                         /* IP packet? */\r
295                         case ETHTYPE_IP:\r
296                                 /* update ARP table */\r
297                                 etharp_ip_input( xNetIf, p );\r
298                 \r
299                                 /* skip Ethernet header */\r
300                                 pbuf_header( p, (s16_t)-sizeof(struct eth_hdr) );\r
301                 \r
302                                 /* pass to network layer */\r
303                                 xNetIf->input( p, xNetIf );\r
304                                 break;\r
305                 \r
306                         case ETHTYPE_ARP:\r
307                                 /* pass p to ARP module */\r
308                                 etharp_arp_input( xNetIf, ethernetif->ethaddr, p );\r
309                                 break;\r
310                 \r
311                         default:\r
312                                 pbuf_free( p );\r
313                                 p = NULL;\r
314                                 break;\r
315                 }\r
316         }\r
317 }\r
318 /*-----------------------------------------------------------*/\r
319 \r
320 static void arp_timer( void *arg )\r
321 {\r
322         ( void ) arg;\r
323 \r
324     etharp_tmr();\r
325     sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );\r
326 }\r
327 /*-----------------------------------------------------------*/\r
328 \r
329 err_t ethernetif_init( struct netif *netif )\r
330 {\r
331 struct ethernetif   *ethernetif;\r
332 \r
333         ethernetif = mem_malloc( sizeof(struct ethernetif) );\r
334 \r
335         if( ethernetif == NULL )\r
336         {\r
337                 LWIP_DEBUGF( NETIF_DEBUG, ("ethernetif_init: out of memory\n") );\r
338                 return ERR_MEM;\r
339         }\r
340 \r
341         netif->state = ethernetif;\r
342         netif->name[0] = IFNAME0;\r
343         netif->name[1] = IFNAME1;\r
344         netif->output = ethernetif_output;\r
345         netif->linkoutput = low_level_output;\r
346 \r
347         ethernetif->ethaddr = ( struct eth_addr * ) &( netif->hwaddr[0] );\r
348 \r
349         low_level_init( netif );\r
350         etharp_init();\r
351         sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );\r
352 \r
353         return ERR_OK;\r
354 }\r