streams.c revision 49413
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 * $Id: streams.c,v 1.8 1999/08/01 12:51:06 newton Exp $ 34105760Srwatson */ 35105760Srwatson 36105760Srwatson#include "streams.h" /* generated file.. defines NSTREAMS */ 37105760Srwatson#include "opt_devfs.h" 38105760Srwatson#include <sys/param.h> 39105760Srwatson#include <sys/systm.h> 40105760Srwatson#include <sys/kernel.h> /* SYSINIT stuff */ 41105760Srwatson#include <sys/conf.h> /* cdevsw stuff */ 42105760Srwatson#include <sys/malloc.h> /* malloc region definitions */ 43105760Srwatson#include <sys/file.h> 44105760Srwatson#include <sys/filedesc.h> 45105760Srwatson#include <sys/unistd.h> 46105760Srwatson#include <sys/fcntl.h> 47105760Srwatson#include <sys/socket.h> 48105760Srwatson#include <sys/protosw.h> 49105760Srwatson#include <sys/socketvar.h> 50105760Srwatson#include <sys/un.h> 51105760Srwatson#include <sys/domain.h> 52105760Srwatson#include <net/if.h> 53105760Srwatson#include <netinet/in.h> 54105760Srwatson#include <sys/proc.h> 55105760Srwatson#include <sys/uio.h> 56105760Srwatson#ifdef DEVFS 57105760Srwatson#include <sys/devfsext.h> /* DEVFS defintitions */ 58105760Srwatson#endif /* DEVFS */ 59105760Srwatson 60105760Srwatson#include <sys/sysproto.h> 61105760Srwatson 62105760Srwatson#include <svr4/svr4_types.h> 63105760Srwatson#include <svr4/svr4_util.h> 64105760Srwatson#include <svr4/svr4_signal.h> 65105760Srwatson#include <svr4/svr4_ioctl.h> 66105760Srwatson#include <svr4/svr4_stropts.h> 67105760Srwatson#include <svr4/svr4_socket.h> 68105760Srwatson 69105760Srwatsonstatic int svr4_soo_close __P((struct file *, struct proc *)); 70105760Srwatsonstatic int svr4_ptm_alloc __P((struct proc *)); 71105760Srwatsonstatic d_open_t streamsopen; 72105760Srwatson 73105760Srwatsonstruct svr4_sockcache_entry { 74105760Srwatson struct proc *p; /* Process for the socket */ 75105760Srwatson void *cookie; /* Internal cookie used for matching */ 76105760Srwatson struct sockaddr_un sock;/* Pathname for the socket */ 77105760Srwatson dev_t dev; /* Device where the socket lives on */ 78105760Srwatson ino_t ino; /* Inode where the socket lives on */ 79105760Srwatson TAILQ_ENTRY(svr4_sockcache_entry) entries; 80105760Srwatson}; 81105760Srwatson 82105760SrwatsonTAILQ_HEAD(svr4_sockcache_head, svr4_sockcache_entry) svr4_head; 83105760Srwatson 84105760Srwatson/* Initialization flag (set/queried by svr4_mod LKM) */ 85105760Srwatsonint svr4_str_initialized = 0; 86105760Srwatson 87105760Srwatson/* 88105760Srwatson * Device minor numbers 89105760Srwatson */ 90105760Srwatsonenum { 91105760Srwatson dev_ptm = 10, 92105760Srwatson dev_arp = 26, 93105760Srwatson dev_icmp = 27, 94105760Srwatson dev_ip = 28, 95105760Srwatson dev_tcp = 35, 96105760Srwatson dev_udp = 36, 97105760Srwatson dev_rawip = 37, 98105760Srwatson dev_unix_dgram = 38, 99105760Srwatson dev_unix_stream = 39, 100105760Srwatson dev_unix_ord_stream = 40 101}; 102 103static struct fileops svr4_netops = { 104 soo_read, soo_write, soo_ioctl, soo_poll, svr4_soo_close 105}; 106 107#define CDEV_MAJOR 103 108static struct cdevsw streams_cdevsw = { 109 /* open */ streamsopen, 110 /* close */ noclose, 111 /* read */ noread, 112 /* write */ nowrite, 113 /* ioctl */ noioctl, 114 /* stop */ nostop, 115 /* reset */ noreset, 116 /* devtotty */ nodevtotty, 117 /* poll */ nopoll, 118 /* mmap */ nommap, 119 /* strategy */ nostrategy, 120 /* name */ "streams", 121 /* parms */ noparms, 122 /* maj */ CDEV_MAJOR, 123 /* dump */ nodump, 124 /* psize */ nopsize, 125 /* flags */ 0, 126 /* maxio */ 0, 127 /* bmaj */ -1 128}; 129 130struct streams_softc { 131 struct isa_device *dev; 132#ifdef DEVFS 133 /* 134 * If this ever becomes an LKM we'll want this crud so we can deallocate 135 * devfs entries when the module is unloaded 136 */ 137 void *devfs_ptm; 138 void *devfs_arp; 139 void *devfs_icmp; 140 void *devfs_ip; 141 void *devfs_tcp; 142 void *devfs_udp; 143 void *devfs_rawip; 144 void *devfs_unix_dgram; 145 void *devfs_unix_stream; 146 void *devfs_unix_ord_stream; 147#endif 148} ; 149 150#define UNIT(dev) minor(dev) /* assume one minor number per unit */ 151 152typedef struct streams_softc *sc_p; 153 154static int 155streams_modevent(module_t mod, int type, void *unused) 156{ 157 switch (type) { 158 case MOD_LOAD: 159 /* XXX should make sure it isn't already loaded first */ 160 cdevsw_add(&streams_cdevsw); 161 return 0; 162 case MOD_UNLOAD: 163 /* XXX should check to see if it's busy first */ 164 cdevsw_remove(&streams_cdevsw); 165 return 0; 166 default: 167 break; 168 } 169 return 0; 170} 171 172static moduledata_t streams_mod = { 173 "streams", 174 streams_modevent, 175 0 176}; 177DECLARE_MODULE(streams, streams_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); 178 179/* 180 * We only need open() and close() routines. open() calls socreate() 181 * to allocate a "real" object behind the stream and mallocs some state 182 * info for use by the svr4 emulator; close() deallocates the state 183 * information and passes the underlying object to the normal socket close 184 * routine. 185 */ 186static int 187streamsopen(dev_t dev, int oflags, int devtype, struct proc *p) 188{ 189 int type, protocol; 190 int fd; 191 struct file *fp; 192 struct socket *so; 193 int error; 194 int family; 195 196 if (p->p_dupfd >= 0) 197 return ENODEV; 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(p); 240 241 default: 242 return EOPNOTSUPP; 243 } 244 245 if ((error = falloc(p, &fp, &fd)) != 0) 246 return error; 247 248 if ((error = socreate(family, &so, type, protocol, p)) != 0) { 249 p->p_fd->fd_ofiles[fd] = 0; 250 ffree(fp); 251 return error; 252 } 253 254 fp->f_data = (caddr_t)so; 255 fp->f_flag = FREAD|FWRITE; 256 fp->f_ops = &svr4_netops; 257 fp->f_type = DTYPE_SOCKET; 258 259 (void)svr4_stream_get(fp); 260 p->p_dupfd = fd; 261 return ENXIO; 262} 263 264static int 265svr4_ptm_alloc(p) 266 struct proc *p; 267{ 268 /* 269 * XXX this is very, very ugly. But I can't find a better 270 * way that won't duplicate a big amount of code from 271 * sys_open(). Ho hum... 272 * 273 * Fortunately for us, Solaris (at least 2.5.1) makes the 274 * /dev/ptmx open automatically just open a pty, that (after 275 * STREAMS I_PUSHes), is just a plain pty. fstat() is used 276 * to get the minor device number to map to a tty. 277 * 278 * Cycle through the names. If sys_open() returns ENOENT (or 279 * ENXIO), short circuit the cycle and exit. 280 */ 281 static char ptyname[] = "/dev/ptyXX"; 282 static char ttyletters[] = "pqrstuwxyzPQRST"; 283 static char ttynumbers[] = "0123456789abcdef"; 284 caddr_t sg = stackgap_init(); 285 char *path = stackgap_alloc(&sg, sizeof(ptyname)); 286 struct open_args oa; 287 int l = 0, n = 0; 288 register_t fd = -1; 289 int error; 290 291 SCARG(&oa, path) = path; 292 SCARG(&oa, flags) = O_RDWR; 293 SCARG(&oa, mode) = 0; 294 295 while (fd == -1) { 296 ptyname[8] = ttyletters[l]; 297 ptyname[9] = ttynumbers[n]; 298 299 if ((error = copyout(ptyname, path, sizeof(ptyname))) != 0) 300 return error; 301 302 switch (error = open(p, &oa)) { 303 case ENOENT: 304 case ENXIO: 305 return error; 306 case 0: 307 p->p_dupfd = p->p_retval[0]; 308 return ENXIO; 309 default: 310 if (ttynumbers[++n] == '\0') { 311 if (ttyletters[++l] == '\0') 312 break; 313 n = 0; 314 } 315 } 316 } 317 return ENOENT; 318} 319 320 321struct svr4_strm * 322svr4_stream_get(fp) 323 struct file *fp; 324{ 325 struct socket *so; 326 struct svr4_strm *st; 327 328 if (fp == NULL || fp->f_type != DTYPE_SOCKET) 329 return NULL; 330 331 so = (struct socket *) fp->f_data; 332 333 if (so->so_emuldata) 334 return so->so_emuldata; 335 336 /* Allocate a new one. */ 337 st = malloc(sizeof(struct svr4_strm), M_TEMP, M_WAITOK); 338 st->s_family = so->so_proto->pr_domain->dom_family; 339 st->s_cmd = ~0; 340 st->s_afd = -1; 341 st->s_eventmask = 0; 342 so->so_emuldata = st; 343 fp->f_ops = &svr4_netops; 344 345 return st; 346} 347 348void 349svr4_delete_socket(p, fp) 350 struct proc *p; 351 struct file *fp; 352{ 353 struct svr4_sockcache_entry *e; 354 void *cookie = ((struct socket *) fp->f_data)->so_emuldata; 355 356 if (!svr4_str_initialized) { 357 TAILQ_INIT(&svr4_head); 358 svr4_str_initialized = 1; 359 return; 360 } 361 362 for (e = svr4_head.tqh_first; e != NULL; e = e->entries.tqe_next) 363 if (e->p == p && e->cookie == cookie) { 364 TAILQ_REMOVE(&svr4_head, e, entries); 365 DPRINTF(("svr4_delete_socket: %s [%p,%d,%d]\n", 366 e->sock.sun_path, p, e->dev, e->ino)); 367 free(e, M_TEMP); 368 return; 369 } 370} 371 372static int 373svr4_soo_close(struct file *fp, struct proc *p) 374{ 375 struct socket *so = (struct socket *)fp->f_data; 376 377 /* CHECKUNIT_DIAG(ENXIO);*/ 378 379 svr4_delete_socket(p, fp); 380 free(so->so_emuldata, M_TEMP); 381 return soo_close(fp, p); 382 return (0); 383} 384