/* This is called by dev loop in order to ensure correct ethernet addressing. * Returns 0 if the destination is unknown, and -1 if the packet is not deliverable * due to ethernet addressing (i.e., no arp association was possible. * * Only IP packets must pass by this. ARP will always use direct dev->send() function, so * we assume IP is used. */ int32_t pico_ethernet_send(struct pico_frame *f) { const struct pico_eth *dstmac = NULL; int32_t ret = -1; if (IS_IPV6(f)) { /*TODO: Neighbor solicitation */ dstmac = NULL; } else if (IS_IPV4(f)) { if (IS_BCAST(f) || destination_is_bcast(f)) { dstmac = (const struct pico_eth *const) PICO_ETHADDR_ALL; } #ifdef PICO_SUPPORT_MCAST else if (destination_is_mcast(f)) { uint8_t pico_mcast_mac[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }; dstmac = pico_ethernet_mcast_translate(f, pico_mcast_mac); } #endif else { dstmac = pico_arp_get(f); if (!dstmac) return 0; } /* This sets destination and source address, then pushes the packet to the device. */ if (dstmac && (f->start > f->buffer) && ((f->start - f->buffer) >= PICO_SIZE_ETHHDR)) { struct pico_eth_hdr *hdr; f->start -= PICO_SIZE_ETHHDR; f->len += PICO_SIZE_ETHHDR; f->datalink_hdr = f->start; hdr = (struct pico_eth_hdr *) f->datalink_hdr; memcpy(hdr->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); memcpy(hdr->daddr, dstmac, PICO_SIZE_ETH); hdr->proto = PICO_IDETH_IPV4; if(!memcmp(hdr->daddr, hdr->saddr, PICO_SIZE_ETH)) { dbg("sending out packet destined for our own mac\n"); return pico_ethernet_receive(f); } else if(IS_LIMITED_BCAST(f)) { ret = pico_device_broadcast(f); } else { ret = (int32_t)f->dev->send(f->dev, f->start, (int) f->len); /* Frame is discarded after this return by the caller */ } if(!ret) pico_frame_discard(f); return ret; } else { return -1; } } /* End IPV4 ethernet addressing */ return -1; }
/* Ethernet send, second attempt: try bcast. * Returns 0 if the packet is not bcast, so it will be handled somewhere else. * Returns 1 if the packet is handled by the pico_device_broadcast() function, so it can be discarded. * */ static int32_t pico_ethsend_bcast(struct pico_frame *f) { if (IS_LIMITED_BCAST(f)) { (void)pico_device_broadcast(f); /* We can discard broadcast even if it's not sent. */ return 1; } return 0; }