1 /*
2  * Copyright (C)2021-2022 Intel Corporation.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <termios.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <pthread.h>
17 #include <limits.h>
18 #include <stdint.h>
19 #include "uart_channel.h"
20 #include "log.h"
21 #include "list.h"
22 #include "config.h"
23 #include "command.h"
24 
25 #define SYNC_FMT "sync:%s"
26 
parse_channel_dev_id(struct channel_dev * c_dev)27 static void parse_channel_dev_id(struct channel_dev *c_dev)
28 {
29 	char *saveptr;
30 
31 	(void) strtok_r(c_dev->buf, ":", &saveptr);
32 	if (strlen(saveptr) > 0) {
33 		strncpy(c_dev->name, saveptr, CHANNEL_DEV_NAME_MAX - 1U);
34 		LOG_PRINTF("Device fd:%d, VM name:%s\n",
35 					get_uart_dev_fd(c_dev->uart_device), c_dev->name);
36 	}
37 }
add_uart_channel_dev_connection_list(struct channel_dev * c_dev)38 static void add_uart_channel_dev_connection_list(struct channel_dev *c_dev)
39 {
40 	struct uart_channel *c = c_dev->channel;
41 
42 	pthread_mutex_lock(&c->tty_conn_list_lock);
43 	LIST_INSERT_HEAD(&c->tty_conn_head, c_dev, list);
44 	pthread_mutex_unlock(&c->tty_conn_list_lock);
45 }
46 /**
47  * @brief Wait to connect device in uart channel
48  *
49  * Wait sync message from slave channel device, parse slave channel device
50  * indentifier from sync message, then add channel device into uart channel
51  * device connection list.
52  */
listen_uart_channel_dev(void * arg)53 void *listen_uart_channel_dev(void *arg)
54 {
55 	ssize_t num;
56 	struct channel_dev *c_dev = (struct channel_dev *)arg;
57 
58 	LOG_PRINTF("Lifecycle manager in service VM fd=%d tty node=%s\n",
59 				get_uart_dev_fd(c_dev->uart_device), get_uart_dev_path(c_dev->uart_device));
60 	memset(c_dev->buf, 0, sizeof(c_dev->buf));
61 	while (c_dev->listening) {
62 		num = receive_message_by_uart(c_dev->uart_device, (void *)c_dev->buf,
63 							sizeof(c_dev->buf));
64 		if (num == 0) {
65 			usleep(LISTEN_INTERVAL);
66 			continue;
67 		}
68 		parse_channel_dev_id(c_dev);
69 		if (strncmp(SYNC_CMD, c_dev->buf, sizeof(SYNC_CMD)) == 0) {
70 			/** Add channel device instance into UART connection list */
71 			add_uart_channel_dev_connection_list(c_dev);
72 
73 			c_dev->listening = false;
74 			LOG_PRINTF("Receive sync message from user VM (%s), start to talk.\n",
75 					c_dev->name);
76 			usleep(2 * WAIT_RECV);
77 			(void)send_message_by_uart(c_dev->uart_device, ACK_SYNC, strlen(ACK_SYNC));
78 			sem_post(&c_dev->dev_sem);
79 		}
80 	}
81 
82 	LOG_PRINTF("Lifecycle manager stops to listen device:%s\n",
83 				get_uart_dev_path(c_dev->uart_device));
84 	return NULL;
85 }
86 /**
87  * @brief Wait to connect device in the uart channel
88  * and poll message
89  *
90  * Send sync message every 5 second and wait acked sync message,
91  * if acked sync message is received, add uart channel device instance
92  * into uart connection list. It acked sync message is not received, the lifecycle
93  * manager will exit.
94  */
connect_uart_channel_dev(void * arg)95 void *connect_uart_channel_dev(void *arg)
96 {
97 	ssize_t ret;
98 	struct channel_dev *c_dev = (struct channel_dev *)arg;
99 	struct uart_channel *c = c_dev->channel;
100 	char buf[CHANNEL_DEV_NAME_MAX + SYNC_LEN];
101 
102 	snprintf(buf, sizeof(buf), SYNC_FMT, c->conf.identifier);
103 	/* TODO: will add SYNC resending */
104 	LOG_PRINTF("Send sync command:%s identifier=%s\n", buf, c->conf.identifier);
105 	ret = send_message_by_uart(c_dev->uart_device, (void *)buf, strlen(buf));
106 	if (ret < 0) {
107 		LOG_WRITE("Send sync command to service VM fail\n");
108 	} else {
109 		usleep(LISTEN_INTERVAL);
110 		memset(c_dev->buf, 0, sizeof(c_dev->buf));
111 		(void) receive_message_by_uart(c_dev->uart_device, (void *)c_dev->buf, sizeof(c_dev->buf));
112 		if (strncmp(ACK_SYNC, c_dev->buf, sizeof(ACK_SYNC)) == 0) {
113 			/** Add channel device instance into UART connection list */
114 			add_uart_channel_dev_connection_list(c_dev);
115 			LOG_WRITE("Lifecycle manager: connected\n");
116 		} else {
117 			ret = -1;
118 			LOG_PRINTF("Device in the (%s): failed to connect\n", c->conf.identifier);
119 		}
120 	}
121 	if (ret < 0)
122 		c_dev->polling = false;
123 	c_dev->listening = false;
124 	sem_post(&c_dev->dev_sem);
125 	return NULL;
126 }
127 
poll_and_dispatch_uart_channel_events(void * arg)128 void *poll_and_dispatch_uart_channel_events(void *arg)
129 {
130 	struct channel_dev *c_dev = (struct channel_dev *)arg;
131 	ssize_t num, ret;
132 	struct uart_channel *c;
133 
134 	c = c_dev->channel;
135 	sem_wait(&c_dev->dev_sem);
136 	LOG_PRINTF("UART polling fd=%d...\n", get_uart_dev_fd(c_dev->uart_device));
137 	while (c_dev->polling) {
138 		memset(c_dev->buf, 0, sizeof(c_dev->buf));
139 		num = receive_message_by_uart(c_dev->uart_device, (void *)c_dev->buf,
140 								sizeof(c_dev->buf));
141 		/**
142 		 * Resend message if resend_time is set.
143 		 */
144 		if (num == 0) {
145 			if (c_dev->resend_time > 1) {
146 				usleep(LISTEN_INTERVAL + SECOND_TO_US);
147 				LOG_PRINTF("Resend (%s) to (%s)\n", c_dev->resend_buf, c_dev->name);
148 				ret = send_message_by_uart(c_dev->uart_device, (void *)c_dev->resend_buf,
149 								strlen(c_dev->resend_buf));
150 				if (ret < 0)
151 					LOG_WRITE("Send poweroff message to user VM fail\n");
152 				c_dev->resend_time--;
153 			} else if (c_dev->resend_time == 1) {
154 				memcpy(c_dev->buf, ACK_TIMEOUT, strlen(ACK_TIMEOUT));
155 				num = strlen(ACK_TIMEOUT);
156 			} else {
157 				/* No action if resend_time is 0 */
158 			}
159 		}
160 		if (num > 0) {
161 			parse_channel_dev_id(c_dev);
162 			c->data_handler((const char *)c_dev->buf, get_uart_dev_fd(c_dev->uart_device));
163 		}
164 	}
165 	LOG_PRINTF("Lifecycle manager stops to poll device:%s\n",
166 			get_uart_dev_path(c_dev->uart_device));
167 	return NULL;
168 }
find_uart_channel_dev(struct uart_channel * c,int fd)169 struct channel_dev *find_uart_channel_dev(struct uart_channel *c, int fd)
170 {
171 	struct channel_dev *c_dev = NULL;
172 
173 	LIST_FOREACH(c_dev, &c->tty_conn_head, list) {
174 		if (get_uart_dev_fd(c_dev->uart_device) == fd)
175 			break;
176 	}
177 	return c_dev;
178 }
find_uart_channel_dev_by_name(struct uart_channel * c,char * name)179 struct channel_dev *find_uart_channel_dev_by_name(struct uart_channel *c, char *name)
180 {
181 	struct channel_dev *c_dev = NULL;
182 
183 	LIST_FOREACH(c_dev, &c->tty_conn_head, list) {
184 		if (strncmp(name, c_dev->name, sizeof(c_dev->name)) == 0)
185 			break;
186 	}
187 	return c_dev;
188 }
189 /**
190  * @brief Set message polling loop flag as flase and remove channel device instance from
191  * the connection list
192  *
193  * @param c_dev point to uart channel device instance
194  * @param c point to uart channel instance
195  */
disconnect_uart_channel_dev(struct channel_dev * c_dev,struct uart_channel * c)196 void disconnect_uart_channel_dev(struct channel_dev *c_dev, struct uart_channel *c)
197 {
198 	c_dev->listening = false;
199 	c_dev->polling = false;
200 
201 	pthread_mutex_lock(&c->tty_conn_list_lock);
202 	LIST_REMOVE(c_dev, list);
203 	pthread_mutex_unlock(&c->tty_conn_list_lock);
204 }
205 /**
206  * @brief Traverse uart channel open list to set listening loop flag and polling loop flag
207  * to false for each channel device which is in listening state.
208  *
209  * @param c point to uart channel instance
210  */
stop_listen_uart_channel_dev(struct uart_channel * c)211 void stop_listen_uart_channel_dev(struct uart_channel *c)
212 {
213 	struct channel_dev *c_dev;
214 
215 	LIST_FOREACH(c_dev, &c->tty_open_head, open_list) {
216 		if (c_dev->listening) {
217 			LOG_PRINTF("Stop to listen uart device (%s)\n",
218 					get_uart_dev_path(c_dev->uart_device));
219 			c_dev->listening = false;
220 			c_dev->polling = false;
221 			sem_post(&c_dev->dev_sem);
222 		}
223 	}
224 }
start_uart_channel_dev_resend(struct channel_dev * c_dev,char * resend_buf,unsigned int resend_time)225 void start_uart_channel_dev_resend(struct channel_dev *c_dev, char *resend_buf, unsigned int resend_time)
226 {
227 	if (resend_time < MIN_RESEND_TIME)
228 		resend_time = MIN_RESEND_TIME;
229 	strncpy(c_dev->resend_buf, resend_buf, CHANNEL_DEV_BUF_LEN - 1);
230 	c_dev->resend_time = resend_time + 1;
231 }
start_all_uart_channel_dev_resend(struct uart_channel * c,char * msg,unsigned int resend_time)232 void start_all_uart_channel_dev_resend(struct uart_channel *c, char *msg, unsigned int resend_time)
233 {
234 	struct channel_dev *c_dev;
235 
236 	/* Enable resend for all connected uart channel devices */
237 	pthread_mutex_lock(&c->tty_conn_list_lock);
238 	LIST_FOREACH(c_dev, &c->tty_conn_head, list) {
239 		start_uart_channel_dev_resend(c_dev, msg, resend_time);
240 	}
241 	pthread_mutex_unlock(&c->tty_conn_list_lock);
242 }
stop_uart_channel_dev_resend(struct channel_dev * c_dev)243 void stop_uart_channel_dev_resend(struct channel_dev *c_dev)
244 {
245 	if (c_dev->resend_time == 1U)
246 		LOG_PRINTF("Timeout of receiving ACK message from (%s)\n", c_dev->name);
247 	c_dev->resend_time = 0U;
248 	memset(c_dev->resend_buf, 0x0, CHANNEL_DEV_BUF_LEN);
249 }
250 /**
251  * @brief Send message to each connected uart channel device
252  *
253  * @param c uart channel instance
254  * @param msg pointer which points to the message to be sent
255  */
notify_all_connected_uart_channel_dev(struct uart_channel * c,char * msg)256 void notify_all_connected_uart_channel_dev(struct uart_channel *c, char *msg)
257 {
258 	struct channel_dev *c_dev;
259 
260 	/* Send message to all tty connected devices*/
261 	pthread_mutex_lock(&c->tty_conn_list_lock);
262 	LIST_FOREACH(c_dev, &c->tty_conn_head, list) {
263 		LOG_PRINTF("Send (%s) to (%s)\n", msg, c_dev->name);
264 		(void) send_message_by_uart(c_dev->uart_device, msg, strlen(msg));
265 	}
266 	pthread_mutex_unlock(&c->tty_conn_list_lock);
267 }
is_uart_channel_connection_list_empty(struct uart_channel * c)268 bool is_uart_channel_connection_list_empty(struct uart_channel *c)
269 {
270 	bool ret = false;
271 
272 	pthread_mutex_lock(&c->tty_conn_list_lock);
273 	if (LIST_EMPTY(&c->tty_conn_head))
274 		ret = true;
275 	pthread_mutex_unlock(&c->tty_conn_list_lock);
276 	return ret;
277 }
create_uart_channel_dev(struct uart_channel * c,char * path,data_handler_f * fn)278 struct channel_dev *create_uart_channel_dev(struct uart_channel *c, char *path, data_handler_f *fn)
279 {
280 	struct uart_dev *dev;
281 	struct channel_dev *c_dev;
282 
283 	if (c == NULL || path == NULL || fn == NULL)
284 		return NULL;
285 	c->data_handler = fn;
286 	dev = init_uart_dev(path);
287 	if (dev == NULL) {
288 		LOG_PRINTF("Failed to initialize UART device %s\n", path);
289 		return NULL;
290 	}
291 
292 	c_dev = calloc(1, sizeof(*c_dev));
293 	if (!c_dev) {
294 		LOG_PRINTF("%s: Failed to allocate memory for UART channel device\n", __func__);
295 		deinit_uart_dev(dev);
296 		return NULL;
297 	}
298 	memset(c_dev, 0x0, sizeof(*c_dev));
299 	c_dev->uart_device = dev;
300 	c_dev->channel = c;
301 	c_dev->listening = true;
302 	c_dev->polling = true;
303 	sem_init(&c_dev->dev_sem, 0, 0);
304 	/** Add channel device instance into open list */
305 	pthread_mutex_lock(&c->tty_conn_list_lock);
306 	LIST_INSERT_HEAD(&c->tty_open_head, c_dev, open_list);
307 	pthread_mutex_unlock(&c->tty_conn_list_lock);
308 	return c_dev;
309 }
destroy_uart_channel_devs(struct uart_channel * c)310 static void destroy_uart_channel_devs(struct uart_channel *c)
311 {
312 	struct channel_dev *c_dev, *tc_dev;
313 
314 	list_foreach_safe(c_dev, &c->tty_open_head, open_list, tc_dev) {
315 		pthread_mutex_lock(&c->tty_conn_list_lock);
316 		LIST_REMOVE(c_dev, open_list);
317 		pthread_mutex_unlock(&c->tty_conn_list_lock);
318 
319 		deinit_uart_dev(c_dev->uart_device);
320 		free(c_dev);
321 	}
322 }
wait_uart_channel_devs_threads(struct uart_channel * c)323 void wait_uart_channel_devs_threads(struct uart_channel *c)
324 {
325 	struct channel_dev *c_dev;
326 
327 	LIST_FOREACH(c_dev, &c->tty_open_head, open_list) {
328 		pthread_join(c_dev->listen_thread, NULL);
329 		pthread_join(c_dev->pool_thread, NULL);
330 	}
331 }
init_uart_channel(char * id)332 struct uart_channel *init_uart_channel(char *id)
333 {
334 	struct uart_channel *c;
335 
336 	if (id == NULL) {
337 		LOG_PRINTF("%s:invlid parameter\n", __func__);
338 		return NULL;
339 	}
340 	c = calloc(1, sizeof(*c));
341 	if (!c) {
342 		LOG_PRINTF("%s: Failed to allocate memory for UART channel\n", __func__);
343 		return NULL;
344 	}
345 	c->data_handler = NULL;
346 	LIST_INIT(&c->tty_conn_head);
347 	LIST_INIT(&c->tty_open_head);
348 	pthread_mutex_init(&c->tty_conn_list_lock, NULL);
349 	memcpy(c->conf.identifier, id, strlen(id));
350 	return c;
351 }
deinit_uart_channel(struct uart_channel * c)352 void deinit_uart_channel(struct uart_channel *c)
353 {
354 	if (c != NULL) {
355 		destroy_uart_channel_devs(c);
356 		free(c);
357 	}
358 }
359