Functonal webserver with supporting code changes. WIP COMMIT
[akaros.git] / user / lwip / netif / ethernetif.c
1 /**
2  * Ethernet Wrapper
3  *  
4  * Based on the skelton from the lwip source.
5  * Ported by Paul Pearce
6  */
7 #include <parlib.h>
8
9 #include "lwip/opt.h"
10 #include "lwip/def.h"
11 #include "lwip/mem.h"
12 #include "lwip/pbuf.h"
13 #include "lwip/sys.h"
14 #include <lwip/stats.h>
15 #include <lwip/snmp.h>
16 #include "netif/etharp.h"
17 #include "netif/ppp_oe.h"
18
19 #define IFNAME0 'e'
20 #define IFNAME1 'n'
21
22 #define eth_debug(...) //printf(__VA_ARGS__)
23
24 struct ethernetif {
25   struct eth_addr *ethaddr;
26   /* Add whatever per-interface state that is needed here. */
27 };
28
29 struct netif* registered_netif;
30
31 /**
32  * In this function, the hardware should be initialized.
33  * Called from ethernetif_init().
34  *
35  * @param netif the already initialized lwip network interface structure
36  *        for this ethernetif
37  */
38 static void
39 low_level_init(struct netif *netif)
40 {
41         eth_debug("In low_level_init\n");
42
43         struct ethernetif *ethernetif = netif->state;
44
45         /* set MAC hardware address length */
46         netif->hwaddr_len = ETHARP_HWADDR_LEN;
47
48         /* set MAC hardware address */
49         sys_eth_get_mac_addr(&(netif->hwaddr));
50         /* maximum transfer unit */
51         netif->mtu = 1500;
52  
53         /* device capabilities */
54         /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
55         netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
56
57         // Done
58 }
59
60
61 /**
62  * This function should do the actual transmission of the packet. The packet is
63  * contained in the pbuf that is passed to the function. This pbuf
64  * might be chained.
65  *
66  * @param netif the lwip network interface structure for this ethernetif
67  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
68  * @return ERR_OK if the packet could be sent
69  *         an err_t value if the packet couldn't be sent
70  *
71  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
72  *       strange results. You might consider waiting for space in the DMA queue
73  *       to become availale since the stack doesn't retry to send a packet
74  *       dropped because of memory failure (except for the TCP timers).
75  */
76
77 // TODO: We go to a lot of trouble to force a single send into multiple descriptors, and
78 // then read all these pbufs into 1 send. A better interface would be for each pbuf to load
79 // a single descriptor
80 // This would only be useful for lwip, as lwip chains pbufs as a mem minimization technique
81 // A real stack wouldnt do this. Thats why I havent written to code to do so.
82 static err_t
83 low_level_output(struct netif *netif, struct pbuf *p)
84 {
85         eth_debug("In low_level_output\n");
86
87          struct ethernetif *ethernetif = netif->state;
88          struct pbuf *q;
89
90         // initiate transfer();
91  
92         #if ETH_PAD_SIZE
93          pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
94         #endif
95
96         char *out_buf = malloc(1518);
97         
98         if (out_buf == NULL) {
99                 #if ETH_PAD_SIZE
100                  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
101                 #endif
102                 return -1;
103         }
104         
105         int cur_pos = 0;
106
107          for(q = p; q != NULL; q = q->next) {
108            /* Send the data from the pbuf to the interface, one pbuf at a
109               time. The size of the data in each pbuf is kept in the ->len
110               variable. */
111                 if ((cur_pos + q->len) > 1518) {
112                         #if ETH_PAD_SIZE
113                          pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
114                         #endif
115                         return -1;
116                         
117                 }
118         
119                 memcpy(out_buf + cur_pos, q->payload, q->len);
120                 cur_pos = cur_pos + q->len;
121         }
122         
123         #if ETH_PAD_SIZE
124          pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
125         #endif
126         
127         if (sys_eth_write(out_buf, cur_pos) < 0)
128                 return -1;
129
130          LINK_STATS_INC(link.xmit);
131
132          return ERR_OK;
133 }
134
135 /**
136  * Should allocate a pbuf and transfer the bytes of the incoming
137  * packet from the interface into the pbuf.
138  *
139  * @param netif the lwip network interface structure for this ethernetif
140  * @return a pbuf filled with the received packet (including MAC header)
141  *         NULL on memory error
142  */
143 static struct pbuf *low_level_input(struct netif *netif) {
144
145         eth_debug("In low_level_input\n");
146
147         struct ethernetif *ethernetif = netif->state;
148         struct pbuf *p, *q;
149         u16_t len;
150
151         char buf[4096];
152         memset(buf, 0x00, 4096);
153         char *buf_ptr = buf;
154
155         len = sys_eth_read(buf);
156
157         if (len == 0)
158                 return NULL;
159
160         #if ETH_PAD_SIZE
161                 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
162         #endif
163
164         /* We allocate a pbuf chain of pbufs from the pool. */
165         p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
166  
167         if (p != NULL) {
168
169                 #if ETH_PAD_SIZE
170                         pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
171                 #endif
172
173                 /* We iterate over the pbuf chain until we have read the entire
174                  * packet into the pbuf. */
175            
176                 for(q = p; q != NULL; q = q->next) {
177                         /* Read enough bytes to fill this pbuf in the chain. The
178                          * available data in the pbuf is given by the q->len
179                         * variable. */
180                         // read data into(q->payload, q->len);
181                         memcpy(q->payload, buf_ptr, q->len);
182                         buf_ptr += q->len;
183                 }
184
185                 #if ETH_PAD_SIZE
186                         pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
187                 #endif
188
189                 LINK_STATS_INC(link.recv);
190         } else {
191                 //drop packet();
192                 LINK_STATS_INC(link.memerr);
193                 LINK_STATS_INC(link.drop);
194         }
195
196         return p;
197 }
198
199 /**
200  * This function should be called when a packet is ready to be read
201  * from the interface. It uses the function low_level_input() that
202  * should handle the actual reception of bytes from the network
203  * interface. Then the type of the received packet is determined and
204  * the appropriate input function is called.
205  *
206  * @param netif the lwip network interface structure for this ethernetif
207  */
208 void
209 ethernetif_input(struct netif *netif)
210 {
211         eth_debug("In ethernetif_input\n");
212
213         struct ethernetif *ethernetif;
214         struct eth_hdr *ethhdr;
215         struct pbuf *p;
216
217         ethernetif = netif->state;
218
219         /* move received packet into a new pbuf */
220         p = low_level_input(netif);
221   
222         /* no packet could be read, silently ignore this */
223         if (p == NULL) return;
224
225         /* points to packet payload, which starts with an Ethernet header */
226         ethhdr = p->payload;
227
228         /* full packet send to tcpip_thread to process */
229         if (netif->input(p, netif)!=ERR_OK) { 
230                 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
231                 pbuf_free(p);
232                 p = NULL;
233         }
234 }
235
236 /**
237  * Should be called at the beginning of the program to set up the
238  * network interface. It calls the function low_level_init() to do the
239  * actual setup of the hardware.
240  *
241  * This function should be passed as a parameter to netif_add().
242  *
243  * @param netif the lwip network interface structure for this ethernetif
244  * @return ERR_OK if the loopif is initialized
245  *         ERR_MEM if private data couldn't be allocated
246  *         any other err_t on error
247  */
248 err_t
249 ethernetif_init(struct netif *netif)
250 {
251         eth_debug("In ethernetif_init\n");
252
253         struct ethernetif *ethernetif;
254
255         LWIP_ASSERT("netif != NULL", (netif != NULL));
256     
257         ethernetif = mem_malloc(sizeof(struct ethernetif));
258         if (ethernetif == NULL) {
259                 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
260                 return ERR_MEM;
261         }
262
263         #if LWIP_NETIF_HOSTNAME
264         /* Initialize interface hostname */
265         netif->hostname = "lwip";
266         #endif /* LWIP_NETIF_HOSTNAME */
267
268         /*
269          * Initialize the snmp variables and counters inside the struct netif.
270          * The last argument should be replaced with your link speed, in units
271          * of bits per second.
272          */
273
274         NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
275
276         netif->state = ethernetif;
277         netif->name[0] = IFNAME0;
278         netif->name[1] = IFNAME1;
279   
280         /* We directly use etharp_output() here to save a function call.
281          * You can instead declare your own function an call etharp_output()
282          * from it if you have to do some checks before sending (e.g. if link
283          * is available...) */
284
285         netif->output = etharp_output;
286         netif->linkoutput = low_level_output;
287
288         ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
289   
290         /* initialize the hardware */
291         low_level_init(netif);
292
293         registered_netif = netif;
294
295         return ERR_OK;
296 }