1d1c5d0cfSMark Johnston /*- 2d1c5d0cfSMark Johnston * SPDX-License-Identifier: BSD-2-Clause 3d1c5d0cfSMark Johnston * 4d1c5d0cfSMark Johnston * Copyright (c) 2012 NetApp, Inc. 5d1c5d0cfSMark Johnston * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6d1c5d0cfSMark Johnston * All rights reserved. 7d1c5d0cfSMark Johnston * 8d1c5d0cfSMark Johnston * Redistribution and use in source and binary forms, with or without 9d1c5d0cfSMark Johnston * modification, are permitted provided that the following conditions 10d1c5d0cfSMark Johnston * are met: 11d1c5d0cfSMark Johnston * 1. Redistributions of source code must retain the above copyright 12d1c5d0cfSMark Johnston * notice, this list of conditions and the following disclaimer. 13d1c5d0cfSMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 14d1c5d0cfSMark Johnston * notice, this list of conditions and the following disclaimer in the 15d1c5d0cfSMark Johnston * documentation and/or other materials provided with the distribution. 16d1c5d0cfSMark Johnston * 17d1c5d0cfSMark Johnston * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18d1c5d0cfSMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19d1c5d0cfSMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20d1c5d0cfSMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21d1c5d0cfSMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22d1c5d0cfSMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23d1c5d0cfSMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24d1c5d0cfSMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25d1c5d0cfSMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26d1c5d0cfSMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27d1c5d0cfSMark Johnston * SUCH DAMAGE. 28d1c5d0cfSMark Johnston */ 29d1c5d0cfSMark Johnston 30d1c5d0cfSMark Johnston #include <sys/types.h> 31*1f903953SSHENG-YI HONG #include <sys/socket.h> 32d1c5d0cfSMark Johnston 33d1c5d0cfSMark Johnston #include <machine/vmm.h> 34d1c5d0cfSMark Johnston #include <machine/vmm_snapshot.h> 35d1c5d0cfSMark Johnston 36*1f903953SSHENG-YI HONG #include <netinet/in.h> 37*1f903953SSHENG-YI HONG 38*1f903953SSHENG-YI HONG #include <arpa/inet.h> 39d1c5d0cfSMark Johnston #include <assert.h> 40d1c5d0cfSMark Johnston #include <capsicum_helpers.h> 41d1c5d0cfSMark Johnston #include <err.h> 42*1f903953SSHENG-YI HONG #include <netdb.h> 43e10b9d66SSHENG-YI HONG #include <pthread.h> 44d1c5d0cfSMark Johnston #include <stdbool.h> 45d1c5d0cfSMark Johnston #include <stdlib.h> 46d1c5d0cfSMark Johnston #include <string.h> 47d1c5d0cfSMark Johnston #include <sysexits.h> 48d1c5d0cfSMark Johnston #include <termios.h> 49d1c5d0cfSMark Johnston #include <unistd.h> 50d1c5d0cfSMark Johnston 51d1c5d0cfSMark Johnston #include "debug.h" 52d1c5d0cfSMark Johnston #include "mevent.h" 53d1c5d0cfSMark Johnston #include "uart_backend.h" 54d1c5d0cfSMark Johnston 55d1c5d0cfSMark Johnston struct ttyfd { 56d1c5d0cfSMark Johnston bool opened; 57*1f903953SSHENG-YI HONG bool is_socket; 58d1c5d0cfSMark Johnston int rfd; /* fd for reading */ 59d1c5d0cfSMark Johnston int wfd; /* fd for writing, may be == rfd */ 60d1c5d0cfSMark Johnston }; 61d1c5d0cfSMark Johnston 62d1c5d0cfSMark Johnston #define FIFOSZ 16 63d1c5d0cfSMark Johnston 64d1c5d0cfSMark Johnston struct fifo { 65d1c5d0cfSMark Johnston uint8_t buf[FIFOSZ]; 66d1c5d0cfSMark Johnston int rindex; /* index to read from */ 67d1c5d0cfSMark Johnston int windex; /* index to write to */ 68d1c5d0cfSMark Johnston int num; /* number of characters in the fifo */ 69d1c5d0cfSMark Johnston int size; /* size of the fifo */ 70d1c5d0cfSMark Johnston }; 71d1c5d0cfSMark Johnston 72d1c5d0cfSMark Johnston struct uart_softc { 73d1c5d0cfSMark Johnston struct ttyfd tty; 74d1c5d0cfSMark Johnston struct fifo rxfifo; 75d1c5d0cfSMark Johnston struct mevent *mev; 76e10b9d66SSHENG-YI HONG pthread_mutex_t mtx; 77d1c5d0cfSMark Johnston }; 78d1c5d0cfSMark Johnston 79*1f903953SSHENG-YI HONG struct uart_socket_softc { 80*1f903953SSHENG-YI HONG struct uart_softc *softc; 81*1f903953SSHENG-YI HONG void (*drain)(int, enum ev_type, void *); 82*1f903953SSHENG-YI HONG void *arg; 83*1f903953SSHENG-YI HONG }; 84*1f903953SSHENG-YI HONG 85d1c5d0cfSMark Johnston static bool uart_stdio; /* stdio in use for i/o */ 86d1c5d0cfSMark Johnston static struct termios tio_stdio_orig; 87d1c5d0cfSMark Johnston 88*1f903953SSHENG-YI HONG static void uart_tcp_disconnect(struct uart_softc *); 89*1f903953SSHENG-YI HONG 90d1c5d0cfSMark Johnston static void 91d1c5d0cfSMark Johnston ttyclose(void) 92d1c5d0cfSMark Johnston { 93d1c5d0cfSMark Johnston tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 94d1c5d0cfSMark Johnston } 95d1c5d0cfSMark Johnston 96d1c5d0cfSMark Johnston static void 97d1c5d0cfSMark Johnston ttyopen(struct ttyfd *tf) 98d1c5d0cfSMark Johnston { 99d1c5d0cfSMark Johnston struct termios orig, new; 100d1c5d0cfSMark Johnston 101d1c5d0cfSMark Johnston tcgetattr(tf->rfd, &orig); 102d1c5d0cfSMark Johnston new = orig; 103d1c5d0cfSMark Johnston cfmakeraw(&new); 104d1c5d0cfSMark Johnston new.c_cflag |= CLOCAL; 105d1c5d0cfSMark Johnston tcsetattr(tf->rfd, TCSANOW, &new); 106d1c5d0cfSMark Johnston if (uart_stdio) { 107d1c5d0cfSMark Johnston tio_stdio_orig = orig; 108d1c5d0cfSMark Johnston atexit(ttyclose); 109d1c5d0cfSMark Johnston } 110d1c5d0cfSMark Johnston raw_stdio = 1; 111d1c5d0cfSMark Johnston } 112d1c5d0cfSMark Johnston 113d1c5d0cfSMark Johnston static int 114*1f903953SSHENG-YI HONG ttyread(struct ttyfd *tf, uint8_t *ret) 115d1c5d0cfSMark Johnston { 116*1f903953SSHENG-YI HONG uint8_t rb; 117*1f903953SSHENG-YI HONG int len; 118d1c5d0cfSMark Johnston 119*1f903953SSHENG-YI HONG len = read(tf->rfd, &rb, 1); 120*1f903953SSHENG-YI HONG if (ret && len == 1) 121*1f903953SSHENG-YI HONG *ret = rb; 122*1f903953SSHENG-YI HONG 123*1f903953SSHENG-YI HONG return (len); 124d1c5d0cfSMark Johnston } 125d1c5d0cfSMark Johnston 126*1f903953SSHENG-YI HONG static int 127d1c5d0cfSMark Johnston ttywrite(struct ttyfd *tf, unsigned char wb) 128d1c5d0cfSMark Johnston { 129*1f903953SSHENG-YI HONG return (write(tf->wfd, &wb, 1)); 130d1c5d0cfSMark Johnston } 131d1c5d0cfSMark Johnston 132d1c5d0cfSMark Johnston static bool 133d1c5d0cfSMark Johnston rxfifo_available(struct uart_softc *sc) 134d1c5d0cfSMark Johnston { 135d1c5d0cfSMark Johnston return (sc->rxfifo.num < sc->rxfifo.size); 136d1c5d0cfSMark Johnston } 137d1c5d0cfSMark Johnston 138d1c5d0cfSMark Johnston int 139d1c5d0cfSMark Johnston uart_rxfifo_getchar(struct uart_softc *sc) 140d1c5d0cfSMark Johnston { 141d1c5d0cfSMark Johnston struct fifo *fifo; 142d1c5d0cfSMark Johnston int c, error, wasfull; 143d1c5d0cfSMark Johnston 144d1c5d0cfSMark Johnston wasfull = 0; 145d1c5d0cfSMark Johnston fifo = &sc->rxfifo; 146d1c5d0cfSMark Johnston if (fifo->num > 0) { 147d1c5d0cfSMark Johnston if (!rxfifo_available(sc)) 148d1c5d0cfSMark Johnston wasfull = 1; 149d1c5d0cfSMark Johnston c = fifo->buf[fifo->rindex]; 150d1c5d0cfSMark Johnston fifo->rindex = (fifo->rindex + 1) % fifo->size; 151d1c5d0cfSMark Johnston fifo->num--; 152d1c5d0cfSMark Johnston if (wasfull) { 153d1c5d0cfSMark Johnston if (sc->tty.opened) { 154d1c5d0cfSMark Johnston error = mevent_enable(sc->mev); 155d1c5d0cfSMark Johnston assert(error == 0); 156d1c5d0cfSMark Johnston } 157d1c5d0cfSMark Johnston } 158d1c5d0cfSMark Johnston return (c); 159d1c5d0cfSMark Johnston } else 160d1c5d0cfSMark Johnston return (-1); 161d1c5d0cfSMark Johnston } 162d1c5d0cfSMark Johnston 163d1c5d0cfSMark Johnston int 164d1c5d0cfSMark Johnston uart_rxfifo_numchars(struct uart_softc *sc) 165d1c5d0cfSMark Johnston { 166d1c5d0cfSMark Johnston return (sc->rxfifo.num); 167d1c5d0cfSMark Johnston } 168d1c5d0cfSMark Johnston 169d1c5d0cfSMark Johnston static int 170d1c5d0cfSMark Johnston rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 171d1c5d0cfSMark Johnston { 172d1c5d0cfSMark Johnston struct fifo *fifo; 173d1c5d0cfSMark Johnston int error; 174d1c5d0cfSMark Johnston 175d1c5d0cfSMark Johnston fifo = &sc->rxfifo; 176d1c5d0cfSMark Johnston 177d1c5d0cfSMark Johnston if (fifo->num < fifo->size) { 178d1c5d0cfSMark Johnston fifo->buf[fifo->windex] = ch; 179d1c5d0cfSMark Johnston fifo->windex = (fifo->windex + 1) % fifo->size; 180d1c5d0cfSMark Johnston fifo->num++; 181d1c5d0cfSMark Johnston if (!rxfifo_available(sc)) { 182d1c5d0cfSMark Johnston if (sc->tty.opened) { 183d1c5d0cfSMark Johnston /* 184d1c5d0cfSMark Johnston * Disable mevent callback if the FIFO is full. 185d1c5d0cfSMark Johnston */ 186d1c5d0cfSMark Johnston error = mevent_disable(sc->mev); 187d1c5d0cfSMark Johnston assert(error == 0); 188d1c5d0cfSMark Johnston } 189d1c5d0cfSMark Johnston } 190d1c5d0cfSMark Johnston return (0); 191d1c5d0cfSMark Johnston } else 192d1c5d0cfSMark Johnston return (-1); 193d1c5d0cfSMark Johnston } 194d1c5d0cfSMark Johnston 195d1c5d0cfSMark Johnston void 196d1c5d0cfSMark Johnston uart_rxfifo_drain(struct uart_softc *sc, bool loopback) 197d1c5d0cfSMark Johnston { 198*1f903953SSHENG-YI HONG uint8_t ch; 199*1f903953SSHENG-YI HONG int len; 200d1c5d0cfSMark Johnston 201d1c5d0cfSMark Johnston if (loopback) { 202*1f903953SSHENG-YI HONG if (ttyread(&sc->tty, &ch) == 0 && sc->tty.is_socket) 203*1f903953SSHENG-YI HONG uart_tcp_disconnect(sc); 204d1c5d0cfSMark Johnston } else { 205*1f903953SSHENG-YI HONG while (rxfifo_available(sc)) { 206*1f903953SSHENG-YI HONG len = ttyread(&sc->tty, &ch); 207*1f903953SSHENG-YI HONG if (len <= 0) { 208*1f903953SSHENG-YI HONG /* read returning 0 means disconnected. */ 209*1f903953SSHENG-YI HONG if (len == 0 && sc->tty.is_socket) 210*1f903953SSHENG-YI HONG uart_tcp_disconnect(sc); 211*1f903953SSHENG-YI HONG break; 212*1f903953SSHENG-YI HONG } 213*1f903953SSHENG-YI HONG 214d1c5d0cfSMark Johnston rxfifo_putchar(sc, ch); 215d1c5d0cfSMark Johnston } 216d1c5d0cfSMark Johnston } 217*1f903953SSHENG-YI HONG } 218d1c5d0cfSMark Johnston 219d1c5d0cfSMark Johnston int 220d1c5d0cfSMark Johnston uart_rxfifo_putchar(struct uart_softc *sc, uint8_t ch, bool loopback) 221d1c5d0cfSMark Johnston { 222d1c5d0cfSMark Johnston if (loopback) { 223d1c5d0cfSMark Johnston return (rxfifo_putchar(sc, ch)); 224d1c5d0cfSMark Johnston } else if (sc->tty.opened) { 225*1f903953SSHENG-YI HONG /* write returning -1 means disconnected. */ 226*1f903953SSHENG-YI HONG if (ttywrite(&sc->tty, ch) == -1 && sc->tty.is_socket) 227*1f903953SSHENG-YI HONG uart_tcp_disconnect(sc); 228d1c5d0cfSMark Johnston return (0); 229d1c5d0cfSMark Johnston } else { 230d1c5d0cfSMark Johnston /* Drop on the floor. */ 231d1c5d0cfSMark Johnston return (0); 232d1c5d0cfSMark Johnston } 233d1c5d0cfSMark Johnston } 234d1c5d0cfSMark Johnston 235d1c5d0cfSMark Johnston void 236d1c5d0cfSMark Johnston uart_rxfifo_reset(struct uart_softc *sc, int size) 237d1c5d0cfSMark Johnston { 238d1c5d0cfSMark Johnston char flushbuf[32]; 239d1c5d0cfSMark Johnston struct fifo *fifo; 240d1c5d0cfSMark Johnston ssize_t nread; 241d1c5d0cfSMark Johnston int error; 242d1c5d0cfSMark Johnston 243d1c5d0cfSMark Johnston fifo = &sc->rxfifo; 244d1c5d0cfSMark Johnston bzero(fifo, sizeof(struct fifo)); 245d1c5d0cfSMark Johnston fifo->size = size; 246d1c5d0cfSMark Johnston 247d1c5d0cfSMark Johnston if (sc->tty.opened) { 248d1c5d0cfSMark Johnston /* 249d1c5d0cfSMark Johnston * Flush any unread input from the tty buffer. 250d1c5d0cfSMark Johnston */ 251d1c5d0cfSMark Johnston while (1) { 252d1c5d0cfSMark Johnston nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 253d1c5d0cfSMark Johnston if (nread != sizeof(flushbuf)) 254d1c5d0cfSMark Johnston break; 255d1c5d0cfSMark Johnston } 256d1c5d0cfSMark Johnston 257d1c5d0cfSMark Johnston /* 258d1c5d0cfSMark Johnston * Enable mevent to trigger when new characters are available 259d1c5d0cfSMark Johnston * on the tty fd. 260d1c5d0cfSMark Johnston */ 261d1c5d0cfSMark Johnston error = mevent_enable(sc->mev); 262d1c5d0cfSMark Johnston assert(error == 0); 263d1c5d0cfSMark Johnston } 264d1c5d0cfSMark Johnston } 265d1c5d0cfSMark Johnston 266d1c5d0cfSMark Johnston int 267d1c5d0cfSMark Johnston uart_rxfifo_size(struct uart_softc *sc __unused) 268d1c5d0cfSMark Johnston { 269d1c5d0cfSMark Johnston return (FIFOSZ); 270d1c5d0cfSMark Johnston } 271d1c5d0cfSMark Johnston 272d1c5d0cfSMark Johnston #ifdef BHYVE_SNAPSHOT 273d1c5d0cfSMark Johnston int 274d1c5d0cfSMark Johnston uart_rxfifo_snapshot(struct uart_softc *sc, struct vm_snapshot_meta *meta) 275d1c5d0cfSMark Johnston { 276d1c5d0cfSMark Johnston int ret; 277d1c5d0cfSMark Johnston 278d1c5d0cfSMark Johnston SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.rindex, meta, ret, done); 279d1c5d0cfSMark Johnston SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.windex, meta, ret, done); 280d1c5d0cfSMark Johnston SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.num, meta, ret, done); 281d1c5d0cfSMark Johnston SNAPSHOT_VAR_OR_LEAVE(sc->rxfifo.size, meta, ret, done); 282d1c5d0cfSMark Johnston SNAPSHOT_BUF_OR_LEAVE(sc->rxfifo.buf, sizeof(sc->rxfifo.buf), 283d1c5d0cfSMark Johnston meta, ret, done); 284d1c5d0cfSMark Johnston 285d1c5d0cfSMark Johnston done: 286d1c5d0cfSMark Johnston return (ret); 287d1c5d0cfSMark Johnston } 288d1c5d0cfSMark Johnston #endif 289d1c5d0cfSMark Johnston 290*1f903953SSHENG-YI HONG /* 291*1f903953SSHENG-YI HONG * Listen on the TCP port, wait for a connection, then accept it. 292*1f903953SSHENG-YI HONG */ 293*1f903953SSHENG-YI HONG static void 294*1f903953SSHENG-YI HONG uart_tcp_listener(int fd, enum ev_type type __unused, void *arg) 295*1f903953SSHENG-YI HONG { 296*1f903953SSHENG-YI HONG const static char tcp_error_msg[] = "Socket already connected\n"; 297*1f903953SSHENG-YI HONG struct uart_socket_softc *socket_softc = (struct uart_socket_softc *) 298*1f903953SSHENG-YI HONG arg; 299*1f903953SSHENG-YI HONG struct uart_softc *sc = socket_softc->softc; 300*1f903953SSHENG-YI HONG int conn_fd; 301*1f903953SSHENG-YI HONG 302*1f903953SSHENG-YI HONG conn_fd = accept(fd, NULL, NULL); 303*1f903953SSHENG-YI HONG if (conn_fd == -1) 304*1f903953SSHENG-YI HONG goto clean; 305*1f903953SSHENG-YI HONG 306*1f903953SSHENG-YI HONG if (fcntl(conn_fd, F_SETFL, O_NONBLOCK) != 0) 307*1f903953SSHENG-YI HONG goto clean; 308*1f903953SSHENG-YI HONG 309*1f903953SSHENG-YI HONG pthread_mutex_lock(&sc->mtx); 310*1f903953SSHENG-YI HONG 311*1f903953SSHENG-YI HONG if (sc->tty.opened) { 312*1f903953SSHENG-YI HONG (void)send(conn_fd, tcp_error_msg, sizeof(tcp_error_msg), 0); 313*1f903953SSHENG-YI HONG pthread_mutex_unlock(&sc->mtx); 314*1f903953SSHENG-YI HONG goto clean; 315*1f903953SSHENG-YI HONG } else { 316*1f903953SSHENG-YI HONG sc->tty.rfd = sc->tty.wfd = conn_fd; 317*1f903953SSHENG-YI HONG sc->tty.opened = true; 318*1f903953SSHENG-YI HONG sc->mev = mevent_add(sc->tty.rfd, EVF_READ, socket_softc->drain, 319*1f903953SSHENG-YI HONG socket_softc->arg); 320*1f903953SSHENG-YI HONG } 321*1f903953SSHENG-YI HONG 322*1f903953SSHENG-YI HONG pthread_mutex_unlock(&sc->mtx); 323*1f903953SSHENG-YI HONG return; 324*1f903953SSHENG-YI HONG 325*1f903953SSHENG-YI HONG clean: 326*1f903953SSHENG-YI HONG if (conn_fd != -1) 327*1f903953SSHENG-YI HONG close(conn_fd); 328*1f903953SSHENG-YI HONG } 329*1f903953SSHENG-YI HONG 330*1f903953SSHENG-YI HONG /* 331*1f903953SSHENG-YI HONG * When a connection-oriented protocol disconnects, this handler is used to 332*1f903953SSHENG-YI HONG * clean it up. 333*1f903953SSHENG-YI HONG * 334*1f903953SSHENG-YI HONG * Note that this function is a helper, so the caller is responsible for 335*1f903953SSHENG-YI HONG * locking the softc. 336*1f903953SSHENG-YI HONG */ 337*1f903953SSHENG-YI HONG static void 338*1f903953SSHENG-YI HONG uart_tcp_disconnect(struct uart_softc *sc) 339*1f903953SSHENG-YI HONG { 340*1f903953SSHENG-YI HONG mevent_delete_close(sc->mev); 341*1f903953SSHENG-YI HONG sc->mev = NULL; 342*1f903953SSHENG-YI HONG sc->tty.opened = false; 343*1f903953SSHENG-YI HONG sc->tty.rfd = sc->tty.wfd = -1; 344*1f903953SSHENG-YI HONG } 345*1f903953SSHENG-YI HONG 346d1c5d0cfSMark Johnston static int 347d1c5d0cfSMark Johnston uart_stdio_backend(struct uart_softc *sc) 348d1c5d0cfSMark Johnston { 349d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM 350d1c5d0cfSMark Johnston cap_rights_t rights; 351d1c5d0cfSMark Johnston cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 352d1c5d0cfSMark Johnston #endif 353d1c5d0cfSMark Johnston 354d1c5d0cfSMark Johnston if (uart_stdio) 355d1c5d0cfSMark Johnston return (-1); 356d1c5d0cfSMark Johnston 357d1c5d0cfSMark Johnston sc->tty.rfd = STDIN_FILENO; 358d1c5d0cfSMark Johnston sc->tty.wfd = STDOUT_FILENO; 359d1c5d0cfSMark Johnston sc->tty.opened = true; 360d1c5d0cfSMark Johnston 361d1c5d0cfSMark Johnston if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 362d1c5d0cfSMark Johnston return (-1); 363d1c5d0cfSMark Johnston if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 364d1c5d0cfSMark Johnston return (-1); 365d1c5d0cfSMark Johnston 366d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM 367d1c5d0cfSMark Johnston cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 368d1c5d0cfSMark Johnston if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 369d1c5d0cfSMark Johnston errx(EX_OSERR, "Unable to apply rights for sandbox"); 370d1c5d0cfSMark Johnston if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 371d1c5d0cfSMark Johnston errx(EX_OSERR, "Unable to apply rights for sandbox"); 372d1c5d0cfSMark Johnston #endif 373d1c5d0cfSMark Johnston 374d1c5d0cfSMark Johnston uart_stdio = true; 375d1c5d0cfSMark Johnston 376d1c5d0cfSMark Johnston return (0); 377d1c5d0cfSMark Johnston } 378d1c5d0cfSMark Johnston 379d1c5d0cfSMark Johnston static int 380d1c5d0cfSMark Johnston uart_tty_backend(struct uart_softc *sc, const char *path) 381d1c5d0cfSMark Johnston { 382d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM 383d1c5d0cfSMark Johnston cap_rights_t rights; 384d1c5d0cfSMark Johnston cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 385d1c5d0cfSMark Johnston #endif 386d1c5d0cfSMark Johnston int fd; 387d1c5d0cfSMark Johnston 388d1c5d0cfSMark Johnston fd = open(path, O_RDWR | O_NONBLOCK); 389d1c5d0cfSMark Johnston if (fd < 0) 390d1c5d0cfSMark Johnston return (-1); 391d1c5d0cfSMark Johnston 392d1c5d0cfSMark Johnston if (!isatty(fd)) { 393d1c5d0cfSMark Johnston close(fd); 394d1c5d0cfSMark Johnston return (-1); 395d1c5d0cfSMark Johnston } 396d1c5d0cfSMark Johnston 397d1c5d0cfSMark Johnston sc->tty.rfd = sc->tty.wfd = fd; 398d1c5d0cfSMark Johnston sc->tty.opened = true; 399d1c5d0cfSMark Johnston 400d1c5d0cfSMark Johnston #ifndef WITHOUT_CAPSICUM 401d1c5d0cfSMark Johnston cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 402d1c5d0cfSMark Johnston if (caph_rights_limit(fd, &rights) == -1) 403d1c5d0cfSMark Johnston errx(EX_OSERR, "Unable to apply rights for sandbox"); 404d1c5d0cfSMark Johnston if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 405d1c5d0cfSMark Johnston errx(EX_OSERR, "Unable to apply rights for sandbox"); 406d1c5d0cfSMark Johnston #endif 407d1c5d0cfSMark Johnston 408d1c5d0cfSMark Johnston return (0); 409d1c5d0cfSMark Johnston } 410d1c5d0cfSMark Johnston 411*1f903953SSHENG-YI HONG /* 412*1f903953SSHENG-YI HONG * Listen on the address and add it to the kqueue. 413*1f903953SSHENG-YI HONG * 414*1f903953SSHENG-YI HONG * If a connection is established (e.g., the TCP handler is triggered), 415*1f903953SSHENG-YI HONG * replace the handler with the connected handler. 416*1f903953SSHENG-YI HONG */ 417*1f903953SSHENG-YI HONG static int 418*1f903953SSHENG-YI HONG uart_tcp_backend(struct uart_softc *sc, const char *path, 419*1f903953SSHENG-YI HONG void (*drain)(int, enum ev_type, void *), void *arg) 420*1f903953SSHENG-YI HONG { 421*1f903953SSHENG-YI HONG #ifndef WITHOUT_CAPSICUM 422*1f903953SSHENG-YI HONG cap_rights_t rights; 423*1f903953SSHENG-YI HONG cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 424*1f903953SSHENG-YI HONG #endif 425*1f903953SSHENG-YI HONG int bind_fd = -1; 426*1f903953SSHENG-YI HONG char addr[256], port[6]; 427*1f903953SSHENG-YI HONG int domain; 428*1f903953SSHENG-YI HONG struct addrinfo hints, *src_addr = NULL; 429*1f903953SSHENG-YI HONG struct uart_socket_softc *socket_softc = NULL; 430*1f903953SSHENG-YI HONG 431*1f903953SSHENG-YI HONG if (sscanf(path, "tcp=[%255[^]]]:%5s", addr, port) == 2) { 432*1f903953SSHENG-YI HONG domain = AF_INET6; 433*1f903953SSHENG-YI HONG } else if (sscanf(path, "tcp=%255[^:]:%5s", addr, port) == 2) { 434*1f903953SSHENG-YI HONG domain = AF_INET; 435*1f903953SSHENG-YI HONG } else { 436*1f903953SSHENG-YI HONG warnx("Invalid number of parameter"); 437*1f903953SSHENG-YI HONG goto clean; 438*1f903953SSHENG-YI HONG } 439*1f903953SSHENG-YI HONG 440*1f903953SSHENG-YI HONG bind_fd = socket(domain, SOCK_STREAM, 0); 441*1f903953SSHENG-YI HONG if (bind_fd < 0) 442*1f903953SSHENG-YI HONG goto clean; 443*1f903953SSHENG-YI HONG 444*1f903953SSHENG-YI HONG memset(&hints, 0, sizeof(hints)); 445*1f903953SSHENG-YI HONG hints.ai_family = domain; 446*1f903953SSHENG-YI HONG hints.ai_socktype = SOCK_STREAM; 447*1f903953SSHENG-YI HONG hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE; 448*1f903953SSHENG-YI HONG 449*1f903953SSHENG-YI HONG if (getaddrinfo(addr, port, &hints, &src_addr) != 0) { 450*1f903953SSHENG-YI HONG warnx("Invalid address %s:%s", addr, port); 451*1f903953SSHENG-YI HONG goto clean; 452*1f903953SSHENG-YI HONG } 453*1f903953SSHENG-YI HONG 454*1f903953SSHENG-YI HONG if (bind(bind_fd, src_addr->ai_addr, src_addr->ai_addrlen) == -1) { 455*1f903953SSHENG-YI HONG warn( 456*1f903953SSHENG-YI HONG "bind(%s:%s)", 457*1f903953SSHENG-YI HONG addr, port); 458*1f903953SSHENG-YI HONG goto clean; 459*1f903953SSHENG-YI HONG } 460*1f903953SSHENG-YI HONG 461*1f903953SSHENG-YI HONG freeaddrinfo(src_addr); 462*1f903953SSHENG-YI HONG src_addr = NULL; 463*1f903953SSHENG-YI HONG 464*1f903953SSHENG-YI HONG if (fcntl(bind_fd, F_SETFL, O_NONBLOCK) == -1) 465*1f903953SSHENG-YI HONG goto clean; 466*1f903953SSHENG-YI HONG 467*1f903953SSHENG-YI HONG if (listen(bind_fd, 1) == -1) { 468*1f903953SSHENG-YI HONG warnx("listen(%s:%s)", addr, port); 469*1f903953SSHENG-YI HONG goto clean; 470*1f903953SSHENG-YI HONG } 471*1f903953SSHENG-YI HONG 472*1f903953SSHENG-YI HONG /* 473*1f903953SSHENG-YI HONG * Set the connection softc structure, which includes both the softc 474*1f903953SSHENG-YI HONG * and the drain function provided by the frontend. 475*1f903953SSHENG-YI HONG */ 476*1f903953SSHENG-YI HONG if ((socket_softc = calloc(sizeof(struct uart_socket_softc), 1)) == 477*1f903953SSHENG-YI HONG NULL) 478*1f903953SSHENG-YI HONG goto clean; 479*1f903953SSHENG-YI HONG 480*1f903953SSHENG-YI HONG sc->tty.is_socket = true; 481*1f903953SSHENG-YI HONG 482*1f903953SSHENG-YI HONG socket_softc->softc = sc; 483*1f903953SSHENG-YI HONG socket_softc->drain = drain; 484*1f903953SSHENG-YI HONG socket_softc->arg = arg; 485*1f903953SSHENG-YI HONG 486*1f903953SSHENG-YI HONG #ifndef WITHOUT_CAPSICUM 487*1f903953SSHENG-YI HONG cap_rights_init(&rights, CAP_EVENT, CAP_ACCEPT, CAP_RECV, CAP_SEND, 488*1f903953SSHENG-YI HONG CAP_FCNTL, CAP_IOCTL); 489*1f903953SSHENG-YI HONG if (caph_rights_limit(bind_fd, &rights) == -1) 490*1f903953SSHENG-YI HONG errx(EX_OSERR, "Unable to apply rights for sandbox"); 491*1f903953SSHENG-YI HONG if (caph_ioctls_limit(bind_fd, cmds, nitems(cmds)) == -1) 492*1f903953SSHENG-YI HONG errx(EX_OSERR, "Unable to apply ioctls for sandbox"); 493*1f903953SSHENG-YI HONG if (caph_fcntls_limit(bind_fd, CAP_FCNTL_SETFL) == -1) 494*1f903953SSHENG-YI HONG errx(EX_OSERR, "Unable to apply fcntls for sandbox"); 495*1f903953SSHENG-YI HONG #endif 496*1f903953SSHENG-YI HONG 497*1f903953SSHENG-YI HONG if ((sc->mev = mevent_add(bind_fd, EVF_READ, uart_tcp_listener, 498*1f903953SSHENG-YI HONG socket_softc)) == NULL) 499*1f903953SSHENG-YI HONG goto clean; 500*1f903953SSHENG-YI HONG 501*1f903953SSHENG-YI HONG return (0); 502*1f903953SSHENG-YI HONG 503*1f903953SSHENG-YI HONG clean: 504*1f903953SSHENG-YI HONG if (bind_fd != -1) 505*1f903953SSHENG-YI HONG close(bind_fd); 506*1f903953SSHENG-YI HONG if (socket_softc != NULL) 507*1f903953SSHENG-YI HONG free(socket_softc); 508*1f903953SSHENG-YI HONG if (src_addr) 509*1f903953SSHENG-YI HONG freeaddrinfo(src_addr); 510*1f903953SSHENG-YI HONG return (-1); 511*1f903953SSHENG-YI HONG } 512*1f903953SSHENG-YI HONG 513d1c5d0cfSMark Johnston struct uart_softc * 514d1c5d0cfSMark Johnston uart_init(void) 515d1c5d0cfSMark Johnston { 516e10b9d66SSHENG-YI HONG struct uart_softc *sc = calloc(1, sizeof(struct uart_softc)); 517e10b9d66SSHENG-YI HONG if (sc == NULL) 518e10b9d66SSHENG-YI HONG return (NULL); 519e10b9d66SSHENG-YI HONG 520e10b9d66SSHENG-YI HONG pthread_mutex_init(&sc->mtx, NULL); 521e10b9d66SSHENG-YI HONG 522e10b9d66SSHENG-YI HONG return (sc); 523d1c5d0cfSMark Johnston } 524d1c5d0cfSMark Johnston 525d1c5d0cfSMark Johnston int 526d1c5d0cfSMark Johnston uart_tty_open(struct uart_softc *sc, const char *path, 527d1c5d0cfSMark Johnston void (*drain)(int, enum ev_type, void *), void *arg) 528d1c5d0cfSMark Johnston { 529d1c5d0cfSMark Johnston int retval; 530d1c5d0cfSMark Johnston 531d1c5d0cfSMark Johnston if (strcmp("stdio", path) == 0) 532d1c5d0cfSMark Johnston retval = uart_stdio_backend(sc); 533*1f903953SSHENG-YI HONG else if (strncmp("tcp", path, 3) == 0) 534*1f903953SSHENG-YI HONG retval = uart_tcp_backend(sc, path, drain, arg); 535d1c5d0cfSMark Johnston else 536d1c5d0cfSMark Johnston retval = uart_tty_backend(sc, path); 537*1f903953SSHENG-YI HONG 538*1f903953SSHENG-YI HONG /* 539*1f903953SSHENG-YI HONG * A connection-oriented protocol should wait for a connection, 540*1f903953SSHENG-YI HONG * so it may not listen to anything during initialization. 541*1f903953SSHENG-YI HONG */ 542*1f903953SSHENG-YI HONG if (retval == 0 && !sc->tty.is_socket) { 543d1c5d0cfSMark Johnston ttyopen(&sc->tty); 544d1c5d0cfSMark Johnston sc->mev = mevent_add(sc->tty.rfd, EVF_READ, drain, arg); 545d1c5d0cfSMark Johnston assert(sc->mev != NULL); 546d1c5d0cfSMark Johnston } 547d1c5d0cfSMark Johnston 548d1c5d0cfSMark Johnston return (retval); 549d1c5d0cfSMark Johnston } 550e10b9d66SSHENG-YI HONG 551e10b9d66SSHENG-YI HONG void 552e10b9d66SSHENG-YI HONG uart_softc_lock(struct uart_softc *sc) 553e10b9d66SSHENG-YI HONG { 554e10b9d66SSHENG-YI HONG pthread_mutex_lock(&sc->mtx); 555e10b9d66SSHENG-YI HONG } 556e10b9d66SSHENG-YI HONG 557e10b9d66SSHENG-YI HONG void 558e10b9d66SSHENG-YI HONG uart_softc_unlock(struct uart_softc *sc) 559e10b9d66SSHENG-YI HONG { 560e10b9d66SSHENG-YI HONG pthread_mutex_unlock(&sc->mtx); 561e10b9d66SSHENG-YI HONG } 562