streams.c revision 174988
1286953Sandrew/*- 2286953Sandrew * Copyright (c) 1998 Mark Newton 3286953Sandrew * Copyright (c) 1994 Christos Zoulas 4286953Sandrew * Copyright (c) 1997 Todd Vierling 5286953Sandrew * All rights reserved. 6286953Sandrew * 7286953Sandrew * Redistribution and use in source and binary forms, with or without 8286953Sandrew * modification, are permitted provided that the following conditions 9286953Sandrew * are met: 10286953Sandrew * 1. Redistributions of source code must retain the above copyright 11286953Sandrew * notice, this list of conditions and the following disclaimer. 12286953Sandrew * 2. Redistributions in binary form must reproduce the above copyright 13286953Sandrew * notice, this list of conditions and the following disclaimer in the 14286953Sandrew * documentation and/or other materials provided with the distribution. 15286953Sandrew * 3. The names of the authors may not be used to endorse or promote products 16286953Sandrew * derived from this software without specific prior written permission 17286953Sandrew * 18286953Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19286953Sandrew * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20286953Sandrew * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21286953Sandrew * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22286953Sandrew * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23286953Sandrew * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24286953Sandrew * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25286953Sandrew * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26286953Sandrew * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27286953Sandrew * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28286953Sandrew * 29286953Sandrew * Stolen from NetBSD /sys/compat/svr4/svr4_net.c. Pseudo-device driver 30286953Sandrew * skeleton produced from /usr/share/examples/drivers/make_pseudo_driver.sh 31286953Sandrew * in 3.0-980524-SNAP then hacked a bit (but probably not enough :-). 32291372Sjhb * 33286953Sandrew */ 34286953Sandrew 35286953Sandrew#include <sys/cdefs.h> 36291406Sjhb__FBSDID("$FreeBSD: head/sys/dev/streams/streams.c 174988 2007-12-30 01:42:15Z jeff $"); 37286953Sandrew 38286953Sandrew#include <sys/param.h> 39286953Sandrew#include <sys/systm.h> 40286953Sandrew#include <sys/kernel.h> /* SYSINIT stuff */ 41286953Sandrew#include <sys/conf.h> /* cdevsw stuff */ 42291406Sjhb#include <sys/malloc.h> /* malloc region definitions */ 43286953Sandrew#include <sys/file.h> 44286953Sandrew#include <sys/filedesc.h> 45286953Sandrew#include <sys/unistd.h> 46286953Sandrew#include <sys/fcntl.h> 47291406Sjhb#include <sys/socket.h> 48286953Sandrew#include <sys/protosw.h> 49291406Sjhb#include <sys/socketvar.h> 50286953Sandrew#include <sys/syscallsubr.h> 51286953Sandrew#include <sys/un.h> 52286953Sandrew#include <sys/domain.h> 53291406Sjhb#include <net/if.h> 54286953Sandrew#include <netinet/in.h> 55286953Sandrew#include <sys/proc.h> 56286953Sandrew#include <sys/uio.h> 57286953Sandrew 58291406Sjhb#include <sys/sysproto.h> 59286953Sandrew 60286953Sandrew#include <compat/svr4/svr4_types.h> 61291406Sjhb#include <compat/svr4/svr4_util.h> 62291406Sjhb#include <compat/svr4/svr4_signal.h> 63286953Sandrew#include <compat/svr4/svr4_ioctl.h> 64286953Sandrew#include <compat/svr4/svr4_stropts.h> 65291406Sjhb#include <compat/svr4/svr4_socket.h> 66291406Sjhb 67286953Sandrewstatic int svr4_soo_close(struct file *, struct thread *); 68286953Sandrewstatic int svr4_ptm_alloc(struct thread *); 69286953Sandrewstatic d_open_t streamsopen; 70291406Sjhb 71286953Sandrew/* 72286953Sandrew * Device minor numbers 73286953Sandrew */ 74286953Sandrewenum { 75286953Sandrew dev_ptm = 10, 76291406Sjhb dev_arp = 26, 77291406Sjhb dev_icmp = 27, 78286953Sandrew dev_ip = 28, 79286953Sandrew dev_tcp = 35, 80291406Sjhb dev_udp = 36, 81286953Sandrew dev_rawip = 37, 82286953Sandrew dev_unix_dgram = 38, 83286953Sandrew dev_unix_stream = 39, 84298485Sngie dev_unix_ord_stream = 40 85286953Sandrew}; 86286953Sandrew 87286953Sandrewstatic struct cdev *dt_ptm, *dt_arp, *dt_icmp, *dt_ip, *dt_tcp, *dt_udp, 88286953Sandrew *dt_rawip, *dt_unix_dgram, *dt_unix_stream, *dt_unix_ord_stream; 89286953Sandrew 90286953Sandrewstatic struct fileops svr4_netops = { 91286953Sandrew .fo_read = soo_read, 92286953Sandrew .fo_write = soo_write, 93286953Sandrew .fo_ioctl = soo_ioctl, 94286953Sandrew .fo_poll = soo_poll, 95286953Sandrew .fo_kqfilter = soo_kqfilter, 96286953Sandrew .fo_stat = soo_stat, 97286953Sandrew .fo_close = svr4_soo_close 98286953Sandrew}; 99286953Sandrew 100291406Sjhbstatic struct cdevsw streams_cdevsw = { 101291406Sjhb .d_version = D_VERSION, 102286953Sandrew .d_open = streamsopen, 103286953Sandrew .d_name = "streams", 104286953Sandrew}; 105286953Sandrew 106291406Sjhbstruct streams_softc { 107291406Sjhb struct isa_device *dev; 108291406Sjhb} ; 109291406Sjhb 110291406Sjhb#define UNIT(dev) minor(dev) /* assume one minor number per unit */ 111291406Sjhb 112291406Sjhbtypedef struct streams_softc *sc_p; 113286953Sandrew 114286953Sandrewstatic int 115291406Sjhbstreams_modevent(module_t mod, int type, void *unused) 116286953Sandrew{ 117291406Sjhb switch (type) { 118291406Sjhb case MOD_LOAD: 119286953Sandrew dt_ptm = make_dev(&streams_cdevsw, dev_ptm, 0, 0, 0666, 120286953Sandrew "ptm"); 121286953Sandrew dt_arp = make_dev(&streams_cdevsw, dev_arp, 0, 0, 0666, 122286953Sandrew "arp"); 123286953Sandrew dt_icmp = make_dev(&streams_cdevsw, dev_icmp, 0, 0, 0666, 124291406Sjhb "icmp"); 125291406Sjhb dt_ip = make_dev(&streams_cdevsw, dev_ip, 0, 0, 0666, 126286953Sandrew "ip"); 127286953Sandrew dt_tcp = make_dev(&streams_cdevsw, dev_tcp, 0, 0, 0666, 128286953Sandrew "tcp"); 129291406Sjhb dt_udp = make_dev(&streams_cdevsw, dev_udp, 0, 0, 0666, 130286953Sandrew "udp"); 131286953Sandrew dt_rawip = make_dev(&streams_cdevsw, dev_rawip, 0, 0, 0666, 132291406Sjhb "rawip"); 133286953Sandrew dt_unix_dgram = make_dev(&streams_cdevsw, dev_unix_dgram, 134286953Sandrew 0, 0, 0666, "ticlts"); 135286953Sandrew dt_unix_stream = make_dev(&streams_cdevsw, dev_unix_stream, 136286953Sandrew 0, 0, 0666, "ticots"); 137286953Sandrew dt_unix_ord_stream = make_dev(&streams_cdevsw, 138286953Sandrew dev_unix_ord_stream, 0, 0, 0666, "ticotsord"); 139291406Sjhb 140286953Sandrew if (! (dt_ptm && dt_arp && dt_icmp && dt_ip && dt_tcp && 141286953Sandrew dt_udp && dt_rawip && dt_unix_dgram && 142286953Sandrew dt_unix_stream && dt_unix_ord_stream)) { 143291406Sjhb printf("WARNING: device config for STREAMS failed\n"); 144291406Sjhb printf("Suggest unloading streams KLD\n"); 145291406Sjhb } 146291406Sjhb return 0; 147291406Sjhb case MOD_UNLOAD: 148286953Sandrew /* XXX should check to see if it's busy first */ 149291406Sjhb destroy_dev(dt_ptm); 150286953Sandrew destroy_dev(dt_arp); 151286953Sandrew destroy_dev(dt_icmp); 152291406Sjhb destroy_dev(dt_ip); 153291406Sjhb destroy_dev(dt_tcp); 154286953Sandrew destroy_dev(dt_udp); 155286953Sandrew destroy_dev(dt_rawip); 156286953Sandrew destroy_dev(dt_unix_dgram); 157286953Sandrew destroy_dev(dt_unix_stream); 158291406Sjhb destroy_dev(dt_unix_ord_stream); 159291406Sjhb 160291406Sjhb return 0; 161286953Sandrew default: 162286953Sandrew return EOPNOTSUPP; 163286953Sandrew break; 164286953Sandrew } 165286953Sandrew return 0; 166291406Sjhb} 167286953Sandrew 168286953Sandrewstatic moduledata_t streams_mod = { 169291406Sjhb "streams", 170291406Sjhb streams_modevent, 171291406Sjhb 0 172291406Sjhb}; 173286953SandrewDECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); 174286953SandrewMODULE_VERSION(streams, 1); 175286953Sandrew 176291406Sjhb/* 177286953Sandrew * We only need open() and close() routines. open() calls socreate() 178286953Sandrew * to allocate a "real" object behind the stream and mallocs some state 179291406Sjhb * info for use by the svr4 emulator; close() deallocates the state 180291406Sjhb * information and passes the underlying object to the normal socket close 181291406Sjhb * routine. 182286953Sandrew */ 183291406Sjhbstatic int 184291406Sjhbstreamsopen(struct cdev *dev, int oflags, int devtype, struct thread *td) 185291406Sjhb{ 186286953Sandrew struct filedesc *fdp; 187286953Sandrew struct svr4_strm *st; 188286953Sandrew struct socket *so; 189291406Sjhb struct file *fp; 190286953Sandrew int family, type, protocol; 191291406Sjhb int error, fd; 192286953Sandrew 193286953Sandrew if (td->td_dupfd >= 0) 194291406Sjhb return ENODEV; 195291406Sjhb 196291406Sjhb switch (minor(dev)) { 197291406Sjhb case dev_udp: 198286953Sandrew family = AF_INET; 199286953Sandrew type = SOCK_DGRAM; 200291406Sjhb protocol = IPPROTO_UDP; 201291406Sjhb break; 202286953Sandrew 203291406Sjhb case dev_tcp: 204291406Sjhb family = AF_INET; 205291406Sjhb type = SOCK_STREAM; 206286953Sandrew protocol = IPPROTO_TCP; 207286953Sandrew break; 208286953Sandrew 209291406Sjhb case dev_ip: 210286953Sandrew case dev_rawip: 211286953Sandrew family = AF_INET; 212291406Sjhb type = SOCK_RAW; 213291406Sjhb protocol = IPPROTO_IP; 214286953Sandrew break; 215286953Sandrew 216286953Sandrew case dev_icmp: 217286953Sandrew family = AF_INET; 218291406Sjhb type = SOCK_RAW; 219286953Sandrew protocol = IPPROTO_ICMP; 220286953Sandrew break; 221286953Sandrew 222291406Sjhb case dev_unix_dgram: 223291406Sjhb family = AF_LOCAL; 224286953Sandrew type = SOCK_DGRAM; 225286953Sandrew protocol = 0; 226286953Sandrew break; 227291406Sjhb 228291406Sjhb case dev_unix_stream: 229286953Sandrew case dev_unix_ord_stream: 230286953Sandrew family = AF_LOCAL; 231291406Sjhb type = SOCK_STREAM; 232286953Sandrew protocol = 0; 233291406Sjhb break; 234291406Sjhb 235291406Sjhb case dev_ptm: 236291406Sjhb return svr4_ptm_alloc(td); 237291406Sjhb 238291406Sjhb default: 239291406Sjhb return EOPNOTSUPP; 240291406Sjhb } 241291406Sjhb 242291406Sjhb fdp = td->td_proc->p_fd; 243291406Sjhb if ((error = falloc(td, &fp, &fd)) != 0) 244291406Sjhb return error; 245291406Sjhb /* An extra reference on `fp' has been held for us by falloc(). */ 246291406Sjhb 247291406Sjhb error = socreate(family, &so, type, protocol, td->td_ucred, td); 248291406Sjhb if (error) { 249291406Sjhb fdclose(fdp, fp, fd, td); 250291406Sjhb fdrop(fp, td); 251291406Sjhb return error; 252291406Sjhb } 253291406Sjhb 254 finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so, &svr4_netops); 255 256 /* 257 * Allocate a stream structure and attach it to this socket. 258 * We don't bother locking so_emuldata for SVR4 stream sockets as 259 * its value is constant for the lifetime of the stream once it 260 * is initialized here. 261 */ 262 st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK); 263 st->s_family = so->so_proto->pr_domain->dom_family; 264 st->s_cmd = ~0; 265 st->s_afd = -1; 266 st->s_eventmask = 0; 267 so->so_emuldata = st; 268 269 fdrop(fp, td); 270 td->td_dupfd = fd; 271 return ENXIO; 272} 273 274static int 275svr4_ptm_alloc(td) 276 struct thread *td; 277{ 278 /* 279 * XXX this is very, very ugly. But I can't find a better 280 * way that won't duplicate a big amount of code from 281 * sys_open(). Ho hum... 282 * 283 * Fortunately for us, Solaris (at least 2.5.1) makes the 284 * /dev/ptmx open automatically just open a pty, that (after 285 * STREAMS I_PUSHes), is just a plain pty. fstat() is used 286 * to get the minor device number to map to a tty. 287 * 288 * Cycle through the names. If sys_open() returns ENOENT (or 289 * ENXIO), short circuit the cycle and exit. 290 */ 291 static char ptyname[] = "/dev/ptyXX"; 292 static char ttyletters[] = "pqrstuwxyzPQRST"; 293 static char ttynumbers[] = "0123456789abcdef"; 294 struct proc *p; 295 register_t fd; 296 int error, l, n; 297 298 fd = -1; 299 n = 0; 300 l = 0; 301 p = td->td_proc; 302 while (fd == -1) { 303 ptyname[8] = ttyletters[l]; 304 ptyname[9] = ttynumbers[n]; 305 306 error = kern_open(td, ptyname, UIO_SYSSPACE, O_RDWR, 0); 307 switch (error) { 308 case ENOENT: 309 case ENXIO: 310 return error; 311 case 0: 312 td->td_dupfd = td->td_retval[0]; 313 return ENXIO; 314 default: 315 if (ttynumbers[++n] == '\0') { 316 if (ttyletters[++l] == '\0') 317 break; 318 n = 0; 319 } 320 } 321 } 322 return ENOENT; 323} 324 325 326struct svr4_strm * 327svr4_stream_get(fp) 328 struct file *fp; 329{ 330 struct socket *so; 331 332 if (fp == NULL || fp->f_type != DTYPE_SOCKET) 333 return NULL; 334 335 so = fp->f_data; 336 return so->so_emuldata; 337} 338 339static int 340svr4_soo_close(struct file *fp, struct thread *td) 341{ 342 struct socket *so = fp->f_data; 343 344 /* CHECKUNIT_DIAG(ENXIO);*/ 345 346 svr4_delete_socket(td->td_proc, fp); 347 free(so->so_emuldata, M_TEMP); 348 return soo_close(fp, td); 349} 350