net: if: vlan: Add virtual lan support
This allows creation of virtual lan (VLAN) networks. VLAN support is only available for ethernet network technology. Fixes #3234 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
700e4bd2e8
commit
de13e979fc
|
@ -15,10 +15,13 @@
|
|||
|
||||
#include <zephyr/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <atomic.h>
|
||||
|
||||
#include <net/net_ip.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <misc/util.h>
|
||||
#include <net/net_if.h>
|
||||
#include <net/ethernet_vlan.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -36,6 +39,7 @@ extern "C" {
|
|||
#define NET_ETH_PTYPE_ARP 0x0806
|
||||
#define NET_ETH_PTYPE_IP 0x0800
|
||||
#define NET_ETH_PTYPE_IPV6 0x86dd
|
||||
#define NET_ETH_PTYPE_VLAN 0x8100
|
||||
|
||||
#define NET_ETH_MINIMAL_FRAME_SIZE 60
|
||||
|
||||
|
@ -45,6 +49,9 @@ enum eth_hw_caps {
|
|||
|
||||
/** RX Checksum offloading supported */
|
||||
ETH_HW_RX_CHKSUM_OFFLOAD = BIT(1),
|
||||
|
||||
/** VLAN supported */
|
||||
ETH_HW_VLAN = BIT(2),
|
||||
};
|
||||
|
||||
struct ethernet_api {
|
||||
|
@ -56,6 +63,13 @@ struct ethernet_api {
|
|||
|
||||
/** Get the device capabilities */
|
||||
enum eth_hw_caps (*get_capabilities)(struct device *dev);
|
||||
|
||||
/** The IP stack will call this function when a VLAN tag is enabled
|
||||
* or disabled. If enable is set to true, then the VLAN tag was added,
|
||||
* if it is false then the tag was removed. The driver can utilize
|
||||
* this information if needed.
|
||||
*/
|
||||
int (*vlan_setup)(struct net_if *iface, u16_t tag, bool enable);
|
||||
};
|
||||
|
||||
struct net_eth_addr {
|
||||
|
@ -68,6 +82,70 @@ struct net_eth_hdr {
|
|||
u16_t type;
|
||||
} __packed;
|
||||
|
||||
struct ethernet_vlan {
|
||||
/** Network interface that has VLAN enabled */
|
||||
struct net_if *iface;
|
||||
|
||||
/** VLAN tag */
|
||||
u16_t tag;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NET_VLAN_COUNT)
|
||||
#define NET_VLAN_MAX_COUNT CONFIG_NET_VLAN_COUNT
|
||||
#else
|
||||
/* Even thou there are no VLAN support, the minimum count must be set to 1.
|
||||
*/
|
||||
#define NET_VLAN_MAX_COUNT 1
|
||||
#endif
|
||||
|
||||
/** Ethernet L2 context that is needed for VLAN */
|
||||
struct ethernet_context {
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct ethernet_vlan vlan[NET_VLAN_MAX_COUNT];
|
||||
|
||||
/** Array that will help when checking if VLAN is enabled for
|
||||
* some specific network interface. Requires that VLAN count
|
||||
* NET_VLAN_MAX_COUNT is not smaller than the actual number
|
||||
* of network interfaces.
|
||||
*/
|
||||
ATOMIC_DEFINE(interfaces, NET_VLAN_MAX_COUNT);
|
||||
|
||||
/** Flag that tells whether how many VLAN tags are enabled for this
|
||||
* context. The same information can be dug from the vlan array but
|
||||
* this saves some time in RX path.
|
||||
*/
|
||||
s8_t vlan_enabled;
|
||||
|
||||
/** Is this context already initialized */
|
||||
bool is_init;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ETHERNET_L2_CTX_TYPE struct ethernet_context
|
||||
|
||||
/**
|
||||
* @brief Initialize Ethernet L2 stack for a given interface
|
||||
*
|
||||
* @param iface A valid pointer to a network interface
|
||||
*/
|
||||
void ethernet_init(struct net_if *iface);
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
/* Separate header for VLAN as some of device interfaces might not
|
||||
* support VLAN.
|
||||
*/
|
||||
struct net_eth_vlan_hdr {
|
||||
struct net_eth_addr dst;
|
||||
struct net_eth_addr src;
|
||||
struct {
|
||||
u16_t tpid; /* tag protocol id */
|
||||
u16_t tci; /* tag control info */
|
||||
} vlan;
|
||||
u16_t type;
|
||||
} __packed;
|
||||
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
|
||||
static inline bool net_eth_is_addr_broadcast(struct net_eth_addr *addr)
|
||||
{
|
||||
if (addr->addr[0] == 0xff &&
|
||||
|
@ -133,6 +211,116 @@ enum eth_hw_caps net_eth_get_hw_capabilities(struct net_if *iface)
|
|||
return eth->get_capabilities(net_if_get_device(iface));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
/**
|
||||
* @brief Add VLAN tag to the interface.
|
||||
*
|
||||
* @param iface Interface to use.
|
||||
* @param tag VLAN tag to add
|
||||
*
|
||||
* @return 0 if ok, <0 if error
|
||||
*/
|
||||
int net_eth_vlan_enable(struct net_if *iface, u16_t tag);
|
||||
|
||||
/**
|
||||
* @brief Remove VLAN tag from the interface.
|
||||
*
|
||||
* @param iface Interface to use.
|
||||
* @param tag VLAN tag to remove
|
||||
*
|
||||
* @return 0 if ok, <0 if error
|
||||
*/
|
||||
int net_eth_vlan_disable(struct net_if *iface, u16_t tag);
|
||||
|
||||
/**
|
||||
* @brief Return VLAN tag specified to network interface
|
||||
*
|
||||
* @param iface Network interface.
|
||||
*
|
||||
* @return VLAN tag for this interface or NET_VLAN_TAG_UNSPEC if VLAN
|
||||
* is not configured for that interface.
|
||||
*/
|
||||
u16_t net_eth_get_vlan_tag(struct net_if *iface);
|
||||
|
||||
/**
|
||||
* @brief Return network interface related to this VLAN tag
|
||||
*
|
||||
* @param iface Master network interface. This is used to get the
|
||||
* pointer to ethernet L2 context
|
||||
* @param tag VLAN tag
|
||||
*
|
||||
* @return Network interface related to this tag or NULL if no such interface
|
||||
* exists.
|
||||
*/
|
||||
struct net_if *net_eth_get_vlan_iface(struct net_if *iface, u16_t tag);
|
||||
|
||||
/**
|
||||
* @brief Check if VLAN is enabled for a specific network interface.
|
||||
*
|
||||
* @param ctx Ethernet context
|
||||
* @param iface Network interface
|
||||
*
|
||||
* @return True if VLAN is enabled for this network interface, false if not.
|
||||
*/
|
||||
bool net_eth_is_vlan_enabled(struct ethernet_context *ctx,
|
||||
struct net_if *iface);
|
||||
|
||||
#define ETH_NET_DEVICE_INIT(dev_name, drv_name, init_fn, \
|
||||
data, cfg_info, prio, api, mtu) \
|
||||
DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, \
|
||||
cfg_info, POST_KERNEL, prio, api); \
|
||||
NET_L2_DATA_INIT(dev_name, 0, NET_L2_GET_CTX_TYPE(ETHERNET_L2)); \
|
||||
NET_IF_INIT(dev_name, 0, ETHERNET_L2, mtu, NET_VLAN_MAX_COUNT)
|
||||
|
||||
#else /* CONFIG_NET_VLAN */
|
||||
|
||||
#define ETH_NET_DEVICE_INIT(dev_name, drv_name, init_fn, \
|
||||
data, cfg_info, prio, api, mtu) \
|
||||
NET_DEVICE_INIT(dev_name, drv_name, init_fn, \
|
||||
data, cfg_info, prio, api, ETHERNET_L2, \
|
||||
NET_L2_GET_CTX_TYPE(ETHERNET_L2), mtu)
|
||||
|
||||
static inline int net_eth_vlan_enable(struct net_if *iface, u16_t vlan_tag)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int net_eth_vlan_disable(struct net_if *iface, u16_t vlan_tag)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline u16_t net_eth_get_vlan_tag(struct net_if *iface)
|
||||
{
|
||||
return NET_VLAN_TAG_UNSPEC;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct net_if *net_eth_get_vlan_iface(struct net_if *iface, u16_t tag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
|
||||
/**
|
||||
* @brief Fill ethernet header in network packet.
|
||||
*
|
||||
* @param ctx Ethernet context
|
||||
* @param pkt Network packet
|
||||
* @param frag Ethernet header in packet
|
||||
* @param ptype Upper level protocol type (in network byte order)
|
||||
* @param src Source ethernet address
|
||||
* @param dst Destination ethernet address
|
||||
*
|
||||
* @return Pointer to ethernet header struct inside net_buf.
|
||||
*/
|
||||
struct net_eth_hdr *net_eth_fill_header(struct ethernet_context *ctx,
|
||||
struct net_pkt *pkt,
|
||||
struct net_buf *frag,
|
||||
u32_t ptype,
|
||||
u8_t *src,
|
||||
u8_t *dst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
76
include/net/ethernet_vlan.h
Normal file
76
include/net/ethernet_vlan.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/** @file
|
||||
* @brief VLAN specific definitions.
|
||||
*
|
||||
* Virtual LAN specific definitions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ETHERNET_VLAN_H
|
||||
#define __ETHERNET_VLAN_H
|
||||
|
||||
/**
|
||||
* @brief VLAN definitions and helpers
|
||||
* @defgroup vlan Virtual LAN definitions and helpers
|
||||
* @ingroup networking
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NET_VLAN_TAG_UNSPEC 0x0fff
|
||||
|
||||
/* Get VLAN identifier from TCI */
|
||||
static inline u16_t net_eth_vlan_get_vid(u16_t tci)
|
||||
{
|
||||
return tci & 0x0fff;
|
||||
}
|
||||
|
||||
/* Get Drop Eligible Indicator from TCI */
|
||||
static inline u8_t net_eth_vlan_get_dei(u16_t tci)
|
||||
{
|
||||
return (tci >> 12) & 0x01;
|
||||
}
|
||||
|
||||
/* Get Priority Code Point from TCI */
|
||||
static inline u8_t net_eth_vlan_get_pcp(u16_t tci)
|
||||
{
|
||||
return (tci >> 13) & 0x07;
|
||||
}
|
||||
|
||||
/* Set VLAN identifier to TCI */
|
||||
static inline u16_t net_eth_vlan_set_vid(u16_t tci, u16_t vid)
|
||||
{
|
||||
return (tci & 0xf000) | (vid & 0x0fff);
|
||||
}
|
||||
|
||||
/* Set Drop Eligible Indicator to TCI */
|
||||
static inline u16_t net_eth_vlan_set_dei(u16_t tci, bool dei)
|
||||
{
|
||||
return (tci & 0xefff) | ((!!dei) << 12);
|
||||
}
|
||||
|
||||
/* Set Priority Code Point to TCI */
|
||||
static inline u16_t net_eth_vlan_set_pcp(u16_t tci, u8_t pcp)
|
||||
{
|
||||
return (tci & 0x1fff) | ((pcp & 0x07) << 13);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#endif /* __ETHERNET_VLAN_H */
|
|
@ -358,7 +358,6 @@ struct net_if_dev {
|
|||
*/
|
||||
struct net_offload *offload;
|
||||
#endif /* CONFIG_NET_OFFLOAD */
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1576,18 +1575,18 @@ struct net_if_api {
|
|||
#define NET_IF_GET(dev_name, sfx) \
|
||||
((struct net_if *)&NET_IF_GET_NAME(dev_name, sfx))
|
||||
|
||||
#define NET_IF_INIT(dev_name, sfx, _l2, _mtu) \
|
||||
static struct net_if_dev (NET_IF_DEV_GET_NAME(dev_name, sfx)) __used \
|
||||
__attribute__((__section__(".net_if_dev.data"))) = { \
|
||||
#define NET_IF_INIT(dev_name, sfx, _l2, _mtu, _num_configs) \
|
||||
static struct net_if_dev (NET_IF_DEV_GET_NAME(dev_name, sfx)) \
|
||||
__used __attribute__((__section__(".net_if_dev.data"))) = { \
|
||||
.dev = &(__device_##dev_name), \
|
||||
.l2 = &(NET_L2_GET_NAME(_l2)), \
|
||||
.l2_data = &(NET_L2_GET_DATA(dev_name, sfx)), \
|
||||
.mtu = _mtu, \
|
||||
}; \
|
||||
static struct net_if \
|
||||
(NET_IF_GET_NAME(dev_name, sfx))[NET_IF_MAX_CONFIGS] __used \
|
||||
(NET_IF_GET_NAME(dev_name, sfx))[_num_configs] __used \
|
||||
__attribute__((__section__(".net_if.data"))) = { \
|
||||
[0 ... (NET_IF_MAX_CONFIGS - 1)] = { \
|
||||
[0 ... (_num_configs - 1)] = { \
|
||||
.if_dev = &(NET_IF_DEV_GET_NAME(dev_name, sfx)), \
|
||||
NET_IF_CONFIG_INIT \
|
||||
} \
|
||||
|
@ -1601,7 +1600,7 @@ struct net_if_api {
|
|||
DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, \
|
||||
cfg_info, POST_KERNEL, prio, api); \
|
||||
NET_L2_DATA_INIT(dev_name, 0, l2_ctx_type); \
|
||||
NET_IF_INIT(dev_name, 0, l2, mtu)
|
||||
NET_IF_INIT(dev_name, 0, l2, mtu, NET_IF_MAX_CONFIGS)
|
||||
|
||||
/**
|
||||
* If your network device needs more than one instance of a network interface,
|
||||
|
@ -1614,7 +1613,7 @@ struct net_if_api {
|
|||
DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, \
|
||||
cfg_info, POST_KERNEL, prio, api); \
|
||||
NET_L2_DATA_INIT(dev_name, instance, l2_ctx_type); \
|
||||
NET_IF_INIT(dev_name, instance, l2, mtu)
|
||||
NET_IF_INIT(dev_name, instance, l2, mtu, NET_IF_MAX_CONFIGS)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Specifying VLAN tag here in order to avoid circular dependencies */
|
||||
#define NET_VLAN_TAG_UNSPEC 0x0fff
|
||||
|
||||
/** Protocol families */
|
||||
#define PF_UNSPEC 0 /* Unspecified. */
|
||||
#define PF_INET 2 /* IP protocol family. */
|
||||
|
|
|
@ -70,7 +70,6 @@ NET_L2_DECLARE_PUBLIC(DUMMY_L2);
|
|||
|
||||
#ifdef CONFIG_NET_L2_ETHERNET
|
||||
#define ETHERNET_L2 ETHERNET
|
||||
#define ETHERNET_L2_CTX_TYPE void*
|
||||
NET_L2_DECLARE_PUBLIC(ETHERNET_L2);
|
||||
#endif /* CONFIG_NET_L2_ETHERNET */
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <net/net_ip.h>
|
||||
#include <net/net_if.h>
|
||||
#include <net/net_context.h>
|
||||
#include <net/ethernet_vlan.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -149,6 +150,15 @@ struct net_pkt {
|
|||
*/
|
||||
u8_t priority;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
/* VLAN TCI (Tag Control Information). This contains the Priority
|
||||
* Code Point (PCP), Drop Eligible Indicator (DEI) and VLAN
|
||||
* Identifier (VID, called more commonly VLAN tag). This value is
|
||||
* kept in host byte order.
|
||||
*/
|
||||
u16_t vlan_tci;
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
/* @endcond */
|
||||
|
||||
/** Reference counter */
|
||||
|
@ -414,12 +424,87 @@ static inline u8_t net_pkt_priority(struct net_pkt *pkt)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void net_pkt_set_priority(struct net_pkt *pkt,
|
||||
u8_t priority)
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
static inline u16_t net_pkt_vlan_tag(struct net_pkt *pkt)
|
||||
{
|
||||
return net_eth_vlan_get_vid(pkt->vlan_tci);
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_tag(struct net_pkt *pkt, u16_t tag)
|
||||
{
|
||||
pkt->vlan_tci = net_eth_vlan_set_vid(pkt->vlan_tci, tag);
|
||||
}
|
||||
|
||||
static inline u8_t net_pkt_vlan_priority(struct net_pkt *pkt)
|
||||
{
|
||||
return net_eth_vlan_get_pcp(pkt->vlan_tci);
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_priority(struct net_pkt *pkt,
|
||||
u8_t priority)
|
||||
{
|
||||
pkt->vlan_tci = net_eth_vlan_set_pcp(pkt->vlan_tci, priority);
|
||||
}
|
||||
|
||||
static inline bool net_pkt_vlan_dei(struct net_pkt *pkt)
|
||||
{
|
||||
return net_eth_vlan_get_dei(pkt->vlan_tci);
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_dei(struct net_pkt *pkt, bool dei)
|
||||
{
|
||||
pkt->vlan_tci = net_eth_vlan_set_dei(pkt->vlan_tci, dei);
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_tci(struct net_pkt *pkt, u16_t tci)
|
||||
{
|
||||
pkt->vlan_tci = tci;
|
||||
}
|
||||
|
||||
static inline u16_t net_pkt_vlan_tci(struct net_pkt *pkt)
|
||||
{
|
||||
return pkt->vlan_tci;
|
||||
}
|
||||
#else
|
||||
static inline u16_t net_pkt_vlan_tag(struct net_pkt *pkt)
|
||||
{
|
||||
return NET_VLAN_TAG_UNSPEC;
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_tag(struct net_pkt *pkt, u16_t tag)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
ARG_UNUSED(priority);
|
||||
ARG_UNUSED(tag);
|
||||
}
|
||||
|
||||
static inline u8_t net_pkt_vlan_priority(struct net_pkt *pkt)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool net_pkt_vlan_dei(struct net_pkt *pkt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_dei(struct net_pkt *pkt, bool dei)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
ARG_UNUSED(dei);
|
||||
}
|
||||
|
||||
static inline u16_t net_pkt_vlan_tci(struct net_pkt *pkt)
|
||||
{
|
||||
return NET_VLAN_TAG_UNSPEC; /* assumes priority is 0 */
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_vlan_tci(struct net_pkt *pkt, u16_t tci)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
ARG_UNUSED(tci);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ config NET_INITIAL_TTL
|
|||
config NET_IF_MAX_IPV4_COUNT
|
||||
int "Max number of IPv4 network interfaces in the system"
|
||||
default 1
|
||||
default NET_VLAN_COUNT if NET_VLAN
|
||||
help
|
||||
This tells how many network interfaces there will be in the system
|
||||
that will have IPv4 enabled.
|
||||
|
|
|
@ -18,6 +18,7 @@ if NET_IPV6
|
|||
config NET_IF_MAX_IPV6_COUNT
|
||||
int "Max number of IPv6 network interfaces in the system"
|
||||
default 1
|
||||
default NET_VLAN_COUNT if NET_VLAN
|
||||
help
|
||||
This tells how many network interfaces there will be in the system
|
||||
that will have IPv6 enabled.
|
||||
|
|
|
@ -22,6 +22,22 @@ config NET_L2_ETHERNET
|
|||
If NET_SLIP_TAP is selected, NET_L2_ETHERNET will enable to fully
|
||||
simulate Ethernet through SLIP.
|
||||
|
||||
config NET_VLAN
|
||||
bool "Enable virtual lan support"
|
||||
default n
|
||||
depends on NET_L2_ETHERNET
|
||||
help
|
||||
Enables virtual lan (VLAN) support for Ethernet.
|
||||
|
||||
config NET_VLAN_COUNT
|
||||
int "Max VLAN tags supported in the system"
|
||||
default 1
|
||||
range 1 1 if SLIP
|
||||
range 1 255
|
||||
depends on NET_VLAN
|
||||
help
|
||||
How many VLAN tags can be configured.
|
||||
|
||||
config NET_DEBUG_L2_ETHERNET
|
||||
bool "Debug Ethernet L2 layer"
|
||||
default n
|
||||
|
|
|
@ -101,14 +101,24 @@ static inline struct net_pkt *prepare_arp(struct net_if *iface,
|
|||
struct arp_entry *entry,
|
||||
struct net_pkt *pending)
|
||||
{
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
u16_t vlan_tag = net_eth_get_vlan_tag(iface);
|
||||
#endif
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
int eth_hdr_len = sizeof(struct net_eth_hdr);
|
||||
struct net_pkt *pkt;
|
||||
struct net_buf *frag;
|
||||
struct net_arp_hdr *hdr;
|
||||
struct net_eth_hdr *eth;
|
||||
struct in_addr *my_addr;
|
||||
|
||||
pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr),
|
||||
NET_BUF_TIMEOUT);
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (ctx->vlan_enabled && vlan_tag != NET_VLAN_TAG_UNSPEC) {
|
||||
eth_hdr_len = sizeof(struct net_eth_vlan_hdr);
|
||||
}
|
||||
#endif
|
||||
|
||||
pkt = net_pkt_get_reserve_tx(eth_hdr_len, NET_BUF_TIMEOUT);
|
||||
if (!pkt) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -124,7 +134,13 @@ static inline struct net_pkt *prepare_arp(struct net_if *iface,
|
|||
net_pkt_set_family(pkt, AF_INET);
|
||||
|
||||
hdr = NET_ARP_HDR(pkt);
|
||||
eth = NET_ETH_HDR(pkt);
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
net_pkt_set_vlan_tag(pkt, vlan_tag);
|
||||
#endif
|
||||
|
||||
eth = net_eth_fill_header(ctx, pkt, frag, htons(NET_ETH_PTYPE_ARP),
|
||||
NULL, NULL);
|
||||
|
||||
/* If entry is not set, then we are just about to send
|
||||
* an ARP request using the data in pending net_pkt.
|
||||
|
@ -146,7 +162,6 @@ static inline struct net_pkt *prepare_arp(struct net_if *iface,
|
|||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
eth->type = htons(NET_ETH_PTYPE_ARP);
|
||||
memset(ð->dst.addr, 0xff, sizeof(struct net_eth_addr));
|
||||
|
||||
hdr->hwtype = htons(NET_ARP_HTYPE_ETH);
|
||||
|
@ -181,8 +196,9 @@ static inline struct net_pkt *prepare_arp(struct net_if *iface,
|
|||
|
||||
struct net_pkt *net_arp_prepare(struct net_pkt *pkt)
|
||||
{
|
||||
struct net_buf *frag;
|
||||
struct ethernet_context *ctx = net_if_l2_data(net_pkt_iface(pkt));
|
||||
struct arp_entry *entry, *free_entry = NULL, *non_pending = NULL;
|
||||
struct net_buf *frag;
|
||||
struct net_linkaddr *ll;
|
||||
struct net_eth_hdr *hdr;
|
||||
struct in_addr *addr;
|
||||
|
@ -191,7 +207,11 @@ struct net_pkt *net_arp_prepare(struct net_pkt *pkt)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (net_pkt_ll_reserve(pkt) != sizeof(struct net_eth_hdr)) {
|
||||
if (net_pkt_ll_reserve(pkt) != sizeof(struct net_eth_hdr)
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
&& net_pkt_ll_reserve(pkt) != sizeof(struct net_eth_vlan_hdr)
|
||||
#endif
|
||||
) {
|
||||
/* Add the ethernet header if it is missing. */
|
||||
struct net_buf *header;
|
||||
|
||||
|
@ -200,24 +220,9 @@ struct net_pkt *net_arp_prepare(struct net_pkt *pkt)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
net_pkt_set_ll_reserve(pkt, sizeof(struct net_eth_hdr));
|
||||
|
||||
hdr = (struct net_eth_hdr *)(header->data -
|
||||
net_pkt_ll_reserve(pkt));
|
||||
|
||||
hdr->type = htons(NET_ETH_PTYPE_IP);
|
||||
|
||||
ll = net_pkt_ll_dst(pkt);
|
||||
if (ll->addr) {
|
||||
memcpy(&hdr->dst.addr, ll->addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
ll = net_pkt_ll_src(pkt);
|
||||
if (ll->addr) {
|
||||
memcpy(&hdr->src.addr, ll->addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
net_eth_fill_header(ctx, pkt, header, htons(NET_ETH_PTYPE_IP),
|
||||
net_pkt_ll_src(pkt)->addr,
|
||||
net_pkt_ll_dst(pkt)->addr);
|
||||
|
||||
net_pkt_frag_insert(pkt, header);
|
||||
|
||||
|
@ -293,14 +298,9 @@ struct net_pkt *net_arp_prepare(struct net_pkt *pkt)
|
|||
continue;
|
||||
}
|
||||
|
||||
hdr = (struct net_eth_hdr *)(frag->data -
|
||||
net_pkt_ll_reserve(pkt));
|
||||
hdr->type = htons(NET_ETH_PTYPE_IP);
|
||||
|
||||
memcpy(&hdr->src.addr, ll->addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
memcpy(&hdr->dst.addr, &entry->eth.addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
hdr = net_eth_fill_header(ctx, pkt, frag,
|
||||
htons(NET_ETH_PTYPE_IP),
|
||||
ll->addr, entry->eth.addr);
|
||||
|
||||
frag = frag->frags;
|
||||
}
|
||||
|
@ -368,13 +368,21 @@ static inline void arp_update(struct net_if *iface,
|
|||
static inline struct net_pkt *prepare_arp_reply(struct net_if *iface,
|
||||
struct net_pkt *req)
|
||||
{
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
int eth_hdr_len = sizeof(struct net_eth_hdr);
|
||||
struct net_pkt *pkt;
|
||||
struct net_buf *frag;
|
||||
struct net_arp_hdr *hdr, *query;
|
||||
struct net_eth_hdr *eth, *eth_query;
|
||||
|
||||
pkt = net_pkt_get_reserve_tx(sizeof(struct net_eth_hdr),
|
||||
NET_BUF_TIMEOUT);
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (ctx->vlan_enabled &&
|
||||
net_eth_get_vlan_tag(iface) != NET_VLAN_TAG_UNSPEC) {
|
||||
eth_hdr_len = sizeof(struct net_eth_vlan_hdr);
|
||||
}
|
||||
#endif
|
||||
|
||||
pkt = net_pkt_get_reserve_tx(eth_hdr_len, NET_BUF_TIMEOUT);
|
||||
if (!pkt) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -393,12 +401,13 @@ static inline struct net_pkt *prepare_arp_reply(struct net_if *iface,
|
|||
query = NET_ARP_HDR(req);
|
||||
eth_query = NET_ETH_HDR(req);
|
||||
|
||||
eth->type = htons(NET_ETH_PTYPE_ARP);
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
net_pkt_set_vlan_tag(pkt, net_pkt_vlan_tag(req));
|
||||
#endif
|
||||
|
||||
memcpy(ð->dst.addr, ð_query->src.addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
memcpy(ð->src.addr, net_if_get_link_addr(iface)->addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
net_eth_fill_header(ctx, pkt, frag, htons(NET_ETH_PTYPE_ARP),
|
||||
net_if_get_link_addr(iface)->addr,
|
||||
eth_query->src.addr);
|
||||
|
||||
hdr->hwtype = htons(NET_ARP_HTYPE_ETH);
|
||||
hdr->protocol = htons(NET_ETH_PTYPE_IP);
|
||||
|
|
|
@ -46,21 +46,40 @@ void net_eth_ipv6_mcast_to_mac_addr(const struct in6_addr *ipv6_addr,
|
|||
}
|
||||
|
||||
#if defined(CONFIG_NET_DEBUG_L2_ETHERNET)
|
||||
#define print_ll_addrs(pkt, type, len) \
|
||||
#define print_ll_addrs(pkt, type, len, src, dst) \
|
||||
do { \
|
||||
char out[sizeof("xx:xx:xx:xx:xx:xx")]; \
|
||||
\
|
||||
snprintk(out, sizeof(out), "%s", \
|
||||
net_sprint_ll_addr(net_pkt_ll_src(pkt)->addr, \
|
||||
net_sprint_ll_addr((src)->addr, \
|
||||
sizeof(struct net_eth_addr))); \
|
||||
\
|
||||
NET_DBG("src %s dst %s type 0x%x len %zu", out, \
|
||||
net_sprint_ll_addr(net_pkt_ll_dst(pkt)->addr, \
|
||||
NET_DBG("iface %p src %s dst %s type 0x%x len %zu", \
|
||||
net_pkt_iface(pkt), out, \
|
||||
net_sprint_ll_addr((dst)->addr, \
|
||||
sizeof(struct net_eth_addr)), \
|
||||
type, (size_t)len); \
|
||||
} while (0)
|
||||
|
||||
#define print_vlan_ll_addrs(pkt, type, tci, len, src, dst) \
|
||||
do { \
|
||||
char out[sizeof("xx:xx:xx:xx:xx:xx")]; \
|
||||
\
|
||||
snprintk(out, sizeof(out), "%s", \
|
||||
net_sprint_ll_addr((src)->addr, \
|
||||
sizeof(struct net_eth_addr))); \
|
||||
\
|
||||
NET_DBG("iface %p src %s dst %s type 0x%x tag %d pri %d " \
|
||||
"len %zu", \
|
||||
net_pkt_iface(pkt), out, \
|
||||
net_sprint_ll_addr((dst)->addr, \
|
||||
sizeof(struct net_eth_addr)), \
|
||||
type, net_eth_vlan_get_vid(tci), \
|
||||
net_eth_vlan_get_pcp(tci), (size_t)len); \
|
||||
} while (0)
|
||||
#else
|
||||
#define print_ll_addrs(...)
|
||||
#define print_vlan_ll_addrs(...)
|
||||
#endif /* CONFIG_NET_DEBUG_L2_ETHERNET */
|
||||
|
||||
static inline void ethernet_update_length(struct net_if *iface,
|
||||
|
@ -100,11 +119,31 @@ static inline void ethernet_update_length(struct net_if *iface,
|
|||
static enum net_verdict ethernet_recv(struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct net_eth_vlan_hdr *hdr_vlan =
|
||||
(struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt);
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
bool vlan_enabled = false;
|
||||
#endif
|
||||
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
|
||||
struct net_linkaddr *lladdr;
|
||||
sa_family_t family;
|
||||
u16_t type = ntohs(hdr->type);
|
||||
u8_t hdr_len = sizeof(struct net_eth_hdr);
|
||||
|
||||
switch (ntohs(hdr->type)) {
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (net_eth_is_vlan_enabled(ctx, iface)) {
|
||||
if (type == NET_ETH_PTYPE_VLAN) {
|
||||
net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci));
|
||||
type = ntohs(hdr_vlan->type);
|
||||
hdr_len = sizeof(struct net_eth_vlan_hdr);
|
||||
}
|
||||
|
||||
vlan_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (type) {
|
||||
case NET_ETH_PTYPE_IP:
|
||||
case NET_ETH_PTYPE_ARP:
|
||||
net_pkt_set_family(pkt, AF_INET);
|
||||
|
@ -115,7 +154,7 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
|
|||
family = AF_INET6;
|
||||
break;
|
||||
default:
|
||||
NET_DBG("Unknown hdr type 0x%04x", hdr->type);
|
||||
NET_DBG("Unknown hdr type 0x%04x", type);
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
|
@ -130,7 +169,17 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
|
|||
lladdr->len = sizeof(struct net_eth_addr);
|
||||
lladdr->type = NET_LINK_ETHERNET;
|
||||
|
||||
print_ll_addrs(pkt, ntohs(hdr->type), net_pkt_get_len(pkt));
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (vlan_enabled) {
|
||||
print_vlan_ll_addrs(pkt, type, ntohs(hdr_vlan->vlan.tci),
|
||||
net_pkt_get_len(pkt),
|
||||
net_pkt_ll_src(pkt), net_pkt_ll_dst(pkt));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
print_ll_addrs(pkt, type, net_pkt_get_len(pkt),
|
||||
net_pkt_ll_src(pkt), net_pkt_ll_dst(pkt));
|
||||
}
|
||||
|
||||
if (!net_eth_is_addr_broadcast((struct net_eth_addr *)lladdr->addr) &&
|
||||
!net_eth_is_addr_multicast((struct net_eth_addr *)lladdr->addr) &&
|
||||
|
@ -145,11 +194,11 @@ static enum net_verdict ethernet_recv(struct net_if *iface,
|
|||
return NET_DROP;
|
||||
}
|
||||
|
||||
net_pkt_set_ll_reserve(pkt, sizeof(struct net_eth_hdr));
|
||||
net_pkt_set_ll_reserve(pkt, hdr_len);
|
||||
net_buf_pull(pkt->frags, net_pkt_ll_reserve(pkt));
|
||||
|
||||
#ifdef CONFIG_NET_ARP
|
||||
if (family == AF_INET && hdr->type == htons(NET_ETH_PTYPE_ARP)) {
|
||||
if (family == AF_INET && type == NET_ETH_PTYPE_ARP) {
|
||||
NET_DBG("ARP packet from %s received",
|
||||
net_sprint_ll_addr((u8_t *)hdr->src.addr,
|
||||
sizeof(struct net_eth_addr)));
|
||||
|
@ -196,10 +245,128 @@ static inline bool check_if_dst_is_broadcast_or_mcast(struct net_if *iface,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
static enum net_verdict set_vlan_tag(struct ethernet_context *ctx,
|
||||
struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (net_pkt_vlan_tag(pkt) != NET_VLAN_TAG_UNSPEC) {
|
||||
return NET_OK;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
if (net_pkt_family(pkt) == AF_INET6) {
|
||||
struct net_if *target;
|
||||
|
||||
if (net_if_ipv6_addr_lookup(&NET_IPV6_HDR(pkt)->src,
|
||||
&target)) {
|
||||
if (target != iface) {
|
||||
NET_DBG("Iface %p should be %p", iface,
|
||||
target);
|
||||
|
||||
iface = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
if (net_pkt_family(pkt) == AF_INET) {
|
||||
struct net_if *target;
|
||||
|
||||
if (net_if_ipv4_addr_lookup(&NET_IPV4_HDR(pkt)->src,
|
||||
&target)) {
|
||||
if (target != iface) {
|
||||
NET_DBG("Iface %p should be %p", iface,
|
||||
target);
|
||||
iface = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (ctx->vlan[i].tag == NET_VLAN_TAG_UNSPEC ||
|
||||
ctx->vlan[i].iface != iface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Depending on source address, use the proper network
|
||||
* interface when sending.
|
||||
*/
|
||||
net_pkt_set_vlan_tag(pkt, ctx->vlan[i].tag);
|
||||
|
||||
return NET_OK;
|
||||
}
|
||||
|
||||
return NET_DROP;
|
||||
}
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
|
||||
struct net_eth_hdr *net_eth_fill_header(struct ethernet_context *ctx,
|
||||
struct net_pkt *pkt,
|
||||
struct net_buf *frag,
|
||||
u32_t ptype,
|
||||
u8_t *src,
|
||||
u8_t *dst)
|
||||
{
|
||||
struct net_eth_hdr *hdr;
|
||||
|
||||
NET_ASSERT(net_buf_headroom(frag) > sizeof(struct net_eth_addr));
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (net_eth_is_vlan_enabled(ctx, net_pkt_iface(pkt))) {
|
||||
struct net_eth_vlan_hdr *hdr_vlan;
|
||||
|
||||
hdr_vlan = (struct net_eth_vlan_hdr *)(frag->data -
|
||||
net_pkt_ll_reserve(pkt));
|
||||
|
||||
if (dst && ((u8_t *)&hdr_vlan->dst != dst)) {
|
||||
memcpy(&hdr_vlan->dst, dst,
|
||||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
if (src && ((u8_t *)&hdr_vlan->src != src)) {
|
||||
memcpy(&hdr_vlan->src, src,
|
||||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
hdr_vlan->type = ptype;
|
||||
hdr_vlan->vlan.tpid = htons(NET_ETH_PTYPE_VLAN);
|
||||
hdr_vlan->vlan.tci = htons(net_pkt_vlan_tci(pkt));
|
||||
|
||||
print_vlan_ll_addrs(pkt, ntohs(hdr_vlan->type),
|
||||
net_pkt_vlan_tci(pkt),
|
||||
frag->len,
|
||||
&hdr_vlan->src, &hdr_vlan->dst);
|
||||
|
||||
return (struct net_eth_hdr *)hdr_vlan;
|
||||
}
|
||||
#endif
|
||||
|
||||
hdr = (struct net_eth_hdr *)(frag->data - net_pkt_ll_reserve(pkt));
|
||||
|
||||
if (dst && ((u8_t *)&hdr->dst != dst)) {
|
||||
memcpy(&hdr->dst, dst, sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
if (src && ((u8_t *)&hdr->src != src)) {
|
||||
memcpy(&hdr->src, src, sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
hdr->type = ptype;
|
||||
|
||||
print_ll_addrs(pkt, ntohs(hdr->type), frag->len, &hdr->src, &hdr->dst);
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
static enum net_verdict ethernet_send(struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
struct net_buf *frag;
|
||||
u16_t ptype;
|
||||
|
||||
|
@ -305,6 +472,14 @@ setup_hdr:
|
|||
ptype = htons(NET_ETH_PTYPE_IPV6);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (net_eth_is_vlan_enabled(ctx, iface)) {
|
||||
if (set_vlan_tag(ctx, iface, pkt) == NET_DROP) {
|
||||
return NET_DROP;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_VLAN */
|
||||
|
||||
/* Then go through the fragments and set the ethernet header.
|
||||
*/
|
||||
frag = pkt->frags;
|
||||
|
@ -312,22 +487,9 @@ setup_hdr:
|
|||
NET_ASSERT_INFO(frag, "No data!");
|
||||
|
||||
while (frag) {
|
||||
NET_ASSERT(net_buf_headroom(frag) > sizeof(struct net_eth_addr));
|
||||
|
||||
hdr = (struct net_eth_hdr *)(frag->data -
|
||||
net_pkt_ll_reserve(pkt));
|
||||
if ((u8_t *)&hdr->dst != net_pkt_ll_dst(pkt)->addr) {
|
||||
memcpy(&hdr->dst, net_pkt_ll_dst(pkt)->addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
if ((u8_t *)&hdr->src != net_pkt_ll_src(pkt)->addr) {
|
||||
memcpy(&hdr->src, net_pkt_ll_src(pkt)->addr,
|
||||
sizeof(struct net_eth_addr));
|
||||
}
|
||||
|
||||
hdr->type = ptype;
|
||||
print_ll_addrs(pkt, ntohs(hdr->type), frag->len);
|
||||
net_eth_fill_header(ctx, pkt, frag, ptype,
|
||||
net_pkt_ll_src(pkt)->addr,
|
||||
net_pkt_ll_dst(pkt)->addr);
|
||||
|
||||
frag = frag->frags;
|
||||
}
|
||||
|
@ -343,7 +505,14 @@ send:
|
|||
|
||||
static inline u16_t ethernet_reserve(struct net_if *iface, void *unused)
|
||||
{
|
||||
ARG_UNUSED(iface);
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
|
||||
if (net_eth_is_vlan_enabled(ctx, iface)) {
|
||||
return sizeof(struct net_eth_vlan_hdr);
|
||||
}
|
||||
#endif
|
||||
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
return sizeof(struct net_eth_hdr);
|
||||
|
@ -360,5 +529,241 @@ static inline int ethernet_enable(struct net_if *iface, bool state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct net_if *net_eth_get_vlan_iface(struct net_if *iface, u16_t tag)
|
||||
{
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (ctx->vlan[i].tag == NET_VLAN_TAG_UNSPEC ||
|
||||
ctx->vlan[i].tag != tag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NET_DBG("[%d] vlan tag %d -> iface %p", i, tag,
|
||||
ctx->vlan[i].iface);
|
||||
|
||||
return ctx->vlan[i].iface;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool enable_vlan_iface(struct ethernet_context *ctx,
|
||||
struct net_if *iface)
|
||||
{
|
||||
int iface_idx = net_if_get_by_iface(iface);
|
||||
|
||||
if (iface_idx < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
atomic_set_bit(ctx->interfaces, iface_idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool disable_vlan_iface(struct ethernet_context *ctx,
|
||||
struct net_if *iface)
|
||||
{
|
||||
int iface_idx = net_if_get_by_iface(iface);
|
||||
|
||||
if (iface_idx < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
atomic_clear_bit(ctx->interfaces, iface_idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_vlan_enabled_for_iface(struct ethernet_context *ctx,
|
||||
struct net_if *iface)
|
||||
{
|
||||
int iface_idx = net_if_get_by_iface(iface);
|
||||
|
||||
if (iface_idx < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!atomic_test_bit(ctx->interfaces, iface_idx);
|
||||
}
|
||||
|
||||
bool net_eth_is_vlan_enabled(struct ethernet_context *ctx,
|
||||
struct net_if *iface)
|
||||
{
|
||||
if (ctx->vlan_enabled) {
|
||||
if (ctx->vlan_enabled == NET_VLAN_MAX_COUNT) {
|
||||
/* All network interface are using VLAN, no need
|
||||
* to check further.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_vlan_enabled_for_iface(ctx, iface)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
u16_t net_eth_get_vlan_tag(struct net_if *iface)
|
||||
{
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (ctx->vlan[i].iface == iface) {
|
||||
return ctx->vlan[i].tag;
|
||||
}
|
||||
}
|
||||
|
||||
return NET_VLAN_TAG_UNSPEC;
|
||||
}
|
||||
|
||||
static struct ethernet_vlan *get_vlan(struct ethernet_context *ctx,
|
||||
struct net_if *iface,
|
||||
u16_t vlan_tag)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (ctx->vlan[i].iface == iface &&
|
||||
ctx->vlan[i].tag == vlan_tag) {
|
||||
return &ctx->vlan[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int net_eth_vlan_enable(struct net_if *iface, u16_t tag)
|
||||
{
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
const struct ethernet_api *eth =
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct ethernet_vlan *vlan;
|
||||
int i;
|
||||
|
||||
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!ctx->is_init) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (tag == NET_VLAN_TAG_UNSPEC) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
vlan = get_vlan(ctx, iface, tag);
|
||||
if (vlan) {
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (ctx->vlan[i].iface != iface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->vlan[i].tag != NET_VLAN_TAG_UNSPEC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NET_DBG("[%d] Adding vlan tag %d to iface %p", i, tag, iface);
|
||||
|
||||
ctx->vlan[i].tag = tag;
|
||||
|
||||
enable_vlan_iface(ctx, iface);
|
||||
|
||||
if (eth->vlan_setup) {
|
||||
eth->vlan_setup(iface, tag, true);
|
||||
}
|
||||
|
||||
ctx->vlan_enabled++;
|
||||
if (ctx->vlan_enabled > NET_VLAN_MAX_COUNT) {
|
||||
ctx->vlan_enabled = NET_VLAN_MAX_COUNT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
int net_eth_vlan_disable(struct net_if *iface, u16_t tag)
|
||||
{
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
const struct ethernet_api *eth =
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct ethernet_vlan *vlan;
|
||||
|
||||
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tag == NET_VLAN_TAG_UNSPEC) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
vlan = get_vlan(ctx, iface, tag);
|
||||
if (!vlan) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
NET_DBG("Removing vlan tag %d from iface %p", vlan->tag, vlan->iface);
|
||||
|
||||
vlan->tag = NET_VLAN_TAG_UNSPEC;
|
||||
|
||||
disable_vlan_iface(ctx, iface);
|
||||
|
||||
if (eth->vlan_setup) {
|
||||
eth->vlan_setup(iface, tag, false);
|
||||
}
|
||||
|
||||
ctx->vlan_enabled--;
|
||||
if (ctx->vlan_enabled < 0) {
|
||||
ctx->vlan_enabled = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
NET_L2_INIT(ETHERNET_L2, ethernet_recv, ethernet_send, ethernet_reserve,
|
||||
ethernet_enable);
|
||||
|
||||
void ethernet_init(struct net_if *iface)
|
||||
{
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct ethernet_context *ctx = net_if_l2_data(iface);
|
||||
int i;
|
||||
|
||||
if (!(net_eth_get_hw_capabilities(iface) & ETH_HW_VLAN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NET_DBG("Initializing Ethernet L2 %p for iface %p", ctx, iface);
|
||||
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (!ctx->vlan[i].iface) {
|
||||
NET_DBG("[%d] alloc ctx %p iface %p", i, ctx, iface);
|
||||
ctx->vlan[i].tag = NET_VLAN_TAG_UNSPEC;
|
||||
ctx->vlan[i].iface = iface;
|
||||
|
||||
if (!ctx->is_init) {
|
||||
atomic_clear(ctx->interfaces);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->is_init = true;
|
||||
#else
|
||||
ARG_UNUSED(iface);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -2192,6 +2192,24 @@ void net_if_init(void)
|
|||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPV6 */
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
/* Make sure that we do not have too many network interfaces
|
||||
* compared to the number of VLAN interfaces.
|
||||
*/
|
||||
for (iface = __net_if_start, if_count = 0;
|
||||
iface != __net_if_end; iface++) {
|
||||
if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
|
||||
if_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (if_count > CONFIG_NET_VLAN_COUNT) {
|
||||
NET_WARN("You have configured only %d VLAN interfaces"
|
||||
" but you have %d network interfaces.",
|
||||
CONFIG_NET_VLAN_COUNT, if_count);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void net_if_post_init(void)
|
||||
|
|
|
@ -322,6 +322,8 @@ struct net_pkt *net_pkt_get_reserve(struct k_mem_slab *slab,
|
|||
net_pkt_set_priority(pkt, CONFIG_NET_TX_DEFAULT_PRIORITY);
|
||||
#endif
|
||||
|
||||
net_pkt_set_vlan_tag(pkt, NET_VLAN_TAG_UNSPEC);
|
||||
|
||||
#if defined(CONFIG_NET_DEBUG_NET_PKT)
|
||||
net_pkt_alloc_add(pkt, true, caller, line);
|
||||
|
||||
|
@ -2012,6 +2014,7 @@ struct net_pkt *net_pkt_clone(struct net_pkt *pkt, s32_t timeout)
|
|||
|
||||
net_pkt_set_next_hdr(clone, NULL);
|
||||
net_pkt_set_ip_hdr_len(clone, net_pkt_ip_hdr_len(pkt));
|
||||
net_pkt_set_vlan_tag(clone, net_pkt_vlan_tag(pkt));
|
||||
|
||||
net_pkt_set_family(clone, net_pkt_family(pkt));
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
#include <net/arp.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
#include <net/ethernet.h>
|
||||
#endif
|
||||
|
||||
#include "net_shell.h"
|
||||
#include "net_stats.h"
|
||||
|
||||
|
@ -165,6 +169,9 @@ static void iface_cb(struct net_if *iface, void *user_data)
|
|||
#endif
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
struct net_if_ipv4 *ipv4;
|
||||
#endif
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
struct ethernet_context *eth_ctx;
|
||||
#endif
|
||||
struct net_if_addr *unicast;
|
||||
struct net_if_mcast_addr *mcast;
|
||||
|
@ -182,10 +189,37 @@ static void iface_cb(struct net_if *iface, void *user_data)
|
|||
return;
|
||||
}
|
||||
|
||||
printk("Link addr : %s\n",
|
||||
net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
|
||||
net_if_get_link_addr(iface)->len));
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
|
||||
printk("Link addr : %s\n",
|
||||
net_sprint_ll_addr(net_if_get_link_addr(iface)->addr,
|
||||
net_if_get_link_addr(iface)->len));
|
||||
printk("MTU : %d\n", net_if_get_mtu(iface));
|
||||
|
||||
eth_ctx = net_if_l2_data(iface);
|
||||
|
||||
if (eth_ctx->vlan_enabled) {
|
||||
for (i = 0; i < CONFIG_NET_VLAN_COUNT; i++) {
|
||||
if (eth_ctx->vlan[i].iface != iface ||
|
||||
eth_ctx->vlan[i].tag ==
|
||||
NET_VLAN_TAG_UNSPEC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
printk("[%d] VLAN tag : %d (0x%x)\n", i,
|
||||
eth_ctx->vlan[i].tag,
|
||||
eth_ctx->vlan[i].tag);
|
||||
}
|
||||
} else {
|
||||
printk("VLAN not enabled\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
printk("Link addr : %s\n", net_sprint_ll_addr(
|
||||
net_if_get_link_addr(iface)->addr,
|
||||
net_if_get_link_addr(iface)->len));
|
||||
printk("MTU : %d\n", net_if_get_mtu(iface));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
count = 0;
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <class/usb_cdc.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "../../usb_descriptor.h"
|
||||
#include "../../composite.h"
|
||||
#include "netusb.h"
|
||||
|
|
|
@ -229,3 +229,6 @@ CONFIG_HTTP_HEADER_FIELD_ITEMS=2
|
|||
CONFIG_HTTP_CLIENT=y
|
||||
CONFIG_HTTP_PARSER=y
|
||||
CONFIG_HTTP_PARSER_STRICT=y
|
||||
|
||||
# VLAN
|
||||
CONFIG_NET_VLAN=y
|
||||
|
|
|
@ -96,6 +96,8 @@ static void eth_iface_init(struct net_if *iface)
|
|||
|
||||
DBG("Iface %p addr %s\n", iface,
|
||||
net_sprint_ll_addr(context->mac_addr, sizeof(context->mac_addr)));
|
||||
|
||||
ethernet_init(iface);
|
||||
}
|
||||
|
||||
static int eth_tx_offloading_disabled(struct net_if *iface, struct net_pkt *pkt)
|
||||
|
@ -250,15 +252,17 @@ static int eth_init(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NET_DEVICE_INIT(eth_offloading_disabled_test, "eth_offloading_disabled_test",
|
||||
eth_init, ð_context_offloading_disabled,
|
||||
NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs_offloading_disabled,
|
||||
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), 1500);
|
||||
ETH_NET_DEVICE_INIT(eth_offloading_disabled_test,
|
||||
"eth_offloading_disabled_test",
|
||||
eth_init, ð_context_offloading_disabled,
|
||||
NULL, CONFIG_ETH_INIT_PRIORITY,
|
||||
&api_funcs_offloading_disabled, 1500);
|
||||
|
||||
NET_DEVICE_INIT(eth_offloading_enabled_test, "eth_offloading_enabled_test",
|
||||
eth_init, ð_context_offloading_enabled,
|
||||
NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs_offloading_enabled,
|
||||
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), 1500);
|
||||
ETH_NET_DEVICE_INIT(eth_offloading_enabled_test,
|
||||
"eth_offloading_enabled_test",
|
||||
eth_init, ð_context_offloading_enabled,
|
||||
NULL, CONFIG_ETH_INIT_PRIORITY,
|
||||
&api_funcs_offloading_enabled, 1500);
|
||||
|
||||
struct user_data {
|
||||
int eth_if_count;
|
||||
|
|
Loading…
Reference in a new issue