xref: /openbmc/obmc-console/console-dbus.c (revision a6b29104)
1 /**
2  * Copyright © 2023 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <assert.h>
18 #include <errno.h>
19 #include <err.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 
23 #include "config.h"
24 #include "console-mux.h"
25 #include "console-server.h"
26 
27 /* size of the dbus object path length */
28 const size_t dbus_obj_path_len = 1024;
29 
30 #define DBUS_ERR    "org.openbmc.error"
31 #define DBUS_NAME   "xyz.openbmc_project.Console.%s"
32 #define OBJ_NAME    "/xyz/openbmc_project/console/%s"
33 #define UART_INTF   "xyz.openbmc_project.Console.UART"
34 #define ACCESS_INTF "xyz.openbmc_project.Console.Access"
35 
tty_change_baudrate(struct console * console)36 static void tty_change_baudrate(struct console *console)
37 {
38 	int i;
39 	int rc;
40 
41 	tty_init_termios(console->server);
42 
43 	for (i = 0; i < console->n_handlers; i++) {
44 		const struct handler_type *type;
45 		struct handler *handler;
46 
47 		handler = console->handlers[i];
48 		type = handler->type;
49 		if (!type->baudrate) {
50 			continue;
51 		}
52 
53 		rc = type->baudrate(handler, console->server->tty.uart.baud);
54 		if (rc) {
55 			warnx("Can't set terminal baudrate for handler %s",
56 			      type->name);
57 		}
58 	}
59 }
60 
set_baud_handler(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * msg,void * userdata,sd_bus_error * err)61 static int set_baud_handler(sd_bus *bus, const char *path,
62 			    const char *interface, const char *property,
63 			    sd_bus_message *msg, void *userdata,
64 			    sd_bus_error *err __attribute__((unused)))
65 {
66 	struct console *console = userdata;
67 	uint64_t baudrate;
68 	speed_t speed;
69 	int r;
70 
71 	if (!console) {
72 		return -ENOENT;
73 	}
74 
75 	r = sd_bus_message_read(msg, "t", &baudrate);
76 	if (r < 0 || baudrate > UINT32_MAX) {
77 		return -EINVAL;
78 	}
79 
80 	speed = parse_int_to_baud((uint32_t)baudrate);
81 	if (!speed) {
82 		warnx("Invalid baud rate: '%" PRIu64 "'", baudrate);
83 		return -EINVAL;
84 	}
85 
86 	assert(console->server->tty.type == TTY_DEVICE_UART);
87 	console->server->tty.uart.baud = speed;
88 	tty_change_baudrate(console);
89 
90 	sd_bus_emit_properties_changed(bus, path, interface, property, NULL);
91 
92 	return 1;
93 }
94 
get_baud_handler(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)95 static int get_baud_handler(sd_bus *bus __attribute__((unused)),
96 			    const char *path __attribute__((unused)),
97 			    const char *interface __attribute__((unused)),
98 			    const char *property __attribute__((unused)),
99 			    sd_bus_message *reply, void *userdata,
100 			    sd_bus_error *error __attribute__((unused)))
101 {
102 	struct console *console = userdata;
103 	struct console_server *server = console->server;
104 	uint64_t baudrate;
105 	int r;
106 
107 	assert(server->tty.type == TTY_DEVICE_UART);
108 	baudrate = parse_baud_to_int(server->tty.uart.baud);
109 	if (!baudrate) {
110 		warnx("Invalid baud rate: '%d'", server->tty.uart.baud);
111 	}
112 
113 	r = sd_bus_message_append(reply, "t", baudrate);
114 
115 	return r;
116 }
117 
method_connect(sd_bus_message * msg,void * userdata,sd_bus_error * err)118 static int method_connect(sd_bus_message *msg, void *userdata,
119 			  sd_bus_error *err)
120 {
121 	struct console *console = userdata;
122 	int rc;
123 	int socket_fd = -1;
124 
125 	if (!console) {
126 		warnx("Internal error: Console pointer is null");
127 		sd_bus_error_set_const(err, DBUS_ERR, "Internal error");
128 		return sd_bus_reply_method_error(msg, err);
129 	}
130 
131 	console_mux_activate(console);
132 
133 	/* Register the consumer. */
134 	socket_fd = dbus_create_socket_consumer(console);
135 	if (socket_fd < 0) {
136 		rc = socket_fd;
137 		warnx("Failed to create socket consumer: %s", strerror(rc));
138 		sd_bus_error_set_const(err, DBUS_ERR,
139 				       "Failed to create socket consumer");
140 		return sd_bus_reply_method_error(msg, err);
141 	}
142 
143 	rc = sd_bus_reply_method_return(msg, "h", socket_fd);
144 
145 	/* Close the our end */
146 	close(socket_fd);
147 
148 	return rc;
149 }
150 
151 static const sd_bus_vtable console_uart_vtable[] = {
152 	SD_BUS_VTABLE_START(0),
153 	SD_BUS_WRITABLE_PROPERTY("Baud", "t", get_baud_handler,
154 				 set_baud_handler, 0,
155 				 SD_BUS_VTABLE_UNPRIVILEGED |
156 					 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
157 	SD_BUS_VTABLE_END,
158 };
159 
160 static const sd_bus_vtable console_access_vtable[] = {
161 	SD_BUS_VTABLE_START(0),
162 	SD_BUS_METHOD("Connect", SD_BUS_NO_ARGS, "h", method_connect,
163 		      SD_BUS_VTABLE_UNPRIVILEGED),
164 	SD_BUS_VTABLE_END,
165 };
166 
dbus_server_init(struct console_server * server)167 int dbus_server_init(struct console_server *server)
168 {
169 	int r;
170 	int fd;
171 	r = sd_bus_default(&server->bus);
172 	if (r < 0) {
173 		warnx("Failed to connect to bus: %s", strerror(-r));
174 		return -1;
175 	}
176 
177 	fd = sd_bus_get_fd(server->bus);
178 	if (fd < 0) {
179 		warnx("Couldn't get the bus file descriptor");
180 		sd_bus_unref(server->bus);
181 		return -1;
182 	}
183 
184 	const ssize_t index = console_server_request_pollfd(server, fd, POLLIN);
185 	if (index < 0) {
186 		warnx("Error: failed to allocate pollfd");
187 		sd_bus_unref(server->bus);
188 		return -1;
189 	}
190 
191 	server->dbus_pollfd_index = index;
192 	return 0;
193 }
194 
dbus_server_fini(struct console_server * server)195 void dbus_server_fini(struct console_server *server)
196 {
197 	if (server->dbus_pollfd_index < server->capacity_pollfds) {
198 		console_server_release_pollfd(server,
199 					      server->dbus_pollfd_index);
200 		server->dbus_pollfd_index = SIZE_MAX;
201 	}
202 
203 	sd_bus_unref(server->bus);
204 }
205 
dbus_init(struct console * console,struct config * config)206 int dbus_init(struct console *console,
207 	      struct config *config __attribute__((unused)))
208 {
209 	char obj_name[dbus_obj_path_len];
210 	char dbus_name[dbus_obj_path_len];
211 	int r;
212 	size_t bytes;
213 
214 	if (!console) {
215 		warnx("Couldn't get valid console");
216 		return -1;
217 	}
218 
219 	/* Register support console interface */
220 	bytes = snprintf(obj_name, dbus_obj_path_len, OBJ_NAME,
221 			 console->console_id);
222 	if (bytes >= dbus_obj_path_len) {
223 		warnx("Console id '%s' is too long. There is no enough space in the buffer.",
224 		      console->console_id);
225 		return -1;
226 	}
227 
228 	if (console->server->tty.type == TTY_DEVICE_UART) {
229 		/* Register UART interface */
230 		r = sd_bus_add_object_vtable(console->server->bus, NULL,
231 					     obj_name, UART_INTF,
232 					     console_uart_vtable, console);
233 		if (r < 0) {
234 			warnx("Failed to register UART interface: %s",
235 			      strerror(-r));
236 			return -1;
237 		}
238 	}
239 
240 	/* Register access interface */
241 	r = sd_bus_add_object_vtable(console->server->bus, NULL, obj_name,
242 				     ACCESS_INTF, console_access_vtable,
243 				     console);
244 	if (r < 0) {
245 		warnx("Failed to issue method call: %s", strerror(-r));
246 		return -1;
247 	}
248 
249 	bytes = snprintf(dbus_name, dbus_obj_path_len, DBUS_NAME,
250 			 console->console_id);
251 	if (bytes >= dbus_obj_path_len) {
252 		warnx("Console id '%s' is too long. There is no enough space in the buffer.",
253 		      console->console_id);
254 		return -1;
255 	}
256 
257 	/* Finally register the bus name */
258 	r = sd_bus_request_name(console->server->bus, dbus_name,
259 				SD_BUS_NAME_ALLOW_REPLACEMENT |
260 					SD_BUS_NAME_REPLACE_EXISTING);
261 	if (r < 0) {
262 		warnx("Failed to acquire service name: %s", strerror(-r));
263 		return -1;
264 	}
265 
266 	return 0;
267 }
268