First version
[3rdparty/ote_partner/tlk.git] / platform / armemu / net.c
1 #if WITH_LWIP
2 /*
3  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
4  * All rights reserved. 
5  * 
6  * Redistribution and use in source and binary forms, with or without modification, 
7  * are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
20  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
26  * OF SUCH DAMAGE.
27  *
28  * This file is part of the lwIP TCP/IP stack.
29  * 
30  * Author: Adam Dunkels <adam@sics.se>
31  *
32  */
33
34 /*
35  * This file is a skeleton for developing Ethernet network interface
36  * drivers for lwIP. Add code to the low_level functions and do a
37  * search-and-replace for the word "ethernetif" to replace it with
38  * something that better describes your network interface.
39  */
40 /*
41  * ARMEMU bits
42  * Copyright (c) 2006 Travis Geiselbrecht
43  *
44  * Permission is hereby granted, free of charge, to any person obtaining
45  * a copy of this software and associated documentation files
46  * (the "Software"), to deal in the Software without restriction,
47  * including without limitation the rights to use, copy, modify, merge,
48  * publish, distribute, sublicense, and/or sell copies of the Software,
49  * and to permit persons to whom the Software is furnished to do so,
50  * subject to the following conditions:
51  * 
52  * The above copyright notice and this permission notice shall be
53  * included in all copies or substantial portions of the Software.
54  * 
55  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
56  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
57  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
58  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
59  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
60  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
61  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
62  */
63
64 #include <malloc.h>
65 #include <dev/ethernet.h>
66 #include <err.h>
67 #include <reg.h>
68 #include <string.h>
69 #include <platform/interrupts.h>
70 #include <platform/armemu/memmap.h>
71
72 #include "lwip/opt.h"
73 #include "lwip/def.h"
74 #include "lwip/mem.h"
75 #include "lwip/pbuf.h"
76 #include "lwip/sys.h"
77 #include <lwip/stats.h>
78
79 #include "netif/etharp.h"
80
81 /* Define those to better describe your network interface. */
82 #define IFNAME0 'e'
83 #define IFNAME1 'n'
84
85 struct ethernetif {
86   struct eth_addr *ethaddr;
87   /* Add whatever per-interface state that is needed here. */
88 };
89
90 static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
91
92 /* Forward declarations. */
93 static void  ethernetif_input(struct netif *netif);
94 static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
95              struct ip_addr *ipaddr);
96
97 static void
98 low_level_init(struct netif *netif)
99 {
100   struct ethernetif *ethernetif = netif->state;
101   
102   /* set MAC hardware address length */
103   netif->hwaddr_len = 6;
104
105   /* set MAC hardware address */
106   netif->hwaddr[0] = 0;
107   netif->hwaddr[1] = 0x01;
108   netif->hwaddr[2] = 0x02;
109   netif->hwaddr[3] = 0x03;
110   netif->hwaddr[4] = 0x04;
111   netif->hwaddr[5] = 0x05;
112
113   /* maximum transfer unit */
114   netif->mtu = 1500;
115   
116   /* broadcast capability */
117   netif->flags = NETIF_FLAG_BROADCAST;
118  
119   /* Do whatever else is needed to initialize interface. */  
120 }
121
122 /*
123  * low_level_output():
124  *
125  * Should do the actual transmission of the packet. The packet is
126  * contained in the pbuf that is passed to the function. This pbuf
127  * might be chained.
128  *
129  */
130
131 static err_t
132 low_level_output(struct netif *netif, struct pbuf *p)
133 {
134   struct ethernetif *ethernetif = netif->state;
135   struct pbuf *q;
136   int i;
137   int j;
138
139 #if ETH_PAD_SIZE
140   pbuf_header(p, -ETH_PAD_SIZE);                        /* drop the padding word */
141 #endif
142
143   /* XXX maybe just a mutex? */
144   enter_critical_section();
145
146   i = 0;
147   for(q = p; q != NULL; q = q->next) {
148     /* Send the data from the pbuf to the interface, one pbuf at a
149        time. The size of the data in each pbuf is kept in the ->len
150        variable. */
151 //      debug_dump_memory_bytes(q->payload, q->len);
152         for (j = 0; j < q->len; j++)
153                 *REG8(NET_OUT_BUF + i + j) = ((unsigned char *)q->payload)[j];
154         i += q->len;
155   }
156
157   *REG(NET_SEND_LEN) = i;
158   *REG(NET_SEND) = 1;
159
160   exit_critical_section();
161
162 #if ETH_PAD_SIZE
163   pbuf_header(p, ETH_PAD_SIZE);                 /* reclaim the padding word */
164 #endif
165   
166 #if LINK_STATS
167   lwip_stats.link.xmit++;
168 #endif /* LINK_STATS */      
169
170   return ERR_OK;
171 }
172
173 /*
174  * low_level_input():
175  *
176  * Should allocate a pbuf and transfer the bytes of the incoming
177  * packet from the interface into the pbuf.
178  *
179  */
180
181 static struct pbuf *
182 low_level_input(struct netif *netif)
183 {
184   struct ethernetif *ethernetif = netif->state;
185   struct pbuf *p, *q;
186   u16_t len;
187   int i;
188   int head, tail;
189
190   /* get the head and tail pointers from the ethernet interface */
191   head = *REG(NET_HEAD);
192   tail = *REG(NET_TAIL);
193
194   if (tail == head)
195           return NULL; // false alarm
196
197   /* Obtain the size of the packet and put it into the "len"
198      variable. */
199   len = *REG(NET_IN_BUF_LEN);
200
201 #if ETH_PAD_SIZE
202   len += ETH_PAD_SIZE;                                          /* allow room for Ethernet padding */
203 #endif
204
205   /* We allocate a pbuf chain of pbufs from the pool. */
206   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
207   if (p != NULL) {
208
209 #if ETH_PAD_SIZE
210     pbuf_header(p, -ETH_PAD_SIZE);                      /* drop the padding word */
211 #endif
212
213     /* We iterate over the pbuf chain until we have read the entire
214      * packet into the pbuf. */
215     int pos = 0;
216     for(q = p; q != NULL; q = q->next) {
217       /* Read enough bytes to fill this pbuf in the chain. The
218        * available data in the pbuf is given by the q->len
219        * variable. */
220           for (i=0; i < q->len; i++) {
221                  ((unsigned char *)q->payload)[i] = *REG8(NET_IN_BUF + pos);
222                  pos++;
223           }
224     }
225
226 #if ETH_PAD_SIZE
227     pbuf_header(p, ETH_PAD_SIZE);                       /* reclaim the padding word */
228 #endif
229
230 #if LINK_STATS
231     lwip_stats.link.recv++;
232 #endif /* LINK_STATS */      
233   } else {
234 #if LINK_STATS
235     lwip_stats.link.memerr++;
236     lwip_stats.link.drop++;
237 #endif /* LINK_STATS */      
238   }
239
240   /* push the tail pointer up by one, giving the buffer back to the hardware */
241   *REG(NET_TAIL) = (tail + 1) % NET_IN_BUF_COUNT;
242
243   return p;  
244 }
245
246 /*
247  * ethernetif_output():
248  *
249  * This function is called by the TCP/IP stack when an IP packet
250  * should be sent. It calls the function called low_level_output() to
251  * do the actual transmission of the packet.
252  *
253  */
254
255 static err_t
256 ethernetif_output(struct netif *netif, struct pbuf *p,
257       struct ip_addr *ipaddr)
258 {
259 //      dprintf("ethernetif_output: netif %p, pbuf %p, ipaddr %p\n", netif, p, ipaddr);
260   
261  /* resolve hardware address, then send (or queue) packet */
262   return etharp_output(netif, ipaddr, p);
263  
264 }
265
266 /*
267  * ethernetif_input():
268  *
269  * This function should be called when a packet is ready to be read
270  * from the interface. It uses the function low_level_input() that
271  * should handle the actual reception of bytes from the network
272  * interface.
273  *
274  */
275
276 static void
277 ethernetif_input(struct netif *netif)
278 {
279   struct ethernetif *ethernetif;
280   struct eth_hdr *ethhdr;
281   struct pbuf *p;
282
283   ethernetif = netif->state;
284   
285   /* move received packet into a new pbuf */
286   p = low_level_input(netif);
287   /* no packet could be read, silently ignore this */
288   if (p == NULL) return;
289   /* points to packet payload, which starts with an Ethernet header */
290   ethhdr = p->payload;
291
292 #if LINK_STATS
293   lwip_stats.link.recv++;
294 #endif /* LINK_STATS */
295
296   ethhdr = p->payload;
297
298 //  dprintf("ethernetif_input: type 0x%x\n", htons(ethhdr->type));
299     
300   switch (htons(ethhdr->type)) {
301   /* IP packet? */
302   case ETHTYPE_IP:
303     /* update ARP table */
304     etharp_ip_input(netif, p);
305     /* skip Ethernet header */
306     pbuf_header(p, -sizeof(struct eth_hdr));
307     /* pass to network layer */
308     netif->input(p, netif);
309     break;
310       
311     case ETHTYPE_ARP:
312       /* pass p to ARP module  */
313       etharp_arp_input(netif, ethernetif->ethaddr, p);
314       break;
315     default:
316       pbuf_free(p);
317       p = NULL;
318       break;
319   }
320 }
321
322 static enum handler_return ethernet_int(void *arg)
323 {
324         struct netif *netif = (struct netif *)arg;
325
326         ethernetif_input(netif);
327
328         return INT_RESCHEDULE;
329 }
330
331
332
333 /*
334  * ethernetif_init():
335  *
336  * Should be called at the beginning of the program to set up the
337  * network interface. It calls the function low_level_init() to do the
338  * actual setup of the hardware.
339  *
340  */
341
342 static err_t
343 ethernetif_init(struct netif *netif)
344 {
345   struct ethernetif *ethernetif;
346     
347   ethernetif = mem_malloc(sizeof(struct ethernetif));
348   
349   if (ethernetif == NULL)
350   {
351         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
352         return ERR_MEM;
353   }
354   
355   netif->state = ethernetif;
356   netif->name[0] = IFNAME0;
357   netif->name[1] = IFNAME1;
358   netif->output = ethernetif_output;
359   netif->linkoutput = low_level_output;
360   
361   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
362   
363   low_level_init(netif);
364
365   return ERR_OK;
366 }
367
368 status_t ethernet_init(void)
369 {
370         /* check to see if the ethernet feature is turned on */
371         if ((*REG(SYSINFO_FEATURES) & SYSINFO_FEATURE_NETWORK) == 0)
372                 return ERR_NOT_FOUND;
373
374         struct netif *netif = calloc(sizeof(struct netif), 1);
375         struct ip_addr *ipaddr = calloc(sizeof(struct ip_addr), 1);
376         struct ip_addr *netmask = calloc(sizeof(struct ip_addr), 1);
377         struct ip_addr *gw = calloc(sizeof(struct ip_addr), 1);
378
379         struct netif *netifret = netif_add(netif, ipaddr, netmask, gw, NULL, &ethernetif_init, &ip_input);
380         if (netifret == NULL) {
381                 free(netif);
382                 free(ipaddr);
383                 free(netmask);
384                 free(gw);
385                 return ERR_NOT_FOUND;
386         }
387
388         /* register for interrupt handlers */
389         register_int_handler(INT_NET, ethernet_int, netif);
390
391         netif_set_default(netif);
392
393         unmask_interrupt(INT_NET, NULL);
394
395         return NO_ERROR;
396 }
397
398 #endif // WITH_LWIP