blob: d1dd674bc2b683c115b0a482a8428652a12a46ef [file] [log] [blame]
Ninad Palsulee258e512023-04-26 22:17:57 -05001/**
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
Andrew Jeffery30ea6382023-05-03 16:56:10 +093017#include <assert.h>
Ninad Palsulee258e512023-04-26 22:17:57 -050018#include <errno.h>
19#include <err.h>
20
21#include "console-server.h"
22
23/* size of the dbus object path length */
24const size_t dbus_obj_path_len = 1024;
25
Ninad Palsuleb14ca192023-03-31 09:49:00 -050026#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"
Ninad Palsulee258e512023-04-26 22:17:57 -050031
32static 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
Andrew Jeffery30ea6382023-05-03 16:56:10 +093046 rc = handler->baudrate(handler, console->tty.uart.baud);
Ninad Palsulee258e512023-04-26 22:17:57 -050047 if (rc) {
48 warnx("Can't set terminal baudrate for handler %s",
49 handler->name);
50 }
51 }
52}
53
54static 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
Andrew Jeffery30ea6382023-05-03 16:56:10 +093079 assert(console->tty.type == TTY_DEVICE_UART);
80 console->tty.uart.baud = speed;
Ninad Palsulee258e512023-04-26 22:17:57 -050081 tty_change_baudrate(console);
82
83 return sd_bus_reply_method_return(msg, "x", r);
84}
85
86static 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
Andrew Jeffery30ea6382023-05-03 16:56:10 +093097 assert(console->tty.type == TTY_DEVICE_UART);
98 baudrate = parse_baud_to_int(console->tty.uart.baud);
Ninad Palsulee258e512023-04-26 22:17:57 -050099 if (!baudrate) {
Andrew Jeffery30ea6382023-05-03 16:56:10 +0930100 warnx("Invalid baud rate: '%d'", console->tty.uart.baud);
Ninad Palsulee258e512023-04-26 22:17:57 -0500101 }
102
103 r = sd_bus_message_append(reply, "u", baudrate);
104
105 return r;
106}
107
Ninad Palsuleb14ca192023-03-31 09:49:00 -0500108static 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
124static const sd_bus_vtable console_tty_vtable[] = {
Ninad Palsulee258e512023-04-26 22:17:57 -0500125 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
Ninad Palsuleb14ca192023-03-31 09:49:00 -0500132static 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
Ninad Palsulee258e512023-04-26 22:17:57 -0500138void 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
Andrew Jeffery30ea6382023-05-03 16:56:10 +0930168 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 }
Ninad Palsuleb14ca192023-03-31 09:49:00 -0500177 }
178
179 /* Register access interface */
180 r = sd_bus_add_object_vtable(console->bus, NULL, obj_name, ACCESS_INTF,
181 console_access_vtable, console);
Ninad Palsulee258e512023-04-26 22:17:57 -0500182 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
Ninad Palsuleb14ca192023-03-31 09:49:00 -0500195 /* Finally register the bus name */
Ninad Palsulee258e512023-04-26 22:17:57 -0500196 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}