streams.c revision 115550
1105760Srwatson/* 2105760Srwatson * Copyright (c) 1998 Mark Newton 3105760Srwatson * Copyright (c) 1994 Christos Zoulas 4105760Srwatson * Copyright (c) 1997 Todd Vierling 5105760Srwatson * All rights reserved. 6105760Srwatson * 7105760Srwatson * Redistribution and use in source and binary forms, with or without 8105760Srwatson * modification, are permitted provided that the following conditions 9105760Srwatson * are met: 10105760Srwatson * 1. Redistributions of source code must retain the above copyright 11105760Srwatson * notice, this list of conditions and the following disclaimer. 12105760Srwatson * 2. Redistributions in binary form must reproduce the above copyright 13105760Srwatson * notice, this list of conditions and the following disclaimer in the 14105760Srwatson * documentation and/or other materials provided with the distribution. 15105760Srwatson * 3. The names of the authors may not be used to endorse or promote products 16105760Srwatson * derived from this software without specific prior written permission 17105760Srwatson * 18105760Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19105760Srwatson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20105760Srwatson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21105760Srwatson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22105760Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23105760Srwatson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24105760Srwatson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25105760Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26105760Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27105760Srwatson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28105760Srwatson * 29105760Srwatson * Stolen from NetBSD /sys/compat/svr4/svr4_net.c. Pseudo-device driver 30105760Srwatson * skeleton produced from /usr/share/examples/drivers/make_pseudo_driver.sh 31105760Srwatson * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-). 32105760Srwatson * 33105760Srwatson * $FreeBSD: head/sys/dev/streams/streams.c 115550 2003-05-31 20:33:18Z phk $ 34105760Srwatson */ 35105760Srwatson 36105760Srwatson#include <sys/param.h> 37105760Srwatson#include <sys/systm.h> 38105760Srwatson#include <sys/kernel.h> /* SYSINIT stuff */ 39105760Srwatson#include <sys/conf.h> /* cdevsw stuff */ 40105760Srwatson#include <sys/malloc.h> /* malloc region definitions */ 41105760Srwatson#include <sys/file.h> 42105760Srwatson#include <sys/filedesc.h> 43105760Srwatson#include <sys/unistd.h> 44105760Srwatson#include <sys/fcntl.h> 45105760Srwatson#include <sys/socket.h> 46105760Srwatson#include <sys/protosw.h> 47105760Srwatson#include <sys/socketvar.h> 48105760Srwatson#include <sys/un.h> 49105760Srwatson#include <sys/domain.h> 50105760Srwatson#include <net/if.h> 51105760Srwatson#include <netinet/in.h> 52105760Srwatson#include <sys/proc.h> 53105825Srwatson#include <sys/uio.h> 54105760Srwatson 55105760Srwatson#include <sys/sysproto.h> 56105760Srwatson 57105760Srwatson#include <compat/svr4/svr4_types.h> 58105760Srwatson#include <compat/svr4/svr4_util.h> 59105760Srwatson#include <compat/svr4/svr4_signal.h> 60105760Srwatson#include <compat/svr4/svr4_ioctl.h> 61105760Srwatson#include <compat/svr4/svr4_stropts.h> 62105760Srwatson#include <compat/svr4/svr4_socket.h> 63105760Srwatson 64105760Srwatsonstatic int svr4_soo_close(struct file *, struct thread *); 65105760Srwatsonstatic int svr4_ptm_alloc(struct thread *); 66105760Srwatsonstatic d_open_t streamsopen; 67105760Srwatson 68105760Srwatsonstruct svr4_sockcache_head svr4_head; 69105760Srwatson 70105760Srwatson/* Initialization flag (set/queried by svr4_mod LKM) */ 71105760Srwatsonint svr4_str_initialized = 0; 72105760Srwatson 73105825Srwatson/* 74105760Srwatson * Device minor numbers 75105760Srwatson */ 76105760Srwatsonenum { 77105760Srwatson dev_ptm = 10, 78105760Srwatson dev_arp = 26, 79105760Srwatson dev_icmp = 27, 80105760Srwatson dev_ip = 28, 81105825Srwatson dev_tcp = 35, 82105760Srwatson dev_udp = 36, 83105760Srwatson dev_rawip = 37, 84105760Srwatson dev_unix_dgram = 38, 85105760Srwatson dev_unix_stream = 39, 86105760Srwatson dev_unix_ord_stream = 40 87105760Srwatson}; 88105760Srwatson 89105760Srwatsonstatic dev_t dt_ptm, dt_arp, dt_icmp, dt_ip, dt_tcp, dt_udp, dt_rawip, 90105760Srwatson dt_unix_dgram, dt_unix_stream, dt_unix_ord_stream; 91105760Srwatson 92105760Srwatsonstatic struct fileops svr4_netops = { 93105760Srwatson soo_read, soo_write, soo_ioctl, soo_poll, soo_kqfilter, 94105760Srwatson soo_stat, svr4_soo_close 95105760Srwatson}; 96105760Srwatson 97105760Srwatson#define CDEV_MAJOR 103 98105760Srwatsonstatic struct cdevsw streams_cdevsw = { 99105760Srwatson .d_open = streamsopen, 100105760Srwatson .d_name = "streams", 101 .d_maj = CDEV_MAJOR, 102}; 103 104struct streams_softc { 105 struct isa_device *dev; 106} ; 107 108#define UNIT(dev) minor(dev) /* assume one minor number per unit */ 109 110typedef struct streams_softc *sc_p; 111 112static int 113streams_modevent(module_t mod, int type, void *unused) 114{ 115 switch (type) { 116 case MOD_LOAD: 117 /* XXX should make sure it isn't already loaded first */ 118 dt_ptm = make_dev(&streams_cdevsw, dev_ptm, 0, 0, 0666, 119 "ptm"); 120 dt_arp = make_dev(&streams_cdevsw, dev_arp, 0, 0, 0666, 121 "arp"); 122 dt_icmp = make_dev(&streams_cdevsw, dev_icmp, 0, 0, 0666, 123 "icmp"); 124 dt_ip = make_dev(&streams_cdevsw, dev_ip, 0, 0, 0666, 125 "ip"); 126 dt_tcp = make_dev(&streams_cdevsw, dev_tcp, 0, 0, 0666, 127 "tcp"); 128 dt_udp = make_dev(&streams_cdevsw, dev_udp, 0, 0, 0666, 129 "udp"); 130 dt_rawip = make_dev(&streams_cdevsw, dev_rawip, 0, 0, 0666, 131 "rawip"); 132 dt_unix_dgram = make_dev(&streams_cdevsw, dev_unix_dgram, 133 0, 0, 0666, "ticlts"); 134 dt_unix_stream = make_dev(&streams_cdevsw, dev_unix_stream, 135 0, 0, 0666, "ticots"); 136 dt_unix_ord_stream = make_dev(&streams_cdevsw, 137 dev_unix_ord_stream, 0, 0, 0666, "ticotsord"); 138 139 if (! (dt_ptm && dt_arp && dt_icmp && dt_ip && dt_tcp && 140 dt_udp && dt_rawip && dt_unix_dgram && 141 dt_unix_stream && dt_unix_ord_stream)) { 142 printf("WARNING: device config for STREAMS failed\n"); 143 printf("Suggest unloading streams KLD\n"); 144 } 145 return 0; 146 case MOD_UNLOAD: 147 /* XXX should check to see if it's busy first */ 148 destroy_dev(dt_ptm); 149 destroy_dev(dt_arp); 150 destroy_dev(dt_icmp); 151 destroy_dev(dt_ip); 152 destroy_dev(dt_tcp); 153 destroy_dev(dt_udp); 154 destroy_dev(dt_rawip); 155 destroy_dev(dt_unix_dgram); 156 destroy_dev(dt_unix_stream); 157 destroy_dev(dt_unix_ord_stream); 158 159 return 0; 160 default: 161 break; 162 } 163 return 0; 164} 165 166static moduledata_t streams_mod = { 167 "streams", 168 streams_modevent, 169 0 170}; 171DECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); 172MODULE_VERSION(streams, 1); 173 174/* 175 * We only need open() and close() routines. open() calls socreate() 176 * to allocate a "real" object behind the stream and mallocs some state 177 * info for use by the svr4 emulator; close() deallocates the state 178 * information and passes the underlying object to the normal socket close 179 * routine. 180 */ 181static int 182streamsopen(dev_t dev, int oflags, int devtype, struct thread *td) 183{ 184 int type, protocol; 185 int fd; 186 struct file *fp; 187 struct socket *so; 188 int error; 189 int family; 190 struct proc *p = td->td_proc; 191 192 PROC_LOCK(p); 193 if (td->td_dupfd >= 0) { 194 PROC_UNLOCK(p); 195 return ENODEV; 196 } 197 PROC_UNLOCK(p); 198 199 switch (minor(dev)) { 200 case dev_udp: 201 family = AF_INET; 202 type = SOCK_DGRAM; 203 protocol = IPPROTO_UDP; 204 break; 205 206 case dev_tcp: 207 family = AF_INET; 208 type = SOCK_STREAM; 209 protocol = IPPROTO_TCP; 210 break; 211 212 case dev_ip: 213 case dev_rawip: 214 family = AF_INET; 215 type = SOCK_RAW; 216 protocol = IPPROTO_IP; 217 break; 218 219 case dev_icmp: 220 family = AF_INET; 221 type = SOCK_RAW; 222 protocol = IPPROTO_ICMP; 223 break; 224 225 case dev_unix_dgram: 226 family = AF_LOCAL; 227 type = SOCK_DGRAM; 228 protocol = 0; 229 break; 230 231 case dev_unix_stream: 232 case dev_unix_ord_stream: 233 family = AF_LOCAL; 234 type = SOCK_STREAM; 235 protocol = 0; 236 break; 237 238 case dev_ptm: 239 return svr4_ptm_alloc(td); 240 241 default: 242 return EOPNOTSUPP; 243 } 244 245 if ((error = falloc(td, &fp, &fd)) != 0) 246 return error; 247 248 if ((error = socreate(family, &so, type, protocol, 249 td->td_ucred, td)) != 0) { 250 FILEDESC_LOCK(p->p_fd); 251 p->p_fd->fd_ofiles[fd] = 0; 252 FILEDESC_UNLOCK(p->p_fd); 253 ffree(fp); 254 return error; 255 } 256 257 FILEDESC_LOCK(p->p_fd); 258 fp->f_data = so; 259 fp->f_flag = FREAD|FWRITE; 260 fp->f_ops = &svr4_netops; 261 fp->f_type = DTYPE_SOCKET; 262 FILEDESC_UNLOCK(p->p_fd); 263 264 (void)svr4_stream_get(fp); 265 PROC_LOCK(p); 266 td->td_dupfd = fd; 267 PROC_UNLOCK(p); 268 return ENXIO; 269} 270 271static int 272svr4_ptm_alloc(td) 273 struct thread *td; 274{ 275 struct proc *p = td->td_proc; 276 /* 277 * XXX this is very, very ugly. But I can't find a better 278 * way that won't duplicate a big amount of code from 279 * sys_open(). Ho hum... 280 * 281 * Fortunately for us, Solaris (at least 2.5.1) makes the 282 * /dev/ptmx open automatically just open a pty, that (after 283 * STREAMS I_PUSHes), is just a plain pty. fstat() is used 284 * to get the minor device number to map to a tty. 285 * 286 * Cycle through the names. If sys_open() returns ENOENT (or 287 * ENXIO), short circuit the cycle and exit. 288 */ 289 static char ptyname[] = "/dev/ptyXX"; 290 static char ttyletters[] = "pqrstuwxyzPQRST"; 291 static char ttynumbers[] = "0123456789abcdef"; 292 caddr_t sg = stackgap_init(); 293 char *path = stackgap_alloc(&sg, sizeof(ptyname)); 294 struct open_args oa; 295 int l = 0, n = 0; 296 register_t fd = -1; 297 int error; 298 299 oa.path = path; 300 oa.flags = O_RDWR; 301 oa.mode = 0; 302 303 while (fd == -1) { 304 ptyname[8] = ttyletters[l]; 305 ptyname[9] = ttynumbers[n]; 306 307 if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0) 308 return error; 309 310 switch (error = open(td, &oa)) { 311 case ENOENT: 312 case ENXIO: 313 return error; 314 case 0: 315 PROC_LOCK(p); 316 td->td_dupfd = td->td_retval[0]; 317 PROC_UNLOCK(p); 318 return ENXIO; 319 default: 320 if (ttynumbers[++n] == '\0') { 321 if (ttyletters[++l] == '\0') 322 break; 323 n = 0; 324 } 325 } 326 } 327 return ENOENT; 328} 329 330 331struct svr4_strm * 332svr4_stream_get(fp) 333 struct file *fp; 334{ 335 struct socket *so; 336 struct svr4_strm *st; 337 338 if (fp == NULL || fp->f_type != DTYPE_SOCKET) 339 return NULL; 340 341 so = fp->f_data; 342 343 /* 344 * mpfixme: lock socketbuffer here 345 */ 346 if (so->so_emuldata) { 347 return so->so_emuldata; 348 } 349 350 /* Allocate a new one. */ 351 st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK); 352 st->s_family = so->so_proto->pr_domain->dom_family; 353 st->s_cmd = ~0; 354 st->s_afd = -1; 355 st->s_eventmask = 0; 356 /* 357 * avoid a race where we loose due to concurrancy issues 358 * of two threads trying to allocate the so_emuldata. 359 */ 360 if (so->so_emuldata) { 361 /* lost the race, use the existing emuldata */ 362 FREE(st, M_TEMP); 363 st = so->so_emuldata; 364 } else { 365 /* we won, or there was no race, use our copy */ 366 so->so_emuldata = st; 367 fp->f_ops = &svr4_netops; 368 } 369 370 return st; 371} 372 373void 374svr4_delete_socket(p, fp) 375 struct proc *p; 376 struct file *fp; 377{ 378 struct svr4_sockcache_entry *e; 379 void *cookie = ((struct socket *)fp->f_data)->so_emuldata; 380 381 while (svr4_str_initialized != 2) { 382 if (atomic_cmpset_acq_int(&svr4_str_initialized, 0, 1)) { 383 TAILQ_INIT(&svr4_head); 384 atomic_store_rel_int(&svr4_str_initialized, 2); 385 } 386 return; 387 } 388 389 TAILQ_FOREACH(e, &svr4_head, entries) 390 if (e->p == p && e->cookie == cookie) { 391 TAILQ_REMOVE(&svr4_head, e, entries); 392 DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n", 393 e->sock.sun_path, p, (int)e->dev, e->ino)); 394 free(e, M_TEMP); 395 return; 396 } 397} 398 399static int 400svr4_soo_close(struct file *fp, struct thread *td) 401{ 402 struct socket *so = fp->f_data; 403 404 /* CHECKUNIT_DIAG(ENXIO);*/ 405 406 svr4_delete_socket(td->td_proc, fp); 407 free(so->so_emuldata, M_TEMP); 408 return soo_close(fp, td); 409} 410