xref: /netbsd-src/share/examples/rump/ttyserv/ttyserv.c (revision d35b86acad83e0ac06b9bb041ea23ab3c4f42d20)
1 /*	$NetBSD: ttyserv.c,v 1.3 2016/01/25 11:45:58 pooka Exp $	*/
2 
3 /*
4  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 /*
29  * This is a [quick, simple & dirty] userspace tty/ucom server.
30  * We probe USB devices using rump and attach them to the host kernel
31  * using pud(4).
32  */
33 
34 #include <sys/types.h>
35 #include <sys/syslimits.h>
36 
37 #include <dev/pud/pud_msgif.h>
38 
39 #include <rump/rump.h>
40 #include <rump/rumpvnode_if.h>
41 
42 #include <assert.h>
43 #include <err.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <paths.h>
47 #include <pthread.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 
53 /*
54  * No devfs?  No problem.  We just hack a bit & wait for the dust to settle.
55  */
56 #define MYMAJOR 412
57 static int
makenodes(void)58 makenodes(void)
59 {
60 	struct stat sb;
61 	int rv;
62 
63 	if (stat("rumpttyU0", &sb) != 0)
64 		rv = mknod("rumpttyU0", S_IFCHR | 0666, makedev(MYMAJOR, 0));
65 	if (rv != 0 && !(rv == -1 && errno == EEXIST))
66 		return rv;
67 
68 	if (stat("rumpttyU1", &sb) != 0)
69 		rv = mknod("rumpttyU1", S_IFCHR | 0666, makedev(MYMAJOR, 1));
70 	if (rv != 0 && !(rv == -1 && errno == EEXIST))
71 		return rv;
72 
73 	return 0;
74 }
75 
76 static struct vnode *devvps[2];
77 static kauth_cred_t rootcred;
78 static int fd;
79 
80 static void *
handlereq(void * arg)81 handlereq(void *arg)
82 {
83 	struct vnode *devvp;
84 	struct pud_creq_open *pr_open;
85 	struct pud_creq_close *pr_close;
86 	struct pud_req_readwrite *pr_rw;
87 	struct pud_req_ioctl *pr_ioctl;
88 	struct uio *uio;
89 	size_t reslen;
90 	struct pud_req *pdr = arg;
91 	int minordev, rv;
92 	ssize_t n;
93 
94 	minordev = minor(pdr->pdr_dev);
95 	if (minordev < 0 || minordev >= 8) {
96 		rv = ENXIO;
97 		goto sendresponse;
98 	}
99 	devvp = devvps[minordev];
100 
101 	switch (pdr->pdr_reqtype) {
102 	case PUD_CDEV_OPEN:
103 		pr_open = (void *)pdr;
104 		RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
105 		rv = RUMP_VOP_OPEN(devvp, pr_open->pm_fmt, rootcred);
106 		RUMP_VOP_UNLOCK(devvp);
107 		break;
108 
109 	case PUD_CDEV_CLOSE:
110 		pr_close = (void *)pdr;
111 		RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
112 		rv = RUMP_VOP_CLOSE(devvp, pr_close->pm_fmt, rootcred);
113 		RUMP_VOP_UNLOCK(devvp);
114 		break;
115 
116 	case PUD_CDEV_IOCTL:
117 		pr_ioctl = (void *)pdr;
118 		rv = RUMP_VOP_IOCTL(devvp, pr_ioctl->pm_iocmd,
119 		    pr_ioctl->pm_data, pr_ioctl->pm_flag, rootcred);
120 		break;
121 
122 	case PUD_CDEV_READ:
123 		pr_rw = (void *)pdr;
124 		assert(pr_rw->pm_resid <= 64*1024);
125 		uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
126 		    pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_READ);
127 		RUMP_VOP_LOCK(devvp, RUMP_LK_SHARED);
128 		rv = RUMP_VOP_READ(devvp, uio, 0, rootcred);
129 		RUMP_VOP_UNLOCK(devvp);
130 		reslen = rump_pub_uio_free(uio);
131 		pdr->pdr_pth.pth_framelen -= reslen;
132 		pr_rw->pm_resid = reslen;
133 		break;
134 
135 	case PUD_CDEV_WRITE:
136 		pr_rw = (void *)pdr;
137 		uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
138 		    pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_WRITE);
139 		RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
140 		rv = RUMP_VOP_WRITE(devvp, uio, 0, rootcred);
141 		RUMP_VOP_UNLOCK(devvp);
142 		reslen = rump_pub_uio_free(uio);
143 		pr_rw->pm_resid = reslen;
144 		pdr->pdr_pth.pth_framelen=sizeof(struct pud_creq_write);
145 		rv = 0;
146 		break;
147 	default:
148 		printf("unknown request %d\n", pdr->pdr_reqtype);
149 		abort();
150 	}
151 
152 sendresponse:
153 	printf("result %d\n", rv);
154 	pdr->pdr_rv = rv;
155 	n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
156 	assert(n == (ssize_t)pdr->pdr_pth.pth_framelen);
157 
158 	pthread_exit(NULL);
159 }
160 
161 int
main(int argc,char * argv[])162 main(int argc, char *argv[])
163 {
164 	struct pud_conf_reg pcr;
165 	struct pud_req *pdr;
166 	ssize_t n;
167 	int rv;
168 
169 	if (makenodes() == -1)
170 		err(1, "makenodes");
171 
172 	fd = open(_PATH_PUD, O_RDWR);
173 	if (fd == -1)
174 		err(1, "open");
175 
176 	memset(&pcr, 0, sizeof(pcr));
177 	pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg);
178 	pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION;
179 	pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF;
180 	pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
181 
182 	pcr.pm_regdev = makedev(MYMAJOR, 0);
183 	pcr.pm_flags = PUD_CONFFLAG_BDEV;
184 	strlcpy(pcr.pm_devname, "youmass", sizeof(pcr.pm_devname));
185 
186 	n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
187 	if (n == -1)
188 		err(1, "configure"); /* XXX: doubles as protocol error */
189 
190 	rump_boot_sethowto(RUMP_AB_VERBOSE);
191 	rump_init();
192 
193 	if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU0",
194 	    NULL, &devvps[0], NULL)) != 0)
195 		errx(1, "raw device 0 lookup failed %d", rv);
196 	if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU1",
197 	    NULL, &devvps[1], NULL)) != 0)
198 		errx(1, "raw device 1 lookup failed %d", rv);
199 
200 	rootcred = rump_pub_cred_create(0, 0, 0, NULL);
201 
202 	/* process requests ad infinitum */
203 	for (;;) {
204 		pthread_t pt;
205 
206 #define PDRSIZE (64*1024+1024)
207 		pdr = malloc(PDRSIZE);
208 		if (pdr == NULL)
209 			err(1, "malloc");
210 
211 		n = read(fd, pdr, PDRSIZE);
212 		if (n == -1)
213 			err(1, "read");
214 
215 		/*
216 		 * tip & cu fork and read/write at the same time.  hence,
217 		 * we need a multithreaded server as otherwise read requests
218 		 * will block eternally since no writes can be done.
219 		 *
220 		 * XXX: do this properly (detached threads, or pool)
221 		 */
222 		pthread_create(&pt, NULL, handlereq, pdr);
223 	}
224 }
225