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>
311f903953SSHENG-YI HONG #include <sys/socket.h>
32d1c5d0cfSMark Johnston
33d1c5d0cfSMark Johnston #include <machine/vmm.h>
34d1c5d0cfSMark Johnston #include <machine/vmm_snapshot.h>
35d1c5d0cfSMark Johnston
361f903953SSHENG-YI HONG #include <netinet/in.h>
371f903953SSHENG-YI HONG
381f903953SSHENG-YI HONG #include <arpa/inet.h>
39d1c5d0cfSMark Johnston #include <assert.h>
40d1c5d0cfSMark Johnston #include <capsicum_helpers.h>
41d1c5d0cfSMark Johnston #include <err.h>
421f903953SSHENG-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;
571f903953SSHENG-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
791f903953SSHENG-YI HONG struct uart_socket_softc {
801f903953SSHENG-YI HONG struct uart_softc *softc;
811f903953SSHENG-YI HONG void (*drain)(int, enum ev_type, void *);
821f903953SSHENG-YI HONG void *arg;
831f903953SSHENG-YI HONG };
841f903953SSHENG-YI HONG
85d1c5d0cfSMark Johnston static bool uart_stdio; /* stdio in use for i/o */
86d1c5d0cfSMark Johnston static struct termios tio_stdio_orig;
87d1c5d0cfSMark Johnston
881f903953SSHENG-YI HONG static void uart_tcp_disconnect(struct uart_softc *);
891f903953SSHENG-YI HONG
90d1c5d0cfSMark Johnston static void
ttyclose(void)91d1c5d0cfSMark Johnston ttyclose(void)
92d1c5d0cfSMark Johnston {
93d1c5d0cfSMark Johnston tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
94d1c5d0cfSMark Johnston }
95d1c5d0cfSMark Johnston
96d1c5d0cfSMark Johnston static void
ttyopen(struct ttyfd * tf)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
ttyread(struct ttyfd * tf,uint8_t * ret)1141f903953SSHENG-YI HONG ttyread(struct ttyfd *tf, uint8_t *ret)
115d1c5d0cfSMark Johnston {
1161f903953SSHENG-YI HONG uint8_t rb;
1171f903953SSHENG-YI HONG int len;
118d1c5d0cfSMark Johnston
1191f903953SSHENG-YI HONG len = read(tf->rfd, &rb, 1);
1201f903953SSHENG-YI HONG if (ret && len == 1)
1211f903953SSHENG-YI HONG *ret = rb;
1221f903953SSHENG-YI HONG
1231f903953SSHENG-YI HONG return (len);
124d1c5d0cfSMark Johnston }
125d1c5d0cfSMark Johnston
1261f903953SSHENG-YI HONG static int
ttywrite(struct ttyfd * tf,unsigned char wb)127d1c5d0cfSMark Johnston ttywrite(struct ttyfd *tf, unsigned char wb)
128d1c5d0cfSMark Johnston {
1291f903953SSHENG-YI HONG return (write(tf->wfd, &wb, 1));
130d1c5d0cfSMark Johnston }
131d1c5d0cfSMark Johnston
132d1c5d0cfSMark Johnston static bool
rxfifo_available(struct uart_softc * sc)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
uart_rxfifo_getchar(struct uart_softc * sc)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
uart_rxfifo_numchars(struct uart_softc * sc)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
rxfifo_putchar(struct uart_softc * sc,uint8_t ch)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
uart_rxfifo_drain(struct uart_softc * sc,bool loopback)196d1c5d0cfSMark Johnston uart_rxfifo_drain(struct uart_softc *sc, bool loopback)
197d1c5d0cfSMark Johnston {
1981f903953SSHENG-YI HONG uint8_t ch;
1991f903953SSHENG-YI HONG int len;
200d1c5d0cfSMark Johnston
201d1c5d0cfSMark Johnston if (loopback) {
2021f903953SSHENG-YI HONG if (ttyread(&sc->tty, &ch) == 0 && sc->tty.is_socket)
2031f903953SSHENG-YI HONG uart_tcp_disconnect(sc);
204d1c5d0cfSMark Johnston } else {
2051f903953SSHENG-YI HONG while (rxfifo_available(sc)) {
2061f903953SSHENG-YI HONG len = ttyread(&sc->tty, &ch);
2071f903953SSHENG-YI HONG if (len <= 0) {
2081f903953SSHENG-YI HONG /* read returning 0 means disconnected. */
2091f903953SSHENG-YI HONG if (len == 0 && sc->tty.is_socket)
2101f903953SSHENG-YI HONG uart_tcp_disconnect(sc);
2111f903953SSHENG-YI HONG break;
2121f903953SSHENG-YI HONG }
2131f903953SSHENG-YI HONG
214d1c5d0cfSMark Johnston rxfifo_putchar(sc, ch);
215d1c5d0cfSMark Johnston }
216d1c5d0cfSMark Johnston }
2171f903953SSHENG-YI HONG }
218d1c5d0cfSMark Johnston
219d1c5d0cfSMark Johnston int
uart_rxfifo_putchar(struct uart_softc * sc,uint8_t ch,bool loopback)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) {
2251f903953SSHENG-YI HONG /* write returning -1 means disconnected. */
2261f903953SSHENG-YI HONG if (ttywrite(&sc->tty, ch) == -1 && sc->tty.is_socket)
2271f903953SSHENG-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
uart_rxfifo_reset(struct uart_softc * sc,int size)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
uart_rxfifo_size(struct uart_softc * sc __unused)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
uart_rxfifo_snapshot(struct uart_softc * sc,struct vm_snapshot_meta * meta)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
2901f903953SSHENG-YI HONG /*
2911f903953SSHENG-YI HONG * Listen on the TCP port, wait for a connection, then accept it.
2921f903953SSHENG-YI HONG */
2931f903953SSHENG-YI HONG static void
uart_tcp_listener(int fd,enum ev_type type __unused,void * arg)2941f903953SSHENG-YI HONG uart_tcp_listener(int fd, enum ev_type type __unused, void *arg)
2951f903953SSHENG-YI HONG {
296*ad152571SJohn Baldwin static const char tcp_error_msg[] = "Socket already connected\n";
2971f903953SSHENG-YI HONG struct uart_socket_softc *socket_softc = (struct uart_socket_softc *)
2981f903953SSHENG-YI HONG arg;
2991f903953SSHENG-YI HONG struct uart_softc *sc = socket_softc->softc;
3001f903953SSHENG-YI HONG int conn_fd;
3011f903953SSHENG-YI HONG
3021f903953SSHENG-YI HONG conn_fd = accept(fd, NULL, NULL);
3031f903953SSHENG-YI HONG if (conn_fd == -1)
3041f903953SSHENG-YI HONG goto clean;
3051f903953SSHENG-YI HONG
3061f903953SSHENG-YI HONG if (fcntl(conn_fd, F_SETFL, O_NONBLOCK) != 0)
3071f903953SSHENG-YI HONG goto clean;
3081f903953SSHENG-YI HONG
3091f903953SSHENG-YI HONG pthread_mutex_lock(&sc->mtx);
3101f903953SSHENG-YI HONG
3111f903953SSHENG-YI HONG if (sc->tty.opened) {
3121f903953SSHENG-YI HONG (void)send(conn_fd, tcp_error_msg, sizeof(tcp_error_msg), 0);
3131f903953SSHENG-YI HONG pthread_mutex_unlock(&sc->mtx);
3141f903953SSHENG-YI HONG goto clean;
3151f903953SSHENG-YI HONG } else {
3161f903953SSHENG-YI HONG sc->tty.rfd = sc->tty.wfd = conn_fd;
3171f903953SSHENG-YI HONG sc->tty.opened = true;
3181f903953SSHENG-YI HONG sc->mev = mevent_add(sc->tty.rfd, EVF_READ, socket_softc->drain,
3191f903953SSHENG-YI HONG socket_softc->arg);
3201f903953SSHENG-YI HONG }
3211f903953SSHENG-YI HONG
3221f903953SSHENG-YI HONG pthread_mutex_unlock(&sc->mtx);
3231f903953SSHENG-YI HONG return;
3241f903953SSHENG-YI HONG
3251f903953SSHENG-YI HONG clean:
3261f903953SSHENG-YI HONG if (conn_fd != -1)
3271f903953SSHENG-YI HONG close(conn_fd);
3281f903953SSHENG-YI HONG }
3291f903953SSHENG-YI HONG
3301f903953SSHENG-YI HONG /*
3311f903953SSHENG-YI HONG * When a connection-oriented protocol disconnects, this handler is used to
3321f903953SSHENG-YI HONG * clean it up.
3331f903953SSHENG-YI HONG *
3341f903953SSHENG-YI HONG * Note that this function is a helper, so the caller is responsible for
3351f903953SSHENG-YI HONG * locking the softc.
3361f903953SSHENG-YI HONG */
3371f903953SSHENG-YI HONG static void
uart_tcp_disconnect(struct uart_softc * sc)3381f903953SSHENG-YI HONG uart_tcp_disconnect(struct uart_softc *sc)
3391f903953SSHENG-YI HONG {
3401f903953SSHENG-YI HONG mevent_delete_close(sc->mev);
3411f903953SSHENG-YI HONG sc->mev = NULL;
3421f903953SSHENG-YI HONG sc->tty.opened = false;
3431f903953SSHENG-YI HONG sc->tty.rfd = sc->tty.wfd = -1;
3441f903953SSHENG-YI HONG }
3451f903953SSHENG-YI HONG
346d1c5d0cfSMark Johnston static int
uart_stdio_backend(struct uart_softc * sc)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
uart_tty_backend(struct uart_softc * sc,const char * path)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
4111f903953SSHENG-YI HONG /*
4121f903953SSHENG-YI HONG * Listen on the address and add it to the kqueue.
4131f903953SSHENG-YI HONG *
4141f903953SSHENG-YI HONG * If a connection is established (e.g., the TCP handler is triggered),
4151f903953SSHENG-YI HONG * replace the handler with the connected handler.
4161f903953SSHENG-YI HONG */
4171f903953SSHENG-YI HONG static int
uart_tcp_backend(struct uart_softc * sc,const char * path,void (* drain)(int,enum ev_type,void *),void * arg)4181f903953SSHENG-YI HONG uart_tcp_backend(struct uart_softc *sc, const char *path,
4191f903953SSHENG-YI HONG void (*drain)(int, enum ev_type, void *), void *arg)
4201f903953SSHENG-YI HONG {
4211f903953SSHENG-YI HONG #ifndef WITHOUT_CAPSICUM
4221f903953SSHENG-YI HONG cap_rights_t rights;
4231f903953SSHENG-YI HONG cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ };
4241f903953SSHENG-YI HONG #endif
4251f903953SSHENG-YI HONG int bind_fd = -1;
4261f903953SSHENG-YI HONG char addr[256], port[6];
4271f903953SSHENG-YI HONG int domain;
4281f903953SSHENG-YI HONG struct addrinfo hints, *src_addr = NULL;
4291f903953SSHENG-YI HONG struct uart_socket_softc *socket_softc = NULL;
4301f903953SSHENG-YI HONG
4311f903953SSHENG-YI HONG if (sscanf(path, "tcp=[%255[^]]]:%5s", addr, port) == 2) {
4321f903953SSHENG-YI HONG domain = AF_INET6;
4331f903953SSHENG-YI HONG } else if (sscanf(path, "tcp=%255[^:]:%5s", addr, port) == 2) {
4341f903953SSHENG-YI HONG domain = AF_INET;
4351f903953SSHENG-YI HONG } else {
4361f903953SSHENG-YI HONG warnx("Invalid number of parameter");
4371f903953SSHENG-YI HONG goto clean;
4381f903953SSHENG-YI HONG }
4391f903953SSHENG-YI HONG
4401f903953SSHENG-YI HONG bind_fd = socket(domain, SOCK_STREAM, 0);
4411f903953SSHENG-YI HONG if (bind_fd < 0)
4421f903953SSHENG-YI HONG goto clean;
4431f903953SSHENG-YI HONG
4441f903953SSHENG-YI HONG memset(&hints, 0, sizeof(hints));
4451f903953SSHENG-YI HONG hints.ai_family = domain;
4461f903953SSHENG-YI HONG hints.ai_socktype = SOCK_STREAM;
4471f903953SSHENG-YI HONG hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_PASSIVE;
4481f903953SSHENG-YI HONG
4491f903953SSHENG-YI HONG if (getaddrinfo(addr, port, &hints, &src_addr) != 0) {
4501f903953SSHENG-YI HONG warnx("Invalid address %s:%s", addr, port);
4511f903953SSHENG-YI HONG goto clean;
4521f903953SSHENG-YI HONG }
4531f903953SSHENG-YI HONG
4541f903953SSHENG-YI HONG if (bind(bind_fd, src_addr->ai_addr, src_addr->ai_addrlen) == -1) {
4551f903953SSHENG-YI HONG warn(
4561f903953SSHENG-YI HONG "bind(%s:%s)",
4571f903953SSHENG-YI HONG addr, port);
4581f903953SSHENG-YI HONG goto clean;
4591f903953SSHENG-YI HONG }
4601f903953SSHENG-YI HONG
4611f903953SSHENG-YI HONG freeaddrinfo(src_addr);
4621f903953SSHENG-YI HONG src_addr = NULL;
4631f903953SSHENG-YI HONG
4641f903953SSHENG-YI HONG if (fcntl(bind_fd, F_SETFL, O_NONBLOCK) == -1)
4651f903953SSHENG-YI HONG goto clean;
4661f903953SSHENG-YI HONG
4671f903953SSHENG-YI HONG if (listen(bind_fd, 1) == -1) {
4681f903953SSHENG-YI HONG warnx("listen(%s:%s)", addr, port);
4691f903953SSHENG-YI HONG goto clean;
4701f903953SSHENG-YI HONG }
4711f903953SSHENG-YI HONG
4721f903953SSHENG-YI HONG /*
4731f903953SSHENG-YI HONG * Set the connection softc structure, which includes both the softc
4741f903953SSHENG-YI HONG * and the drain function provided by the frontend.
4751f903953SSHENG-YI HONG */
476*ad152571SJohn Baldwin if ((socket_softc = calloc(1, sizeof(struct uart_socket_softc))) ==
4771f903953SSHENG-YI HONG NULL)
4781f903953SSHENG-YI HONG goto clean;
4791f903953SSHENG-YI HONG
4801f903953SSHENG-YI HONG sc->tty.is_socket = true;
4811f903953SSHENG-YI HONG
4821f903953SSHENG-YI HONG socket_softc->softc = sc;
4831f903953SSHENG-YI HONG socket_softc->drain = drain;
4841f903953SSHENG-YI HONG socket_softc->arg = arg;
4851f903953SSHENG-YI HONG
4861f903953SSHENG-YI HONG #ifndef WITHOUT_CAPSICUM
4871f903953SSHENG-YI HONG cap_rights_init(&rights, CAP_EVENT, CAP_ACCEPT, CAP_RECV, CAP_SEND,
4881f903953SSHENG-YI HONG CAP_FCNTL, CAP_IOCTL);
4891f903953SSHENG-YI HONG if (caph_rights_limit(bind_fd, &rights) == -1)
4901f903953SSHENG-YI HONG errx(EX_OSERR, "Unable to apply rights for sandbox");
4911f903953SSHENG-YI HONG if (caph_ioctls_limit(bind_fd, cmds, nitems(cmds)) == -1)
4921f903953SSHENG-YI HONG errx(EX_OSERR, "Unable to apply ioctls for sandbox");
4931f903953SSHENG-YI HONG if (caph_fcntls_limit(bind_fd, CAP_FCNTL_SETFL) == -1)
4941f903953SSHENG-YI HONG errx(EX_OSERR, "Unable to apply fcntls for sandbox");
4951f903953SSHENG-YI HONG #endif
4961f903953SSHENG-YI HONG
4971f903953SSHENG-YI HONG if ((sc->mev = mevent_add(bind_fd, EVF_READ, uart_tcp_listener,
4981f903953SSHENG-YI HONG socket_softc)) == NULL)
4991f903953SSHENG-YI HONG goto clean;
5001f903953SSHENG-YI HONG
5011f903953SSHENG-YI HONG return (0);
5021f903953SSHENG-YI HONG
5031f903953SSHENG-YI HONG clean:
5041f903953SSHENG-YI HONG if (bind_fd != -1)
5051f903953SSHENG-YI HONG close(bind_fd);
5061f903953SSHENG-YI HONG if (socket_softc != NULL)
5071f903953SSHENG-YI HONG free(socket_softc);
5081f903953SSHENG-YI HONG if (src_addr)
5091f903953SSHENG-YI HONG freeaddrinfo(src_addr);
5101f903953SSHENG-YI HONG return (-1);
5111f903953SSHENG-YI HONG }
5121f903953SSHENG-YI HONG
513d1c5d0cfSMark Johnston struct uart_softc *
uart_init(void)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
uart_tty_open(struct uart_softc * sc,const char * path,void (* drain)(int,enum ev_type,void *),void * arg)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);
5331f903953SSHENG-YI HONG else if (strncmp("tcp", path, 3) == 0)
5341f903953SSHENG-YI HONG retval = uart_tcp_backend(sc, path, drain, arg);
535d1c5d0cfSMark Johnston else
536d1c5d0cfSMark Johnston retval = uart_tty_backend(sc, path);
5371f903953SSHENG-YI HONG
5381f903953SSHENG-YI HONG /*
5391f903953SSHENG-YI HONG * A connection-oriented protocol should wait for a connection,
5401f903953SSHENG-YI HONG * so it may not listen to anything during initialization.
5411f903953SSHENG-YI HONG */
5421f903953SSHENG-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
uart_softc_lock(struct uart_softc * sc)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
uart_softc_unlock(struct uart_softc * sc)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