zephyr/net/ip/net_driver_ethernet.c
Michael LeMay 0927378a59 net: Add Ethernet support to the network stack
This patch adds support for Ethernet to the network stack, which
entails relying on the Ethernet device driver to set the MAC address,
invoking ARP routines at the appropriate points, configuring the
Contiki network stack to use the appropriate link-level header length,
etc.

Change-Id: I153a6f4c83c28ca7129ef5affa1e9a18b0f92913
Signed-off-by: Michael LeMay <michael.lemay@intel.com>
2016-02-05 20:24:38 -05:00

147 lines
3.1 KiB
C

/* net_driver_ethernet.c - Ethernet driver */
/*
* Copyright (c) 2015 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 <nanokernel.h>
#include <toolchain.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#if defined(CONFIG_STDOUT_CONSOLE)
#include <stdio.h>
#define PRINT printf
#else
#include <misc/printk.h>
#define PRINT printk
#endif
#include <net/net_core.h>
#include "net_driver_ethernet.h"
#include "contiki/ipv4/uip_arp.h"
static bool opened;
static ethernet_tx_callback tx_cb;
void net_driver_ethernet_register_tx(ethernet_tx_callback cb)
{
tx_cb = cb;
}
static int net_driver_ethernet_open(void)
{
NET_DBG("Initialized Ethernet driver\n");
opened = true;
return 0;
}
bool net_driver_ethernet_is_opened(void)
{
return opened;
}
static int net_driver_ethernet_send(struct net_buf *buf)
{
#ifdef CONFIG_NETWORKING_WITH_IPV6
struct uip_eth_hdr *eth_hdr = (struct uip_eth_hdr *)uip_buf(buf);
#endif
int res;
NET_DBG("Sending %d bytes\n", buf->len);
if (!tx_cb) {
NET_ERR("Ethernet transmit callback is uninitialized.\n");
return -1;
}
#ifdef CONFIG_NETWORKING_WITH_IPV4
/* Note that uip_arp_out overwrites the outgoing packet if it needs to
* send an ARP request. It relies on higher layers to resend the
* original packet if necessary.
*/
uip_arp_out(buf);
#else
memcpy(eth_hdr->dest.addr, buf->dest.u8, UIP_LLADDR_LEN);
memcpy(eth_hdr->src.addr, uip_lladdr.addr, UIP_LLADDR_LEN);
#endif
res = tx_cb(buf);
if (res == 1) {
/* Release the buffer because we sent all the data
* successfully.
*/
net_buf_put(buf);
}
return res;
}
void net_driver_ethernet_recv(struct net_buf *buf)
{
#ifdef CONFIG_NETWORKING_WITH_IPV4
struct uip_eth_hdr *eth_hdr = (struct uip_eth_hdr *)uip_buf(buf);
if (eth_hdr->type == uip_htons(UIP_ETHTYPE_ARP)) {
uip_arp_arpin(buf);
/* If uip_arp_arpin needs to send an ARP response, it
* overwrites the contents of buf and updates its
* length variable. Otherwise, it zeroes out the
* length variable.
*/
if (uip_len(buf) == 0) {
net_buf_put(buf);
return;
}
if (!tx_cb) {
NET_ERR("Ethernet transmit callback is uninitialized.\n");
net_buf_put(buf);
return;
}
if (tx_cb(buf) != 1) {
NET_ERR("Failed to send ARP response.\n");
}
net_buf_put(buf);
} else
#endif
if (net_recv(buf) != 0) {
NET_ERR("Unexpected return value from net_recv.\n");
net_buf_put(buf);
}
}
static struct net_driver net_driver_ethernet = {
.head_reserve = 0,
.open = net_driver_ethernet_open,
.send = net_driver_ethernet_send,
};
int net_driver_ethernet_init(void)
{
net_register_driver(&net_driver_ethernet);
return 0;
}