diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt index 5f0b3444df0d0..4cbdc605cbe7c 100644 --- a/drivers/net/CMakeLists.txt +++ b/drivers/net/CMakeLists.txt @@ -2,4 +2,5 @@ zephyr_sources_ifdef(CONFIG_SLIP slip.c) zephyr_sources_ifdef(CONFIG_NET_LOOPBACK loopback.c) -zephyr_sources_ifdef(CONFIG_NET_PPP ppp.c) +zephyr_sources_ifdef(CONFIG_NET_PPP_UART ppp.c) +zephyr_sources_ifdef(CONFIG_NET_PPPOE pppoe.c) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b4e2df2825b82..80444a69645e4 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -5,16 +5,21 @@ # PPP options # menuconfig NET_PPP - bool "Point-to-point (PPP) UART based driver" + bool "Point-to-point (PPP) driver support" depends on NET_L2_PPP - select UART_PIPE - select UART_INTERRUPT_DRIVEN if NET_PPP +config NET_PPP_UART + bool "Enable PPP UART based driver" + default y + select UART_PIPE + select UART_INTERRUPT_DRIVEN + config NET_PPP_DRV_NAME string "PPP Driver name" default "ppp" + depends on NET_PPP_UART help This option sets the driver name @@ -25,6 +30,54 @@ config NET_PPP_UART_PIPE_BUF_LEN This options sets the size of the UART pipe buffer where data is being read to. +config NET_PPPOE + bool "Enable PPP over Ethernet" + depends on NET_L2_ETHERNET + help + Support PPP over Ethernet links. This option will cause ppp + specific network interface to be created. All the packets sent + to it will be directed to real Ethernet network interface. + +config NET_PPPOE_SERVICE_NAME + string "Service name" + default "" + depends on NET_PPPOE + help + This option sets the PPPoE service name that is set in Discovery + messages. This can be left empty which indicates that any service is + acceptable + +config NET_PPPOE_DRV_NAME + string "PPPoE Driver name" + default "pppoe" + depends on NET_PPPOE + help + This option sets the PPPoE driver name + +config NET_PPPOE_ETH_DRV_NAME + string "Name of the Ethernet device" + depends on NET_PPPOE + help + This setting binds PPP over this Ethernet device. If this is left + empty, then first Ethernet device is used instead. + +config NET_PPPOE_DELAY_STARTUP_MS + int "Delay in ms before sending 1st Discovery" + default 0 + depends on NET_PPPOE + help + Delay the sending of first PPPoE Discovery packet. This is useful in + debugging. The value is in milliseconds. Value 0 disables the wait. + +config NET_PPPOE_MAX_WAIT_IN_DISCOVERY + int "Max delay in sec between two Discovery packets" + default 60 + depends on NET_PPPOE + help + When we do not receive a PADO packet within a specified amount + of time, we will resend PADI packet and double the waiting + period. This value tells the maximum wait. The value is in seconds. + config NET_PPP_MTU int "PPP MTU" default 1500 diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c new file mode 100644 index 0000000000000..751c832c25b9f --- /dev/null +++ b/drivers/net/pppoe.c @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * PPP over Ethernet driver. + */ + +#define LOG_LEVEL CONFIG_NET_PPP_LOG_LEVEL +#include +LOG_MODULE_REGISTER(net_ppp, LOG_LEVEL); + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../subsys/net/ip/net_stats.h" +#include "../../subsys/net/ip/net_private.h" + +#define PPPOE_STARTUP_DELAY K_MSEC(100) + +enum pppoe_driver_state { + STATE_DISCOVERY, + STATE_SESSION, +}; + +struct pppoe_driver_context { + /** PPP discover worker. */ + struct k_delayed_work discover; + + /* PPP interface */ + struct net_if *iface; + + /* Ethernet device where the packet is directed */ + struct device *eth_dev; + + u8_t mac_addr[6]; + struct net_linkaddr ll_addr; + +#if defined(CONFIG_NET_STATISTICS_PPP) + struct net_stats_ppp stats; +#endif + int discovery_delay; + + enum pppoe_driver_state state; + + u8_t init_done : 1; + u8_t next_escaped : 1; +}; + +static struct pppoe_driver_context pppoe_driver_context_data; + +static const char *pppoe_driver_state_str(enum pppoe_driver_state state) +{ +#if (CONFIG_NET_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) + switch (state) { + case STATE_DISCOVERY: + return "DISCOVERY"; + case STATE_SESSION: + return "SESSION"; + } +#else + ARG_UNUSED(state); +#endif + + return ""; +} + +static void pppoe_change_state(struct pppoe_driver_context *ctx, + enum pppoe_driver_state new_state) +{ + NET_ASSERT(ctx); + + if (ctx->state == new_state) { + return; + } + + NET_ASSERT(new_state >= STATE_DISCOVERY && + new_state <= STATE_SESSION); + + NET_DBG("[%p] state %s (%d) => %s (%d)", + ctx, pppoe_driver_state_str(ctx->state), ctx->state, + pppoe_driver_state_str(new_state), new_state); + + ctx->state = new_state; +} + +static bool pppoe_check_fcs(struct pppoe_driver_context *ppp, + struct net_pkt *pkt) +{ + struct net_buf *buf; + u16_t crc; + + buf = pkt->buffer; + if (!buf) { + return false; + } + + crc = crc16_ccitt(0xffff, buf->data, buf->len); + + buf = buf->frags; + + while (buf) { + crc = crc16_ccitt(crc, buf->data, buf->len); + buf = buf->frags; + } + + if (crc != 0xf0b8) { + LOG_DBG("Invalid FCS (0x%x)", crc); +#if defined(CONFIG_NET_STATISTICS_PPP) + ppp->stats.chkerr++; +#endif + return false; + } + + return true; +} + +static enum net_verdict pppoe_process_msg(struct pppoe_driver_context *ppp, + struct net_if *iface, + struct net_pkt *pkt) +{ + if (LOG_LEVEL >= LOG_LEVEL_DBG) { + net_pkt_hexdump(pkt, "recv ppp"); + } + + if (IS_ENABLED(CONFIG_NET_PPP_VERIFY_FCS) && + !pppoe_check_fcs(ppp, pkt)) { +#if defined(CONFIG_NET_STATISTICS_PPP) + ppp->stats.drop++; + ppp->stats.pkts.rx++; +#endif + return NET_DROP; + } else { + /* Remove the Address (0xff), Control (0x03) and + * FCS fields (16-bit) as the PPP L2 layer does not need + * those bytes. + */ + u16_t addr_and_ctrl = net_buf_pull_be16(pkt->buffer); + + /* Currently we do not support compressed Address and Control + * fields so they must always be present. + */ + if (addr_and_ctrl != (0xff << 8 | 0x03)) { +#if defined(CONFIG_NET_STATISTICS_PPP) + ppp->stats.drop++; + ppp->stats.pkts.rx++; +#endif + return NET_DROP; + } else { + /* Skip FCS bytes (2) */ + net_buf_frag_last(pkt->buffer)->len -= 2; + + /* Make sure we now start reading from PPP header in + * PPP L2 recv() + */ + net_pkt_cursor_init(pkt); + net_pkt_set_overwrite(pkt, true); + + net_pkt_set_iface(pkt, ppp->iface); + + if (net_recv_data(ppp->iface, pkt) < 0) { + return NET_DROP; + } + } + } + + return NET_CONTINUE; +} + +static bool calc_fcs(struct net_pkt *pkt, u16_t *fcs, u16_t protocol) +{ + struct net_buf *buf; + u16_t crc; + u16_t c; + + buf = pkt->buffer; + if (!buf) { + return false; + } + + /* HDLC Address and Control fields */ + c = sys_cpu_to_be16(0xff << 8 | 0x03); + + crc = crc16_ccitt(0xffff, (const u8_t *)&c, sizeof(c)); + + if (protocol > 0) { + crc = crc16_ccitt(crc, (const u8_t *)&protocol, + sizeof(protocol)); + } + + while (buf) { + crc = crc16_ccitt(crc, buf->data, buf->len); + buf = buf->frags; + } + + crc ^= 0xffff; + *fcs = crc; + + return true; +} + +static int pppoe_send(struct device *dev, struct net_pkt *pkt) +{ +#if 0 + struct pppoe_driver_context *ppp = dev->driver_data; + struct net_buf *buf = pkt->buffer; + u16_t protocol = 0; + int send_off = 0; + u32_t sync_addr_ctrl; + u16_t fcs, escaped; + u8_t byte; + int i, offset; + +#if defined(CONFIG_NET_TEST) + return 0; +#endif + + ARG_UNUSED(dev); + + if (!buf) { + /* No data? */ + return -ENODATA; + } + + /* If the packet is a normal network packet, we must add the protocol + * value here. + */ + if (!net_pkt_is_ppp(pkt)) { + if (net_pkt_family(pkt) == AF_INET) { + protocol = htons(PPP_IP); + } else if (net_pkt_family(pkt) == AF_INET6) { + protocol = htons(PPP_IPV6); + } else { + return -EPROTONOSUPPORT; + } + } + + if (!calc_fcs(pkt, &fcs, protocol)) { + return -ENOMEM; + } + + /* Sync, Address & Control fields */ + sync_addr_ctrl = sys_cpu_to_be32(0x7e << 24 | 0xff << 16 | + 0x7d << 8 | 0x23); + send_off = ppp_send_bytes(ppp, (const u8_t *)&sync_addr_ctrl, + sizeof(sync_addr_ctrl), send_off); + + if (protocol > 0) { + escaped = htons(ppp_escape_byte(protocol, &offset)); + send_off = ppp_send_bytes(ppp, (u8_t *)&escaped + offset, + offset ? 1 : 2, + send_off); + + escaped = htons(ppp_escape_byte(protocol >> 8, &offset)); + send_off = ppp_send_bytes(ppp, (u8_t *)&escaped + offset, + offset ? 1 : 2, + send_off); + } + + /* Note that we do not print the first four bytes and FCS bytes at the + * end so that we do not need to allocate separate net_buf just for + * that purpose. + */ + if (LOG_LEVEL >= LOG_LEVEL_DBG) { + net_pkt_hexdump(pkt, "send ppp"); + } + + + escaped = htons(ppp_escape_byte(fcs, &offset)); + send_off = ppp_send_bytes(ppp, (u8_t *)&escaped + offset, + offset ? 1 : 2, + send_off); + + escaped = htons(ppp_escape_byte(fcs >> 8, &offset)); + send_off = ppp_send_bytes(ppp, (u8_t *)&escaped + offset, + offset ? 1 : 2, + send_off); + + byte = 0x7e; + send_off = ppp_send_bytes(ppp, &byte, 1, send_off); + + (void)ppp_send_flush(ppp, send_off); +#endif + return 0; +} + +static int pppoe_driver_init(struct device *dev) +{ + struct pppoe_driver_context *ppp = dev->driver_data; + + LOG_DBG("[%p] dev %p", ppp, dev); + + pppoe_change_state(ppp, STATE_DISCOVERY); + + return 0; +} + +static struct net_pkt *pppoe_create_packet(struct net_if *iface, + u8_t code, u16_t session_id, + u16_t len, u8_t *tags) +{ + struct net_pkt *pkt; + int ret; + + pkt = net_pkt_alloc_with_buffer(iface, + sizeof(u8_t) + sizeof(code) + + sizeof(session_id) + sizeof(len) + + len + sizeof(u16_t) /* eof */, + AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + LOG_DBG("Alloc failed"); + goto out; + } + + ret = net_pkt_write_be32(pkt, + /* version and type are fixed */ + (BIT(4) | BIT(0)) << 24 | + code << 16 | session_id); + if (ret < 0) { + goto free; + } + + ret = net_pkt_write_be16(pkt, len); + if (ret < 0) { + goto free; + } + + ret = net_pkt_write(pkt, tags, len); + if (ret < 0) { + goto free; + } + + /* End-of-tag is the last one */ + ret = net_pkt_write_be16(pkt, 0x00); + if (ret < 0) { + goto free; + } + + return pkt; + +free: + net_pkt_unref(pkt); + +out: + return NULL; +} + +static struct net_pkt *pppoe_create_padi(struct net_if *iface, + u16_t len, u8_t *tags) +{ + struct net_pkt *pkt; + + /* The session (0x0000) for PADI packets is specified in RFC 2516 */ + pkt = pppoe_create_packet(iface, PPPOE_PADI, 0x0000, len, tags); + + net_pkt_lladdr_dst(pkt)->addr = net_eth_broadcast_addr()->addr; + net_pkt_lladdr_dst(pkt)->len = sizeof(((struct net_eth_addr *)0)->addr); + + return pkt; +} + +static void pppoe_discover(struct k_work *work) +{ + struct pppoe_driver_context *ppp = + CONTAINER_OF(work, struct pppoe_driver_context, discover); + + struct net_pkt *pkt = NULL; + int ret = -ENOENT; + struct net_if *iface; + + iface = net_if_lookup_by_dev(ppp->eth_dev); + if (!iface) { + LOG_DBG("Cannot get Ethernet iface"); + goto resend; + } + + pkt = pppoe_create_padi(iface, + /* The terminating NULL is not transmitted */ + sizeof(CONFIG_NET_PPPOE_SERVICE_NAME) - 1, + CONFIG_NET_PPPOE_SERVICE_NAME); + if (!pkt) { + LOG_DBG("Cannot create %s", "PADI"); + goto resend; + } + + net_pkt_set_ppp(pkt, true); + net_pkt_set_pppoe_discovery_type(pkt, true); + + net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_if(pkt)->addr; + net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_if(pkt)->len; + + ret = net_if_l2(iface)->send(iface, pkt); + if (ret < 0) { + LOG_DBG("Cannot send %s", "PADI"); + goto resend; + } + +resend: + if (ret < 0 && pkt) { + net_pkt_unref(pkt); + } + + ppp->discovery_delay <<= 1; + + if (ppp->discovery_delay > CONFIG_NET_PPPOE_MAX_WAIT_IN_DISCOVERY) { + ppp->discovery_delay = CONFIG_NET_PPPOE_MAX_WAIT_IN_DISCOVERY; + } + + k_delayed_work_submit(&ppp->discover, K_SECONDS(ppp->discovery_delay)); +} + +static void pppoe_start_discovery(struct pppoe_driver_context *ppp) +{ + k_delayed_work_submit(&ppp->discover, + K_MSEC(CONFIG_NET_PPPOE_DELAY_STARTUP_MS)); +} + +static void pppoe_startup(struct k_work *work) +{ + struct pppoe_driver_context *ppp = + CONTAINER_OF(work, struct pppoe_driver_context, discover); + + struct net_linkaddr *ll_addr; + + /* The MAC address is set to be the same as what Ethernet has as + * we are passing packets via that interface anyway + */ + ll_addr = net_if_get_link_addr(net_if_lookup_by_dev(ppp->eth_dev)); + if (ll_addr->addr) { + net_if_set_link_addr(ppp->iface, ll_addr->addr, ll_addr->len, + NET_LINK_ETHERNET); + } else { + /* Ethernet is not yet ready, try again */ + k_delayed_work_submit(&ppp->discover, + PPPOE_STARTUP_DELAY); + return; + } + + /* Start the PPPoE Discovery procedure, RFC 2516 chapter 5 */ + k_delayed_work_init(&ppp->discover, pppoe_discover); + ppp->discovery_delay = K_MSEC(1); + pppoe_start_discovery(ppp); +} + +static void pppoe_iface_init(struct net_if *iface) +{ + struct pppoe_driver_context *ppp = + net_if_get_device(iface)->driver_data; + + LOG_DBG("[%p] iface %p", ppp, iface); + + net_ppp_init(iface); + + if (ppp->init_done) { + return; + } + + ppp->init_done = true; + ppp->iface = iface; + + /* The PPP interface will go up after the Discovery has finished + * and we are in Session state. + */ + net_if_flag_set(iface, NET_IF_NO_AUTO_START); + + /* If user has not defined the Ethernet device, then take the first + * one. + */ + if (CONFIG_NET_PPPOE_ETH_DRV_NAME[0] == '\0') { + struct net_if *eth_iface; + + eth_iface = net_if_get_first_by_type( + &NET_L2_GET_NAME(ETHERNET)); + ppp->eth_dev = net_if_get_device(eth_iface); + } else { + ppp->eth_dev = + device_get_binding(CONFIG_NET_PPPOE_ETH_DRV_NAME); + } + + if (!ppp->eth_dev) { + LOG_ERR("Ethernet dev not found"); + } else { + LOG_DBG("Using %s Ethernet device", ppp->eth_dev->config->name); + } + + /* The network interface startup is delayed a bit so that the + * Ethernet network interface is properly setup because we need + * the Ethernet to have MAC address set. + */ + k_delayed_work_init(&ppp->discover, pppoe_startup); + k_delayed_work_submit(&ppp->discover, PPPOE_STARTUP_DELAY); +} + +#if defined(CONFIG_NET_STATISTICS_PPP) +static struct net_stats_ppp *pppoe_get_stats(struct device *dev) +{ + struct pppoe_driver_context *context = dev->driver_data; + + return &context->stats; +} +#endif + +static int pppoe_start(struct device *dev) +{ + struct pppoe_driver_context *context = dev->driver_data; + + net_ppp_carrier_on(context->iface); + + return 0; +} + +static int pppoe_stop(struct device *dev) +{ + struct pppoe_driver_context *context = dev->driver_data; + + net_ppp_carrier_off(context->iface); + + return 0; +} + +static const struct ppp_api pppoe_if_api = { + .iface_api.init = pppoe_iface_init, + + .send = pppoe_send, + .start = pppoe_start, + .stop = pppoe_stop, +#if defined(CONFIG_NET_STATISTICS_PPP) + .get_stats = pppoe_get_stats, +#endif +}; + +enum net_verdict net_pppoe_recv(struct net_if *iface, struct net_pkt *pkt) +{ + return pppoe_process_msg(&pppoe_driver_context_data, iface, pkt); +} + +/* Note that Ethernet device must be setup before pppoe + * as otherwise we cannot setup things properly in this driver. + */ +NET_DEVICE_INIT(pppoe, CONFIG_NET_PPPOE_DRV_NAME, pppoe_driver_init, + &pppoe_driver_context_data, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &pppoe_if_api, + PPP_L2, NET_L2_GET_CTX_TYPE(PPP_L2), PPPOE_MTU); diff --git a/include/net/ethernet.h b/include/net/ethernet.h index f363a7bb55af2..cf952847723dc 100644 --- a/include/net/ethernet.h +++ b/include/net/ethernet.h @@ -52,6 +52,8 @@ struct net_eth_addr { #define NET_ETH_PTYPE_IP 0x0800 #define NET_ETH_PTYPE_IPV6 0x86dd #define NET_ETH_PTYPE_VLAN 0x8100 +#define NET_ETH_PTYPE_PPP_DISCOVERY 0x8863 +#define NET_ETH_PTYPE_PPP_SESSION 0x8864 #define NET_ETH_PTYPE_PTP 0x88f7 #define NET_ETH_PTYPE_LLDP 0x88cc #define NET_ETH_PTYPE_ALL 0x0003 /* from linux/if_ether.h */ diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 4ddbc352ed513..9b44cc8e722a1 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -138,6 +138,10 @@ struct net_pkt { * a GPTP packet. * Used only if defined (CONFIG_NET_GPTP) */ + u8_t pppoe_discovery: 1; /* For outgoing packet: is this + * a PPPoE Discovery packet or not. + * Used only if CONFIG_NET_PPPOE. + */ }; u8_t forwarding : 1; /* Are we forwarding this pkt @@ -860,6 +864,17 @@ static inline void net_pkt_set_ppp(struct net_pkt *pkt, { pkt->ppp_msg = is_ppp_msg; } + +static inline bool net_pkt_is_pppoe_discovery(struct net_pkt *pkt) +{ + return pkt->pppoe_discovery == true; +} + +static inline void net_pkt_set_pppoe_discovery_type(struct net_pkt *pkt, + bool is_pppoe_discovery) +{ + pkt->pppoe_discovery = is_pppoe_discovery; +} #else /* CONFIG_NET_PPP */ static inline bool net_pkt_is_ppp(struct net_pkt *pkt) { @@ -874,6 +889,20 @@ static inline void net_pkt_set_ppp(struct net_pkt *pkt, ARG_UNUSED(pkt); ARG_UNUSED(is_ppp_msg); } + +static inline bool net_pkt_is_pppoe_discovery(struct net_pkt *pkt) +{ + ARG_UNUSED(pkt); + + return false; +} + +static inline void net_pkt_set_pppoe_discovery_type(struct net_pkt *pkt, + bool is_pppoe_discovery) +{ + ARG_UNUSED(pkt); + ARG_UNUSED(is_pppoe_discovery); +} #endif /* CONFIG_NET_PPP */ #define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt)) diff --git a/include/net/ppp.h b/include/net/ppp.h index 138480da950f4..9354cd2cb4a20 100644 --- a/include/net/ppp.h +++ b/include/net/ppp.h @@ -30,6 +30,9 @@ extern "C" { /** PPP maximum transfer unit (MTU) */ #define PPP_MTU PPP_MRU +/** PPP over Ethernet MTU, see RFC 2516 for details */ +#define PPPOE_MTU 1492 + /** Max length of terminate description string */ #define PPP_MAX_TERMINATE_REASON_LEN 32 @@ -128,6 +131,16 @@ enum ppp_packet_type { PPP_DISCARD_REQ = 11 }; +/** + * PPPoE protocol packets from RFC 2516 + */ +enum pppoe_packet_type { + PPPOE_PADI = 0x09, + PPPOE_PADO = 0x07, + PPPOE_PADR = 0x19, + PPPOE_PADS = 0x65, +}; + /** * LCP option types from RFC 1661 ch. 6 */ @@ -626,6 +639,20 @@ static inline struct ppp_context *net_ppp_context_get(int idx) } #endif +#if defined(CONFIG_NET_PPPOE) +enum net_verdict net_pppoe_recv(struct net_if *iface, struct net_pkt *pkt); +#else +enum net_verdict net_pppoe_recv(struct net_if *iface, struct net_pkt *pkt) +{ + ARG_UNUSED(iface); + ARG_UNUSED(pkt); + + LOG_ERR("PPPoE not enabled"); + + return NET_DROP; +} +#endif /* CONFIG_NET_PPPOE */ + #ifdef __cplusplus } #endif diff --git a/subsys/net/l2/ethernet/ethernet.c b/subsys/net/l2/ethernet/ethernet.c index cc9e4df2b756c..f9ed3309cc353 100644 --- a/subsys/net/l2/ethernet/ethernet.c +++ b/subsys/net/l2/ethernet/ethernet.c @@ -19,6 +19,10 @@ LOG_MODULE_REGISTER(net_ethernet, CONFIG_NET_L2_ETHERNET_LOG_LEVEL); #include #endif +#if defined(CONFIG_NET_PPPOE) +#include +#endif + #include #include "arp.h" @@ -207,6 +211,14 @@ static enum net_verdict ethernet_recv(struct net_if *iface, #else NET_DBG("LLDP Rx agent not enabled"); goto drop; +#endif +#if defined(CONFIG_NET_PPPOE) + case NET_ETH_PTYPE_PPP_DISCOVERY: + net_pkt_set_pppoe_discovery_type(pkt, true); + /* fallthrough */ + case NET_ETH_PTYPE_PPP_SESSION: + net_buf_pull(pkt->frags, hdr_len); + return net_pppoe_recv(iface, pkt); #endif default: NET_DBG("Unknown hdr type 0x%04x iface %p", type, iface); @@ -589,6 +601,12 @@ static int ethernet_send(struct net_if *iface, struct net_pkt *pkt) ptype = htons(NET_ETH_PTYPE_PTP); } else if (IS_ENABLED(CONFIG_NET_LLDP) && net_pkt_is_lldp(pkt)) { ptype = htons(NET_ETH_PTYPE_LLDP); + } else if (IS_ENABLED(CONFIG_NET_PPPOE) && net_pkt_is_ppp(pkt)) { + if (net_pkt_is_pppoe_discovery(pkt)) { + ptype = htons(NET_ETH_PTYPE_PPP_DISCOVERY); + } else { + ptype = htons(NET_ETH_PTYPE_PPP_SESSION); + } } else if (IS_ENABLED(CONFIG_NET_ARP)) { /* Unktown type: Unqueued pkt is an ARP reply. */