2016-06-01 15:06:27 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Intel Corporation.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <net/net_core.h>
|
|
|
|
#include <net/net_l2.h>
|
|
|
|
#include <net/net_if.h>
|
|
|
|
#include <net/arp.h>
|
|
|
|
|
|
|
|
static enum net_verdict ethernet_recv(struct net_if *iface,
|
|
|
|
struct net_buf *buf)
|
|
|
|
{
|
2016-06-03 12:40:19 +03:00
|
|
|
struct net_eth_hdr *hdr = NET_ETH_BUF(buf);
|
2016-06-07 14:17:51 +03:00
|
|
|
struct net_linkaddr *lladdr;
|
2016-06-03 12:40:19 +03:00
|
|
|
|
|
|
|
switch (ntohs(hdr->type)) {
|
|
|
|
case NET_ETH_PTYPE_IP:
|
|
|
|
case NET_ETH_PTYPE_ARP:
|
|
|
|
net_nbuf_family(buf) = AF_INET;
|
|
|
|
break;
|
|
|
|
case NET_ETH_PTYPE_IPV6:
|
|
|
|
net_nbuf_family(buf) = AF_INET6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-06-07 14:17:51 +03:00
|
|
|
/* Set the pointers to ll src and dst addresses */
|
|
|
|
lladdr = net_nbuf_ll_src(buf);
|
|
|
|
lladdr->addr = ((struct net_eth_hdr *)net_nbuf_ll(buf))->src.addr;
|
|
|
|
lladdr->len = sizeof(struct net_eth_hdr);
|
|
|
|
|
|
|
|
lladdr = net_nbuf_ll_dst(buf);
|
|
|
|
lladdr->addr = ((struct net_eth_hdr *)net_nbuf_ll(buf))->dst.addr;
|
|
|
|
lladdr->len = sizeof(struct net_eth_hdr);
|
|
|
|
|
2016-06-01 15:06:27 +02:00
|
|
|
#ifdef CONFIG_NET_ARP
|
2016-06-02 17:22:42 +03:00
|
|
|
if (net_nbuf_family(buf) == AF_INET &&
|
|
|
|
(net_nbuf_ll_reserve(buf) == sizeof(struct net_eth_hdr))) {
|
2016-06-01 15:06:27 +02:00
|
|
|
struct net_eth_hdr *eth_hdr =
|
|
|
|
(struct net_eth_hdr *) net_nbuf_ll(buf);
|
|
|
|
|
|
|
|
if (ntohs(eth_hdr->type) == NET_ETH_PTYPE_ARP) {
|
|
|
|
NET_DBG("ARP packet from %s received",
|
|
|
|
net_sprint_ll_addr(
|
|
|
|
(uint8_t *)eth_hdr->src.addr,
|
|
|
|
sizeof(struct net_eth_addr)));
|
|
|
|
return net_arp_input(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return NET_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum net_verdict ethernet_send(struct net_if *iface,
|
|
|
|
struct net_buf *buf)
|
|
|
|
{
|
2016-06-07 14:19:12 +03:00
|
|
|
struct net_eth_hdr *hdr;
|
|
|
|
|
2016-06-01 15:06:27 +02:00
|
|
|
#ifdef CONFIG_NET_ARP
|
2016-06-02 17:22:42 +03:00
|
|
|
if (net_nbuf_family(buf) == AF_INET) {
|
|
|
|
struct net_buf *arp_buf = net_arp_prepare(buf);
|
2016-06-01 15:06:27 +02:00
|
|
|
|
2016-06-02 17:22:42 +03:00
|
|
|
if (!arp_buf) {
|
|
|
|
return NET_DROP;
|
|
|
|
}
|
2016-06-01 15:06:27 +02:00
|
|
|
|
2016-06-02 17:22:42 +03:00
|
|
|
buf = arp_buf;
|
|
|
|
}
|
2016-06-01 15:06:27 +02:00
|
|
|
#endif
|
|
|
|
|
2016-06-07 14:20:15 +03:00
|
|
|
/* If the src ll address is multicast or broadcast, then
|
|
|
|
* what probably happened is that the RX buffer is used
|
|
|
|
* for sending data back to recipient. We must substitute
|
|
|
|
* the src address using the real ll address.
|
|
|
|
* If the ll address is not set at all, then we must set
|
|
|
|
* it here.
|
|
|
|
*/
|
|
|
|
if (!net_nbuf_ll_src(buf)->addr ||
|
|
|
|
net_eth_is_addr_broadcast(
|
|
|
|
(struct net_eth_addr *)net_nbuf_ll_src(buf)->addr) ||
|
|
|
|
net_eth_is_addr_multicast(
|
|
|
|
(struct net_eth_addr *)net_nbuf_ll_src(buf)->addr)) {
|
|
|
|
net_nbuf_ll_src(buf)->addr = net_nbuf_ll_if(buf)->addr;
|
|
|
|
net_nbuf_ll_src(buf)->len = net_nbuf_ll_if(buf)->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the destination address is not set, then use broadcast
|
|
|
|
* address.
|
|
|
|
*/
|
|
|
|
if (!net_nbuf_ll_dst(buf)->addr) {
|
|
|
|
memset((uint8_t *)net_nbuf_ll(buf), 0xff,
|
|
|
|
sizeof(struct net_eth_addr));
|
|
|
|
net_nbuf_ll_dst(buf)->addr = net_nbuf_ll(buf);
|
|
|
|
net_nbuf_ll_dst(buf)->len = sizeof(struct net_eth_addr);
|
|
|
|
}
|
|
|
|
|
2016-06-07 14:19:12 +03:00
|
|
|
hdr = NET_ETH_BUF(buf);
|
|
|
|
|
|
|
|
if (net_nbuf_family(buf) == AF_INET) {
|
|
|
|
/* ARP pre-fills the type so don't overwrite it */
|
|
|
|
if (hdr->type != htons(NET_ETH_PTYPE_ARP)) {
|
|
|
|
hdr->type = htons(NET_ETH_PTYPE_IP);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hdr->type = htons(NET_ETH_PTYPE_IPV6);
|
|
|
|
}
|
|
|
|
|
2016-06-01 15:06:27 +02:00
|
|
|
net_if_queue_tx(iface, buf);
|
|
|
|
|
|
|
|
return NET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NET_L2_INIT(ETHERNET_L2, ethernet_recv, ethernet_send);
|