blob: aebb8dd756107e546779ee55345356b0183f79fa [file] [log] [blame]
/*
* 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
/** Length of network interface identifier */
#define PPP_INTERFACE_IDENTIFIER_LEN 8
/** 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
};
/* Make sure that the network interface API is properly setup inside
* PPP API struct (it is the first one).
*/
BUILD_ASSERT(offsetof(struct ppp_api, iface_api) == 0);
/**
* 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_IPV6CP = 0x8057, /**< RFC 5072 */
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;
/**
* IPV6CP option types from RFC 5072
*/
enum ipv6cp_option_type {
IPV6CP_OPTION_RESERVED = 0,
/** Interface identifier */
IPV6CP_OPTION_INTERFACE_IDENTIFIER = 1,
} __packed;
/**
* @typedef net_ppp_lcp_echo_reply_cb_t
* @brief A callback function that can be called if a Echo-Reply needs to
* be received.
* @param user_data User settable data that is passed to the callback
* function.
* @param user_data_len Length of the user data.
*/
typedef void (*net_ppp_lcp_echo_reply_cb_t)(void *user_data,
size_t user_data_len);
/**
* 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;
enum ipv6cp_option_type ipv6cp;
} 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;
};
struct ipv6cp_options {
/** Interface identifier */
u8_t iid[PPP_INTERFACE_IDENTIFIER_LEN];
};
/** PPP L2 context specific to certain network interface */
struct ppp_context {
/** PPP startup worker. */
struct k_delayed_work startup;
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_IPV6)
struct {
/** Finite state machine for IPV6CP */
struct ppp_fsm fsm;
/** Options that we want to request */
struct ipv6cp_options my_options;
/** Options that peer want to request */
struct ipv6cp_options peer_options;
/** Options that we accepted */
struct ipv6cp_options my_accepted;
/** Options that peer accepted */
struct ipv6cp_options peer_accepted;
} ipv6cp;
#endif
#if defined(CONFIG_NET_SHELL)
struct {
struct {
/** Callback to be called when Echo-Reply is received.
*/
net_ppp_lcp_echo_reply_cb_t cb;
/** User specific data for the callback */
void *user_data;
/** User data length */
size_t user_data_len;
} echo_reply;
/** 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;
/** PPP startup pending */
u16_t is_startup_pending : 1;
/** PPP enable pending */
u16_t is_enable_done : 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;
/** IPV6CP status (up / down) */
u16_t is_ipv6cp_up : 1;
/** IPV6CP open status (open / closed) */
u16_t is_ipv6cp_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
/**
* @brief Get PPP context information. This is only used by net-shell to
* print information about PPP.
*
* @param idx PPP network interface index
*
* @return PPP context or NULL if idx is invalid.
*/
#if defined(CONFIG_NET_L2_PPP) && defined(CONFIG_NET_SHELL)
struct ppp_context *net_ppp_context_get(int idx);
#else
static inline struct ppp_context *net_ppp_context_get(int idx)
{
ARG_UNUSED(idx);
return NULL;
}
#endif
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_NET_PPP_H_ */