1 /*
2  * Copyright (c) 2022 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/types.h>
9 #include <zephyr/net/net_if.h>
10 #include <zephyr/net/net_pkt.h>
11 #include <zephyr/sys/ring_buffer.h>
12 #include <zephyr/sys/atomic.h>
13 
14 #include <zephyr/modem/pipe.h>
15 #include <zephyr/modem/stats.h>
16 
17 #ifndef ZEPHYR_MODEM_PPP_
18 #define ZEPHYR_MODEM_PPP_
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /**
25  * @brief Modem PPP
26  * @defgroup modem_ppp Modem PPP
27  * @ingroup modem
28  * @{
29  */
30 
31 /** L2 network interface init callback */
32 typedef void (*modem_ppp_init_iface)(struct net_if *iface);
33 
34 /**
35  * @cond INTERNAL_HIDDEN
36  */
37 
38 enum modem_ppp_receive_state {
39 	/* Searching for start of frame and header */
40 	MODEM_PPP_RECEIVE_STATE_HDR_SOF = 0,
41 	MODEM_PPP_RECEIVE_STATE_HDR_FF,
42 	MODEM_PPP_RECEIVE_STATE_HDR_7D,
43 	MODEM_PPP_RECEIVE_STATE_HDR_23,
44 	/* Writing bytes to network packet */
45 	MODEM_PPP_RECEIVE_STATE_WRITING,
46 	/* Unescaping next byte before writing to network packet */
47 	MODEM_PPP_RECEIVE_STATE_UNESCAPING,
48 };
49 
50 enum modem_ppp_transmit_state {
51 	/* Idle */
52 	MODEM_PPP_TRANSMIT_STATE_IDLE = 0,
53 	/* Writing header */
54 	MODEM_PPP_TRANSMIT_STATE_SOF,
55 	MODEM_PPP_TRANSMIT_STATE_HDR_FF,
56 	MODEM_PPP_TRANSMIT_STATE_HDR_7D,
57 	MODEM_PPP_TRANSMIT_STATE_HDR_23,
58 	/* Writing protocol */
59 	MODEM_PPP_TRANSMIT_STATE_PROTOCOL_HIGH,
60 	MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_HIGH,
61 	MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW,
62 	MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_LOW,
63 	/* Writing data */
64 	MODEM_PPP_TRANSMIT_STATE_DATA,
65 	MODEM_PPP_TRANSMIT_STATE_ESCAPING_DATA,
66 	/* Writing FCS */
67 	MODEM_PPP_TRANSMIT_STATE_FCS_LOW,
68 	MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_LOW,
69 	MODEM_PPP_TRANSMIT_STATE_FCS_HIGH,
70 	MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_HIGH,
71 	/* Writing end of frame */
72 	MODEM_PPP_TRANSMIT_STATE_EOF,
73 };
74 
75 struct modem_ppp {
76 	/* Network interface instance is bound to */
77 	struct net_if *iface;
78 
79 	/* Hook for PPP L2 network interface initialization */
80 	modem_ppp_init_iface init_iface;
81 
82 	atomic_t state;
83 
84 	/* Buffers used for processing partial frames */
85 	uint8_t *receive_buf;
86 	uint8_t *transmit_buf;
87 	uint16_t buf_size;
88 
89 	/* Wrapped PPP frames are sent and received through this pipe */
90 	struct modem_pipe *pipe;
91 
92 	/* Receive PPP frame state */
93 	enum modem_ppp_receive_state receive_state;
94 
95 	/* Allocated network packet being created */
96 	struct net_pkt *rx_pkt;
97 
98 	/* Packet being sent */
99 	enum modem_ppp_transmit_state transmit_state;
100 	struct net_pkt *tx_pkt;
101 	uint8_t tx_pkt_escaped;
102 	uint16_t tx_pkt_protocol;
103 	uint16_t tx_pkt_fcs;
104 
105 	/* Ring buffer used for transmitting partial PPP frame */
106 	struct ring_buf transmit_rb;
107 
108 	struct k_fifo tx_pkt_fifo;
109 
110 	/* Work */
111 	struct k_work send_work;
112 	struct k_work process_work;
113 
114 #if defined(CONFIG_NET_STATISTICS_PPP)
115 	struct net_stats_ppp stats;
116 #endif
117 
118 #if CONFIG_MODEM_STATS
119 	struct modem_stats_buffer receive_buf_stats;
120 	struct modem_stats_buffer transmit_buf_stats;
121 #endif
122 };
123 
124 /**
125  * @endcond
126  */
127 
128 /**
129  * @brief Attach pipe to instance and connect
130  *
131  * @param ppp Modem PPP instance
132  * @param pipe Pipe to attach to modem PPP instance
133  */
134 int modem_ppp_attach(struct modem_ppp *ppp, struct modem_pipe *pipe);
135 
136 /**
137  * @brief Get network interface modem PPP instance is bound to
138  *
139  * @param ppp Modem PPP instance
140  * @returns Pointer to network interface modem PPP instance is bound to
141  */
142 struct net_if *modem_ppp_get_iface(struct modem_ppp *ppp);
143 
144 /**
145  * @brief Release pipe from instance
146  *
147  * @param ppp Modem PPP instance
148  */
149 void modem_ppp_release(struct modem_ppp *ppp);
150 
151 /**
152  * @cond INTERNAL_HIDDEN
153  */
154 
155 /**
156  * @brief Initialize modem PPP instance device
157  * @param dev Device instance associated with network interface
158  * @warning Should not be used directly
159  */
160 int modem_ppp_init_internal(const struct device *dev);
161 
162 /**
163  * @endcond
164  */
165 
166 /**
167  * @brief Define a modem PPP module and bind it to a network interface
168  *
169  * @details This macro defines the modem_ppp instance, initializes a PPP L2
170  * network device instance, and binds the modem_ppp instance to the PPP L2
171  * instance.
172  *
173  * @param _name Name of the statically defined modem_ppp instance
174  * @param _init_iface Hook for the PPP L2 network interface init function
175  * @param _prio Initialization priority of the PPP L2 net iface
176  * @param _mtu Max size of net_pkt data sent and received on PPP L2 net iface
177  * @param _buf_size Size of partial PPP frame transmit and receive buffers
178  */
179 #define MODEM_PPP_DEFINE(_name, _init_iface, _prio, _mtu, _buf_size)                               \
180 	extern const struct ppp_api modem_ppp_ppp_api;                                             \
181                                                                                                    \
182 	static uint8_t _CONCAT(_name, _receive_buf)[_buf_size];                                    \
183 	static uint8_t _CONCAT(_name, _transmit_buf)[_buf_size];                                   \
184                                                                                                    \
185 	static struct modem_ppp _name = {                                                          \
186 		.init_iface = _init_iface,                                                         \
187 		.receive_buf = _CONCAT(_name, _receive_buf),                                       \
188 		.transmit_buf = _CONCAT(_name, _transmit_buf),                                     \
189 		.buf_size = _buf_size,                                                             \
190 	};                                                                                         \
191                                                                                                    \
192 	NET_DEVICE_INIT(_CONCAT(ppp_net_dev_, _name), "modem_ppp_" # _name,                        \
193 			modem_ppp_init_internal, NULL, &_name, NULL, _prio, &modem_ppp_ppp_api,    \
194 			PPP_L2, NET_L2_GET_CTX_TYPE(PPP_L2), _mtu)
195 
196 /**
197  * @}
198  */
199 
200 #ifdef __cplusplus
201 }
202 #endif
203 
204 #endif /* ZEPHYR_MODEM_PPP_ */
205