1/**
2 * \file
3 * Barrelfish standard ethernet interface
4 */
5
6/*
7 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 *    this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 *    this list of conditions and the following disclaimer in the documentation
17 *    and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 *
32 * This file is part of the lwIP TCP/IP stack.
33 *
34 * Author: Adam Dunkels <adam@sics.se>
35 *
36 */
37
38/*
39 * Copyright (c) 2007, 2008, ETH Zurich.
40 * All rights reserved.
41 *
42 * This file is distributed under the terms in the attached LICENSE file.
43 * If you do not find this file, copies can be found by writing to:
44 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
45 */
46
47/*
48 * This file is a skeleton for developing Ethernet network interface
49 * drivers for lwIP. Add code to the low_level functions and do a
50 * search-and-replace for the word "ethernetif" to replace it with
51 * something that better describes your network interface.
52 */
53
54#include "lwip/opt.h"
55#include "lwip/def.h"
56#include "lwip/init.h"
57#include "lwip/mem.h"
58#include "lwip/pbuf.h"
59#include "lwip/sys.h"
60#include <lwip/stats.h>
61#include <lwip/snmp.h>
62#include "netif/etharp.h"
63#include <assert.h>
64
65#include <netif/bfeth.h>
66
67#include <barrelfish/barrelfish.h>
68#include <netbench/netbench.h>
69#include <idc_barrelfish.h>
70#include <mem_barrelfish.h>
71
72#include <arpa/inet.h>
73
74// 10MBit interface
75#define BFETH_NETSPEED  10000000
76
77/* Define those to better describe your network interface. */
78#define IFNAME0 'e'
79#define IFNAME1 'n'
80
81
82/**
83 * Helper struct to hold private data used to operate your ethernet interface.
84 * Keeping the ethernet address of the MAC in this struct is not necessary
85 * as it is already kept in the struct netif.
86 * But this is only an example, anyway...
87 */
88struct bfeth {
89    struct eth_addr *ethaddr;
90    /* Add whatever per-interface state that is needed here. */
91};
92
93/**
94 * In this function, the hardware should be initialized.
95 * Called from bfeth_init().
96 *
97 * @param netif the already initialized lwip network interface structure
98 *        for this bfeth
99 */
100static void low_level_init(struct netif *netif)
101{
102    /* set MAC hardware address length */
103    netif->hwaddr_len = ETHARP_HWADDR_LEN;
104
105    /* set MAC hardware address */
106    idc_get_mac_address(netif->hwaddr);
107
108    /* maximum transfer unit */
109    netif->mtu = 1500;
110
111    /* device capabilities */
112    netif->flags =
113      NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
114}
115
116/**
117 * This function should do the actual transmission of the packet. The packet is
118 * contained in the pbuf that is passed to the function. This pbuf
119 * might be chained.
120 *
121 * @param netif the lwip network interface structure for this bfeth
122 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
123 * @return ERR_OK if the packet could be sent
124 *         an err_t value if the packet couldn't be sent
125 *
126 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
127 *       strange results. You might consider waiting for space in the DMA queue
128 *       to become availale since the stack doesn't retry to send a packet
129 *       dropped because of memory failure (except for the TCP timers).
130 */
131
132static err_t low_level_output(struct netif *netif, struct pbuf *p)
133{
134    uint8_t numpbuf = 0;
135    //avoid that lwip frees this buffer before it has been sent by the network card.
136    for (struct pbuf * tmpp = p; tmpp != 0; tmpp = tmpp->next) {
137        pbuf_ref(tmpp);
138        ++numpbuf;
139    }
140#if ETH_PAD_SIZE
141    pbuf_header(p, -ETH_PAD_SIZE);      /* drop the padding word */
142#endif
143    //tell the network driver from which buffer and which offset to send the
144    //new data.
145    uint64_t ret = idc_send_packet_to_network_driver(p);
146
147#if ETH_PAD_SIZE
148    pbuf_header(p, ETH_PAD_SIZE);       /* reclaim the padding word */
149#endif
150
151    LINK_STATS_INC(link.xmit);
152
153    if (ret == numpbuf) {
154        return ERR_OK;
155    }
156    return ERR_IF;
157}
158
159uint64_t pbuf_free_tx_done_counter = 0;
160static void bfeth_freeing_handler(struct pbuf *p)
161{
162    assert(p != 0);
163    uint8_t freed_pbufs = pbuf_free(p);
164    pbuf_free_tx_done_counter += freed_pbufs;
165}
166
167typedef void (*packetfilter_func_t) (struct pbuf *, struct netif *, uint64_t);
168static packetfilter_func_t packetfilter = NULL;
169void bfeth_register_packetfilter(packetfilter_func_t filter);
170
171void bfeth_register_packetfilter(packetfilter_func_t filter)
172{
173    packetfilter = filter;
174}
175
176
177
178uint64_t pbuf_free_incoming_counter = 0;
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 bfeth
187 */
188void
189bfeth_input(struct netif *netif, uint64_t pbuf_id, uint64_t paddr, uint64_t len,
190            uint64_t packet_len, struct pbuf *pp)
191{
192    struct bfeth *bfeth;
193    struct eth_hdr *ethhdr;
194    struct pbuf *p;
195
196    bfeth = netif->state;
197
198    //asq: low_level_input is not needed anymore, because p was preallocated
199    //and filled with an arrived packet by the network card driver.
200    //We only need to find the original vaddr of p according to the received
201    //index.
202    //We have to adjust the len and tot_len fields. The packet is
203    //most probably shorter than pbuf's size.
204    //LWIP is freeing the memory by looking at the type, not by the len or
205    //tot_len fields, so that should be fine.
206
207    //get vaddr of p and adjust the length according to the packet length.
208    p = mem_barrelfish_get_pbuf(pbuf_id);
209    //* Buffer has to be found
210    assert(p != 0);
211
212    assert(packet_len != 0);
213    p->len = packet_len;
214    p->tot_len = packet_len;
215    ethhdr = p->payload;
216
217    struct pbuf *replaced_pbuf = get_pbuf_for_packet();
218    if (replaced_pbuf == NULL) {
219       printf("%s:No free pbufs for replacement.  Assuming that packet is dropped\n", disp_name());
220        USER_PANIC("ERROR: No more free pbufs, aborting\n");
221        abort();
222        replaced_pbuf = p;
223//        printf("pbuf stats: total len = %"PRIu16", len = %"PRIu16", buf len = %"PRIu16", ref count = %"PRIu16", \n",
224//                p->tot_len, p->len, p->buff_len, p->ref);
225        replaced_pbuf->tot_len =  replaced_pbuf->buff_len;
226        replaced_pbuf->len =  replaced_pbuf->buff_len;
227        // Maybe I need to reset some pointers here!!
228    } else { // Now doing  packet processing
229
230        /* points to packet payload, which starts with an Ethernet header */
231
232        switch (htons(ethhdr->type)) {
233            /* IP or ARP packet? */
234            case ETHTYPE_IP:
235            case ETHTYPE_ARP:
236#if PPPOE_SUPPORT
237                /* PPPoE packet? */
238            case ETHTYPE_PPPOEDISC:
239            case ETHTYPE_PPPOE:
240#endif                          /* PPPOE_SUPPORT */
241                LWIP_DEBUGF(NETIF_DEBUG, ("bfeth_input: consuming the packet\n"));
242                if (packetfilter != NULL) {
243                    packetfilter(p, netif, pbuf_id);
244                    return;
245                } else {
246                    /* full packet send to tcpip_thread to process */
247                    assert(netif->input != NULL);
248                    if (netif->input(p, netif) != ERR_OK) {
249                        LWIP_DEBUGF(NETIF_DEBUG, ("bfeth_input: IP input error\n"));
250                        ++pbuf_free_incoming_counter;
251                        pbuf_free(p);
252                        p = NULL;
253                    }
254                }
255                break;
256
257            default:
258                LWIP_DEBUGF(NETIF_DEBUG,
259                        ("unknown type %x!!!!!\n", htons(ethhdr->type)));
260                ++pbuf_free_incoming_counter;
261                pbuf_free(p);
262
263                p = NULL;
264                break;
265        }
266
267    }
268
269    //now we have consumed the preregistered pbuf containing a received packet
270    //which was processed in this function. Therefore we have to register a new
271    //free buffer for receiving packets. We can reuse the odl buffer's index
272    //and the corresponding data structures (i.e. array entries)
273    //uint64_t ts = rdtsc();
274    errval_t err = mem_barrelfish_replace_pbuf(replaced_pbuf);
275    if (err != SYS_ERR_OK) {
276        printf("Can't replace received pbuf in RX ring\n");
277        pbuf_free(replaced_pbuf);
278        USER_PANIC("Can't replace received pbuf in RX ring\n");
279    }
280
281    //netbench_record_event_simple(nb, RE_PBUF_REPLACE, ts);
282}
283
284static void bfeth_input_handler(void *data, uint64_t pbuf_id, uint64_t paddr,
285                                uint64_t len, uint64_t packet_len,
286                                struct pbuf *p)
287{
288    bfeth_input((struct netif *) data, pbuf_id, paddr, len, packet_len, p);
289}
290
291
292/**
293 * Should be called at the beginning of the program to set up the
294 * network interface. It calls the function low_level_init() to do the
295 * actual setup of the hardware.
296 *
297 * This function should be passed as a parameter to netif_add().
298 *
299 * @param netif the lwip network interface structure for this bfeth
300 * @return ERR_OK if the loopif is initialized
301 *         ERR_MEM if private data couldn't be allocated
302 *         any other err_t on error
303 */
304err_t bfeth_init(struct netif *netif)
305{
306    struct bfeth *bfeth;
307
308    LWIP_ASSERT("netif != NULL", (netif != NULL));
309
310    bfeth = mem_malloc(sizeof(struct bfeth));
311    if (bfeth == NULL) {
312        LWIP_DEBUGF(NETIF_DEBUG, ("bfeth_init: out of memory\n"));
313        return ERR_MEM;
314    }
315#if LWIP_NETIF_HOSTNAME
316    /* Initialize interface hostname */
317    netif->hostname = "lwip";
318#endif                          /* LWIP_NETIF_HOSTNAME */
319
320    /*
321     * Initialize the snmp variables and counters inside the struct netif.
322     * The last argument should be replaced with your link speed, in units
323     * of bits per second.
324     */
325    NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, BFETH_NETSPEED);
326
327    netif->state = bfeth;
328    netif->name[0] = IFNAME0;
329    netif->name[1] = IFNAME1;
330    /* We directly use etharp_output() here to save a function call.
331     * You can instead declare your own function an call etharp_output()
332     * from it if you have to do some checks before sending (e.g. if link
333     * is available...) */
334    netif->output = etharp_output;
335    netif->linkoutput = low_level_output;
336
337    bfeth->ethaddr = (struct eth_addr *) &(netif->hwaddr[0]);
338
339    /* initialize the hardware */
340    low_level_init(netif);
341
342    // register a callback to get notified of arrived packets
343    idc_register_receive_callback(bfeth_input_handler, (void *) netif);
344
345    //register a function which is called if a transmit descriptor can be freed
346    //(which means the packet has been sent out of the network card and the buffer
347    //is free now)
348    idc_register_freeing_callback(bfeth_freeing_handler);
349
350    return ERR_OK;
351}
352