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 21 #include "console-server.h" 22 23 /* size of the dbus object path length */ 24 const size_t dbus_obj_path_len = 1024; 25 26 #define DBUS_ERR "org.openbmc.error" 27 #define DBUS_NAME "xyz.openbmc_project.Console.%s" 28 #define OBJ_NAME "/xyz/openbmc_project/console/%s" 29 #define TTY_INTF "xyz.openbmc_project.console" 30 #define ACCESS_INTF "xyz.openbmc_project.Console.Access" 31 32 static void tty_change_baudrate(struct console *console) 33 { 34 struct handler *handler; 35 int i; 36 int rc; 37 38 tty_init_termios(console); 39 40 for (i = 0; i < console->n_handlers; i++) { 41 handler = console->handlers[i]; 42 if (!handler->baudrate) { 43 continue; 44 } 45 46 rc = handler->baudrate(handler, console->tty.uart.baud); 47 if (rc) { 48 warnx("Can't set terminal baudrate for handler %s", 49 handler->name); 50 } 51 } 52 } 53 54 static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 55 sd_bus_error *err) 56 { 57 struct console *console = userdata; 58 uint32_t baudrate; 59 speed_t speed; 60 int r; 61 62 if (!console) { 63 sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 64 return sd_bus_reply_method_return(msg, "x", 0); 65 } 66 67 r = sd_bus_message_read(msg, "u", &baudrate); 68 if (r < 0) { 69 sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 70 return sd_bus_reply_method_return(msg, "x", -EINVAL); 71 } 72 73 speed = parse_int_to_baud(baudrate); 74 if (!speed) { 75 warnx("Invalid baud rate: '%u'", baudrate); 76 return sd_bus_reply_method_return(msg, "x", -EINVAL); 77 } 78 79 assert(console->tty.type == TTY_DEVICE_UART); 80 console->tty.uart.baud = speed; 81 tty_change_baudrate(console); 82 83 return sd_bus_reply_method_return(msg, "x", r); 84 } 85 86 static int get_handler(sd_bus *bus __attribute__((unused)), 87 const char *path __attribute__((unused)), 88 const char *interface __attribute__((unused)), 89 const char *property __attribute__((unused)), 90 sd_bus_message *reply, void *userdata, 91 sd_bus_error *error __attribute__((unused))) 92 { 93 struct console *console = userdata; 94 uint32_t baudrate; 95 int r; 96 97 assert(console->tty.type == TTY_DEVICE_UART); 98 baudrate = parse_baud_to_int(console->tty.uart.baud); 99 if (!baudrate) { 100 warnx("Invalid baud rate: '%d'", console->tty.uart.baud); 101 } 102 103 r = sd_bus_message_append(reply, "u", baudrate); 104 105 return r; 106 } 107 108 static int get_socket_name(sd_bus *bus __attribute__((unused)), 109 const char *path __attribute__((unused)), 110 const char *interface __attribute__((unused)), 111 const char *property __attribute__((unused)), 112 sd_bus_message *reply, void *userdata, 113 sd_bus_error *error __attribute__((unused))) 114 { 115 struct console *console = userdata; 116 117 /* The abstract socket name starts with null character hence we need to 118 * send it as a byte stream instead of regular string. 119 */ 120 return sd_bus_message_append_array(reply, 'y', console->socket_name, 121 console->socket_name_len); 122 } 123 124 static const sd_bus_vtable console_tty_vtable[] = { 125 SD_BUS_VTABLE_START(0), 126 SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 127 SD_BUS_VTABLE_UNPRIVILEGED), 128 SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 129 SD_BUS_VTABLE_END, 130 }; 131 132 static const sd_bus_vtable console_access_vtable[] = { 133 SD_BUS_VTABLE_START(0), 134 SD_BUS_PROPERTY("SocketName", "ay", get_socket_name, 0, 0), 135 SD_BUS_VTABLE_END, 136 }; 137 138 void dbus_init(struct console *console, 139 struct config *config __attribute__((unused))) 140 { 141 char obj_name[dbus_obj_path_len]; 142 char dbus_name[dbus_obj_path_len]; 143 int dbus_poller = 0; 144 int fd; 145 int r; 146 size_t bytes; 147 148 if (!console) { 149 warnx("Couldn't get valid console"); 150 return; 151 } 152 153 r = sd_bus_default_system(&console->bus); 154 if (r < 0) { 155 warnx("Failed to connect to system bus: %s", strerror(-r)); 156 return; 157 } 158 159 /* Register support console interface */ 160 bytes = snprintf(obj_name, dbus_obj_path_len, OBJ_NAME, 161 console->console_id); 162 if (bytes >= dbus_obj_path_len) { 163 warnx("Console id '%s' is too long. There is no enough space in the buffer.", 164 console->console_id); 165 return; 166 } 167 168 if (console->tty.type == TTY_DEVICE_UART) { 169 /* Register tty interface */ 170 r = sd_bus_add_object_vtable(console->bus, NULL, obj_name, 171 TTY_INTF, console_tty_vtable, 172 console); 173 if (r < 0) { 174 warnx("Failed to issue method call: %s", strerror(-r)); 175 return; 176 } 177 } 178 179 /* Register access interface */ 180 r = sd_bus_add_object_vtable(console->bus, NULL, obj_name, ACCESS_INTF, 181 console_access_vtable, console); 182 if (r < 0) { 183 warnx("Failed to issue method call: %s", strerror(-r)); 184 return; 185 } 186 187 bytes = snprintf(dbus_name, dbus_obj_path_len, DBUS_NAME, 188 console->console_id); 189 if (bytes >= dbus_obj_path_len) { 190 warnx("Console id '%s' is too long. There is no enough space in the buffer.", 191 console->console_id); 192 return; 193 } 194 195 /* Finally register the bus name */ 196 r = sd_bus_request_name(console->bus, dbus_name, 197 SD_BUS_NAME_ALLOW_REPLACEMENT | 198 SD_BUS_NAME_REPLACE_EXISTING); 199 if (r < 0) { 200 warnx("Failed to acquire service name: %s", strerror(-r)); 201 return; 202 } 203 204 fd = sd_bus_get_fd(console->bus); 205 if (fd < 0) { 206 warnx("Couldn't get the bus file descriptor"); 207 return; 208 } 209 210 dbus_poller = POLLFD_DBUS; 211 212 console->pollfds[dbus_poller].fd = fd; 213 console->pollfds[dbus_poller].events = POLLIN; 214 } 215