static int _marshall_ethernet(ng_netdev_eth_t *dev, uint8_t *buffer, ng_pktsnip_t *pkt) { int data_len = 0; ethernet_hdr_t *hdr = (ethernet_hdr_t *)buffer; ng_netif_hdr_t *netif_hdr; ng_pktsnip_t *payload; if (pkt == NULL) { DEBUG("ng_netdev_eth: pkt was NULL"); return -EINVAL; } payload = pkt->next; if (pkt->type != NG_NETTYPE_NETIF) { DEBUG("ng_netdev_eth: First header was not generic netif header\n"); return -EBADMSG; } if (payload) { hdr->type = byteorder_htons(ng_nettype_to_ethertype(payload->type)); } else { hdr->type = byteorder_htons(ETHERTYPE_UNKNOWN); } netif_hdr = pkt->data; /* set ethernet header */ if (netif_hdr->src_l2addr_len == ETHERNET_ADDR_LEN) { memcpy(hdr->dst, ng_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len); } else { dev_eth_t *ethdev = dev->ethdev; ethdev->driver->get_mac_addr(ethdev, hdr->src); } if (netif_hdr->flags & NG_NETIF_HDR_FLAGS_BROADCAST) { _addr_set_broadcast(hdr->dst); } else if (netif_hdr->flags & NG_NETIF_HDR_FLAGS_MULTICAST) { _addr_set_multicast(hdr->dst, payload); } else if (netif_hdr->dst_l2addr_len == ETHERNET_ADDR_LEN) { memcpy(hdr->dst, ng_netif_hdr_get_dst_addr(netif_hdr), ETHERNET_ADDR_LEN); } else { DEBUG("ng_netdev_eth: destination address had unexpected format\n"); return -EBADMSG; } DEBUG("ng_netdev_eth: send to %02x:%02x:%02x:%02x:%02x:%02x\n", hdr->dst[0], hdr->dst[1], hdr->dst[2], hdr->dst[3], hdr->dst[4], hdr->dst[5]); data_len += sizeof(ethernet_hdr_t); while (payload != NULL) { if ((data_len + payload->size) > ETHERNET_MAX_LEN) { DEBUG("ng_netdev_eth: Packet too big for ethernet frame\n"); return -ENOBUFS; } memcpy(send_buffer + data_len, payload->data, payload->size); data_len += payload->size; payload = payload->next; } /* Pad to minimum payload size. * Linux does this on its own, but it doesn't hurt to do it here. * As of now only tuntaposx needs this. */ if (data_len < (ETHERNET_MIN_LEN)) { DEBUG("ng_netdev_eth: padding data! (%d -> ", data_len); memset(send_buffer + data_len, 0, ETHERNET_MIN_LEN - data_len); data_len = ETHERNET_MIN_LEN; DEBUG("%d)\n", data_len); } return data_len; }
static int _send(gnrc_netdev2_t *gnrc_netdev2, gnrc_pktsnip_t *pkt) { ethernet_hdr_t hdr; gnrc_netif_hdr_t *netif_hdr; gnrc_pktsnip_t *payload; netdev2_t *dev = gnrc_netdev2->dev; if (pkt == NULL) { DEBUG("gnrc_netdev2_eth: pkt was NULL"); return -EINVAL; } payload = pkt->next; if (pkt->type != GNRC_NETTYPE_NETIF) { DEBUG("gnrc_netdev2_eth: First header was not generic netif header\n"); return -EBADMSG; } if (payload) { hdr.type = byteorder_htons(gnrc_nettype_to_ethertype(payload->type)); } else { hdr.type = byteorder_htons(ETHERTYPE_UNKNOWN); } netif_hdr = pkt->data; /* set ethernet header */ if (netif_hdr->src_l2addr_len == ETHERNET_ADDR_LEN) { memcpy(hdr.dst, gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len); } else { dev->driver->get(dev, NETOPT_ADDRESS, hdr.src, ETHERNET_ADDR_LEN); } if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) { _addr_set_broadcast(hdr.dst); } else if (netif_hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST) { _addr_set_multicast(hdr.dst, payload); } else if (netif_hdr->dst_l2addr_len == ETHERNET_ADDR_LEN) { memcpy(hdr.dst, gnrc_netif_hdr_get_dst_addr(netif_hdr), ETHERNET_ADDR_LEN); } else { DEBUG("gnrc_netdev2_eth: destination address had unexpected format\n"); return -EBADMSG; } DEBUG("gnrc_netdev2_eth: send to %02x:%02x:%02x:%02x:%02x:%02x\n", hdr.dst[0], hdr.dst[1], hdr.dst[2], hdr.dst[3], hdr.dst[4], hdr.dst[5]); size_t n; pkt = gnrc_pktbuf_get_iovec(pkt, &n); struct iovec *vector = (struct iovec *)pkt->data; vector[0].iov_base = (char*)&hdr; vector[0].iov_len = sizeof(ethernet_hdr_t); dev->driver->send(dev, vector, n); gnrc_pktbuf_release(pkt); return 0; }