net: ppp: Initial support for point-to-point protocol
This implements ppp L2 component, LCP and IPCP modules. Fixes #14034 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
504dffa38c
commit
f95938da0f
24 changed files with 4003 additions and 1 deletions
|
@ -82,6 +82,16 @@
|
|||
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_L2_PPP)
|
||||
SECTION_PROLOGUE(net_ppp_proto,,)
|
||||
{
|
||||
__net_ppp_proto_start = .;
|
||||
*(".net_ppp_proto.*")
|
||||
KEEP(*(SORT_BY_NAME(".net_ppp_proto.*")))
|
||||
__net_ppp_proto_end = .;
|
||||
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||
#endif
|
||||
|
||||
SECTION_DATA_PROLOGUE(_bt_channels_area,,SUBALIGN(4))
|
||||
{
|
||||
_bt_l2cap_fixed_chan_list_start = .;
|
||||
|
|
|
@ -37,6 +37,11 @@ enum net_l2_flags {
|
|||
|
||||
/** Is promiscuous mode supported */
|
||||
NET_L2_PROMISC_MODE = BIT(2),
|
||||
|
||||
/** Is this L2 point-to-point with tunneling so no need to have
|
||||
* IP address etc to network interface.
|
||||
*/
|
||||
NET_L2_POINT_TO_POINT = BIT(3),
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
|
@ -88,6 +93,11 @@ NET_L2_DECLARE_PUBLIC(DUMMY_L2);
|
|||
NET_L2_DECLARE_PUBLIC(ETHERNET_L2);
|
||||
#endif /* CONFIG_NET_L2_ETHERNET */
|
||||
|
||||
#ifdef CONFIG_NET_L2_PPP
|
||||
#define PPP_L2 PPP
|
||||
NET_L2_DECLARE_PUBLIC(PPP_L2);
|
||||
#endif /* CONFIG_NET_L2_PPP */
|
||||
|
||||
#ifdef CONFIG_NET_L2_IEEE802154
|
||||
#define IEEE802154_L2 IEEE802154
|
||||
NET_L2_DECLARE_PUBLIC(IEEE802154_L2);
|
||||
|
|
|
@ -158,6 +158,7 @@ struct net_pkt {
|
|||
* Note: family needs to be
|
||||
* AF_UNSPEC.
|
||||
*/
|
||||
u8_t ppp_msg : 1; /* This is a PPP message */
|
||||
};
|
||||
|
||||
union {
|
||||
|
@ -848,6 +849,33 @@ static inline void net_pkt_set_lldp(struct net_pkt *pkt, bool is_lldp)
|
|||
}
|
||||
#endif /* CONFIG_NET_LLDP */
|
||||
|
||||
#if defined(CONFIG_NET_PPP)
|
||||
static inline bool net_pkt_is_ppp(struct net_pkt *pkt)
|
||||
{
|
||||
return pkt->ppp_msg;
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_ppp(struct net_pkt *pkt,
|
||||
bool is_ppp_msg)
|
||||
{
|
||||
pkt->ppp_msg = is_ppp_msg;
|
||||
}
|
||||
#else /* CONFIG_NET_PPP */
|
||||
static inline bool net_pkt_is_ppp(struct net_pkt *pkt)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void net_pkt_set_ppp(struct net_pkt *pkt,
|
||||
bool is_ppp_msg)
|
||||
{
|
||||
ARG_UNUSED(pkt);
|
||||
ARG_UNUSED(is_ppp_msg);
|
||||
}
|
||||
#endif /* CONFIG_NET_PPP */
|
||||
|
||||
#define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt))
|
||||
#define NET_IPV4_HDR(pkt) ((struct net_ipv4_hdr *)net_pkt_ip_data(pkt))
|
||||
|
||||
|
|
|
@ -376,6 +376,20 @@ struct net_stats_eth {
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief All PPP specific statistics
|
||||
*/
|
||||
struct net_stats_ppp {
|
||||
struct net_stats_bytes bytes;
|
||||
struct net_stats_pkts pkts;
|
||||
|
||||
/** Number of received and dropped PPP frames. */
|
||||
net_stats_t drop;
|
||||
|
||||
/** Number of received PPP frames with a bad checksum. */
|
||||
net_stats_t chkerr;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NET_STATISTICS_USER_API)
|
||||
/* Management part definitions */
|
||||
|
||||
|
@ -398,6 +412,7 @@ enum net_request_stats_cmd {
|
|||
NET_REQUEST_STATS_CMD_GET_UDP,
|
||||
NET_REQUEST_STATS_CMD_GET_TCP,
|
||||
NET_REQUEST_STATS_CMD_GET_ETHERNET,
|
||||
NET_REQUEST_STATS_CMD_GET_PPP,
|
||||
};
|
||||
|
||||
#define NET_REQUEST_STATS_GET_ALL \
|
||||
|
@ -469,6 +484,13 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_TCP);
|
|||
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ETHERNET);
|
||||
#endif /* CONFIG_NET_STATISTICS_ETHERNET */
|
||||
|
||||
#if defined(CONFIG_NET_STATISTICS_PPP)
|
||||
#define NET_REQUEST_STATS_GET_PPP \
|
||||
(_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_PPP)
|
||||
|
||||
NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PPP);
|
||||
#endif /* CONFIG_NET_STATISTICS_PPP */
|
||||
|
||||
#endif /* CONFIG_NET_STATISTICS_USER_API */
|
||||
|
||||
/**
|
||||
|
|
541
include/net/ppp.h
Normal file
541
include/net/ppp.h
Normal file
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_NET_PPP_H_
|
||||
#define ZEPHYR_INCLUDE_NET_PPP_H_
|
||||
|
||||
#include <net/net_if.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <net/net_stats.h>
|
||||
#include <net/net_mgmt.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Point-to-point (PPP) L2/driver support functions
|
||||
* @defgroup ppp PPP L2/driver Support Functions
|
||||
* @ingroup networking
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** PPP maximum receive unit (MRU) */
|
||||
#define PPP_MRU 1500
|
||||
|
||||
/** PPP maximum transfer unit (MTU) */
|
||||
#define PPP_MTU PPP_MRU
|
||||
|
||||
/** Max length of terminate description string */
|
||||
#define PPP_MAX_TERMINATE_REASON_LEN 32
|
||||
|
||||
/** PPP L2 API */
|
||||
struct ppp_api {
|
||||
/**
|
||||
* The net_if_api must be placed in first position in this
|
||||
* struct so that we are compatible with network interface API.
|
||||
*/
|
||||
struct net_if_api iface_api;
|
||||
|
||||
/** Start the device */
|
||||
int (*start)(struct device *dev);
|
||||
|
||||
/** Stop the device */
|
||||
int (*stop)(struct device *dev);
|
||||
|
||||
/** Send a network packet */
|
||||
int (*send)(struct device *dev, struct net_pkt *pkt);
|
||||
|
||||
#if defined(CONFIG_NET_STATISTICS_PPP)
|
||||
/** Collect optional PPP specific statistics. This pointer
|
||||
* should be set by driver if statistics needs to be collected
|
||||
* for that driver.
|
||||
*/
|
||||
struct net_stats_ppp *(*get_stats)(struct device *dev);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* PPP protocol types.
|
||||
* See https://www.iana.org/assignments/ppp-numbers/ppp-numbers.xhtml
|
||||
* for details.
|
||||
*/
|
||||
enum ppp_protocol_type {
|
||||
PPP_IP = 0x0021, /**< RFC 1332 */
|
||||
PPP_IPV6 = 0x0057, /**< RFC 5072 */
|
||||
PPP_IPCP = 0x8021, /**< RFC 1332 */
|
||||
PPP_ECP = 0x8053, /**< RFC 1968 */
|
||||
PPP_CCP = 0x80FD, /**< RFC 1962 */
|
||||
PPP_LCP = 0xc021, /**< RFC 1661 */
|
||||
};
|
||||
|
||||
/**
|
||||
* PPP phases
|
||||
*/
|
||||
enum ppp_phase {
|
||||
/** Physical-layer not ready */
|
||||
PPP_DEAD,
|
||||
/** Link is being established */
|
||||
PPP_ESTABLISH,
|
||||
/** Link authentication with peer */
|
||||
PPP_AUTH,
|
||||
/** Network connection establishment */
|
||||
PPP_NETWORK,
|
||||
/** Network running */
|
||||
PPP_RUNNING,
|
||||
/** Link termination */
|
||||
PPP_TERMINATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* PPP states, RFC 1661 ch. 4.2
|
||||
*/
|
||||
enum ppp_state {
|
||||
PPP_INITIAL,
|
||||
PPP_STARTING,
|
||||
PPP_CLOSED,
|
||||
PPP_STOPPED,
|
||||
PPP_CLOSING,
|
||||
PPP_STOPPING,
|
||||
PPP_REQUEST_SENT,
|
||||
PPP_ACK_RECEIVED,
|
||||
PPP_ACK_SENT,
|
||||
PPP_OPENED
|
||||
};
|
||||
|
||||
/**
|
||||
* PPP protocol operations from RFC 1661
|
||||
*/
|
||||
enum ppp_packet_type {
|
||||
PPP_CONFIGURE_REQ = 1,
|
||||
PPP_CONFIGURE_ACK = 2,
|
||||
PPP_CONFIGURE_NACK = 3,
|
||||
PPP_CONFIGURE_REJ = 4,
|
||||
PPP_TERMINATE_REQ = 5,
|
||||
PPP_TERMINATE_ACK = 6,
|
||||
PPP_CODE_REJ = 7,
|
||||
PPP_PROTOCOL_REJ = 8,
|
||||
PPP_ECHO_REQ = 9,
|
||||
PPP_ECHO_REPLY = 10,
|
||||
PPP_DISCARD_REQ = 11
|
||||
};
|
||||
|
||||
/**
|
||||
* LCP option types from RFC 1661 ch. 6
|
||||
*/
|
||||
enum lcp_option_type {
|
||||
LCP_OPTION_RESERVED = 0,
|
||||
|
||||
/** Maximum-Receive-Unit */
|
||||
LCP_OPTION_MRU = 1,
|
||||
|
||||
/** Async-Control-Character-Map */
|
||||
LCP_OPTION_ASYNC_CTRL_CHAR_MAP = 2,
|
||||
|
||||
/** Authentication-Protocol */
|
||||
LCP_OPTION_AUTH_PROTO = 3,
|
||||
|
||||
/** Quality-Protocol */
|
||||
LCP_OPTION_QUALITY_PROTO = 4,
|
||||
|
||||
/** Magic-Number */
|
||||
LCP_OPTION_MAGIC_NUMBER = 5,
|
||||
|
||||
/** Protocol-Field-Compression */
|
||||
LCP_OPTION_PROTO_COMPRESS = 7,
|
||||
|
||||
/** Address-and-Control-Field-Compression */
|
||||
LCP_OPTION_ADDR_CTRL_COMPRESS = 8
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* IPCP option types from RFC 1332
|
||||
*/
|
||||
enum ipcp_option_type {
|
||||
IPCP_OPTION_RESERVED = 0,
|
||||
|
||||
/** IP Addresses */
|
||||
IPCP_OPTION_IP_ADDRESSES = 1,
|
||||
|
||||
/** IP Compression Protocol */
|
||||
IPCP_OPTION_IP_COMP_PROTO = 2,
|
||||
|
||||
/** IP Address */
|
||||
IPCP_OPTION_IP_ADDRESS = 3,
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* Generic PPP Finite State Machine
|
||||
*/
|
||||
struct ppp_fsm {
|
||||
/** Timeout timer */
|
||||
struct k_delayed_work timer;
|
||||
|
||||
/* We need to send a packet from separate thread so that we do not
|
||||
* receive reply before we are ready to receive it. The issue was seen
|
||||
* with QEMU where the link to peer is so fast that we received the
|
||||
* reply before the net_send_data() returned.
|
||||
*/
|
||||
struct {
|
||||
/** Packet sending timer. */
|
||||
struct k_delayed_work work;
|
||||
|
||||
/** Packet to send */
|
||||
struct net_pkt *pkt;
|
||||
} sender;
|
||||
|
||||
struct {
|
||||
/** Acknowledge Configuration Information */
|
||||
int (*config_info_ack)(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length);
|
||||
|
||||
/** Add Configuration Information */
|
||||
struct net_buf *(*config_info_add)(struct ppp_fsm *fsm);
|
||||
|
||||
/** Length of Configuration Information */
|
||||
int (*config_info_len)(struct ppp_fsm *fsm);
|
||||
|
||||
/** Negative Acknowledge Configuration Information */
|
||||
int (*config_info_nack)(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length,
|
||||
bool rejected);
|
||||
|
||||
/** Request peer's Configuration Information */
|
||||
int (*config_info_req)(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length,
|
||||
struct net_buf **buf);
|
||||
|
||||
/** Reject Configuration Information */
|
||||
int (*config_info_rej)(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length);
|
||||
|
||||
/** Reset Configuration Information */
|
||||
void (*config_info_reset)(struct ppp_fsm *fsm);
|
||||
|
||||
/** FSM goes to OPENED state */
|
||||
void (*up)(struct ppp_fsm *fsm);
|
||||
|
||||
/** FSM leaves OPENED state */
|
||||
void (*down)(struct ppp_fsm *fsm);
|
||||
|
||||
/** Starting this protocol */
|
||||
void (*starting)(struct ppp_fsm *fsm);
|
||||
|
||||
/** Quitting this protocol */
|
||||
void (*finished)(struct ppp_fsm *fsm);
|
||||
|
||||
/** We received Protocol-Reject */
|
||||
void (*proto_reject)(struct ppp_fsm *fsm);
|
||||
|
||||
/** Retransmit */
|
||||
void (*retransmit)(struct ppp_fsm *fsm);
|
||||
|
||||
/** Any code that is not understood by PPP is passed to
|
||||
* this FSM for further processing.
|
||||
*/
|
||||
enum net_verdict (*proto_extension)(struct ppp_fsm *fsm,
|
||||
enum ppp_packet_type code,
|
||||
u8_t id,
|
||||
struct net_pkt *pkt);
|
||||
} cb;
|
||||
|
||||
/** Option bits */
|
||||
u32_t flags;
|
||||
|
||||
/** Number of re-transmissions left */;
|
||||
u32_t retransmits;
|
||||
|
||||
/** Number of NACK loops since last ACK */
|
||||
u32_t nack_loops;
|
||||
|
||||
/** Number of NACKs received */
|
||||
u32_t recv_nack_loops;
|
||||
|
||||
/** Reason for closing protocol */
|
||||
char terminate_reason[PPP_MAX_TERMINATE_REASON_LEN];
|
||||
|
||||
/** PPP protocol number for this FSM */
|
||||
u16_t protocol;
|
||||
|
||||
/** Current state of PPP link */
|
||||
enum ppp_state state;
|
||||
|
||||
/** Protocol/layer name of this FSM (for debugging) */
|
||||
const char *name;
|
||||
|
||||
/** Current id */
|
||||
u8_t id;
|
||||
|
||||
/** Current request id */
|
||||
u8_t req_id;
|
||||
|
||||
/** Have received valid Ack, Nack or Reject to a Request */
|
||||
u8_t ack_received : 1;
|
||||
};
|
||||
|
||||
/** PPP configuration options */
|
||||
struct ppp_option_pkt {
|
||||
/** Option value */
|
||||
struct net_pkt_cursor value;
|
||||
|
||||
/** Option type */
|
||||
union {
|
||||
enum lcp_option_type lcp;
|
||||
enum ipcp_option_type ipcp;
|
||||
} type;
|
||||
|
||||
/** Option length */
|
||||
u8_t len;
|
||||
};
|
||||
|
||||
struct lcp_options {
|
||||
/** Magic number */
|
||||
u32_t magic;
|
||||
|
||||
/** Async char map */
|
||||
u32_t async_map;
|
||||
|
||||
/** Maximum Receive Unit value */
|
||||
u16_t mru;
|
||||
|
||||
/* Flags what to negotiate */
|
||||
|
||||
/** Negotiate MRU */
|
||||
u16_t negotiate_mru : 1;
|
||||
|
||||
/** Negotiate */
|
||||
u16_t negotiate_async_map :1;
|
||||
|
||||
/** Negotiate HDLC protocol field compression*/
|
||||
u16_t negotiate_proto_compression :1;
|
||||
|
||||
/** Negotiate HDLC address/control field compression */
|
||||
u16_t negotiate_addr_compression :1;
|
||||
|
||||
/** Negotiate magic number */
|
||||
u16_t negotiate_magic :1;
|
||||
};
|
||||
|
||||
struct ipcp_options {
|
||||
/** IPv4 address */
|
||||
struct in_addr address;
|
||||
};
|
||||
|
||||
/** PPP L2 context specific to certain network interface */
|
||||
struct ppp_context {
|
||||
struct {
|
||||
/** Carrier ON/OFF handler worker. This is used to create
|
||||
* network interface UP/DOWN event when PPP L2 driver
|
||||
* notices carrier ON/OFF situation. We must not create another
|
||||
* network management event from inside management handler thus
|
||||
* we use worker thread to trigger the UP/DOWN event.
|
||||
*/
|
||||
struct k_work work;
|
||||
|
||||
/** Is the carrier enabled already */
|
||||
bool enabled;
|
||||
} carrier_mgmt;
|
||||
|
||||
struct {
|
||||
/** Finite state machine for LCP */
|
||||
struct ppp_fsm fsm;
|
||||
|
||||
/** Options that we want to request */
|
||||
struct lcp_options my_options;
|
||||
|
||||
/** Options that peer want to request */
|
||||
struct lcp_options peer_options;
|
||||
|
||||
/** Options that we accepted */
|
||||
struct lcp_options my_accepted;
|
||||
|
||||
/** Options that peer accepted */
|
||||
struct lcp_options peer_accepted;
|
||||
|
||||
/** Magic-Number value */
|
||||
u32_t magic;
|
||||
} lcp;
|
||||
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
struct {
|
||||
/** Finite state machine for IPCP */
|
||||
struct ppp_fsm fsm;
|
||||
|
||||
/** Options that we want to request */
|
||||
struct ipcp_options my_options;
|
||||
|
||||
/** Options that peer want to request */
|
||||
struct ipcp_options peer_options;
|
||||
|
||||
/** Options that we accepted */
|
||||
struct ipcp_options my_accepted;
|
||||
|
||||
/** Options that peer accepted */
|
||||
struct ipcp_options peer_accepted;
|
||||
} ipcp;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_SHELL)
|
||||
struct {
|
||||
/** Used when waiting Echo-Reply */
|
||||
struct k_sem wait_echo_reply;
|
||||
|
||||
/** Echo-Req data value */
|
||||
u32_t echo_req_data;
|
||||
|
||||
/** Echo-Reply data value */
|
||||
u32_t echo_reply_data;
|
||||
} shell;
|
||||
#endif
|
||||
|
||||
/** Network interface related to this PPP connection */
|
||||
struct net_if *iface;
|
||||
|
||||
/** Current phase of PPP link */
|
||||
enum ppp_phase phase;
|
||||
|
||||
/** This tells what features the PPP supports. */
|
||||
enum net_l2_flags ppp_l2_flags;
|
||||
|
||||
/** This tells how many network protocols are open */
|
||||
int network_protos_open;
|
||||
|
||||
/** This tells how many network protocols are up */
|
||||
int network_protos_up;
|
||||
|
||||
/** Is this context already initialized */
|
||||
u16_t is_init : 1;
|
||||
|
||||
/** Is PPP ready to receive packets */
|
||||
u16_t is_ready_to_serve : 1;
|
||||
|
||||
/** Is PPP L2 enabled or not */
|
||||
u16_t is_enabled : 1;
|
||||
|
||||
/** Network status (up / down) */
|
||||
u16_t is_network_up : 1;
|
||||
|
||||
/** IPCP status (up / down) */
|
||||
u16_t is_ipcp_up : 1;
|
||||
|
||||
/** IPCP open status (open / closed) */
|
||||
u16_t is_ipcp_open : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Inform PPP L2 driver that carrier is detected.
|
||||
* This happens when cable is connected etc.
|
||||
*
|
||||
* @param iface Network interface
|
||||
*/
|
||||
void net_ppp_carrier_on(struct net_if *iface);
|
||||
|
||||
/**
|
||||
* @brief Inform PPP L2 driver that carrier was lost.
|
||||
* This happens when cable is disconnected etc.
|
||||
*
|
||||
* @param iface Network interface
|
||||
*/
|
||||
void net_ppp_carrier_off(struct net_if *iface);
|
||||
|
||||
/**
|
||||
* @brief Initialize PPP L2 stack for a given interface
|
||||
*
|
||||
* @param iface A valid pointer to a network interface
|
||||
*/
|
||||
void net_ppp_init(struct net_if *iface);
|
||||
|
||||
/* Management API for PPP */
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
|
||||
#define PPP_L2_CTX_TYPE struct ppp_context
|
||||
|
||||
#define _NET_PPP_LAYER NET_MGMT_LAYER_L2
|
||||
#define _NET_PPP_CODE 0x209
|
||||
#define _NET_PPP_BASE (NET_MGMT_IFACE_BIT | \
|
||||
NET_MGMT_LAYER(_NET_PPP_LAYER) | \
|
||||
NET_MGMT_LAYER_CODE(_NET_PPP_CODE))
|
||||
#define _NET_PPP_EVENT (_NET_PPP_BASE | NET_MGMT_EVENT_BIT)
|
||||
|
||||
enum net_event_ppp_cmd {
|
||||
NET_EVENT_PPP_CMD_CARRIER_ON = 1,
|
||||
NET_EVENT_PPP_CMD_CARRIER_OFF,
|
||||
};
|
||||
|
||||
#define NET_EVENT_PPP_CARRIER_ON \
|
||||
(_NET_PPP_EVENT | NET_EVENT_PPP_CMD_CARRIER_ON)
|
||||
|
||||
#define NET_EVENT_PPP_CARRIER_OFF \
|
||||
(_NET_PPP_EVENT | NET_EVENT_PPP_CMD_CARRIER_OFF)
|
||||
|
||||
struct net_if;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
* @brief Raise CARRIER_ON event when PPP is connected.
|
||||
*
|
||||
* @param iface PPP network interface.
|
||||
*/
|
||||
#if defined(CONFIG_NET_L2_PPP_MGMT)
|
||||
void ppp_mgmt_raise_carrier_on_event(struct net_if *iface);
|
||||
#else
|
||||
static inline void ppp_mgmt_raise_carrier_on_event(struct net_if *iface)
|
||||
{
|
||||
ARG_UNUSED(iface);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Raise CARRIER_OFF event when PPP is disconnected.
|
||||
*
|
||||
* @param iface PPP network interface.
|
||||
*/
|
||||
#if defined(CONFIG_NET_L2_PPP_MGMT)
|
||||
void ppp_mgmt_raise_carrier_off_event(struct net_if *iface);
|
||||
#else
|
||||
static inline void ppp_mgmt_raise_carrier_off_event(struct net_if *iface)
|
||||
{
|
||||
ARG_UNUSED(iface);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Send PPP Echo-Request to peer. We expect to receive Echo-Reply back.
|
||||
*
|
||||
* @param idx PPP network interface index
|
||||
* @param timeout Amount of time to wait Echo-Reply.
|
||||
*
|
||||
* @return 0 if Echo-Reply was received, < 0 if there is a timeout or network
|
||||
* index is not a valid PPP network index.
|
||||
*/
|
||||
#if defined(CONFIG_NET_L2_PPP)
|
||||
int net_ppp_ping(int idx, s32_t timeout);
|
||||
#else
|
||||
static inline int net_ppp_ping(int idx, s32_t timeout)
|
||||
{
|
||||
ARG_UNUSED(idx);
|
||||
ARG_UNUSED(timeout);
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_NET_PPP_H_ */
|
|
@ -922,7 +922,7 @@ class SizeCalculator:
|
|||
"rodata", "devconfig", "net_l2", "vector", "sw_isr_table",
|
||||
"_settings_handlers_area", "_bt_channels_area",
|
||||
"_bt_br_channels_area", "_bt_services_area",
|
||||
"vectors", "net_socket_register"]
|
||||
"vectors", "net_socket_register", "net_ppp_proto"]
|
||||
|
||||
def __init__(self, filename, extra_sections):
|
||||
"""Constructor
|
||||
|
|
|
@ -22,6 +22,7 @@ if !NET_RAW_MODE
|
|||
|
||||
choice
|
||||
prompt "Qemu networking"
|
||||
default NET_QEMU_PPP if NET_PPP
|
||||
default NET_QEMU_SLIP
|
||||
depends on QEMU_TARGET
|
||||
help
|
||||
|
@ -34,6 +35,11 @@ config NET_QEMU_SLIP
|
|||
help
|
||||
Connect to host or to another Qemu via SLIP.
|
||||
|
||||
config NET_QEMU_PPP
|
||||
bool "PPP"
|
||||
help
|
||||
Connect to host via PPP.
|
||||
|
||||
config NET_QEMU_ETHERNET
|
||||
bool "Ethernet"
|
||||
help
|
||||
|
|
|
@ -89,6 +89,13 @@ config NET_STATISTICS_MLD
|
|||
help
|
||||
Keep track of MLD related statistics
|
||||
|
||||
config NET_STATISTICS_PPP
|
||||
bool "Point-to-point (PPP) statistics"
|
||||
depends on NET_PPP
|
||||
default y
|
||||
help
|
||||
Keep track of PPP related statistics
|
||||
|
||||
config NET_STATISTICS_ETHERNET
|
||||
bool "Ethernet statistics"
|
||||
depends on NET_L2_ETHERNET
|
||||
|
|
|
@ -12,6 +12,10 @@ if(CONFIG_NET_L2_ETHERNET)
|
|||
add_subdirectory(ethernet)
|
||||
endif()
|
||||
|
||||
if(CONFIG_NET_L2_PPP)
|
||||
add_subdirectory(ppp)
|
||||
endif()
|
||||
|
||||
if(CONFIG_NET_L2_IEEE802154)
|
||||
add_subdirectory(ieee802154)
|
||||
endif()
|
||||
|
|
|
@ -71,6 +71,8 @@ config NET_L2_BT_SHELL
|
|||
|
||||
source "subsys/net/l2/ethernet/Kconfig"
|
||||
|
||||
source "subsys/net/l2/ppp/Kconfig"
|
||||
|
||||
source "subsys/net/l2/ieee802154/Kconfig"
|
||||
|
||||
source "subsys/net/l2/openthread/Kconfig"
|
||||
|
|
25
subsys/net/l2/ppp/CMakeLists.txt
Normal file
25
subsys/net/l2/ppp/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_include_directories(. ${ZEPHYR_BASE}/subsys/net/ip)
|
||||
zephyr_library_compile_definitions_ifdef(
|
||||
CONFIG_NEWLIB_LIBC __LINUX_ERRNO_EXTENSIONS__
|
||||
)
|
||||
|
||||
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_NET_L2_PPP
|
||||
ppp_l2.c
|
||||
fsm.c
|
||||
lcp.c
|
||||
auth.c
|
||||
options.c
|
||||
link.c
|
||||
network.c
|
||||
misc.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_NET_STATISTICS_PPP ppp_stats.c)
|
||||
|
||||
if(CONFIG_NET_IPV4)
|
||||
zephyr_library_sources_ifdef(CONFIG_NET_L2_PPP ipcp.c)
|
||||
endif()
|
71
subsys/net/l2/ppp/Kconfig
Normal file
71
subsys/net/l2/ppp/Kconfig
Normal file
|
@ -0,0 +1,71 @@
|
|||
#
|
||||
# Copyright (c) 2019 Intel Corporation.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
menuconfig NET_L2_PPP
|
||||
bool "Enable point-to-point (PPP) support [EXPERIMENTAL]"
|
||||
help
|
||||
Add support for PPP.
|
||||
|
||||
if NET_L2_PPP
|
||||
|
||||
config NET_L2_PPP_TIMEOUT
|
||||
int "Maximum timeout in ms for Configure-Req"
|
||||
default 3000
|
||||
range 1 4294967295
|
||||
help
|
||||
How long to wait Configure-Req.
|
||||
|
||||
config NET_L2_PPP_MAX_CONFIGURE_REQ_RETRANSMITS
|
||||
int "Maximum number of Configure-Req retransmits"
|
||||
default 10
|
||||
range 0 4294967295
|
||||
help
|
||||
How many times to resend Configure-Req messages before deciding the
|
||||
link is not working properly.
|
||||
|
||||
config NET_L2_PPP_MAX_TERMINATE_REQ_RETRANSMITS
|
||||
int "Maximum number of Terminate-Req retransmits"
|
||||
default 2
|
||||
range 0 4294967295
|
||||
help
|
||||
How many times to resend Terminate-Req messages before terminating
|
||||
the link.
|
||||
|
||||
config NET_L2_PPP_MAX_NACK_LOOPS
|
||||
int "Maximum number of NACK loops accepted"
|
||||
default 5
|
||||
range 0 4294967295
|
||||
help
|
||||
How many times to accept NACK loops.
|
||||
|
||||
config NET_L2_PPP_MAX_OPTIONS
|
||||
int "Maximum number of options supported"
|
||||
default 8
|
||||
range 0 16
|
||||
help
|
||||
How many options we support. This is used to allocate space for
|
||||
each option. The default (8) is a reasonably small value.
|
||||
|
||||
config NET_L2_PPP_OPTION_MRU_NEG
|
||||
bool "Negotiate MRU option if needed"
|
||||
help
|
||||
Try to negotiate with peer for MRU (MTU) for the link.
|
||||
|
||||
module = NET_L2_PPP
|
||||
module-dep = NET_LOG
|
||||
module-str = Log level for ppp L2 layer
|
||||
module-help = Enables ppp L2 to output debug messages.
|
||||
source "subsys/net/Kconfig.template.log_config.net"
|
||||
|
||||
config NET_L2_PPP_MGMT
|
||||
bool "Enable ppp network management interface"
|
||||
select NET_MGMT
|
||||
select NET_MGMT_EVENT
|
||||
help
|
||||
Enable support net_mgmt ppp interface which can be used to
|
||||
configure at run-time ppp drivers and L2 settings.
|
||||
|
||||
endif # NET_L2_PPP
|
19
subsys/net/l2/ppp/auth.c
Normal file
19
subsys/net/l2/ppp/auth.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_internal.h"
|
||||
|
||||
|
1096
subsys/net/l2/ppp/fsm.c
Normal file
1096
subsys/net/l2/ppp/fsm.c
Normal file
File diff suppressed because it is too large
Load diff
453
subsys/net/l2/ppp/ipcp.c
Normal file
453
subsys/net/l2/ppp/ipcp.c
Normal file
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_internal.h"
|
||||
|
||||
static enum net_verdict ipcp_handle(struct ppp_context *ctx,
|
||||
struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
return ppp_fsm_input(&ctx->ipcp.fsm, PPP_IPCP, pkt);
|
||||
}
|
||||
|
||||
static bool append_to_buf(struct net_buf *buf, u8_t *data, u8_t data_len)
|
||||
{
|
||||
if (data_len > net_buf_tailroom(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* FIXME: use net_pkt api so that we can handle a case where data might
|
||||
* split to two net_buf's
|
||||
*/
|
||||
net_buf_add_mem(buf, data, data_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Length is (6): code + id + IPv4 address length */
|
||||
#define IP_ADDRESS_OPTION_LEN (1 + 1 + 4)
|
||||
|
||||
static struct net_buf *ipcp_config_info_add(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
ipcp.fsm);
|
||||
|
||||
/* Currently we support only one option (IP address) */
|
||||
u8_t option[IP_ADDRESS_OPTION_LEN];
|
||||
const struct in_addr *my_addr;
|
||||
struct net_buf *buf;
|
||||
bool added;
|
||||
|
||||
my_addr = net_if_ipv4_select_src_addr(ctx->iface,
|
||||
&ctx->ipcp.peer_options.address);
|
||||
if (!my_addr) {
|
||||
my_addr = net_ipv4_unspecified_address();
|
||||
}
|
||||
|
||||
option[0] = IPCP_OPTION_IP_ADDRESS;
|
||||
option[1] = IP_ADDRESS_OPTION_LEN;
|
||||
memcpy(&option[2], &my_addr->s_addr, sizeof(my_addr->s_addr));
|
||||
|
||||
buf = ppp_get_net_buf(NULL, 0);
|
||||
if (!buf) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
added = append_to_buf(buf, option, sizeof(option));
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
out_of_mem:
|
||||
if (buf) {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ipcp_config_info_req(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length,
|
||||
struct net_buf **ret_buf)
|
||||
{
|
||||
int nack_idx = 0, count_rej = 0, address_option_idx = -1;
|
||||
struct net_buf *buf = NULL;
|
||||
struct ppp_option_pkt options[MAX_IPCP_OPTIONS];
|
||||
struct ppp_option_pkt nack_options[MAX_IPCP_OPTIONS];
|
||||
enum ppp_packet_type code;
|
||||
enum net_verdict verdict;
|
||||
int i;
|
||||
|
||||
memset(options, 0, sizeof(options));
|
||||
memset(nack_options, 0, sizeof(nack_options));
|
||||
|
||||
verdict = ppp_parse_options(fsm, pkt, length, options,
|
||||
ARRAY_SIZE(options));
|
||||
if (verdict != NET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(options); i++) {
|
||||
if (options[i].type.ipcp != IPCP_OPTION_RESERVED) {
|
||||
NET_DBG("[%s/%p] %s option %s (%d) len %d",
|
||||
fsm->name, fsm, "Check",
|
||||
ppp_option2str(PPP_IPCP, options[i].type.ipcp),
|
||||
options[i].type.ipcp, options[i].len);
|
||||
}
|
||||
|
||||
switch (options[i].type.ipcp) {
|
||||
case IPCP_OPTION_RESERVED:
|
||||
continue;
|
||||
|
||||
case IPCP_OPTION_IP_ADDRESSES:
|
||||
count_rej++;
|
||||
goto ignore_option;
|
||||
|
||||
case IPCP_OPTION_IP_COMP_PROTO:
|
||||
count_rej++;
|
||||
goto ignore_option;
|
||||
|
||||
case IPCP_OPTION_IP_ADDRESS:
|
||||
/* Currently we only accept one option (IP address) */
|
||||
address_option_idx = i;
|
||||
break;
|
||||
|
||||
default:
|
||||
ignore_option:
|
||||
nack_options[nack_idx].type.ipcp =
|
||||
options[i].type.ipcp;
|
||||
nack_options[nack_idx].len = options[i].len;
|
||||
|
||||
if (options[i].len > 2) {
|
||||
memcpy(&nack_options[nack_idx].value,
|
||||
&options[i].value,
|
||||
sizeof(nack_options[nack_idx].value));
|
||||
}
|
||||
|
||||
nack_idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nack_idx > 0) {
|
||||
struct net_buf *nack_buf;
|
||||
|
||||
if (count_rej > 0) {
|
||||
code = PPP_CONFIGURE_REJ;
|
||||
} else {
|
||||
code = PPP_CONFIGURE_NACK;
|
||||
}
|
||||
|
||||
/* Create net_buf containing options that are not accepted */
|
||||
for (i = 0; i < MIN(nack_idx, ARRAY_SIZE(nack_options)); i++) {
|
||||
bool added;
|
||||
|
||||
nack_buf = ppp_get_net_buf(buf, nack_options[i].len);
|
||||
if (!nack_buf) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
buf = nack_buf;
|
||||
}
|
||||
|
||||
added = append_to_buf(nack_buf,
|
||||
&nack_options[i].type.ipcp, 1);
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
added = append_to_buf(nack_buf, &nack_options[i].len,
|
||||
1);
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
/* If there is some data, copy it to result buf */
|
||||
if (nack_options[i].value.pos) {
|
||||
added = append_to_buf(nack_buf,
|
||||
nack_options[i].value.pos,
|
||||
nack_options[i].len - 1 - 1);
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
out_of_mem:
|
||||
if (nack_buf) {
|
||||
net_buf_unref(nack_buf);
|
||||
}
|
||||
|
||||
goto bail_out;
|
||||
}
|
||||
} else {
|
||||
struct ppp_context *ctx;
|
||||
struct in_addr addr;
|
||||
int ret;
|
||||
|
||||
ctx = CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
|
||||
|
||||
if (address_option_idx < 0) {
|
||||
/* Address option was not present */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
code = PPP_CONFIGURE_ACK;
|
||||
|
||||
net_pkt_cursor_restore(pkt,
|
||||
&options[address_option_idx].value);
|
||||
|
||||
ret = net_pkt_read(pkt, (u32_t *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
/* Should not happen, is the pkt corrupt? */
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
memcpy(&ctx->ipcp.peer_options.address, &addr, sizeof(addr));
|
||||
|
||||
if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
|
||||
char dst[INET_ADDRSTRLEN];
|
||||
char *addr_str;
|
||||
|
||||
addr_str = net_addr_ntop(AF_INET, &addr, dst,
|
||||
sizeof(dst));
|
||||
|
||||
NET_DBG("[%s/%p] Received %saddress %s",
|
||||
fsm->name, fsm, "peer ", log_strdup(addr_str));
|
||||
}
|
||||
|
||||
if (addr.s_addr) {
|
||||
bool added;
|
||||
u8_t val;
|
||||
|
||||
/* The address is the remote address, we then need
|
||||
* to figure out what our address should be.
|
||||
*
|
||||
* TODO:
|
||||
* - check that the IP address can be accepted
|
||||
*/
|
||||
|
||||
buf = ppp_get_net_buf(NULL, IP_ADDRESS_OPTION_LEN);
|
||||
if (!buf) {
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
val = IPCP_OPTION_IP_ADDRESS;
|
||||
added = append_to_buf(buf, &val, sizeof(val));
|
||||
if (!added) {
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
val = IP_ADDRESS_OPTION_LEN;
|
||||
added = append_to_buf(buf, &val, sizeof(val));
|
||||
if (!added) {
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
added = append_to_buf(buf, (u8_t *)&addr.s_addr,
|
||||
sizeof(addr.s_addr));
|
||||
if (!added) {
|
||||
goto bail_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
*ret_buf = buf;
|
||||
}
|
||||
|
||||
return code;
|
||||
|
||||
bail_out:
|
||||
if (buf) {
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int ipcp_config_info_rej(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length)
|
||||
{
|
||||
struct ppp_option_pkt nack_options[MAX_IPCP_OPTIONS];
|
||||
enum net_verdict verdict;
|
||||
int i, ret, address_option_idx = -1;
|
||||
struct in_addr addr;
|
||||
|
||||
memset(nack_options, 0, sizeof(nack_options));
|
||||
|
||||
verdict = ppp_parse_options(fsm, pkt, length, nack_options,
|
||||
ARRAY_SIZE(nack_options));
|
||||
if (verdict != NET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nack_options); i++) {
|
||||
if (nack_options[i].type.ipcp != IPCP_OPTION_RESERVED) {
|
||||
NET_DBG("[%s/%p] %s option %s (%d) len %d",
|
||||
fsm->name, fsm, "Check",
|
||||
ppp_option2str(PPP_IPCP,
|
||||
nack_options[i].type.ipcp),
|
||||
nack_options[i].type.ipcp,
|
||||
nack_options[i].len);
|
||||
}
|
||||
|
||||
switch (nack_options[i].type.ipcp) {
|
||||
case IPCP_OPTION_RESERVED:
|
||||
continue;
|
||||
|
||||
case IPCP_OPTION_IP_ADDRESSES:
|
||||
continue;
|
||||
|
||||
case IPCP_OPTION_IP_COMP_PROTO:
|
||||
continue;
|
||||
|
||||
case IPCP_OPTION_IP_ADDRESS:
|
||||
address_option_idx = i;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (address_option_idx < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
net_pkt_cursor_restore(pkt, &nack_options[address_option_idx].value);
|
||||
|
||||
ret = net_pkt_read(pkt, (u32_t *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
/* Should not happen, is the pkt corrupt? */
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
|
||||
char dst[INET_ADDRSTRLEN];
|
||||
char *addr_str;
|
||||
|
||||
addr_str = net_addr_ntop(AF_INET, &addr, dst,
|
||||
sizeof(dst));
|
||||
|
||||
NET_DBG("[%s/%p] Received %saddress %s",
|
||||
fsm->name, fsm, "", log_strdup(addr_str));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipcp_lower_down(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_fsm_lower_down(&ctx->ipcp.fsm);
|
||||
}
|
||||
|
||||
static void ipcp_lower_up(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_fsm_lower_up(&ctx->ipcp.fsm);
|
||||
}
|
||||
|
||||
static void ipcp_open(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_fsm_open(&ctx->ipcp.fsm);
|
||||
}
|
||||
|
||||
static void ipcp_close(struct ppp_context *ctx, const u8_t *reason)
|
||||
{
|
||||
ppp_fsm_close(&ctx->ipcp.fsm, reason);
|
||||
}
|
||||
|
||||
static void ipcp_up(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
ipcp.fsm);
|
||||
|
||||
if (ctx->is_ipcp_up) {
|
||||
return;
|
||||
}
|
||||
|
||||
ppp_network_up(ctx, PPP_IP);
|
||||
|
||||
ctx->is_network_up = true;
|
||||
ctx->is_ipcp_up = true;
|
||||
|
||||
NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
|
||||
ppp_state_str(fsm->state), fsm->state);
|
||||
}
|
||||
|
||||
static void ipcp_down(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
ipcp.fsm);
|
||||
|
||||
if (!ctx->is_network_up) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->is_network_up = false;
|
||||
|
||||
ppp_network_down(ctx, PPP_IP);
|
||||
}
|
||||
|
||||
static void ipcp_finished(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
ipcp.fsm);
|
||||
|
||||
if (!ctx->is_ipcp_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->is_ipcp_open = false;
|
||||
|
||||
ppp_network_done(ctx, PPP_IP);
|
||||
}
|
||||
|
||||
static void ipcp_proto_reject(struct ppp_fsm *fsm)
|
||||
{
|
||||
ppp_fsm_lower_down(fsm);
|
||||
}
|
||||
|
||||
static void ipcp_init(struct ppp_context *ctx)
|
||||
{
|
||||
NET_DBG("proto %s (0x%04x) fsm %p", ppp_proto2str(PPP_IPCP), PPP_IPCP,
|
||||
&ctx->ipcp.fsm);
|
||||
|
||||
memset(&ctx->ipcp.fsm, 0, sizeof(ctx->ipcp.fsm));
|
||||
|
||||
ppp_fsm_init(&ctx->ipcp.fsm, PPP_IPCP);
|
||||
|
||||
ppp_fsm_name_set(&ctx->ipcp.fsm, ppp_proto2str(PPP_IPCP));
|
||||
|
||||
ctx->ipcp.fsm.cb.up = ipcp_up;
|
||||
ctx->ipcp.fsm.cb.down = ipcp_down;
|
||||
ctx->ipcp.fsm.cb.finished = ipcp_finished;
|
||||
ctx->ipcp.fsm.cb.proto_reject = ipcp_proto_reject;
|
||||
ctx->ipcp.fsm.cb.config_info_add = ipcp_config_info_add;
|
||||
ctx->ipcp.fsm.cb.config_info_req = ipcp_config_info_req;
|
||||
ctx->ipcp.fsm.cb.config_info_rej = ipcp_config_info_rej;
|
||||
}
|
||||
|
||||
PPP_PROTOCOL_REGISTER(IPCP, PPP_IPCP,
|
||||
ipcp_init, ipcp_handle,
|
||||
ipcp_lower_up, ipcp_lower_down,
|
||||
ipcp_open, ipcp_close);
|
312
subsys/net/l2/ppp/lcp.c
Normal file
312
subsys/net/l2/ppp/lcp.c
Normal file
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_l2.h>
|
||||
#include <net/net_if.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <net/net_mgmt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_stats.h"
|
||||
#include "ppp_internal.h"
|
||||
|
||||
static enum net_verdict lcp_handle_ext(struct ppp_fsm *fsm,
|
||||
enum ppp_packet_type code, u8_t id,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
enum net_verdict verdict = NET_DROP;
|
||||
|
||||
switch (code) {
|
||||
case PPP_PROTOCOL_REJ:
|
||||
NET_DBG("PPP Protocol-Rej");
|
||||
return ppp_fsm_recv_protocol_rej(fsm, id, pkt);
|
||||
|
||||
case PPP_ECHO_REQ:
|
||||
NET_DBG("PPP Echo-Req");
|
||||
return ppp_fsm_recv_echo_req(fsm, id, pkt);
|
||||
|
||||
case PPP_ECHO_REPLY:
|
||||
NET_DBG("PPP Echo-Reply");
|
||||
return ppp_fsm_recv_echo_reply(fsm, id, pkt);
|
||||
|
||||
case PPP_DISCARD_REQ:
|
||||
NET_DBG("PPP Discard-Req");
|
||||
return ppp_fsm_recv_discard_req(fsm, id, pkt);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return verdict;
|
||||
}
|
||||
|
||||
static enum net_verdict lcp_handle(struct ppp_context *ctx,
|
||||
struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
return ppp_fsm_input(&ctx->lcp.fsm, PPP_LCP, pkt);
|
||||
}
|
||||
|
||||
static bool append_to_buf(struct net_buf *buf, u8_t *data, u8_t data_len)
|
||||
{
|
||||
if (data_len > net_buf_tailroom(buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* FIXME: use net_pkt api so that we can handle a case where data
|
||||
* might split to two net_buf's
|
||||
*/
|
||||
net_buf_add_mem(buf, data, data_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int lcp_config_info_req(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length,
|
||||
struct net_buf **buf)
|
||||
{
|
||||
struct ppp_option_pkt options[MAX_LCP_OPTIONS];
|
||||
struct ppp_option_pkt nack_options[MAX_LCP_OPTIONS];
|
||||
struct net_buf *nack = NULL;
|
||||
enum ppp_packet_type code;
|
||||
enum net_verdict verdict;
|
||||
int i, nack_idx = 0;
|
||||
int count_rej = 0, count_nack = 0;
|
||||
|
||||
memset(options, 0, sizeof(options));
|
||||
memset(nack_options, 0, sizeof(nack_options));
|
||||
|
||||
verdict = ppp_parse_options(fsm, pkt, length, options,
|
||||
ARRAY_SIZE(options));
|
||||
if (verdict != NET_OK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(options); i++) {
|
||||
if (options[i].type.lcp != LCP_OPTION_RESERVED) {
|
||||
NET_DBG("[%s/%p] %s option %s (%d) len %d",
|
||||
fsm->name, fsm, "Check",
|
||||
ppp_option2str(PPP_LCP, options[i].type.lcp),
|
||||
options[i].type.lcp, options[i].len);
|
||||
}
|
||||
|
||||
switch (options[i].type.lcp) {
|
||||
case LCP_OPTION_RESERVED:
|
||||
continue;
|
||||
|
||||
case LCP_OPTION_MRU:
|
||||
break;
|
||||
|
||||
/* TODO: Check from ctx->lcp.my_options what options to accept
|
||||
*/
|
||||
case LCP_OPTION_ASYNC_CTRL_CHAR_MAP:
|
||||
count_nack++;
|
||||
goto ignore_option;
|
||||
|
||||
case LCP_OPTION_AUTH_PROTO:
|
||||
count_nack++;
|
||||
goto ignore_option;
|
||||
|
||||
case LCP_OPTION_QUALITY_PROTO:
|
||||
count_rej++;
|
||||
goto ignore_option;
|
||||
|
||||
case LCP_OPTION_MAGIC_NUMBER:
|
||||
count_nack++;
|
||||
goto ignore_option;
|
||||
|
||||
case LCP_OPTION_PROTO_COMPRESS:
|
||||
count_rej++;
|
||||
goto ignore_option;
|
||||
|
||||
case LCP_OPTION_ADDR_CTRL_COMPRESS:
|
||||
count_rej++;
|
||||
goto ignore_option;
|
||||
|
||||
default:
|
||||
ignore_option:
|
||||
nack_options[nack_idx].type.lcp = options[i].type.lcp;
|
||||
nack_options[nack_idx].len = options[i].len;
|
||||
|
||||
if (options[i].len > 2) {
|
||||
memcpy(&nack_options[nack_idx].value,
|
||||
&options[i].value,
|
||||
sizeof(nack_options[nack_idx].value));
|
||||
}
|
||||
|
||||
nack_idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nack_idx > 0) {
|
||||
struct net_buf *nack_buf;
|
||||
|
||||
if (count_rej > 0) {
|
||||
code = PPP_CONFIGURE_REJ;
|
||||
} else {
|
||||
code = PPP_CONFIGURE_NACK;
|
||||
}
|
||||
|
||||
/* Create net_buf containing options that are not accepted */
|
||||
for (i = 0; i < MIN(nack_idx, ARRAY_SIZE(nack_options)); i++) {
|
||||
bool added;
|
||||
|
||||
nack_buf = ppp_get_net_buf(nack, nack_options[i].len);
|
||||
if (!nack_buf) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
if (!nack) {
|
||||
nack = nack_buf;
|
||||
}
|
||||
|
||||
added = append_to_buf(nack_buf,
|
||||
&nack_options[i].type.lcp, 1);
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
added = append_to_buf(nack_buf, &nack_options[i].len,
|
||||
1);
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
|
||||
/* If there is some data, copy it to result buf */
|
||||
if (nack_options[i].value.pos) {
|
||||
added = append_to_buf(nack_buf,
|
||||
nack_options[i].value.pos,
|
||||
nack_options[i].len - 1 - 1);
|
||||
if (!added) {
|
||||
goto out_of_mem;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
out_of_mem:
|
||||
if (nack) {
|
||||
net_buf_unref(nack);
|
||||
} else {
|
||||
if (nack_buf) {
|
||||
net_buf_unref(nack_buf);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
code = PPP_CONFIGURE_ACK;
|
||||
}
|
||||
|
||||
if (nack) {
|
||||
*buf = nack;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static void lcp_lower_down(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_fsm_lower_down(&ctx->lcp.fsm);
|
||||
}
|
||||
|
||||
static void lcp_lower_up(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_fsm_lower_up(&ctx->lcp.fsm);
|
||||
}
|
||||
|
||||
static void lcp_open(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_fsm_open(&ctx->lcp.fsm);
|
||||
}
|
||||
|
||||
static void lcp_close(struct ppp_context *ctx, const u8_t *reason)
|
||||
{
|
||||
if (ctx->phase != PPP_DEAD) {
|
||||
ppp_change_phase(ctx, PPP_TERMINATE);
|
||||
}
|
||||
|
||||
ppp_change_state(&ctx->lcp.fsm, PPP_STOPPED);
|
||||
|
||||
ppp_fsm_close(&ctx->lcp.fsm, reason);
|
||||
}
|
||||
|
||||
static void lcp_down(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
lcp.fsm);
|
||||
|
||||
ppp_link_down(ctx);
|
||||
|
||||
ppp_change_phase(ctx, PPP_ESTABLISH);
|
||||
}
|
||||
|
||||
static void lcp_up(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
lcp.fsm);
|
||||
|
||||
/* TODO: Set MRU/MTU of the network interface here */
|
||||
|
||||
ppp_link_established(ctx, fsm);
|
||||
}
|
||||
|
||||
static void lcp_starting(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
lcp.fsm);
|
||||
|
||||
ppp_link_needed(ctx);
|
||||
}
|
||||
|
||||
static void lcp_finished(struct ppp_fsm *fsm)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
|
||||
lcp.fsm);
|
||||
|
||||
ppp_link_terminated(ctx);
|
||||
}
|
||||
|
||||
static void lcp_init(struct ppp_context *ctx)
|
||||
{
|
||||
NET_DBG("proto %s (0x%04x) fsm %p", ppp_proto2str(PPP_LCP), PPP_LCP,
|
||||
&ctx->lcp.fsm);
|
||||
|
||||
memset(&ctx->lcp.fsm, 0, sizeof(ctx->lcp.fsm));
|
||||
|
||||
ppp_fsm_init(&ctx->lcp.fsm, PPP_LCP);
|
||||
|
||||
ppp_fsm_name_set(&ctx->lcp.fsm, ppp_proto2str(PPP_LCP));
|
||||
|
||||
ctx->lcp.fsm.cb.up = lcp_up;
|
||||
ctx->lcp.fsm.cb.down = lcp_down;
|
||||
ctx->lcp.fsm.cb.starting = lcp_starting;
|
||||
ctx->lcp.fsm.cb.finished = lcp_finished;
|
||||
ctx->lcp.fsm.cb.proto_extension = lcp_handle_ext;
|
||||
ctx->lcp.fsm.cb.config_info_req = lcp_config_info_req;
|
||||
|
||||
ctx->lcp.my_options.negotiate_proto_compression = false;
|
||||
ctx->lcp.my_options.negotiate_addr_compression = false;
|
||||
ctx->lcp.my_options.negotiate_async_map = false;
|
||||
ctx->lcp.my_options.negotiate_magic = false;
|
||||
ctx->lcp.my_options.negotiate_mru =
|
||||
IS_ENABLED(CONFIG_NET_L2_PPP_OPTION_MRU_NEG) ? true : false;
|
||||
}
|
||||
|
||||
PPP_PROTOCOL_REGISTER(LCP, PPP_LCP,
|
||||
lcp_init, lcp_handle,
|
||||
lcp_lower_up, lcp_lower_down,
|
||||
lcp_open, lcp_close);
|
124
subsys/net/l2/ppp/link.c
Normal file
124
subsys/net/l2/ppp/link.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_internal.h"
|
||||
|
||||
static void lcp_up(struct ppp_context *ctx)
|
||||
{
|
||||
struct ppp_protocol_handler *proto;
|
||||
|
||||
for (proto = __net_ppp_proto_start;
|
||||
proto != __net_ppp_proto_end;
|
||||
proto++) {
|
||||
if (proto->protocol == PPP_LCP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (proto->lower_up) {
|
||||
proto->lower_up(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_network(struct ppp_context *ctx)
|
||||
{
|
||||
const struct ppp_protocol_handler *proto;
|
||||
|
||||
ppp_change_phase(ctx, PPP_NETWORK);
|
||||
|
||||
for (proto = __net_ppp_proto_start;
|
||||
proto != __net_ppp_proto_end;
|
||||
proto++) {
|
||||
if (proto->protocol == PPP_CCP || proto->protocol == PPP_ECP) {
|
||||
if (proto->open) {
|
||||
proto->open(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the other network protocols if encryption is not needed for
|
||||
* them.
|
||||
*/
|
||||
/* TODO possible encryption stuff here*/
|
||||
|
||||
for (proto = __net_ppp_proto_start;
|
||||
proto != __net_ppp_proto_end;
|
||||
proto++) {
|
||||
if (proto->protocol == PPP_CCP || proto->protocol == PPP_ECP ||
|
||||
proto->protocol >= 0xC000) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (proto->open) {
|
||||
ctx->network_protos_open++;
|
||||
proto->open(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->network_protos_open == 0) {
|
||||
proto = ppp_lcp_get();
|
||||
if (proto) {
|
||||
proto->close(ctx, "No network protocols open");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppp_link_established(struct ppp_context *ctx, struct ppp_fsm *fsm)
|
||||
{
|
||||
NET_DBG("[%p] Link established", ctx);
|
||||
|
||||
ppp_change_phase(ctx, PPP_ESTABLISH);
|
||||
|
||||
ppp_change_phase(ctx, PPP_AUTH);
|
||||
|
||||
/* If no authentication is need, then we are done */
|
||||
/* TODO: check here if auth is needed */
|
||||
|
||||
do_network(ctx);
|
||||
|
||||
lcp_up(ctx);
|
||||
}
|
||||
|
||||
void ppp_link_terminated(struct ppp_context *ctx)
|
||||
{
|
||||
if (ctx->phase == PPP_DEAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: cleanup things etc here if needed */
|
||||
|
||||
ppp_change_phase(ctx, PPP_DEAD);
|
||||
|
||||
NET_DBG("[%p] Link terminated", ctx);
|
||||
}
|
||||
|
||||
void ppp_link_down(struct ppp_context *ctx)
|
||||
{
|
||||
if (ctx->phase == PPP_DEAD) {
|
||||
return;
|
||||
}
|
||||
|
||||
ppp_change_phase(ctx, PPP_NETWORK);
|
||||
|
||||
ppp_network_all_down(ctx);
|
||||
|
||||
ppp_change_phase(ctx, PPP_DEAD);
|
||||
}
|
||||
|
||||
void ppp_link_needed(struct ppp_context *ctx)
|
||||
{
|
||||
/* TODO: Try to create link if needed. */
|
||||
}
|
341
subsys/net/l2/ppp/misc.c
Normal file
341
subsys/net/l2/ppp/misc.c
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_internal.h"
|
||||
|
||||
const char *ppp_phase_str(enum ppp_phase phase)
|
||||
{
|
||||
#if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) || defined(CONFIG_NET_SHELL)
|
||||
switch (phase) {
|
||||
case PPP_DEAD:
|
||||
return "DEAD";
|
||||
case PPP_ESTABLISH:
|
||||
return "ESTABLISH";
|
||||
case PPP_AUTH:
|
||||
return "AUTH";
|
||||
case PPP_NETWORK:
|
||||
return "NETWORK";
|
||||
case PPP_RUNNING:
|
||||
return "RUNNING";
|
||||
case PPP_TERMINATE:
|
||||
return "TERMINATE";
|
||||
}
|
||||
#else
|
||||
ARG_UNUSED(phase);
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
static void validate_phase_transition(enum ppp_phase current,
|
||||
enum ppp_phase new)
|
||||
{
|
||||
static const u8_t valid_transitions[] = {
|
||||
[PPP_DEAD] = 1 << PPP_ESTABLISH,
|
||||
[PPP_ESTABLISH] = 1 << PPP_DEAD |
|
||||
1 << PPP_AUTH |
|
||||
1 << PPP_TERMINATE,
|
||||
[PPP_AUTH] = 1 << PPP_TERMINATE |
|
||||
1 << PPP_NETWORK,
|
||||
[PPP_NETWORK] = 1 << PPP_TERMINATE |
|
||||
1 << PPP_RUNNING,
|
||||
[PPP_RUNNING] = 1 << PPP_TERMINATE |
|
||||
1 << PPP_NETWORK,
|
||||
[PPP_TERMINATE] = 1 << PPP_DEAD,
|
||||
};
|
||||
|
||||
if (!(valid_transitions[current] & 1 << new)) {
|
||||
NET_DBG("Invalid phase transition: %s (%d) => %s (%d)",
|
||||
ppp_phase_str(current), current,
|
||||
ppp_phase_str(new), new);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void validate_phase_transition(enum ppp_phase current,
|
||||
enum ppp_phase new)
|
||||
{
|
||||
ARG_UNUSED(current);
|
||||
ARG_UNUSED(new);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
void ppp_change_phase_debug(struct ppp_context *ctx, enum ppp_phase new_phase,
|
||||
const char *caller, int line)
|
||||
#else
|
||||
void ppp_change_phase(struct ppp_context *ctx, enum ppp_phase new_phase)
|
||||
#endif
|
||||
{
|
||||
NET_ASSERT(ctx);
|
||||
|
||||
if (ctx->phase == new_phase) {
|
||||
return;
|
||||
}
|
||||
|
||||
NET_ASSERT(new_phase >= PPP_DEAD &&
|
||||
new_phase <= PPP_TERMINATE);
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
NET_DBG("[%p] phase %s (%d) => %s (%d) (%s():%d)",
|
||||
ctx, ppp_phase_str(ctx->phase), ctx->phase,
|
||||
ppp_phase_str(new_phase), new_phase, caller, line);
|
||||
#endif
|
||||
|
||||
validate_phase_transition(ctx->phase, new_phase);
|
||||
|
||||
ctx->phase = new_phase;
|
||||
}
|
||||
|
||||
const char *ppp_state_str(enum ppp_state state)
|
||||
{
|
||||
#if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) || defined(CONFIG_NET_SHELL)
|
||||
switch (state) {
|
||||
case PPP_INITIAL:
|
||||
return "INITIAL";
|
||||
case PPP_STARTING:
|
||||
return "STARTING";
|
||||
case PPP_CLOSED:
|
||||
return "CLOSED";
|
||||
case PPP_STOPPED:
|
||||
return "STOPPED";
|
||||
case PPP_CLOSING:
|
||||
return "CLOSING";
|
||||
case PPP_STOPPING:
|
||||
return "STOPPING";
|
||||
case PPP_REQUEST_SENT:
|
||||
return "REQUEST_SENT";
|
||||
case PPP_ACK_RECEIVED:
|
||||
return "ACK_RECEIVED";
|
||||
case PPP_ACK_SENT:
|
||||
return "ACK_SENT";
|
||||
case PPP_OPENED:
|
||||
return "OPENED";
|
||||
}
|
||||
#else
|
||||
ARG_UNUSED(state);
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *ppp_pkt_type2str(enum ppp_packet_type type)
|
||||
{
|
||||
#if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) || defined(CONFIG_NET_SHELL)
|
||||
switch (type) {
|
||||
case PPP_CONFIGURE_REQ:
|
||||
return "Configure-Req";
|
||||
case PPP_CONFIGURE_ACK:
|
||||
return "Configure-Ack";
|
||||
case PPP_CONFIGURE_NACK:
|
||||
return "Configure-Nack";
|
||||
case PPP_CONFIGURE_REJ:
|
||||
return "Configure-Rej";
|
||||
case PPP_TERMINATE_REQ:
|
||||
return "Terminate-Req";
|
||||
case PPP_TERMINATE_ACK:
|
||||
return "Terminate-Ack";
|
||||
case PPP_CODE_REJ:
|
||||
return "Code-Rej";
|
||||
case PPP_PROTOCOL_REJ:
|
||||
return "Protocol-Rej";
|
||||
case PPP_ECHO_REQ:
|
||||
return "Echo-Req";
|
||||
case PPP_ECHO_REPLY:
|
||||
return "Echo-Reply";
|
||||
case PPP_DISCARD_REQ:
|
||||
return "Discard-Req";
|
||||
}
|
||||
#else
|
||||
ARG_UNUSED(type);
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *ppp_proto2str(u16_t proto)
|
||||
{
|
||||
#if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG)
|
||||
switch (proto) {
|
||||
case PPP_IP:
|
||||
return "IPv4";
|
||||
case PPP_IPV6:
|
||||
return "IPv6";
|
||||
case PPP_ECP:
|
||||
return "ECP";
|
||||
case PPP_CCP:
|
||||
return "CCP";
|
||||
case PPP_LCP:
|
||||
return "LCP";
|
||||
case PPP_IPCP:
|
||||
return "IPCP";
|
||||
}
|
||||
#else
|
||||
ARG_UNUSED(proto);
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
static void validate_state_transition(enum ppp_state current,
|
||||
enum ppp_state new)
|
||||
{
|
||||
/* See RFC 1661 ch. 4.1 */
|
||||
static const u16_t valid_transitions[] = {
|
||||
[PPP_INITIAL] = 1 << PPP_CLOSED |
|
||||
1 << PPP_STARTING,
|
||||
[PPP_STARTING] = 1 << PPP_INITIAL |
|
||||
1 << PPP_REQUEST_SENT,
|
||||
[PPP_CLOSED] = 1 << PPP_INITIAL |
|
||||
1 << PPP_REQUEST_SENT,
|
||||
[PPP_STOPPED] = 1 << PPP_STARTING |
|
||||
1 << PPP_CLOSED |
|
||||
1 << PPP_ACK_RECEIVED |
|
||||
1 << PPP_REQUEST_SENT,
|
||||
[PPP_CLOSING] = 1 << PPP_INITIAL |
|
||||
1 << PPP_STOPPING |
|
||||
1 << PPP_CLOSED,
|
||||
[PPP_STOPPING] = 1 << PPP_STARTING |
|
||||
1 << PPP_CLOSING |
|
||||
1 << PPP_STOPPED,
|
||||
[PPP_REQUEST_SENT] = 1 << PPP_STARTING |
|
||||
1 << PPP_CLOSING |
|
||||
1 << PPP_STOPPED |
|
||||
1 << PPP_ACK_SENT |
|
||||
1 << PPP_ACK_RECEIVED,
|
||||
[PPP_ACK_RECEIVED] = 1 << PPP_STARTING |
|
||||
1 << PPP_CLOSING |
|
||||
1 << PPP_OPENED |
|
||||
1 << PPP_REQUEST_SENT |
|
||||
1 << PPP_STOPPED,
|
||||
[PPP_ACK_SENT] = 1 << PPP_STARTING |
|
||||
1 << PPP_CLOSING |
|
||||
1 << PPP_STOPPED |
|
||||
1 << PPP_REQUEST_SENT |
|
||||
1 << PPP_OPENED,
|
||||
[PPP_OPENED] = 1 << PPP_STARTING |
|
||||
1 << PPP_CLOSING |
|
||||
1 << PPP_ACK_SENT |
|
||||
1 << PPP_REQUEST_SENT |
|
||||
1 << PPP_CLOSING |
|
||||
1 << PPP_STOPPING,
|
||||
};
|
||||
|
||||
if (!(valid_transitions[current] & 1 << new)) {
|
||||
NET_DBG("Invalid state transition: %s (%d) => %s (%d)",
|
||||
ppp_state_str(current), current,
|
||||
ppp_state_str(new), new);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline void validate_state_transition(enum ppp_state current,
|
||||
enum ppp_state new)
|
||||
{
|
||||
ARG_UNUSED(current);
|
||||
ARG_UNUSED(new);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
void ppp_change_state_debug(struct ppp_fsm *fsm, enum ppp_state new_state,
|
||||
const char *caller, int line)
|
||||
#else
|
||||
void ppp_change_state(struct ppp_fsm *fsm, enum ppp_state new_state)
|
||||
#endif
|
||||
{
|
||||
NET_ASSERT(fsm);
|
||||
|
||||
if (fsm->state == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
NET_ASSERT(new_state >= PPP_INITIAL &&
|
||||
new_state <= PPP_OPENED);
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
NET_DBG("[%s/%p] state %s (%d) => %s (%d) (%s():%d)",
|
||||
fsm->name, fsm, ppp_state_str(fsm->state), fsm->state,
|
||||
ppp_state_str(new_state), new_state, caller, line);
|
||||
#endif
|
||||
|
||||
validate_state_transition(fsm->state, new_state);
|
||||
|
||||
fsm->state = new_state;
|
||||
}
|
||||
|
||||
const char *ppp_option2str(enum ppp_protocol_type protocol,
|
||||
int type)
|
||||
{
|
||||
#if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) || defined(CONFIG_NET_SHELL)
|
||||
switch (protocol) {
|
||||
case PPP_LCP:
|
||||
switch (type) {
|
||||
case LCP_OPTION_RESERVED:
|
||||
return "RESERVED";
|
||||
case LCP_OPTION_MRU:
|
||||
return "MRU";
|
||||
case LCP_OPTION_ASYNC_CTRL_CHAR_MAP:
|
||||
return "ASYNC_CTRL_CHAR_MAP";
|
||||
case LCP_OPTION_AUTH_PROTO:
|
||||
return "AUTH_PROTO";
|
||||
case LCP_OPTION_QUALITY_PROTO:
|
||||
return "QUALITY_PROTO";
|
||||
case LCP_OPTION_MAGIC_NUMBER:
|
||||
return "MAGIC_NUMBER";
|
||||
case LCP_OPTION_PROTO_COMPRESS:
|
||||
return "PROTO_COMPRESS";
|
||||
case LCP_OPTION_ADDR_CTRL_COMPRESS:
|
||||
return "ADDR_CTRL_COMPRESS";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
case PPP_IPCP:
|
||||
switch (type) {
|
||||
case IPCP_OPTION_RESERVED:
|
||||
return "RESERVED";
|
||||
case IPCP_OPTION_IP_ADDRESSES:
|
||||
return "IP_ADDRESSES";
|
||||
case IPCP_OPTION_IP_COMP_PROTO:
|
||||
return "IP_COMPRESSION_PROTOCOL";
|
||||
case IPCP_OPTION_IP_ADDRESS:
|
||||
return "IP_ADDRESS";
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
ARG_UNUSED(type);
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void ppp_fsm_name_set(struct ppp_fsm *fsm, const char *name)
|
||||
{
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG
|
||||
fsm->name = name;
|
||||
#else
|
||||
ARG_UNUSED(fsm);
|
||||
ARG_UNUSED(name);
|
||||
#endif
|
||||
}
|
79
subsys/net/l2/ppp/network.c
Normal file
79
subsys/net/l2/ppp/network.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_internal.h"
|
||||
|
||||
void ppp_network_up(struct ppp_context *ctx, int proto)
|
||||
{
|
||||
if (ctx->network_protos_up == 0) {
|
||||
ppp_change_phase(ctx, PPP_RUNNING);
|
||||
}
|
||||
|
||||
ctx->network_protos_up++;
|
||||
|
||||
NET_DBG("[%p] Proto %s (0x%04x) %s (%d)", ctx, ppp_proto2str(proto),
|
||||
proto, "up", ctx->network_protos_up);
|
||||
}
|
||||
|
||||
void ppp_network_down(struct ppp_context *ctx, int proto)
|
||||
{
|
||||
ctx->network_protos_up--;
|
||||
|
||||
if (ctx->network_protos_up <= 0) {
|
||||
ctx->network_protos_up = 0;
|
||||
ppp_change_phase(ctx, PPP_TERMINATE);
|
||||
}
|
||||
|
||||
NET_DBG("[%p] Proto %s (0x%04x) %s (%d)", ctx, ppp_proto2str(proto),
|
||||
proto, "down", ctx->network_protos_up);
|
||||
}
|
||||
|
||||
void ppp_network_done(struct ppp_context *ctx, int proto)
|
||||
{
|
||||
ctx->network_protos_up--;
|
||||
if (ctx->network_protos_up <= 0) {
|
||||
const struct ppp_protocol_handler *proto = ppp_lcp_get();
|
||||
|
||||
if (proto) {
|
||||
proto->close(ctx, "All networks down");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ppp_network_all_down(struct ppp_context *ctx)
|
||||
{
|
||||
struct ppp_protocol_handler *proto;
|
||||
|
||||
for (proto = __net_ppp_proto_start;
|
||||
proto != __net_ppp_proto_end;
|
||||
proto++) {
|
||||
if (proto->protocol != PPP_LCP && proto->lower_down) {
|
||||
proto->lower_down(ctx);
|
||||
}
|
||||
|
||||
if (proto->protocol < 0xC000 && proto->close) {
|
||||
ctx->network_protos_open--;
|
||||
proto->close(ctx, "LCP down");
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->network_protos_open > 0) {
|
||||
NET_WARN("Not all network protocols were closed (%d)",
|
||||
ctx->network_protos_open);
|
||||
}
|
||||
|
||||
ctx->network_protos_open = 0;
|
||||
}
|
117
subsys/net/l2/ppp/options.c
Normal file
117
subsys/net/l2/ppp/options.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_pkt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_internal.h"
|
||||
|
||||
#define ALLOC_TIMEOUT K_MSEC(100)
|
||||
|
||||
enum net_verdict ppp_parse_options(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length,
|
||||
struct ppp_option_pkt options[],
|
||||
int options_len)
|
||||
{
|
||||
int remaining = length, pkt_remaining;
|
||||
enum net_verdict verdict;
|
||||
u8_t opt_type, opt_len;
|
||||
int ret, idx = 0;
|
||||
|
||||
pkt_remaining = net_pkt_remaining_data(pkt);
|
||||
if (remaining != pkt_remaining) {
|
||||
NET_DBG("Expecting %d but pkt data length is %d bytes",
|
||||
remaining, pkt_remaining);
|
||||
verdict = NET_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (remaining > 0) {
|
||||
ret = net_pkt_read_u8(pkt, &opt_type);
|
||||
if (ret < 0) {
|
||||
NET_DBG("Cannot read %s (%d) (remaining len %d)",
|
||||
"opt_type", ret, pkt_remaining);
|
||||
verdict = NET_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = net_pkt_read_u8(pkt, &opt_len);
|
||||
if (ret < 0) {
|
||||
NET_DBG("Cannot read %s (%d) (remaining len %d)",
|
||||
"opt_len", ret, remaining);
|
||||
verdict = NET_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (idx >= options_len) {
|
||||
NET_DBG("Cannot insert options (max %d)", options_len);
|
||||
verdict = NET_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
options[idx].type.lcp = opt_type;
|
||||
options[idx].len = opt_len;
|
||||
|
||||
NET_DBG("[%s/%p] %s option %s (%d) len %d", fsm->name, fsm,
|
||||
"Recv", ppp_option2str(fsm->protocol, opt_type),
|
||||
opt_type, opt_len);
|
||||
|
||||
if (opt_len > 2) {
|
||||
/* There is an option value here */
|
||||
net_pkt_cursor_backup(pkt, &options[idx].value);
|
||||
}
|
||||
|
||||
net_pkt_skip(pkt,
|
||||
opt_len - sizeof(opt_type) - sizeof(opt_len));
|
||||
remaining -= opt_len;
|
||||
|
||||
idx++;
|
||||
};
|
||||
|
||||
if (remaining < 0) {
|
||||
verdict = NET_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
verdict = NET_OK;
|
||||
|
||||
out:
|
||||
return verdict;
|
||||
}
|
||||
|
||||
struct net_buf *ppp_get_net_buf(struct net_buf *root_buf, u8_t len)
|
||||
{
|
||||
struct net_buf *tmp;
|
||||
|
||||
if (root_buf) {
|
||||
tmp = net_buf_frag_last(root_buf);
|
||||
|
||||
if (len > net_buf_tailroom(tmp)) {
|
||||
tmp = net_pkt_get_reserve_tx_data(ALLOC_TIMEOUT);
|
||||
if (tmp) {
|
||||
net_buf_frag_add(root_buf, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
tmp = net_pkt_get_reserve_tx_data(ALLOC_TIMEOUT);
|
||||
if (tmp) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
163
subsys/net/l2/ppp/ppp_internal.h
Normal file
163
subsys/net/l2/ppp/ppp_internal.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
/** @file
|
||||
@brief PPP private header
|
||||
|
||||
This is not to be included by the application.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
/**
|
||||
* FSM flags that control how it operates.
|
||||
*/
|
||||
#define FSM_RESTART BIT(0) /**< Treat 2nd OPEN as DOWN followed by UP */
|
||||
|
||||
/**
|
||||
* PPP packet format.
|
||||
*/
|
||||
struct ppp_packet {
|
||||
u8_t code;
|
||||
u8_t id;
|
||||
u16_t length;
|
||||
} __packed;
|
||||
|
||||
/** Timeout in milliseconds */
|
||||
#define PPP_TIMEOUT K_SECONDS(3)
|
||||
|
||||
/** Max Terminate-Request transmissions */
|
||||
#define MAX_TERMINATE_REQ CONFIG_NET_L2_PPP_MAX_TERMINATE_REQ_RETRANSMITS
|
||||
|
||||
/** Max Configure-Request transmissions */
|
||||
#define MAX_CONFIGURE_REQ CONFIG_NET_L2_PPP_MAX_CONFIGURE_REQ_RETRANSMITS
|
||||
|
||||
/** Max number of LCP options */
|
||||
#define MAX_LCP_OPTIONS CONFIG_NET_L2_PPP_MAX_OPTIONS
|
||||
|
||||
/** Max number of IPCP options */
|
||||
#define MAX_IPCP_OPTIONS 3
|
||||
|
||||
/*
|
||||
* Special alignment is needed for ppp_protocol_handler. This is the
|
||||
* same issue as in net_if. See net_if.h __net_if_align for explanation.
|
||||
*/
|
||||
#define __ppp_proto_align __aligned(32)
|
||||
|
||||
/** Protocol handler information. */
|
||||
struct ppp_protocol_handler {
|
||||
/** Protocol init function */
|
||||
void (*init)(struct ppp_context *ctx);
|
||||
|
||||
/** Process a received packet */
|
||||
enum net_verdict (*handler)(struct ppp_context *ctx,
|
||||
struct net_if *iface,
|
||||
struct net_pkt *pkt);
|
||||
|
||||
/** Lower layer up */
|
||||
void (*lower_up)(struct ppp_context *ctx);
|
||||
|
||||
/** Lower layer down */
|
||||
void (*lower_down)(struct ppp_context *ctx);
|
||||
|
||||
/** Enable this protocol */
|
||||
void (*open)(struct ppp_context *ctx);
|
||||
|
||||
/** Disable this protocol */
|
||||
void (*close)(struct ppp_context *ctx, const u8_t *reason);
|
||||
|
||||
/** PPP protocol number */
|
||||
u16_t protocol;
|
||||
} __ppp_proto_align;
|
||||
|
||||
#define PPP_PROTO_GET_NAME(proto_name) \
|
||||
(ppp_protocol_handler_##proto_name)
|
||||
|
||||
#define PPP_PROTOCOL_REGISTER(name, proto, init_func, proto_handler, \
|
||||
proto_lower_up, proto_lower_down, \
|
||||
proto_open, proto_close) \
|
||||
static const struct ppp_protocol_handler \
|
||||
(PPP_PROTO_GET_NAME(name)) __used \
|
||||
__attribute__((__section__(".net_ppp_proto.data"))) = { \
|
||||
.protocol = proto, \
|
||||
.init = init_func, \
|
||||
.handler = proto_handler, \
|
||||
.lower_up = proto_lower_up, \
|
||||
.lower_down = proto_lower_down, \
|
||||
.open = proto_open, \
|
||||
.close = proto_close, \
|
||||
}
|
||||
|
||||
extern struct ppp_protocol_handler __net_ppp_proto_start[];
|
||||
extern struct ppp_protocol_handler __net_ppp_proto_end[];
|
||||
|
||||
const char *ppp_phase_str(enum ppp_phase phase);
|
||||
const char *ppp_state_str(enum ppp_state state);
|
||||
const char *ppp_proto2str(u16_t proto);
|
||||
const char *ppp_pkt_type2str(enum ppp_packet_type type);
|
||||
const char *ppp_option2str(enum ppp_protocol_type protocol, int type);
|
||||
void ppp_fsm_name_set(struct ppp_fsm *fsm, const char *name);
|
||||
|
||||
#if CONFIG_NET_L2_PPP_LOG_LEVEL < LOG_LEVEL_DBG
|
||||
void ppp_change_phase(struct ppp_context *ctx, enum ppp_phase new_phase);
|
||||
void ppp_change_state(struct ppp_fsm *fsm, enum ppp_state new_state);
|
||||
#else
|
||||
void ppp_change_phase_debug(struct ppp_context *ctx,
|
||||
enum ppp_phase new_phase,
|
||||
const char *caller, int line);
|
||||
|
||||
#define ppp_change_phase(ctx, state) \
|
||||
ppp_change_phase_debug(ctx, state, __func__, __LINE__)
|
||||
|
||||
#define ppp_change_state(fsm, state) \
|
||||
ppp_change_state_debug(fsm, state, __func__, __LINE__)
|
||||
|
||||
void ppp_change_state_debug(struct ppp_fsm *fsm, enum ppp_state new_state,
|
||||
const char *caller, int line);
|
||||
#endif
|
||||
|
||||
struct net_buf *ppp_get_net_buf(struct net_buf *root_buf, u8_t len);
|
||||
int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
|
||||
enum ppp_packet_type type, u8_t id,
|
||||
void *data, u32_t data_len);
|
||||
|
||||
void ppp_fsm_init(struct ppp_fsm *fsm, u16_t protocol);
|
||||
void ppp_fsm_lower_up(struct ppp_fsm *fsm);
|
||||
void ppp_fsm_lower_down(struct ppp_fsm *fsm);
|
||||
void ppp_fsm_open(struct ppp_fsm *fsm);
|
||||
void ppp_fsm_close(struct ppp_fsm *fsm, const u8_t *reason);
|
||||
void ppp_fsm_proto_reject(struct ppp_fsm *fsm);
|
||||
enum net_verdict ppp_fsm_input(struct ppp_fsm *fsm, u16_t proto,
|
||||
struct net_pkt *pkt);
|
||||
enum net_verdict ppp_fsm_recv_protocol_rej(struct ppp_fsm *fsm,
|
||||
u8_t id,
|
||||
struct net_pkt *pkt);
|
||||
enum net_verdict ppp_fsm_recv_echo_req(struct ppp_fsm *fsm,
|
||||
u8_t id,
|
||||
struct net_pkt *pkt);
|
||||
enum net_verdict ppp_fsm_recv_echo_reply(struct ppp_fsm *fsm,
|
||||
u8_t id,
|
||||
struct net_pkt *pkt);
|
||||
enum net_verdict ppp_fsm_recv_discard_req(struct ppp_fsm *fsm,
|
||||
u8_t id,
|
||||
struct net_pkt *pkt);
|
||||
|
||||
const struct ppp_protocol_handler *ppp_lcp_get(void);
|
||||
enum net_verdict ppp_parse_options(struct ppp_fsm *fsm,
|
||||
struct net_pkt *pkt,
|
||||
u16_t length,
|
||||
struct ppp_option_pkt options[],
|
||||
int options_len);
|
||||
|
||||
void ppp_link_established(struct ppp_context *ctx, struct ppp_fsm *fsm);
|
||||
void ppp_link_terminated(struct ppp_context *ctx);
|
||||
void ppp_link_down(struct ppp_context *ctx);
|
||||
void ppp_link_needed(struct ppp_context *ctx);
|
||||
|
||||
void ppp_network_up(struct ppp_context *ctx, int proto);
|
||||
void ppp_network_down(struct ppp_context *ctx, int proto);
|
||||
void ppp_network_done(struct ppp_context *ctx, int proto);
|
||||
void ppp_network_all_down(struct ppp_context *ctx);
|
381
subsys/net/l2/ppp/ppp_l2.c
Normal file
381
subsys/net/l2/ppp/ppp_l2.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <net/net_core.h>
|
||||
#include <net/net_l2.h>
|
||||
#include <net/net_if.h>
|
||||
#include <net/net_pkt.h>
|
||||
#include <net/net_mgmt.h>
|
||||
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
|
||||
#include "ppp_stats.h"
|
||||
#include "ppp_internal.h"
|
||||
|
||||
#define BUF_ALLOC_TIMEOUT K_MSEC(100)
|
||||
|
||||
static const struct ppp_protocol_handler *ppp_lcp;
|
||||
|
||||
static void ppp_update_rx_stats(struct net_if *iface,
|
||||
struct net_pkt *pkt, size_t length)
|
||||
{
|
||||
#if defined(CONFIG_NET_STATISTICS_PPP)
|
||||
ppp_stats_update_bytes_rx(iface, length);
|
||||
ppp_stats_update_pkts_rx(iface);
|
||||
#endif /* CONFIG_NET_STATISTICS_PPP */
|
||||
}
|
||||
|
||||
static void ppp_update_tx_stats(struct net_if *iface,
|
||||
struct net_pkt *pkt, size_t length)
|
||||
{
|
||||
#if defined(CONFIG_NET_STATISTICS_PPP)
|
||||
ppp_stats_update_bytes_tx(iface, length);
|
||||
ppp_stats_update_pkts_tx(iface);
|
||||
#endif /* CONFIG_NET_STATISTICS_PPP */
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_TEST)
|
||||
typedef enum net_verdict (*ppp_l2_callback_t)(struct net_if *iface,
|
||||
struct net_pkt *pkt);
|
||||
|
||||
static ppp_l2_callback_t testing_cb;
|
||||
|
||||
void ppp_l2_register_pkt_cb(ppp_l2_callback_t cb)
|
||||
{
|
||||
testing_cb = cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum net_verdict process_ppp_msg(struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
enum net_verdict verdict = NET_DROP;
|
||||
struct ppp_protocol_handler *proto;
|
||||
u16_t protocol;
|
||||
int ret;
|
||||
|
||||
if (!ctx->is_init || !ctx->is_ready_to_serve) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
ret = net_pkt_read_be16(pkt, &protocol);
|
||||
if (ret < 0) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if ((IS_ENABLED(CONFIG_NET_IPV4) && protocol == PPP_IP) ||
|
||||
(IS_ENABLED(CONFIG_NET_IPV6) && protocol == PPP_IPV6)) {
|
||||
/* Remove the protocol field so that IP packet processing
|
||||
* continues properly in net_core.c:process_data()
|
||||
*/
|
||||
(void)net_buf_pull_be16(pkt->buffer);
|
||||
net_pkt_cursor_init(pkt);
|
||||
return NET_CONTINUE;
|
||||
}
|
||||
|
||||
for (proto = __net_ppp_proto_start;
|
||||
proto != __net_ppp_proto_end;
|
||||
proto++) {
|
||||
if (proto->protocol != protocol) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return proto->handler(ctx, iface, pkt);
|
||||
}
|
||||
|
||||
NET_DBG("%s protocol %s%s(0x%02x)",
|
||||
ppp_proto2str(protocol) ? "Unhandled" : "Unknown",
|
||||
ppp_proto2str(protocol),
|
||||
ppp_proto2str(protocol) ? " " : "",
|
||||
protocol);
|
||||
|
||||
quit:
|
||||
return verdict;
|
||||
}
|
||||
|
||||
static enum net_verdict ppp_recv(struct net_if *iface,
|
||||
struct net_pkt *pkt)
|
||||
{
|
||||
enum net_verdict verdict;
|
||||
|
||||
#if defined(CONFIG_NET_TEST)
|
||||
/* If we are running a PPP unit test, then feed the packet
|
||||
* back to test app for verification.
|
||||
*/
|
||||
if (testing_cb) {
|
||||
return testing_cb(iface, pkt);
|
||||
}
|
||||
#endif
|
||||
|
||||
ppp_update_rx_stats(iface, pkt, net_pkt_get_len(pkt));
|
||||
|
||||
if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
|
||||
net_pkt_hexdump(pkt, "recv L2");
|
||||
}
|
||||
|
||||
verdict = process_ppp_msg(iface, pkt);
|
||||
|
||||
switch (verdict) {
|
||||
case NET_OK:
|
||||
net_pkt_unref(pkt);
|
||||
break;
|
||||
case NET_DROP:
|
||||
ppp_stats_update_drop_rx(iface);
|
||||
break;
|
||||
case NET_CONTINUE:
|
||||
break;
|
||||
}
|
||||
|
||||
return verdict;
|
||||
}
|
||||
|
||||
static int ppp_send(struct net_if *iface, struct net_pkt *pkt)
|
||||
{
|
||||
const struct ppp_api *api = net_if_get_device(iface)->driver_api;
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
int ret;
|
||||
|
||||
if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
|
||||
net_pkt_hexdump(pkt, "send L2");
|
||||
}
|
||||
|
||||
if (!ctx->is_init) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* If PPP is not yet ready, then just give error to caller as there
|
||||
* is no way to send before the PPP handshake is finished.
|
||||
*/
|
||||
if (ctx->phase != PPP_RUNNING && !net_pkt_is_ppp(pkt)) {
|
||||
return -ENETDOWN;
|
||||
}
|
||||
|
||||
ret = api->send(net_if_get_device(iface), pkt);
|
||||
if (!ret) {
|
||||
ret = net_pkt_get_len(pkt);
|
||||
ppp_update_tx_stats(iface, pkt, ret);
|
||||
net_pkt_unref(pkt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ppp_lower_down(struct ppp_context *ctx)
|
||||
{
|
||||
if (ppp_lcp) {
|
||||
ppp_lcp->lower_down(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void ppp_lower_up(struct ppp_context *ctx)
|
||||
{
|
||||
if (ppp_lcp) {
|
||||
ppp_lcp->lower_up(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_ppp(struct ppp_context *ctx)
|
||||
{
|
||||
ppp_change_phase(ctx, PPP_ESTABLISH);
|
||||
|
||||
ppp_lower_up(ctx);
|
||||
|
||||
if (ppp_lcp) {
|
||||
NET_DBG("Starting LCP");
|
||||
ppp_lcp->open(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static int ppp_enable(struct net_if *iface, bool state)
|
||||
{
|
||||
const struct ppp_api *ppp =
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
|
||||
if (!ctx->is_init) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ctx->is_enabled == state) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->is_enabled = state;
|
||||
|
||||
if (!state) {
|
||||
ppp_lower_down(ctx);
|
||||
|
||||
if (ppp->stop) {
|
||||
ppp->stop(net_if_get_device(iface));
|
||||
}
|
||||
} else {
|
||||
if (ppp->start) {
|
||||
ppp->start(net_if_get_device(iface));
|
||||
}
|
||||
|
||||
start_ppp(ctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum net_l2_flags ppp_flags(struct net_if *iface)
|
||||
{
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
|
||||
return ctx->ppp_l2_flags;
|
||||
}
|
||||
|
||||
NET_L2_INIT(PPP_L2, ppp_recv, ppp_send, ppp_enable, ppp_flags);
|
||||
|
||||
static void carrier_on(struct k_work *work)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(work, struct ppp_context,
|
||||
carrier_mgmt.work);
|
||||
|
||||
if (ctx->iface == NULL || ctx->carrier_mgmt.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
NET_DBG("Carrier ON for interface %p", ctx->iface);
|
||||
|
||||
ppp_mgmt_raise_carrier_on_event(ctx->iface);
|
||||
|
||||
ctx->carrier_mgmt.enabled = true;
|
||||
|
||||
net_if_up(ctx->iface);
|
||||
}
|
||||
|
||||
static void carrier_off(struct k_work *work)
|
||||
{
|
||||
struct ppp_context *ctx = CONTAINER_OF(work, struct ppp_context,
|
||||
carrier_mgmt.work);
|
||||
|
||||
if (ctx->iface == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
NET_DBG("Carrier OFF for interface %p", ctx->iface);
|
||||
|
||||
ppp_lower_down(ctx);
|
||||
|
||||
ppp_change_phase(ctx, PPP_DEAD);
|
||||
|
||||
ppp_mgmt_raise_carrier_off_event(ctx->iface);
|
||||
|
||||
net_if_carrier_down(ctx->iface);
|
||||
|
||||
ctx->carrier_mgmt.enabled = false;
|
||||
}
|
||||
|
||||
static void handle_carrier(struct ppp_context *ctx,
|
||||
k_work_handler_t handler)
|
||||
{
|
||||
k_work_init(&ctx->carrier_mgmt.work, handler);
|
||||
|
||||
k_work_submit(&ctx->carrier_mgmt.work);
|
||||
}
|
||||
|
||||
void net_ppp_carrier_on(struct net_if *iface)
|
||||
{
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
|
||||
handle_carrier(ctx, carrier_on);
|
||||
}
|
||||
|
||||
void net_ppp_carrier_off(struct net_if *iface)
|
||||
{
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
|
||||
handle_carrier(ctx, carrier_off);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_SHELL)
|
||||
int net_ppp_ping(int idx, s32_t timeout)
|
||||
{
|
||||
struct net_if *iface = net_if_get_by_index(idx);
|
||||
struct ppp_context *ctx;
|
||||
int ret;
|
||||
|
||||
if (!iface) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (net_if_l2(iface) != &NET_L2_GET_NAME(PPP)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctx = net_if_l2_data(iface);
|
||||
|
||||
ctx->shell.echo_req_data = sys_rand32_get();
|
||||
|
||||
ret = ppp_send_pkt(&ctx->lcp.fsm, iface, PPP_ECHO_REQ, 0,
|
||||
UINT_TO_POINTER(ctx->shell.echo_req_data),
|
||||
sizeof(ctx->shell.echo_req_data));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return k_sem_take(&ctx->shell.wait_echo_reply, timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct ppp_protocol_handler *ppp_lcp_get(void)
|
||||
{
|
||||
return ppp_lcp;
|
||||
}
|
||||
|
||||
void net_ppp_init(struct net_if *iface)
|
||||
{
|
||||
struct ppp_context *ctx = net_if_l2_data(iface);
|
||||
const struct ppp_protocol_handler *proto;
|
||||
|
||||
NET_DBG("Initializing PPP L2 %p for iface %p", ctx, iface);
|
||||
|
||||
if (!ctx->is_init) {
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
ctx->ppp_l2_flags = NET_L2_MULTICAST | NET_L2_POINT_TO_POINT;
|
||||
ctx->iface = iface;
|
||||
|
||||
if (!ctx->is_init) {
|
||||
int count;
|
||||
|
||||
#if defined(CONFIG_NET_SHELL)
|
||||
k_sem_init(&ctx->shell.wait_echo_reply, 0, UINT_MAX);
|
||||
#endif
|
||||
|
||||
for (proto = __net_ppp_proto_start, count = 0;
|
||||
proto != __net_ppp_proto_end;
|
||||
proto++, count++) {
|
||||
if (proto->protocol == PPP_LCP) {
|
||||
ppp_lcp = proto;
|
||||
}
|
||||
|
||||
proto->init(ctx);
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
NET_ERR("There are no PPP protocols configured!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ppp_lcp == NULL) {
|
||||
NET_ERR("No LCP found!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->is_init = true;
|
||||
ctx->is_ready_to_serve = true;
|
||||
}
|
54
subsys/net/l2/ppp/ppp_stats.c
Normal file
54
subsys/net/l2/ppp/ppp_stats.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(net_ppp_stats, CONFIG_NET_L2_PPP_LOG_LEVEL);
|
||||
|
||||
#include <kernel.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <net/net_core.h>
|
||||
#include <net/ppp.h>
|
||||
|
||||
#include "net_stats.h"
|
||||
|
||||
#if defined(CONFIG_NET_STATISTICS_USER_API)
|
||||
|
||||
static int ppp_stats_get(u32_t mgmt_request, struct net_if *iface,
|
||||
void *data, size_t len)
|
||||
{
|
||||
size_t len_chk = 0;
|
||||
void *src = NULL;
|
||||
const struct ppp_api *ppp;
|
||||
|
||||
if (NET_MGMT_GET_COMMAND(mgmt_request) ==
|
||||
NET_REQUEST_STATS_CMD_GET_PPP) {
|
||||
if (net_if_l2(iface) != &NET_L2_GET_NAME(PPP)) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ppp = net_if_get_device(iface)->driver_api;
|
||||
if (ppp->get_stats == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
len_chk = sizeof(struct net_stats_ppp);
|
||||
src = ppp->get_stats(net_if_get_device(iface));
|
||||
}
|
||||
|
||||
if (len != len_chk || !src) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(data, src, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PPP,
|
||||
ppp_stats_get);
|
||||
|
||||
#endif /* CONFIG_NET_STATISTICS_USER_API */
|
137
subsys/net/l2/ppp/ppp_stats.h
Normal file
137
subsys/net/l2/ppp/ppp_stats.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __PPP_STATS_H__
|
||||
#define __PPP_STATS_H__
|
||||
|
||||
#if defined(CONFIG_NET_STATISTICS_PPP)
|
||||
|
||||
#include <net/net_ip.h>
|
||||
#include <net/net_stats.h>
|
||||
#include <net/net_if.h>
|
||||
|
||||
static inline void ppp_stats_update_bytes_rx(struct net_if *iface,
|
||||
u32_t bytes)
|
||||
{
|
||||
const struct ppp_api *api = (const struct ppp_api *)
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct net_stats_ppp *stats;
|
||||
|
||||
if (!api->get_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = api->get_stats(net_if_get_device(iface));
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats->bytes.received += bytes;
|
||||
}
|
||||
|
||||
static inline void ppp_stats_update_bytes_tx(struct net_if *iface,
|
||||
u32_t bytes)
|
||||
{
|
||||
const struct ppp_api *api = (const struct ppp_api *)
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct net_stats_ppp *stats;
|
||||
|
||||
if (!api->get_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = api->get_stats(net_if_get_device(iface));
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats->bytes.sent += bytes;
|
||||
}
|
||||
|
||||
static inline void ppp_stats_update_pkts_rx(struct net_if *iface)
|
||||
{
|
||||
const struct ppp_api *api = (const struct ppp_api *)
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct net_stats_ppp *stats;
|
||||
|
||||
if (!api->get_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = api->get_stats(net_if_get_device(iface));
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats->pkts.rx++;
|
||||
}
|
||||
|
||||
static inline void ppp_stats_update_pkts_tx(struct net_if *iface)
|
||||
{
|
||||
const struct ppp_api *api = (const struct ppp_api *)
|
||||
net_if_get_device(iface)->driver_api;
|
||||
struct net_stats_ppp *stats;
|
||||
|
||||
if (!api->get_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = api->get_stats(net_if_get_device(iface));
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats->pkts.tx++;
|
||||
}
|
||||
|
||||
static inline void ppp_stats_update_drop_rx(struct net_if *iface)
|
||||
{
|
||||
const struct ppp_api *api = ((const struct ppp_api *)
|
||||
net_if_get_device(iface)->driver_api);
|
||||
struct net_stats_ppp *stats;
|
||||
|
||||
if (!api->get_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = api->get_stats(net_if_get_device(iface));
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats->drop++;
|
||||
}
|
||||
|
||||
static inline void ppp_stats_update_fcs_error_rx(struct net_if *iface)
|
||||
{
|
||||
const struct ppp_api *api = ((const struct ppp_api *)
|
||||
net_if_get_device(iface)->driver_api);
|
||||
struct net_stats_ppp *stats;
|
||||
|
||||
if (!api->get_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats = api->get_stats(net_if_get_device(iface));
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats->chkerr++;
|
||||
}
|
||||
|
||||
#else /* CONFIG_NET_STATISTICS_PPP */
|
||||
|
||||
#define ppp_stats_update_bytes_rx(iface, bytes)
|
||||
#define ppp_stats_update_bytes_tx(iface, bytes)
|
||||
#define ppp_stats_update_pkts_rx(iface)
|
||||
#define ppp_stats_update_pkts_tx(iface)
|
||||
#define ppp_stats_update_drop_rx(iface)
|
||||
#define ppp_stats_update_fcs_error_rx(iface)
|
||||
|
||||
#endif /* CONFIG_NET_STATISTICS_PPP */
|
||||
|
||||
#endif /* __PPP_STATS_H__ */
|
Loading…
Add table
Add a link
Reference in a new issue