1 /*
2 * Copyright (C)2021-2022 Intel Corporation.
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdbool.h>
9 #include <unistd.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <sys/un.h>
13 #include <libgen.h>
14 #include "uart.h"
15 #include "uart_channel.h"
16 #include "command.h"
17 #include "socket.h"
18 #include "command_handler.h"
19 #include "log.h"
20 #include "config.h"
21
22 bool system_shutdown_flag;
get_system_shutdown_flag(void)23 bool get_system_shutdown_flag(void)
24 {
25 return system_shutdown_flag;
26 }
27
28 bool user_vm_reboot_flag;
29 bool system_reboot_flag;
30 bool system_reboot_request_flag;
get_vm_reboot_flag(void)31 bool get_vm_reboot_flag(void)
32 {
33 return user_vm_reboot_flag | system_reboot_flag;
34 }
35
36 /**
37 * @brief check whether all acrn-dm instance have been exit or not
38 *
39 * @return true all acrn-dm instance have been exit
40 * @return false at least one acrn-dm exist
41 */
wait_post_vms_shutdown(void)42 static bool wait_post_vms_shutdown(void)
43 {
44 FILE *fp = NULL;
45 char command[64], buf[8];
46 char *endptr, *ret_str;
47 long val;
48 int check_time = SHUTDOWN_TIMEOUT/5;
49 bool all_done = false;
50
51 snprintf(command, sizeof(command), "pgrep -u root -f acrn-dm | wc -l");
52 do {
53 fp = popen(command, "r");
54 ret_str = fgets(buf, sizeof(buf), fp);
55 if (ret_str == NULL)
56 LOG_WRITE("Failed to check acrn-dm process\n");
57 val = strtol(buf, &endptr, 10) - 1;
58 if (val == 0) {
59 all_done = true;
60 pclose(fp);
61 break;
62 }
63 check_time--;
64 LOG_PRINTF("Wait post launched VMs shutdown check_time:%d, Running VM num:%ld\n",
65 check_time, val);
66 pclose(fp);
67 sleep(5);
68 } while (check_time > 0);
69 return all_done;
70 }
start_system_reboot(void)71 static void start_system_reboot(void)
72 {
73 static bool platform_reboot;
74
75 if (is_uart_channel_connection_list_empty(channel) && (!platform_reboot)) {
76 platform_reboot = true;
77 LOG_WRITE("UART connection list is empty, will trigger system reboot\n");
78 close_socket(sock_server);
79 stop_listen_uart_channel_dev(channel);
80 if (wait_post_vms_shutdown()) {
81 LOG_WRITE("Service VM starts to reboot.\n");
82 system_reboot_flag = true;
83 } else {
84 LOG_WRITE("Some User VMs failed to power off, cancelled the platform reboot process.\n");
85 }
86 }
87 }
start_system_shutdown(void)88 static void start_system_shutdown(void)
89 {
90 static bool platform_shutdown;
91
92 if (is_uart_channel_connection_list_empty(channel) && (!platform_shutdown)) {
93 platform_shutdown = true;
94 LOG_WRITE("UART connection list is empty, will trigger shutdown system\n");
95 close_socket(sock_server);
96 stop_listen_uart_channel_dev(channel);
97 if (wait_post_vms_shutdown()) {
98 LOG_WRITE("Service VM starts to power off.\n");
99 system_shutdown_flag = true;
100 } else {
101 LOG_WRITE("Some User VMs failed to power off, cancelled the platform shutdown process.\n");
102 }
103 }
104 }
105
send_socket_ack(void * arg,int fd,char * ack)106 static int send_socket_ack(void *arg, int fd, char *ack)
107 {
108 int ret = 0;
109 struct socket_dev *sock = (struct socket_dev *)arg;
110 struct socket_client *client = NULL;
111
112 client = find_socket_client(sock, fd);
113 if (client == NULL)
114 return -1;
115
116 LOG_PRINTF("Receive shutdown request from unix socket, fd=%d\n", client->fd);
117 memset(client->buf, 0, CLIENT_BUF_LEN);
118 memcpy(client->buf, ack, strlen(ack));
119 client->len = strlen(ack);
120 ret = write_socket_char(client);
121 LOG_PRINTF("Send acked message to unix socket, message=%s\n", ack);
122 return ret;
123 }
socket_req_shutdown_service_vm_handler(void * arg,int fd)124 int socket_req_shutdown_service_vm_handler(void *arg, int fd)
125 {
126 int ret;
127
128 usleep(LISTEN_INTERVAL + SECOND_TO_US);
129 ret = send_socket_ack(arg, fd, ACK_REQ_SYS_SHUTDOWN);
130 if (ret < 0)
131 return 0;
132 start_all_uart_channel_dev_resend(channel, POWEROFF_CMD, VM_SHUTDOWN_RETRY_TIMES);
133 notify_all_connected_uart_channel_dev(channel, POWEROFF_CMD);
134 start_system_shutdown();
135 return 0;
136 }
req_user_vm_shutdown_reboot(void * arg,int fd,char * msg,char * ack_msg)137 static int req_user_vm_shutdown_reboot(void *arg, int fd, char *msg, char *ack_msg)
138 {
139 int ret;
140 struct channel_dev *c_dev = NULL;
141 struct socket_dev *sock = (struct socket_dev *)arg;
142 struct socket_client *client = NULL;
143
144 usleep(LISTEN_INTERVAL + SECOND_TO_US);
145 client = find_socket_client(sock, fd);
146 if (client == NULL)
147 return -1;
148
149 c_dev = find_uart_channel_dev_by_name(channel, client->name);
150 if (c_dev == NULL) {
151 (void) send_socket_ack(arg, fd, USER_VM_DISCONNECT);
152 LOG_PRINTF("Failed to fail to find uart device to communicate with user VM (%s)\n",
153 client->name);
154 return 0;
155 }
156 ret = send_socket_ack(arg, fd, ack_msg);
157 if (ret < 0) {
158 LOG_WRITE("Failed to send ACK by socket\n");
159 return 0;
160 }
161 LOG_PRINTF("Foward (%s) to user VM (%s) by UART\n", msg, c_dev->name);
162 start_uart_channel_dev_resend(c_dev, msg, MIN_RESEND_TIME);
163 ret = send_message_by_uart(c_dev->uart_device, msg, strlen(msg));
164 if (ret < 0)
165 LOG_PRINTF("Failed to foward (%s) to user VM by UART\n", msg);
166 return ret;
167 }
socket_req_user_vm_shutdown_handler(void * arg,int fd)168 int socket_req_user_vm_shutdown_handler(void *arg, int fd)
169 {
170 return req_user_vm_shutdown_reboot(arg, fd, USER_VM_SHUTDOWN, ACK_REQ_USER_VM_SHUTDOWN);
171 }
socket_req_user_vm_reboot_handler(void * arg,int fd)172 int socket_req_user_vm_reboot_handler(void *arg, int fd)
173 {
174 return req_user_vm_shutdown_reboot(arg, fd, USER_VM_REBOOT, ACK_REQ_USER_VM_REBOOT);
175 }
176
req_system_shutdown_reboot(void * arg,int fd,char * msg,char * ack_msg)177 int req_system_shutdown_reboot(void *arg, int fd, char *msg, char *ack_msg)
178 {
179 int ret;
180 struct channel_dev *c_dev = NULL;
181
182 usleep(LISTEN_INTERVAL + SECOND_TO_US);
183 c_dev = (struct channel_dev *)LIST_FIRST(&channel->tty_conn_head);
184 if (c_dev == NULL) {
185 (void) send_socket_ack(arg, fd, USER_VM_DISCONNECT);
186 LOG_WRITE("User VM is disconnect\n");
187 return 0;
188 }
189
190 ret = send_socket_ack(arg, fd, ack_msg);
191 if (ret < 0) {
192 LOG_WRITE("Failed to send ACK by socket\n");
193 return 0;
194 }
195 LOG_PRINTF("Foward (%s) req to service VM by UART\n", msg);
196 start_uart_channel_dev_resend(c_dev, msg, MIN_RESEND_TIME);
197 ret = send_message_by_uart(c_dev->uart_device, msg, strlen(msg));
198 if (ret < 0)
199 LOG_PRINTF("Failed to foward (%s) to service VM by UART\n", msg);
200 return ret;
201 }
202
socket_req_system_reboot_user_vm_handler(void * arg,int fd)203 int socket_req_system_reboot_user_vm_handler(void *arg, int fd)
204 {
205 return req_system_shutdown_reboot(arg, fd, REQ_SYS_REBOOT, ACK_REQ_SYS_REBOOT);
206 }
207
socket_req_system_shutdown_user_vm_handler(void * arg,int fd)208 int socket_req_system_shutdown_user_vm_handler(void *arg, int fd)
209 {
210 return req_system_shutdown_reboot(arg, fd, REQ_SYS_SHUTDOWN, ACK_REQ_SYS_SHUTDOWN);
211 }
212
is_allowed_s5_channel_dev(struct life_mngr_config * conf,struct channel_dev * c_dev)213 static int is_allowed_s5_channel_dev(struct life_mngr_config *conf, struct channel_dev *c_dev)
214 {
215 return strncmp(get_allow_s5_config(conf), get_uart_dev_path(c_dev->uart_device),
216 TTY_PATH_MAX);
217 }
218
is_allowed_sysreboot_channel_dev(struct life_mngr_config * conf,struct channel_dev * c_dev)219 static int is_allowed_sysreboot_channel_dev(struct life_mngr_config *conf, struct channel_dev *c_dev)
220 {
221 return strncmp(get_allow_sysreboot_config(conf), get_uart_dev_path(c_dev->uart_device),
222 TTY_PATH_MAX);
223 }
224
225 /**
226 * @brief The handler of sync command of lifecycle manager in service VM
227 *
228 * @param arg uart channel device instance
229 * @param fd the file directory of the uart which receives message
230 * @return indicate this command is handled successful or not
231 */
sync_cmd_handler(void * arg,int fd)232 int sync_cmd_handler(void *arg, int fd)
233 {
234 struct channel_dev *c_dev = NULL;
235 struct uart_channel *c = (struct uart_channel *)arg;
236
237 c_dev = find_uart_channel_dev(c, fd);
238 if (c_dev == NULL)
239 return 0;
240
241 (void)send_message_by_uart(c_dev->uart_device, ACK_SYNC, strlen(ACK_SYNC));
242 LOG_PRINTF("Receive sync message from user VM (%s), start to talk.\n",
243 c_dev->name);
244 usleep(2 * WAIT_RECV);
245 return 0;
246 }
req_reboot_handler(void * arg,int fd)247 int req_reboot_handler(void *arg, int fd)
248 {
249 int ret;
250 struct channel_dev *c_dev = NULL;
251 struct uart_channel *c = (struct uart_channel *)arg;
252
253 c_dev = find_uart_channel_dev(c, fd);
254 if (c_dev == NULL)
255 return 0;
256
257 if (is_allowed_sysreboot_channel_dev(&life_conf, c_dev)) {
258 LOG_PRINTF("The user VM (%s) is not allowed to trigger system reboot\n",
259 c_dev->name);
260 return 0;
261 }
262 LOG_PRINTF("Receive reboot request from user VM (%s)\n", c_dev->name);
263 ret = send_message_by_uart(c_dev->uart_device, ACK_REQ_SYS_REBOOT,
264 strlen(ACK_REQ_SYS_REBOOT));
265 if (ret < 0)
266 LOG_WRITE("Sending a reboot acknowledgement message to user VM failed.\n");
267 system_reboot_request_flag = true;
268 usleep(SECOND_TO_US);
269 LOG_PRINTF("Send acked shutdown request message to user VM (%s)\n", c_dev->name);
270 start_all_uart_channel_dev_resend(c, POWEROFF_CMD, VM_SHUTDOWN_RETRY_TIMES);
271 notify_all_connected_uart_channel_dev(c, POWEROFF_CMD);
272 usleep(2 * WAIT_RECV);
273 return ret;
274 }
275
276 /**
277 * @brief The handler of system shutdown request command of lifecycle manager in service VM
278 *
279 * @param arg uart channel device instance
280 * @param fd the file directory of the uart which receives message
281 * @return indicate this command is handled successful or not
282 */
req_shutdown_handler(void * arg,int fd)283 int req_shutdown_handler(void *arg, int fd)
284 {
285 int ret;
286 struct channel_dev *c_dev = NULL;
287 struct uart_channel *c = (struct uart_channel *)arg;
288
289 c_dev = find_uart_channel_dev(c, fd);
290 if (c_dev == NULL)
291 return 0;
292
293 if (is_allowed_s5_channel_dev(&life_conf, c_dev)) {
294 LOG_PRINTF("The user VM (%s) is not allowed to trigger system shutdown\n",
295 c_dev->name);
296 return 0;
297 }
298 LOG_PRINTF("Receive shutdown request from user VM (%s)\n", c_dev->name);
299 ret = send_message_by_uart(c_dev->uart_device, ACK_REQ_SYS_SHUTDOWN,
300 strlen(ACK_REQ_SYS_SHUTDOWN));
301 if (ret < 0)
302 LOG_WRITE("Sending a shutdown acknowledgement message to user VM failed.\n");
303 usleep(SECOND_TO_US);
304 LOG_PRINTF("Send acked shutdown request message to user VM (%s)\n", c_dev->name);
305 start_all_uart_channel_dev_resend(c, POWEROFF_CMD, VM_SHUTDOWN_RETRY_TIMES);
306 notify_all_connected_uart_channel_dev(c, POWEROFF_CMD);
307 usleep(2 * WAIT_RECV);
308 return ret;
309 }
310
311 /**
312 * @brief The handler of acked poweroff command of lifecycle manager in service VM
313 *
314 * @param arg uart channel instance
315 * @param fd the file directory of the uart which receives message
316 * @return indicate this command is handled successful or not
317 */
ack_poweroff_handler(void * arg,int fd)318 int ack_poweroff_handler(void *arg, int fd)
319 {
320 struct channel_dev *c_dev = NULL;
321 struct uart_channel *c = (struct uart_channel *)arg;
322
323 c_dev = find_uart_channel_dev(c, fd);
324 if (c_dev == NULL)
325 return 0;
326 LOG_PRINTF("Receive poweroff ACK from user VM (%s)\n", c_dev->name);
327 stop_uart_channel_dev_resend(c_dev);
328 disconnect_uart_channel_dev(c_dev, c);
329 usleep(WAIT_USER_VM_POWEROFF);
330 if (system_reboot_request_flag) {
331 start_system_reboot();
332 } else {
333 start_system_shutdown();
334 }
335 return 0;
336 }
337 /**
338 * @brief The handler of ACK timeout command of lifecycle manager in service VM
339 *
340 * @param arg uart channel instance
341 * @param fd the file directory of the uart which receives message
342 * @return indicate this command is handled successful or not
343 */
ack_timeout_handler(void * arg,int fd)344 int ack_timeout_handler(void *arg, int fd)
345 {
346 struct channel_dev *c_dev = NULL;
347 struct uart_channel *c = (struct uart_channel *)arg;
348
349 c_dev = find_uart_channel_dev(c, fd);
350 if (c_dev == NULL)
351 return 0;
352 if (strncmp(c_dev->resend_buf, POWEROFF_CMD, strlen(POWEROFF_CMD)) == 0)
353 ack_poweroff_handler(arg, fd);
354 else
355 stop_uart_channel_dev_resend(c_dev);
356 return 0;
357 }
ack_user_vm_cmd(void * arg,int fd,char * ack_msg)358 static int ack_user_vm_cmd(void *arg, int fd, char *ack_msg)
359 {
360 struct channel_dev *c_dev = NULL;
361 struct uart_channel *c = (struct uart_channel *)arg;
362
363 c_dev = find_uart_channel_dev(c, fd);
364 if (c_dev == NULL)
365 return 0;
366 LOG_PRINTF("Receive (%s) from user VM (%s)\n", ack_msg, c_dev->name);
367 stop_uart_channel_dev_resend(c_dev);
368 return 0;
369 }
ack_user_vm_shutdown_cmd_handler(void * arg,int fd)370 int ack_user_vm_shutdown_cmd_handler(void *arg, int fd)
371 {
372 return ack_user_vm_cmd(arg, fd, ACK_USER_VM_SHUTDOWN);
373 }
374
ack_user_vm_reboot_cmd_handler(void * arg,int fd)375 int ack_user_vm_reboot_cmd_handler(void *arg, int fd)
376 {
377 return ack_user_vm_cmd(arg, fd, ACK_USER_VM_REBOOT);
378 }
379 /**
380 * @brief The handler of acked sync command of lifecycle manager in user VM
381 *
382 * @param arg uart channel device instance
383 * @param fd the file directory of the uart which receives message
384 * @return indicate this command is handled successful or not
385 */
acked_sync_handler(void * arg,int fd)386 int acked_sync_handler(void *arg, int fd)
387 {
388 struct channel_dev *c_dev = NULL;
389 struct uart_channel *c = (struct uart_channel *)arg;
390
391 c_dev = find_uart_channel_dev(c, fd);
392 if (c_dev == NULL)
393 return 0;
394 LOG_WRITE("Receive acked sync message from service VM\n");
395 return 0;
396 }
397
398 /**
399 * @brief The handler of acked system shutdown request command of lifecycle manager in user VM
400 *
401 * @param arg uart channel instance
402 * @param fd the file directory of the uart which receives message
403 * @return indicate this command is handled successful or not
404 */
acked_req_shutdown_reboot_handler(void * arg,int fd)405 int acked_req_shutdown_reboot_handler(void *arg, int fd)
406 {
407 struct channel_dev *c_dev = NULL;
408 struct uart_channel *c = (struct uart_channel *)arg;
409
410 c_dev = find_uart_channel_dev(c, fd);
411 if (c_dev == NULL)
412 return 0;
413 stop_uart_channel_dev_resend(c_dev);
414 LOG_WRITE("Receive shutdown request ACK from service VM\n");
415 return 0;
416 }
user_vm_shutdown_reboot(struct uart_channel * c,int fd,char * ack,bool reboot)417 static int user_vm_shutdown_reboot(struct uart_channel *c, int fd, char *ack, bool reboot)
418 {
419 int ret;
420 struct channel_dev *c_dev = NULL;
421
422 c_dev = find_uart_channel_dev(c, fd);
423 if (c_dev == NULL)
424 return 0;
425
426 ret = send_message_by_uart(c_dev->uart_device, ack, strlen(ack));
427 if (ret < 0) {
428 LOG_PRINTF("Failed to send (%s) to service VM\n", ack);
429 }
430 disconnect_uart_channel_dev(c_dev, c);
431 usleep(2 * WAIT_RECV);
432 close_socket(sock_server);
433 if (reboot) {
434 user_vm_reboot_flag = true;
435 } else {
436 system_shutdown_flag = true;
437 }
438 return 0;
439 }
440 /**
441 * @brief The handler of poweroff command of lifecycle manager in user VM
442 *
443 * @param arg uart channel device instance
444 * @param fd the file directory of the uart which receives message
445 * @return indicate this command is handled successful or not
446 */
poweroff_cmd_handler(void * arg,int fd)447 int poweroff_cmd_handler(void *arg, int fd)
448 {
449
450 struct uart_channel *c = (struct uart_channel *)arg;
451 (void) user_vm_shutdown_reboot(c, fd, ACK_POWEROFF, false);
452 return 0;
453 }
user_vm_shutdown_cmd_handler(void * arg,int fd)454 int user_vm_shutdown_cmd_handler(void *arg, int fd)
455 {
456 struct uart_channel *c = (struct uart_channel *)arg;
457 (void) user_vm_shutdown_reboot(c, fd, ACK_USER_VM_SHUTDOWN, false);
458 return 0;
459 }
user_vm_reboot_cmd_handler(void * arg,int fd)460 int user_vm_reboot_cmd_handler(void *arg, int fd)
461 {
462 struct uart_channel *c = (struct uart_channel *)arg;
463 (void) user_vm_shutdown_reboot(c, fd, ACK_USER_VM_REBOOT, true);
464 return 0;
465 }
466 /**
467 * @brief The handler of ACK timeout command of lifecycle manager in user VM
468 *
469 * @param arg uart channel instance
470 * @param fd the file directory of the uart which receives message
471 * @return indicate this command is handled successful or not
472 */
ack_timeout_default_handler(void * arg,int fd)473 int ack_timeout_default_handler(void *arg, int fd)
474 {
475 struct channel_dev *c_dev = NULL;
476 struct uart_channel *c = (struct uart_channel *)arg;
477
478 c_dev = find_uart_channel_dev(c, fd);
479 if (c_dev == NULL)
480 return 0;
481 stop_uart_channel_dev_resend(c_dev);
482 disconnect_uart_channel_dev(c_dev, c);
483 close_socket(sock_server);
484 LOG_PRINTF("Failed to receive ACK message from service VM (fd = %d)\n", fd);
485 return 0;
486 }
487