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