/* * Copyright (c) 2019 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_NET_PPP_H_ #define ZEPHYR_INCLUDE_NET_PPP_H_ #include #include #include #include #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_ */