ttyserv.c revision 1.2 1 /* $NetBSD: ttyserv.c,v 1.2 2010/06/24 13:03:05 hannken 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
41 #include <assert.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <paths.h>
46 #include <pthread.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 /*
53 * No devfs? No problem. We just hack a bit & wait for the dust to settle.
54 */
55 #define MYMAJOR 412
56 static int
57 makenodes(void)
58 {
59 struct stat sb;
60 int rv;
61
62 if (stat("rumpttyU0", &sb) != 0)
63 rv = mknod("rumpttyU0", S_IFCHR | 0666, makedev(MYMAJOR, 0));
64 if (rv != 0 && !(rv == -1 && errno == EEXIST))
65 return rv;
66
67 if (stat("rumpttyU1", &sb) != 0)
68 rv = mknod("rumpttyU1", S_IFCHR | 0666, makedev(MYMAJOR, 1));
69 if (rv != 0 && !(rv == -1 && errno == EEXIST))
70 return rv;
71
72 return 0;
73 }
74
75 static struct vnode *devvps[2];
76 static kauth_cred_t rootcred;
77 static int fd;
78
79 static void *
80 handlereq(void *arg)
81 {
82 struct vnode *devvp;
83 struct pud_creq_open *pr_open;
84 struct pud_creq_close *pr_close;
85 struct pud_req_readwrite *pr_rw;
86 struct pud_req_ioctl *pr_ioctl;
87 struct uio *uio;
88 size_t reslen;
89 struct pud_req *pdr = arg;
90 int minordev, rv;
91 ssize_t n;
92
93 minordev = minor(pdr->pdr_dev);
94 if (minordev < 0 || minordev >= 8) {
95 rv = ENXIO;
96 goto sendresponse;
97 }
98 devvp = devvps[minordev];
99
100 switch (pdr->pdr_reqtype) {
101 case PUD_CDEV_OPEN:
102 pr_open = (void *)pdr;
103 RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
104 rv = RUMP_VOP_OPEN(devvp, pr_open->pm_fmt, rootcred);
105 RUMP_VOP_UNLOCK(devvp);
106 break;
107
108 case PUD_CDEV_CLOSE:
109 pr_close = (void *)pdr;
110 RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
111 rv = RUMP_VOP_CLOSE(devvp, pr_close->pm_fmt, rootcred);
112 RUMP_VOP_UNLOCK(devvp);
113 break;
114
115 case PUD_CDEV_IOCTL:
116 pr_ioctl = (void *)pdr;
117 rv = RUMP_VOP_IOCTL(devvp, pr_ioctl->pm_iocmd,
118 pr_ioctl->pm_data, pr_ioctl->pm_flag, rootcred);
119 break;
120
121 case PUD_CDEV_READ:
122 pr_rw = (void *)pdr;
123 assert(pr_rw->pm_resid <= 64*1024);
124 uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
125 pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_READ);
126 RUMP_VOP_LOCK(devvp, RUMP_LK_SHARED);
127 rv = RUMP_VOP_READ(devvp, uio, 0, rootcred);
128 RUMP_VOP_UNLOCK(devvp);
129 reslen = rump_pub_uio_free(uio);
130 pdr->pdr_pth.pth_framelen -= reslen;
131 pr_rw->pm_resid = reslen;
132 break;
133
134 case PUD_CDEV_WRITE:
135 pr_rw = (void *)pdr;
136 uio = rump_pub_uio_setup(&pr_rw->pm_data[0],
137 pr_rw->pm_resid, pr_rw->pm_offset, RUMPUIO_WRITE);
138 RUMP_VOP_LOCK(devvp, RUMP_LK_EXCLUSIVE);
139 rv = RUMP_VOP_WRITE(devvp, uio, 0, rootcred);
140 RUMP_VOP_UNLOCK(devvp);
141 reslen = rump_pub_uio_free(uio);
142 pr_rw->pm_resid = reslen;
143 pdr->pdr_pth.pth_framelen=sizeof(struct pud_creq_write);
144 rv = 0;
145 break;
146 default:
147 printf("unknown request %d\n", pdr->pdr_reqtype);
148 abort();
149 }
150
151 sendresponse:
152 printf("result %d\n", rv);
153 pdr->pdr_rv = rv;
154 n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
155 assert(n == (ssize_t)pdr->pdr_pth.pth_framelen);
156
157 pthread_exit(NULL);
158 }
159
160 int
161 main(int argc, char *argv[])
162 {
163 struct pud_conf_reg pcr;
164 struct pud_req *pdr;
165 ssize_t n;
166 int rv;
167
168 if (makenodes() == -1)
169 err(1, "makenodes");
170
171 fd = open(_PATH_PUD, O_RDWR);
172 if (fd == -1)
173 err(1, "open");
174
175 memset(&pcr, 0, sizeof(pcr));
176 pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg);
177 pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION;
178 pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF;
179 pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
180
181 pcr.pm_regdev = makedev(MYMAJOR, 0);
182 pcr.pm_flags = PUD_CONFFLAG_BDEV;
183 strlcpy(pcr.pm_devname, "youmass", sizeof(pcr.pm_devname));
184
185 n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
186 if (n == -1)
187 err(1, "configure"); /* XXX: doubles as protocol error */
188
189 rump_boot_sethowto(RUMP_AB_VERBOSE);
190 rump_init();
191
192 if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU0",
193 NULL, &devvps[0], NULL)) != 0)
194 errx(1, "raw device 0 lookup failed %d", rv);
195 if ((rv = rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, "/dev/ttyU1",
196 NULL, &devvps[1], NULL)) != 0)
197 errx(1, "raw device 1 lookup failed %d", rv);
198
199 rootcred = rump_pub_cred_create(0, 0, 0, NULL);
200
201 /* process requests ad infinitum */
202 for (;;) {
203 pthread_t pt;
204
205 #define PDRSIZE (64*1024+1024)
206 pdr = malloc(PDRSIZE);
207 if (pdr == NULL)
208 err(1, "malloc");
209
210 n = read(fd, pdr, PDRSIZE);
211 if (n == -1)
212 err(1, "read");
213
214 /*
215 * tip & cu fork and read/write at the same time. hence,
216 * we need a multithreaded server as otherwise read requests
217 * will block eternally since no writes can be done.
218 *
219 * XXX: do this properly (detached threads, or pool)
220 */
221 pthread_create(&pt, NULL, handlereq, pdr);
222 }
223 }
224