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