]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/netif/ethernetif.c
c10ae3b062f762a7c0d2f618ffaf671369074afa
[pes-rpp/rpp-lwip.git] / src / netif / ethernetif.c
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3  * All rights reserved. 
4  * 
5  * Redistribution and use in source and binary forms, with or without modification, 
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission. 
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  * 
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  */
32
33 /*
34  * This file is a skeleton for developing Ethernet network interface
35  * drivers for lwIP. Add code to the low_level functions and do a
36  * search-and-replace for the word "ethernetif" to replace it with
37  * something that better describes your network interface.
38  *
39  * THIS CODE NEEDS TO BE FIXED - IT IS NOT In SYNC WITH CURRENT ETHARP API
40  */
41
42 #include "lwip/debug.h"
43
44 #include "lwip/opt.h"
45 #include "lwip/def.h"
46 #include "lwip/mem.h"
47 #include "lwip/pbuf.h"
48 #include "lwip/sys.h"
49
50 #include "netif/arp.h"
51
52 /* Define those to better describe your network interface. */
53 #define IFNAME0 'e'
54 #define IFNAME1 't'
55
56 struct ethernetif {
57   struct eth_addr *ethaddr;
58   /* Add whatever per-interface state that is needed here. */
59 };
60
61 static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
62
63 /* Forward declarations. */
64 static void  ethernetif_input(struct netif *netif);
65 static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
66                                struct ip_addr *ipaddr);
67
68 /*-----------------------------------------------------------------------------------*/
69 static void
70 low_level_init(struct netif *netif)
71 {
72   struct ethernetif *ethernetif;
73
74   ethernetif = netif->state;
75   
76   /* Obtain MAC address from network interface. */
77   ethernetif->ethaddr->addr[0] = ;
78   ethernetif->ethaddr->addr[1] = ;
79   ethernetif->ethaddr->addr[2] = ;
80
81   /* Do whatever else is needed to initialize interface. */  
82 }
83 /*-----------------------------------------------------------------------------------*/
84 /*
85  * low_level_output():
86  *
87  * Should do the actual transmission of the packet. The packet is
88  * contained in the pbuf that is passed to the function. This pbuf
89  * might be chained.
90  *
91  */
92 /*-----------------------------------------------------------------------------------*/
93
94 static err_t
95 low_level_output(struct ethernetif *ethernetif, struct pbuf *p)
96 {
97   struct pbuf *q;
98
99   initiate transfer();
100   
101   for(q = p; q != NULL; q = q->next) {
102     /* Send the data from the pbuf to the interface, one pbuf at a
103        time. The size of the data in each pbuf is kept in the ->len
104        variable. */
105     send data from(q->payload, q->len);
106   }
107
108   signal that packet should be sent();
109   
110 #ifdef LINK_STATS
111   lwip_stats.link.xmit++;
112 #endif /* LINK_STATS */      
113
114   return ERR_OK;
115 }
116 /*-----------------------------------------------------------------------------------*/
117 /*
118  * low_level_input():
119  *
120  * Should allocate a pbuf and transfer the bytes of the incoming
121  * packet from the interface into the pbuf.
122  *
123  */
124 /*-----------------------------------------------------------------------------------*/
125 static struct pbuf *
126 low_level_input(struct ethernetif *ethernetif)
127 {
128   struct pbuf *p, *q;
129   u16_t len;
130
131   /* Obtain the size of the packet and put it into the "len"
132      variable. */
133   len = ;
134
135   /* We allocate a pbuf chain of pbufs from the pool. */
136   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
137   
138   if(p != NULL) {
139     /* We iterate over the pbuf chain until we have read the entire
140        packet into the pbuf. */
141     for(q = p; q != NULL; q = q->next) {
142       /* Read enough bytes to fill this pbuf in the chain. The
143          available data in the pbuf is given by the q->len
144          variable. */
145       read data into(q->payload, q->len);
146     }
147     acknowledge that packet has been read();
148 #ifdef LINK_STATS
149     lwip_stats.link.recv++;
150 #endif /* LINK_STATS */      
151   } else {
152     drop packet();
153 #ifdef LINK_STATS
154     lwip_stats.link.memerr++;
155     lwip_stats.link.drop++;
156 #endif /* LINK_STATS */      
157   }
158
159   return p;  
160 }
161 /*-----------------------------------------------------------------------------------*/
162 /*
163  * ethernetif_output():
164  *
165  * This function is called by the TCP/IP stack when an IP packet
166  * should be sent. It calls the function called low_level_output() to
167  * do the actuall transmission of the packet.
168  *
169  */
170 /*-----------------------------------------------------------------------------------*/
171 static err_t
172 ethernetif_output(struct netif *netif, struct pbuf *p,
173                   struct ip_addr *ipaddr)
174 {
175   struct ethernetif *ethernetif;
176   struct pbuf *q;
177   struct eth_hdr *ethhdr;
178   struct eth_addr *dest, mcastaddr;
179   struct ip_addr *queryaddr;
180   err_t err;
181   u8_t i;
182   
183   ethernetif = netif->state;
184
185   /* Make room for Ethernet header. */
186   if(pbuf_header(p, 14) != 0) {
187     /* The pbuf_header() call shouldn't fail, but we allocate an extra
188        pbuf just in case. */
189     q = pbuf_alloc(PBUF_LINK, 14, PBUF_RAM);
190     if(q == NULL) {
191 #ifdef LINK_STATS
192       lwip_stats.link.drop++;
193       lwip_stats.link.memerr++;
194 #endif /* LINK_STATS */      
195       return ERR_MEM;
196     }
197     pbuf_chain(q, p);
198     p = q;
199   }
200
201   /* Construct Ethernet header. Start with looking up deciding which
202      MAC address to use as a destination address. Broadcasts and
203      multicasts are special, all other addresses are looked up in the
204      ARP table. */
205   queryaddr = ipaddr;
206   if(ip_addr_isany(ipaddr) ||
207      ip_addr_isbroadcast(ipaddr, &(netif->netmask))) {
208     dest = (struct eth_addr *)&ethbroadcast;
209   } else if(ip_addr_ismulticast(ipaddr)) {
210     /* Hash IP multicast address to MAC address. */
211     mcastaddr.addr[0] = 0x01;
212     mcastaddr.addr[1] = 0x0;
213     mcastaddr.addr[2] = 0x5e;
214     mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
215     mcastaddr.addr[4] = ip4_addr3(ipaddr);
216     mcastaddr.addr[5] = ip4_addr4(ipaddr);
217     dest = &mcastaddr;
218   } else {
219
220     if(ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
221       /* Use destination IP address if the destination is on the same
222          subnet as we are. */
223       queryaddr = ipaddr;
224     } else {
225       /* Otherwise we use the default router as the address to send
226          the Ethernet frame to. */
227       queryaddr = &(netif->gw);
228     }
229     dest = arp_lookup(queryaddr);
230   }
231
232
233   /* If the arp_lookup() didn't find an address, we send out an ARP
234      query for the IP address. */
235   if(dest == NULL) {
236     q = arp_query(netif, ethernetif->ethaddr, queryaddr);
237     if(q != NULL) {
238       err = low_level_output(ethernetif, q);
239       pbuf_free(q);
240       return err;
241     }
242 #ifdef LINK_STATS
243     lwip_stats.link.drop++;
244     lwip_stats.link.memerr++;
245 #endif /* LINK_STATS */          
246     return ERR_MEM;
247   }
248   ethhdr = p->payload;
249
250   for(i = 0; i < 6; i++) {
251     ethhdr->dest.addr[i] = dest->addr[i];
252     ethhdr->src.addr[i] = ethernetif->ethaddr->addr[i];
253   }
254   
255   ethhdr->type = htons(ETHTYPE_IP);
256   
257   return low_level_output(ethernetif, p);
258
259 }
260 /*-----------------------------------------------------------------------------------*/
261 /*
262  * ethernetif_input():
263  *
264  * This function should be called when a packet is ready to be read
265  * from the interface. It uses the function low_level_input() that
266  * should handle the actual reception of bytes from the network
267  * interface.
268  *
269  */
270 /*-----------------------------------------------------------------------------------*/
271 static void
272 ethernetif_input(struct netif *netif)
273 {
274   struct ethernetif *ethernetif;
275   struct eth_hdr *ethhdr;
276   struct pbuf *p;
277
278
279   ethernetif = netif->state;
280   
281   p = low_level_input(ethernetif);
282
283   if(p != NULL) {
284
285 #ifdef LINK_STATS
286     lwip_stats.link.recv++;
287 #endif /* LINK_STATS */
288
289     ethhdr = p->payload;
290     
291     switch(htons(ethhdr->type)) {
292     case ETHTYPE_IP:
293       arp_ip_input(netif, p);
294       pbuf_header(p, -14);
295       netif->input(p, netif);
296       break;
297     case ETHTYPE_ARP:
298       p = arp_arp_input(netif, ethernetif->ethaddr, p);
299       if(p != NULL) {
300         low_level_output(ethernetif, p);
301         pbuf_free(p);
302       }
303       break;
304     default:
305       pbuf_free(p);
306       break;
307     }
308   }
309 }
310 /*-----------------------------------------------------------------------------------*/
311 static void
312 arp_timer(void *arg)
313 {
314   arp_tmr();
315   sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL);
316 }
317 /*-----------------------------------------------------------------------------------*/
318 /*
319  * ethernetif_init():
320  *
321  * Should be called at the beginning of the program to set up the
322  * network interface. It calls the function low_level_init() to do the
323  * actual setup of the hardware.
324  *
325  */
326 /*-----------------------------------------------------------------------------------*/
327 void
328 ethernetif_init(struct netif *netif)
329 {
330   struct ethernetif *ethernetif;
331     
332   ethernetif = mem_malloc(sizeof(struct ethernetif));
333   netif->state = ethernetif;
334   netif->name[0] = IFNAME0;
335   netif->name[1] = IFNAME1;
336   netif->output = ethernetif_output;
337   netif->linkoutput = low_level_output;
338   
339   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
340   
341   low_level_init(netif);
342   arp_init();
343
344   sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL);
345 }
346 /*-----------------------------------------------------------------------------------*/