err_t ether_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) { struct pbuf *q; struct eth_hdr *ethhdr; struct eth_addr *dest, mcastaddr; struct ip_addr *queryaddr; err_t err; int i; int loopback = 0; //kprintf("ether: xmit %d bytes, %d bufs\n", p->tot_len, pbuf_clen(p)); if ((netif->flags & NETIF_UP) == 0) return -ENETDOWN; if (pbuf_header(p, ETHER_HLEN)) { kprintf(KERN_ERR "ether_output: not enough room for Ethernet header in pbuf\n"); stats.link.err++; return -EBUF; } // Construct Ethernet header. Start with looking up deciding which // MAC address to use as a destination address. Broadcasts and // multicasts are special, all other addresses are looked up in the // ARP table. queryaddr = ipaddr; if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, &netif->netmask)) { dest = (struct eth_addr *) ðbroadcast; } else if (ip_addr_ismulticast(ipaddr)) { // Hash IP multicast address to MAC address. mcastaddr.addr[0] = 0x01; mcastaddr.addr[1] = 0x0; mcastaddr.addr[2] = 0x5e; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); dest = &mcastaddr; } else if (ip_addr_cmp(ipaddr, &netif->ipaddr)) { dest = &netif->hwaddr; loopback = 1; } else { if (ip_addr_maskcmp(ipaddr, &netif->ipaddr, &netif->netmask)) { // Use destination IP address if the destination is on the same subnet as we are. queryaddr = ipaddr; } else { // Otherwise we use the default router as the address to send the Ethernet frame to. queryaddr = &netif->gw; } dest = arp_lookup(queryaddr); } // If the arp_lookup() didn't find an address, we send out an ARP query for the IP address. if (dest == NULL) { q = arp_query(netif, &netif->hwaddr, queryaddr); if (q != NULL) { err = dev_transmit((dev_t) netif->state, q); if (err < 0) { kprintf(KERN_ERR "ether: error %d sending arp packet\n", err); pbuf_free(q); stats.link.drop++; return err; } } // Queue packet for transmission, when the ARP reply returns err = arp_queue(netif, p, queryaddr); if (err < 0) { kprintf(KERN_ERR "ether: error %d queueing packet\n", err); stats.link.drop++; stats.link.memerr++; return err; } return 0; } ethhdr = p->payload; for (i = 0; i < 6; i++) { ethhdr->dest.addr[i] = dest->addr[i]; ethhdr->src.addr[i] = netif->hwaddr.addr[i]; } ethhdr->type = htons(ETHTYPE_IP); if (loopback) { struct pbuf *q; q = pbuf_dup(PBUF_RAW, p); if (!q) return -ENOMEM; err = ether_input(netif, q); if (err < 0) { pbuf_free(q); return err; } } else { err = dev_transmit((dev_t) netif->state, p); if (err < 0) { kprintf(KERN_ERR "ether: error %d sending packet\n", err); return err; } } return 0; }
/*-----------------------------------------------------------------------------------*/ static err_t tapif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) { struct tapif *tapif; struct pbuf *q; struct eth_hdr *ethhdr; struct eth_addr *dest, mcastaddr; struct ip_addr *queryaddr; err_t err; u8_t i; tapif = netif->state; /* Make room for Ethernet header. */ if(pbuf_header(p, sizeof(struct eth_hdr)) != 0) { /* The pbuf_header() call shouldn't fail, but we allocate an extra pbuf just in case. */ q = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr), PBUF_RAM); if(q == NULL) { return ERR_MEM; } pbuf_chain(q, p); p = q; } /* Construct Ethernet header. Start with looking up deciding which MAC address to use as a destination address. Broadcasts and multicasts are special, all other addresses are looked up in the ARP table. */ queryaddr = ipaddr; if(ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, &(netif->netmask))) { dest = (struct eth_addr *)ðbroadcast; } else if(ip_addr_ismulticast(ipaddr)) { /* Hash IP multicast address to MAC address. */ mcastaddr.addr[0] = 0x01; mcastaddr.addr[1] = 0x0; mcastaddr.addr[2] = 0x5e; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); dest = &mcastaddr; } else { if(ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { /* Use destination IP address if the destination is on the same subnet as we are. */ queryaddr = ipaddr; } else { /* Otherwise we use the default router as the address to send the Ethernet frame to. */ queryaddr = &(netif->gw); } dest = arp_lookup(queryaddr); } /* If the arp_lookup() didn't find an address, we send out an ARP query for the IP address. */ if(dest == NULL) { q = arp_query(netif, tapif->ethaddr, queryaddr); if(q != NULL) { printf("Sending ARP after query\n"); err = low_level_output(tapif, q); pbuf_free(q); return err; } return ERR_MEM; } ethhdr = p->payload; for(i = 0; i < 6; i++) { ethhdr->dest.addr[i] = dest->addr[i]; ethhdr->src.addr[i] = tapif->ethaddr->addr[i]; } ethhdr->type = htons(ETHTYPE_IP); return low_level_output(tapif, p); }