1e258e51fSNinad Palsule /**
2e258e51fSNinad Palsule * Copyright © 2023 IBM Corporation
3e258e51fSNinad Palsule *
4e258e51fSNinad Palsule * Licensed under the Apache License, Version 2.0 (the "License");
5e258e51fSNinad Palsule * you may not use this file except in compliance with the License.
6e258e51fSNinad Palsule * You may obtain a copy of the License at
7e258e51fSNinad Palsule *
8e258e51fSNinad Palsule * http://www.apache.org/licenses/LICENSE-2.0
9e258e51fSNinad Palsule *
10e258e51fSNinad Palsule * Unless required by applicable law or agreed to in writing, software
11e258e51fSNinad Palsule * distributed under the License is distributed on an "AS IS" BASIS,
12e258e51fSNinad Palsule * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e258e51fSNinad Palsule * See the License for the specific language governing permissions and
14e258e51fSNinad Palsule * limitations under the License.
15e258e51fSNinad Palsule */
16e258e51fSNinad Palsule
1730ea6385SAndrew Jeffery #include <assert.h>
18e258e51fSNinad Palsule #include <errno.h>
19e258e51fSNinad Palsule #include <err.h>
20bd992c9fSNinad Palsule #include <string.h>
21bd992c9fSNinad Palsule #include <sys/socket.h>
22e258e51fSNinad Palsule
231e04f449SAlexander Hansen #include "config.h"
24*a6b29104SAlexander Hansen #include "console-mux.h"
25*a6b29104SAlexander Hansen #include "console-server.h"
26e258e51fSNinad Palsule
27e258e51fSNinad Palsule /* size of the dbus object path length */
28e258e51fSNinad Palsule const size_t dbus_obj_path_len = 1024;
29e258e51fSNinad Palsule
30e258e51fSNinad Palsule #define DBUS_ERR "org.openbmc.error"
31e258e51fSNinad Palsule #define DBUS_NAME "xyz.openbmc_project.Console.%s"
32e258e51fSNinad Palsule #define OBJ_NAME "/xyz/openbmc_project/console/%s"
339598b866SJonathan Doman #define UART_INTF "xyz.openbmc_project.Console.UART"
34b14ca19cSNinad Palsule #define ACCESS_INTF "xyz.openbmc_project.Console.Access"
35e258e51fSNinad Palsule
tty_change_baudrate(struct console * console)36e258e51fSNinad Palsule static void tty_change_baudrate(struct console *console)
37e258e51fSNinad Palsule {
38e258e51fSNinad Palsule int i;
39e258e51fSNinad Palsule int rc;
40e258e51fSNinad Palsule
41c2b0d8c7SAlexander Hansen tty_init_termios(console->server);
42e258e51fSNinad Palsule
43e258e51fSNinad Palsule for (i = 0; i < console->n_handlers; i++) {
44e2826c7dSJeremy Kerr const struct handler_type *type;
45e2826c7dSJeremy Kerr struct handler *handler;
46e2826c7dSJeremy Kerr
47e258e51fSNinad Palsule handler = console->handlers[i];
48e2826c7dSJeremy Kerr type = handler->type;
49e2826c7dSJeremy Kerr if (!type->baudrate) {
50e258e51fSNinad Palsule continue;
51e258e51fSNinad Palsule }
52e258e51fSNinad Palsule
53c2b0d8c7SAlexander Hansen rc = type->baudrate(handler, console->server->tty.uart.baud);
54e258e51fSNinad Palsule if (rc) {
55e258e51fSNinad Palsule warnx("Can't set terminal baudrate for handler %s",
56e2826c7dSJeremy Kerr type->name);
57e258e51fSNinad Palsule }
58e258e51fSNinad Palsule }
59e258e51fSNinad Palsule }
60e258e51fSNinad Palsule
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)619598b866SJonathan Doman static int set_baud_handler(sd_bus *bus, const char *path,
629598b866SJonathan Doman const char *interface, const char *property,
639598b866SJonathan Doman sd_bus_message *msg, void *userdata,
649598b866SJonathan Doman sd_bus_error *err __attribute__((unused)))
659598b866SJonathan Doman {
669598b866SJonathan Doman struct console *console = userdata;
679598b866SJonathan Doman uint64_t baudrate;
689598b866SJonathan Doman speed_t speed;
699598b866SJonathan Doman int r;
709598b866SJonathan Doman
719598b866SJonathan Doman if (!console) {
729598b866SJonathan Doman return -ENOENT;
739598b866SJonathan Doman }
749598b866SJonathan Doman
759598b866SJonathan Doman r = sd_bus_message_read(msg, "t", &baudrate);
769598b866SJonathan Doman if (r < 0 || baudrate > UINT32_MAX) {
779598b866SJonathan Doman return -EINVAL;
789598b866SJonathan Doman }
799598b866SJonathan Doman
809598b866SJonathan Doman speed = parse_int_to_baud((uint32_t)baudrate);
819598b866SJonathan Doman if (!speed) {
829598b866SJonathan Doman warnx("Invalid baud rate: '%" PRIu64 "'", baudrate);
839598b866SJonathan Doman return -EINVAL;
849598b866SJonathan Doman }
859598b866SJonathan Doman
86c2b0d8c7SAlexander Hansen assert(console->server->tty.type == TTY_DEVICE_UART);
87c2b0d8c7SAlexander Hansen console->server->tty.uart.baud = speed;
889598b866SJonathan Doman tty_change_baudrate(console);
899598b866SJonathan Doman
909598b866SJonathan Doman sd_bus_emit_properties_changed(bus, path, interface, property, NULL);
919598b866SJonathan Doman
929598b866SJonathan Doman return 1;
939598b866SJonathan Doman }
949598b866SJonathan Doman
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)959598b866SJonathan Doman static int get_baud_handler(sd_bus *bus __attribute__((unused)),
969598b866SJonathan Doman const char *path __attribute__((unused)),
979598b866SJonathan Doman const char *interface __attribute__((unused)),
989598b866SJonathan Doman const char *property __attribute__((unused)),
999598b866SJonathan Doman sd_bus_message *reply, void *userdata,
1009598b866SJonathan Doman sd_bus_error *error __attribute__((unused)))
1019598b866SJonathan Doman {
1029598b866SJonathan Doman struct console *console = userdata;
103c2b0d8c7SAlexander Hansen struct console_server *server = console->server;
1049598b866SJonathan Doman uint64_t baudrate;
1059598b866SJonathan Doman int r;
1069598b866SJonathan Doman
107c2b0d8c7SAlexander Hansen assert(server->tty.type == TTY_DEVICE_UART);
108c2b0d8c7SAlexander Hansen baudrate = parse_baud_to_int(server->tty.uart.baud);
1099598b866SJonathan Doman if (!baudrate) {
110c2b0d8c7SAlexander Hansen warnx("Invalid baud rate: '%d'", server->tty.uart.baud);
1119598b866SJonathan Doman }
1129598b866SJonathan Doman
1139598b866SJonathan Doman r = sd_bus_message_append(reply, "t", baudrate);
1149598b866SJonathan Doman
1159598b866SJonathan Doman return r;
1169598b866SJonathan Doman }
1179598b866SJonathan Doman
method_connect(sd_bus_message * msg,void * userdata,sd_bus_error * err)118bd992c9fSNinad Palsule static int method_connect(sd_bus_message *msg, void *userdata,
119bd992c9fSNinad Palsule sd_bus_error *err)
120b14ca19cSNinad Palsule {
121b14ca19cSNinad Palsule struct console *console = userdata;
122bd992c9fSNinad Palsule int rc;
123bd992c9fSNinad Palsule int socket_fd = -1;
124b14ca19cSNinad Palsule
125bd992c9fSNinad Palsule if (!console) {
126bd992c9fSNinad Palsule warnx("Internal error: Console pointer is null");
127bd992c9fSNinad Palsule sd_bus_error_set_const(err, DBUS_ERR, "Internal error");
128bd992c9fSNinad Palsule return sd_bus_reply_method_error(msg, err);
129bd992c9fSNinad Palsule }
130bd992c9fSNinad Palsule
131*a6b29104SAlexander Hansen console_mux_activate(console);
132*a6b29104SAlexander Hansen
133bd992c9fSNinad Palsule /* Register the consumer. */
134bd992c9fSNinad Palsule socket_fd = dbus_create_socket_consumer(console);
135bd992c9fSNinad Palsule if (socket_fd < 0) {
136bd992c9fSNinad Palsule rc = socket_fd;
137bd992c9fSNinad Palsule warnx("Failed to create socket consumer: %s", strerror(rc));
138bd992c9fSNinad Palsule sd_bus_error_set_const(err, DBUS_ERR,
139bd992c9fSNinad Palsule "Failed to create socket consumer");
140bd992c9fSNinad Palsule return sd_bus_reply_method_error(msg, err);
141bd992c9fSNinad Palsule }
142bd992c9fSNinad Palsule
143bd992c9fSNinad Palsule rc = sd_bus_reply_method_return(msg, "h", socket_fd);
144bd992c9fSNinad Palsule
145bd992c9fSNinad Palsule /* Close the our end */
146bd992c9fSNinad Palsule close(socket_fd);
147bd992c9fSNinad Palsule
148bd992c9fSNinad Palsule return rc;
149b14ca19cSNinad Palsule }
150b14ca19cSNinad Palsule
1519598b866SJonathan Doman static const sd_bus_vtable console_uart_vtable[] = {
1529598b866SJonathan Doman SD_BUS_VTABLE_START(0),
1539598b866SJonathan Doman SD_BUS_WRITABLE_PROPERTY("Baud", "t", get_baud_handler,
1549598b866SJonathan Doman set_baud_handler, 0,
1559598b866SJonathan Doman SD_BUS_VTABLE_UNPRIVILEGED |
1569598b866SJonathan Doman SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1579598b866SJonathan Doman SD_BUS_VTABLE_END,
1589598b866SJonathan Doman };
1599598b866SJonathan Doman
160b14ca19cSNinad Palsule static const sd_bus_vtable console_access_vtable[] = {
161b14ca19cSNinad Palsule SD_BUS_VTABLE_START(0),
162bd992c9fSNinad Palsule SD_BUS_METHOD("Connect", SD_BUS_NO_ARGS, "h", method_connect,
163bd992c9fSNinad Palsule SD_BUS_VTABLE_UNPRIVILEGED),
164b14ca19cSNinad Palsule SD_BUS_VTABLE_END,
165b14ca19cSNinad Palsule };
166b14ca19cSNinad Palsule
dbus_server_init(struct console_server * server)167312ecdc2SAlexander Hansen int dbus_server_init(struct console_server *server)
168312ecdc2SAlexander Hansen {
169312ecdc2SAlexander Hansen int r;
170312ecdc2SAlexander Hansen int fd;
171312ecdc2SAlexander Hansen r = sd_bus_default(&server->bus);
172312ecdc2SAlexander Hansen if (r < 0) {
173312ecdc2SAlexander Hansen warnx("Failed to connect to bus: %s", strerror(-r));
174312ecdc2SAlexander Hansen return -1;
175312ecdc2SAlexander Hansen }
176312ecdc2SAlexander Hansen
177312ecdc2SAlexander Hansen fd = sd_bus_get_fd(server->bus);
178312ecdc2SAlexander Hansen if (fd < 0) {
179312ecdc2SAlexander Hansen warnx("Couldn't get the bus file descriptor");
180312ecdc2SAlexander Hansen sd_bus_unref(server->bus);
181312ecdc2SAlexander Hansen return -1;
182312ecdc2SAlexander Hansen }
183312ecdc2SAlexander Hansen
184312ecdc2SAlexander Hansen const ssize_t index = console_server_request_pollfd(server, fd, POLLIN);
185312ecdc2SAlexander Hansen if (index < 0) {
186312ecdc2SAlexander Hansen warnx("Error: failed to allocate pollfd");
187312ecdc2SAlexander Hansen sd_bus_unref(server->bus);
188312ecdc2SAlexander Hansen return -1;
189312ecdc2SAlexander Hansen }
190312ecdc2SAlexander Hansen
191312ecdc2SAlexander Hansen server->dbus_pollfd_index = index;
192312ecdc2SAlexander Hansen return 0;
193312ecdc2SAlexander Hansen }
194312ecdc2SAlexander Hansen
dbus_server_fini(struct console_server * server)195312ecdc2SAlexander Hansen void dbus_server_fini(struct console_server *server)
196312ecdc2SAlexander Hansen {
197312ecdc2SAlexander Hansen if (server->dbus_pollfd_index < server->capacity_pollfds) {
198312ecdc2SAlexander Hansen console_server_release_pollfd(server,
199312ecdc2SAlexander Hansen server->dbus_pollfd_index);
200312ecdc2SAlexander Hansen server->dbus_pollfd_index = SIZE_MAX;
201312ecdc2SAlexander Hansen }
202312ecdc2SAlexander Hansen
203312ecdc2SAlexander Hansen sd_bus_unref(server->bus);
204312ecdc2SAlexander Hansen }
205312ecdc2SAlexander Hansen
dbus_init(struct console * console,struct config * config)206498a4a81SAndrew Jeffery int dbus_init(struct console *console,
207e258e51fSNinad Palsule struct config *config __attribute__((unused)))
208e258e51fSNinad Palsule {
209e258e51fSNinad Palsule char obj_name[dbus_obj_path_len];
210e258e51fSNinad Palsule char dbus_name[dbus_obj_path_len];
211e258e51fSNinad Palsule int r;
212e258e51fSNinad Palsule size_t bytes;
213e258e51fSNinad Palsule
214e258e51fSNinad Palsule if (!console) {
215e258e51fSNinad Palsule warnx("Couldn't get valid console");
216498a4a81SAndrew Jeffery return -1;
217e258e51fSNinad Palsule }
218e258e51fSNinad Palsule
219e258e51fSNinad Palsule /* Register support console interface */
220e258e51fSNinad Palsule bytes = snprintf(obj_name, dbus_obj_path_len, OBJ_NAME,
221e258e51fSNinad Palsule console->console_id);
222e258e51fSNinad Palsule if (bytes >= dbus_obj_path_len) {
223e258e51fSNinad Palsule warnx("Console id '%s' is too long. There is no enough space in the buffer.",
224e258e51fSNinad Palsule console->console_id);
225498a4a81SAndrew Jeffery return -1;
226e258e51fSNinad Palsule }
227e258e51fSNinad Palsule
228c2b0d8c7SAlexander Hansen if (console->server->tty.type == TTY_DEVICE_UART) {
2299598b866SJonathan Doman /* Register UART interface */
230312ecdc2SAlexander Hansen r = sd_bus_add_object_vtable(console->server->bus, NULL,
231312ecdc2SAlexander Hansen obj_name, UART_INTF,
232312ecdc2SAlexander Hansen console_uart_vtable, console);
2339598b866SJonathan Doman if (r < 0) {
2349598b866SJonathan Doman warnx("Failed to register UART interface: %s",
2359598b866SJonathan Doman strerror(-r));
236498a4a81SAndrew Jeffery return -1;
2379598b866SJonathan Doman }
23830ea6385SAndrew Jeffery }
239b14ca19cSNinad Palsule
240b14ca19cSNinad Palsule /* Register access interface */
241312ecdc2SAlexander Hansen r = sd_bus_add_object_vtable(console->server->bus, NULL, obj_name,
242312ecdc2SAlexander Hansen ACCESS_INTF, console_access_vtable,
243312ecdc2SAlexander Hansen console);
244e258e51fSNinad Palsule if (r < 0) {
245e258e51fSNinad Palsule warnx("Failed to issue method call: %s", strerror(-r));
246498a4a81SAndrew Jeffery return -1;
247e258e51fSNinad Palsule }
248e258e51fSNinad Palsule
249e258e51fSNinad Palsule bytes = snprintf(dbus_name, dbus_obj_path_len, DBUS_NAME,
250e258e51fSNinad Palsule console->console_id);
251e258e51fSNinad Palsule if (bytes >= dbus_obj_path_len) {
252e258e51fSNinad Palsule warnx("Console id '%s' is too long. There is no enough space in the buffer.",
253e258e51fSNinad Palsule console->console_id);
254498a4a81SAndrew Jeffery return -1;
255e258e51fSNinad Palsule }
256e258e51fSNinad Palsule
257b14ca19cSNinad Palsule /* Finally register the bus name */
258312ecdc2SAlexander Hansen r = sd_bus_request_name(console->server->bus, dbus_name,
259e258e51fSNinad Palsule SD_BUS_NAME_ALLOW_REPLACEMENT |
260e258e51fSNinad Palsule SD_BUS_NAME_REPLACE_EXISTING);
261e258e51fSNinad Palsule if (r < 0) {
262e258e51fSNinad Palsule warnx("Failed to acquire service name: %s", strerror(-r));
263498a4a81SAndrew Jeffery return -1;
264e258e51fSNinad Palsule }
265e258e51fSNinad Palsule
266498a4a81SAndrew Jeffery return 0;
267e258e51fSNinad Palsule }
268