1 /*
2  * Copyright (C) 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 <cjson/cJSON.h>
15 #include "command.h"
16 #include "socket.h"
17 #include "command_handler.h"
18 #include "dm.h"
19 #include "pm.h"
20 #include "vmmapi.h"
21 #include "log.h"
22 #include "monitor.h"
23 
24 #define SUCCEEDED 0
25 #define FAILED -1
26 
generate_ack_message(int ret_val)27 static char *generate_ack_message(int ret_val)
28 {
29 	char *ack_msg;
30 	cJSON *val;
31 	cJSON *ret_obj = cJSON_CreateObject();
32 
33 	if (ret_obj == NULL)
34 		return NULL;
35 	val = cJSON_CreateNumber(ret_val);
36 	if (val == NULL)
37 		return NULL;
38 	cJSON_AddItemToObject(ret_obj, "ack", val);
39 	ack_msg = cJSON_Print(ret_obj);
40 	if (ack_msg == NULL)
41 		fprintf(stderr, "Failed to generate ACK message.\n");
42 	cJSON_Delete(ret_obj);
43 	return ack_msg;
44 }
send_socket_ack(struct socket_dev * sock,int fd,bool normal)45 static int send_socket_ack(struct socket_dev *sock, int fd, bool normal)
46 {
47 	int ret = 0, val;
48 	char *ack_message;
49 	struct socket_client *client = NULL;
50 
51 	client = find_socket_client(sock, fd);
52 	if (client == NULL)
53 		return -1;
54 	val = normal ? SUCCEEDED : FAILED;
55 	ack_message = generate_ack_message(val);
56 
57 	if (ack_message != NULL) {
58 		memset(client->buf, 0, CLIENT_BUF_LEN);
59 		memcpy(client->buf, ack_message, strlen(ack_message));
60 		client->len = strlen(ack_message);
61 		ret = write_socket_char(client);
62 		free(ack_message);
63 	} else {
64 		pr_err("Failed to generate ACK message.\n");
65 		ret = -1;
66 	}
67 	return ret;
68 }
69 
70 static struct socket_client *vm_event_client = NULL;
71 static pthread_mutex_t vm_event_client_mutex = PTHREAD_MUTEX_INITIALIZER;
72 
vm_event_free_cb(struct socket_client * self)73 static void vm_event_free_cb(struct socket_client *self)
74 {
75 	vm_event_client = NULL;
76 }
77 
set_vm_event_client(struct socket_client * client)78 static int set_vm_event_client(struct socket_client *client)
79 {
80 	if (vm_event_client != NULL) {
81 		pr_err("vm event client already registerred.\n");
82 		return -1;
83 	} else {
84 		vm_event_client = client;
85 		client->per_client_mutex = &vm_event_client_mutex;
86 		client->free_client_cb = vm_event_free_cb;
87 		return 0;
88 	}
89 }
90 
vm_monitor_send_vm_event(const char * msg)91 int vm_monitor_send_vm_event(const char *msg)
92 {
93 	int ret = -1;
94 	struct socket_client *client;
95 	pthread_mutex_t *per_client_mutex = &vm_event_client_mutex;
96 
97 	pthread_mutex_lock(per_client_mutex);
98 	client = vm_event_client;
99 	if (msg == NULL || client == NULL) {
100 		pthread_mutex_unlock(per_client_mutex);
101 		return -1;
102 	}
103 	memset(client->buf, 0, CLIENT_BUF_LEN);
104 	memcpy(client->buf, msg, strlen(msg));
105 	client->len = strlen(msg);
106 	ret = write_socket_char(client);
107 	pthread_mutex_unlock(per_client_mutex);
108 	return ret;
109 }
110 
111 /* When a client issues the REGISTER_VM_EVENT_CLIENT command,
112  * this handler will register that client as this VM's only vm_event receiver,
113  * and keeps the socket connection. Then vm events will be sent to
114  * the client through this connection.
115  */
user_vm_register_vm_event_client_handler(void * arg,void * command_para)116 int user_vm_register_vm_event_client_handler(void *arg, void *command_para)
117 {
118 	int ret;
119 	struct command_parameters *cmd_para = (struct command_parameters *)command_para;
120 	struct handler_args *hdl_arg = (struct handler_args *)arg;
121 	struct socket_dev *sock = (struct socket_dev *)hdl_arg->channel_arg;
122 	struct socket_client *client = NULL;
123 	bool cmd_completed = false;
124 
125 	client = find_socket_client(sock, cmd_para->fd);
126 	if (client == NULL)
127 		return -1;
128 
129 	if (set_vm_event_client(client) == 0) {
130 		cmd_completed = true;
131 	}
132 
133 	pr_dbg("%s: client with fd %d registerred\n", __func__, client->fd);
134 
135 	ret = send_socket_ack(sock, cmd_para->fd, cmd_completed);
136 	if (ret < 0) {
137 		pr_err("%s: Failed to send ACK message by socket.\n", __func__);
138 	}
139 	return ret;
140 }
141 
user_vm_destroy_handler(void * arg,void * command_para)142 int user_vm_destroy_handler(void *arg, void *command_para)
143 {
144 	int ret;
145 	struct command_parameters *cmd_para = (struct command_parameters *)command_para;
146 	struct handler_args *hdl_arg = (struct handler_args *)arg;
147 	struct socket_dev *sock = (struct socket_dev *)hdl_arg->channel_arg;
148 	struct socket_client *client = NULL;
149 	bool cmd_completed = false;
150 
151 	client = find_socket_client(sock, cmd_para->fd);
152 	if (client == NULL)
153 		return -1;
154 
155 	if (!is_rtvm) {
156 		pr_info("%s: setting VM state to %s.\n", __func__, vm_state_to_str(VM_SUSPEND_POWEROFF));
157 		vm_set_suspend_mode(VM_SUSPEND_POWEROFF);
158 		cmd_completed = true;
159 	} else {
160 		pr_err("Failed to destroy post-launched RTVM.\n");
161 		ret = -1;
162 	}
163 
164 	ret = send_socket_ack(sock, cmd_para->fd, cmd_completed);
165 	if (ret < 0) {
166 		pr_err("Failed to send ACK message by socket.\n");
167 	}
168 	return ret;
169 }
170 
user_vm_blkrescan_handler(void * arg,void * command_para)171 int user_vm_blkrescan_handler(void *arg, void *command_para)
172 {
173 	int ret = 0;
174 	struct command_parameters *cmd_para = (struct command_parameters *)command_para;
175 	struct handler_args *hdl_arg = (struct handler_args *)arg;
176 	struct socket_dev *sock = (struct socket_dev *)hdl_arg->channel_arg;
177 	struct socket_client *client = NULL;
178 	bool cmd_completed = false;
179 
180 	client = find_socket_client(sock, cmd_para->fd);
181 	if (client == NULL)
182 		return -1;
183 
184 	ret = vm_monitor_blkrescan(hdl_arg->ctx_arg, cmd_para->option);
185 	if (ret >= 0) {
186 		cmd_completed = true;
187 	} else {
188 		pr_err("Failed to rescan virtio-blk device.\n");
189 	}
190 
191 	ret = send_socket_ack(sock, cmd_para->fd, cmd_completed);
192 	if (ret < 0) {
193 		pr_err("Failed to send ACK by socket.\n");
194 	}
195 	return ret;
196 }
197