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