1dde8a05bSUgen J.S. Antsilevich /* 2dde8a05bSUgen J.S. Antsilevich * Copyright (c) 1995 Ugen J.S.Antsilevich 3dde8a05bSUgen J.S. Antsilevich * 4dde8a05bSUgen J.S. Antsilevich * Redistribution and use in source forms, with and without modification, 5dde8a05bSUgen J.S. Antsilevich * are permitted provided that this entire comment appears intact. 6dde8a05bSUgen J.S. Antsilevich * 7dde8a05bSUgen J.S. Antsilevich * Redistribution in binary form may occur without any restrictions. 8dde8a05bSUgen J.S. Antsilevich * Obviously, it would be nice if you gave credit where credit is due 9dde8a05bSUgen J.S. Antsilevich * but requiring it would be too onerous. 10dde8a05bSUgen J.S. Antsilevich * 11dde8a05bSUgen J.S. Antsilevich * This software is provided ``AS IS'' without any warranties of any kind. 12dde8a05bSUgen J.S. Antsilevich * 13dde8a05bSUgen J.S. Antsilevich * Snoop stuff. 14dde8a05bSUgen J.S. Antsilevich */ 15dde8a05bSUgen J.S. Antsilevich 16dde8a05bSUgen J.S. Antsilevich #include "snp.h" 17dde8a05bSUgen J.S. Antsilevich 18019b4d63SUgen J.S. Antsilevich #if NSNP > 0 19dde8a05bSUgen J.S. Antsilevich 20dde8a05bSUgen J.S. Antsilevich #include <sys/param.h> 21dde8a05bSUgen J.S. Antsilevich #include <sys/systm.h> 22dde8a05bSUgen J.S. Antsilevich #include <sys/ioctl.h> 23dde8a05bSUgen J.S. Antsilevich #include <sys/ioctl_compat.h> /* Oooh..We need O/NTTYDISC */ 24dde8a05bSUgen J.S. Antsilevich #include <sys/proc.h> 25dde8a05bSUgen J.S. Antsilevich #define TTYDEFCHARS 26dde8a05bSUgen J.S. Antsilevich #include <sys/tty.h> 27dde8a05bSUgen J.S. Antsilevich #undef TTYDEFCHARS 28dde8a05bSUgen J.S. Antsilevich #include <sys/file.h> 29dde8a05bSUgen J.S. Antsilevich #include <sys/conf.h> 30dde8a05bSUgen J.S. Antsilevich #include <sys/uio.h> 31dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h> 32dde8a05bSUgen J.S. Antsilevich #include <sys/malloc.h> 3353ac6efbSJulian Elischer #ifdef DEVFS 3453ac6efbSJulian Elischer #include <sys/devfsext.h> 3553ac6efbSJulian Elischer #endif /*DEVFS*/ 3687f6c662SJulian Elischer 3787f6c662SJulian Elischer #include <sys/snoop.h> 3887f6c662SJulian Elischer 3987f6c662SJulian Elischer static d_open_t snpopen; 4087f6c662SJulian Elischer static d_close_t snpclose; 4187f6c662SJulian Elischer static d_read_t snpread; 4287f6c662SJulian Elischer static d_write_t snpwrite; 4387f6c662SJulian Elischer static d_ioctl_t snpioctl; 4487f6c662SJulian Elischer static d_select_t snpselect; 4587f6c662SJulian Elischer 4653ac6efbSJulian Elischer #define CDEV_MAJOR 53 4787f6c662SJulian Elischer struct cdevsw snp_cdevsw = 4887f6c662SJulian Elischer { snpopen, snpclose, snpread, snpwrite, /*53*/ 4987f6c662SJulian Elischer snpioctl, nostop, nullreset, nodevtotty,/* snoop */ 5087f6c662SJulian Elischer snpselect, nommap, NULL, "snp", NULL, -1 }; 5187f6c662SJulian Elischer 5253ac6efbSJulian Elischer 53dde8a05bSUgen J.S. Antsilevich #ifndef MIN 54dde8a05bSUgen J.S. Antsilevich #define MIN(a,b) (((a)<(b))?(a):(b)) 55dde8a05bSUgen J.S. Antsilevich #endif 56dde8a05bSUgen J.S. Antsilevich 57dde8a05bSUgen J.S. Antsilevich static struct snoop snoopsw[NSNP]; 58dde8a05bSUgen J.S. Antsilevich 5998d93822SBruce Evans static struct tty *devtotty __P((dev_t dev)); 6098d93822SBruce Evans 6177f77631SPaul Traina static struct tty * 6277f77631SPaul Traina devtotty (dev) 6377f77631SPaul Traina dev_t dev; 6477f77631SPaul Traina { 6577f77631SPaul Traina if (major(dev) > nchrdev) 6677f77631SPaul Traina return (NULL); /* no such device available */ 6777f77631SPaul Traina 6877f77631SPaul Traina return (*cdevsw[major(dev)].d_devtotty)(dev); 6977f77631SPaul Traina } 7077f77631SPaul Traina 710739a0dcSUgen J.S. Antsilevich #define SNP_INPUT_BUF 5 /* This is even too much,the maximal 720739a0dcSUgen J.S. Antsilevich * interactive mode write is 3 bytes 730739a0dcSUgen J.S. Antsilevich * length for function keys... 740739a0dcSUgen J.S. Antsilevich */ 750739a0dcSUgen J.S. Antsilevich 7687f6c662SJulian Elischer static int 770739a0dcSUgen J.S. Antsilevich snpwrite(dev, uio, flag) 780739a0dcSUgen J.S. Antsilevich dev_t dev; 790739a0dcSUgen J.S. Antsilevich struct uio *uio; 800739a0dcSUgen J.S. Antsilevich int flag; 810739a0dcSUgen J.S. Antsilevich { 820739a0dcSUgen J.S. Antsilevich int unit = minor(dev), len, i, error; 830739a0dcSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 840739a0dcSUgen J.S. Antsilevich struct tty *tp; 850739a0dcSUgen J.S. Antsilevich char c[SNP_INPUT_BUF]; 860739a0dcSUgen J.S. Antsilevich 870739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 880739a0dcSUgen J.S. Antsilevich return (EIO); 890739a0dcSUgen J.S. Antsilevich 900739a0dcSUgen J.S. Antsilevich tp = snp->snp_tty; 910739a0dcSUgen J.S. Antsilevich 920739a0dcSUgen J.S. Antsilevich if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) && 930739a0dcSUgen J.S. Antsilevich (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) 940739a0dcSUgen J.S. Antsilevich goto tty_input; 950739a0dcSUgen J.S. Antsilevich 960739a0dcSUgen J.S. Antsilevich printf("Snoop: attempt to write to bad tty.\n"); 970739a0dcSUgen J.S. Antsilevich return (EIO); 980739a0dcSUgen J.S. Antsilevich 990739a0dcSUgen J.S. Antsilevich tty_input: 1000739a0dcSUgen J.S. Antsilevich if (!(tp->t_state & TS_ISOPEN)) 1010739a0dcSUgen J.S. Antsilevich return (EIO); 1020739a0dcSUgen J.S. Antsilevich 1030739a0dcSUgen J.S. Antsilevich while (uio->uio_resid > 0) { 1040739a0dcSUgen J.S. Antsilevich len = MIN(uio->uio_resid,SNP_INPUT_BUF); 1050739a0dcSUgen J.S. Antsilevich if ((error = uiomove(c, len, uio)) != 0) 1060739a0dcSUgen J.S. Antsilevich return (error); 1070739a0dcSUgen J.S. Antsilevich for (i=0;i<len;i++) { 1080739a0dcSUgen J.S. Antsilevich if (ttyinput(c[i] , tp)) 1090739a0dcSUgen J.S. Antsilevich return (EIO); 1100739a0dcSUgen J.S. Antsilevich } 1110739a0dcSUgen J.S. Antsilevich } 1120739a0dcSUgen J.S. Antsilevich return 0; 1130739a0dcSUgen J.S. Antsilevich 1140739a0dcSUgen J.S. Antsilevich } 1150739a0dcSUgen J.S. Antsilevich 1160739a0dcSUgen J.S. Antsilevich 11787f6c662SJulian Elischer static int 118dde8a05bSUgen J.S. Antsilevich snpread(dev, uio, flag) 119dde8a05bSUgen J.S. Antsilevich dev_t dev; 120dde8a05bSUgen J.S. Antsilevich struct uio *uio; 121dde8a05bSUgen J.S. Antsilevich int flag; 122dde8a05bSUgen J.S. Antsilevich { 123dde8a05bSUgen J.S. Antsilevich int unit = minor(dev), s; 124dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 125dde8a05bSUgen J.S. Antsilevich int len, n, nblen, error = 0; 126dde8a05bSUgen J.S. Antsilevich caddr_t from; 127dde8a05bSUgen J.S. Antsilevich char *nbuf; 128dde8a05bSUgen J.S. Antsilevich 129dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC 130dde8a05bSUgen J.S. Antsilevich if ((snp->snp_len + snp->snp_base) > snp->snp_blen) 131dde8a05bSUgen J.S. Antsilevich panic("snoop buffer error"); 132dde8a05bSUgen J.S. Antsilevich #endif 13377f77631SPaul Traina 1340739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 135dde8a05bSUgen J.S. Antsilevich return (EIO); 136dde8a05bSUgen J.S. Antsilevich 137dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 138dde8a05bSUgen J.S. Antsilevich 139dde8a05bSUgen J.S. Antsilevich do { 140dde8a05bSUgen J.S. Antsilevich if (snp->snp_len == 0) { 141dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_NBIO) { 142dde8a05bSUgen J.S. Antsilevich return EWOULDBLOCK; 143dde8a05bSUgen J.S. Antsilevich } 144dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_RWAIT; 145dde8a05bSUgen J.S. Antsilevich tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0); 146dde8a05bSUgen J.S. Antsilevich } 147dde8a05bSUgen J.S. Antsilevich } while (snp->snp_len == 0); 148dde8a05bSUgen J.S. Antsilevich 149019b4d63SUgen J.S. Antsilevich n = snp->snp_len; 150dde8a05bSUgen J.S. Antsilevich 151dde8a05bSUgen J.S. Antsilevich while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { 152dde8a05bSUgen J.S. Antsilevich len = MIN(uio->uio_resid, snp->snp_len); 153dde8a05bSUgen J.S. Antsilevich from = (caddr_t) (snp->snp_buf + snp->snp_base); 154dde8a05bSUgen J.S. Antsilevich if (len == 0) 155dde8a05bSUgen J.S. Antsilevich break; 156dde8a05bSUgen J.S. Antsilevich 157dde8a05bSUgen J.S. Antsilevich error = uiomove(from, len, uio); 158dde8a05bSUgen J.S. Antsilevich snp->snp_base += len; 159dde8a05bSUgen J.S. Antsilevich snp->snp_len -= len; 160dde8a05bSUgen J.S. Antsilevich } 161019b4d63SUgen J.S. Antsilevich if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) { 162dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OFLOW; 163019b4d63SUgen J.S. Antsilevich } 164dde8a05bSUgen J.S. Antsilevich s = spltty(); 165dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen; 166dde8a05bSUgen J.S. Antsilevich if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) { 167dde8a05bSUgen J.S. Antsilevich while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN)) 168dde8a05bSUgen J.S. Antsilevich nblen = nblen / 2; 169dde8a05bSUgen J.S. Antsilevich if (nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) { 170dde8a05bSUgen J.S. Antsilevich bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 171dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 172dde8a05bSUgen J.S. Antsilevich snp->snp_buf = nbuf; 173dde8a05bSUgen J.S. Antsilevich snp->snp_blen = nblen; 174dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 175dde8a05bSUgen J.S. Antsilevich } 176dde8a05bSUgen J.S. Antsilevich } 177dde8a05bSUgen J.S. Antsilevich splx(s); 178dde8a05bSUgen J.S. Antsilevich 179dde8a05bSUgen J.S. Antsilevich return error; 180dde8a05bSUgen J.S. Antsilevich } 181dde8a05bSUgen J.S. Antsilevich 1820739a0dcSUgen J.S. Antsilevich int 1830739a0dcSUgen J.S. Antsilevich snpinc(snp, c) 1840739a0dcSUgen J.S. Antsilevich struct snoop *snp; 1850739a0dcSUgen J.S. Antsilevich char c; 1860739a0dcSUgen J.S. Antsilevich { 1870739a0dcSUgen J.S. Antsilevich char buf[1]; 1880739a0dcSUgen J.S. Antsilevich 1890739a0dcSUgen J.S. Antsilevich buf[0]=c; 1900739a0dcSUgen J.S. Antsilevich return (snpin(snp,buf,1)); 1910739a0dcSUgen J.S. Antsilevich } 1920739a0dcSUgen J.S. Antsilevich 193dde8a05bSUgen J.S. Antsilevich 194dde8a05bSUgen J.S. Antsilevich int 195dde8a05bSUgen J.S. Antsilevich snpin(snp, buf, n) 196dde8a05bSUgen J.S. Antsilevich struct snoop *snp; 197dde8a05bSUgen J.S. Antsilevich char *buf; 198dde8a05bSUgen J.S. Antsilevich int n; 199dde8a05bSUgen J.S. Antsilevich { 200dde8a05bSUgen J.S. Antsilevich int s_free, s_tail; 201dde8a05bSUgen J.S. Antsilevich int s, len, nblen; 202dde8a05bSUgen J.S. Antsilevich caddr_t from, to; 203dde8a05bSUgen J.S. Antsilevich char *nbuf; 204dde8a05bSUgen J.S. Antsilevich 205dde8a05bSUgen J.S. Antsilevich 206dde8a05bSUgen J.S. Antsilevich if (n == 0) 207dde8a05bSUgen J.S. Antsilevich return 0; 208dde8a05bSUgen J.S. Antsilevich 209dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC 210dde8a05bSUgen J.S. Antsilevich if (n < 0) 211dde8a05bSUgen J.S. Antsilevich panic("bad snoop char count"); 212dde8a05bSUgen J.S. Antsilevich 213019b4d63SUgen J.S. Antsilevich if (!(snp->snp_flags & SNOOP_OPEN)) { 214019b4d63SUgen J.S. Antsilevich printf("Snoop: data coming to closed device.\n"); 215019b4d63SUgen J.S. Antsilevich return 0; 216dde8a05bSUgen J.S. Antsilevich } 217019b4d63SUgen J.S. Antsilevich #endif 218019b4d63SUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_DOWN) { 219019b4d63SUgen J.S. Antsilevich printf("Snoop: more data to down interface.\n"); 220019b4d63SUgen J.S. Antsilevich return 0; 221019b4d63SUgen J.S. Antsilevich } 222964587caSUgen J.S. Antsilevich 223019b4d63SUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OFLOW) { 224019b4d63SUgen J.S. Antsilevich printf("Snoop: buffer overflow.\n"); 225019b4d63SUgen J.S. Antsilevich /* 226019b4d63SUgen J.S. Antsilevich * On overflow we just repeat the standart close 227019b4d63SUgen J.S. Antsilevich * procedure...yes , this is waste of space but.. Then next 228019b4d63SUgen J.S. Antsilevich * read from device will fail if one would recall he is 229019b4d63SUgen J.S. Antsilevich * snooping and retry... 230019b4d63SUgen J.S. Antsilevich */ 231dde8a05bSUgen J.S. Antsilevich 232964587caSUgen J.S. Antsilevich return (snpdown(snp)); 233019b4d63SUgen J.S. Antsilevich } 234019b4d63SUgen J.S. Antsilevich s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base); 235019b4d63SUgen J.S. Antsilevich s_free = snp->snp_blen - snp->snp_len; 236dde8a05bSUgen J.S. Antsilevich 237dde8a05bSUgen J.S. Antsilevich 238dde8a05bSUgen J.S. Antsilevich if (n > s_free) { 239dde8a05bSUgen J.S. Antsilevich s = spltty(); 240dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen; 241dde8a05bSUgen J.S. Antsilevich while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) { 242dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen * 2; 243dde8a05bSUgen J.S. Antsilevich s_free = nblen - (snp->snp_len + snp->snp_base); 244dde8a05bSUgen J.S. Antsilevich } 245dde8a05bSUgen J.S. Antsilevich if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) { 246dde8a05bSUgen J.S. Antsilevich bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 247dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 248dde8a05bSUgen J.S. Antsilevich snp->snp_buf = nbuf; 249dde8a05bSUgen J.S. Antsilevich snp->snp_blen = nblen; 250dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 251dde8a05bSUgen J.S. Antsilevich } else { 252dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_OFLOW; 253dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_RWAIT) { 254dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 255dde8a05bSUgen J.S. Antsilevich wakeup((caddr_t) snp); 256dde8a05bSUgen J.S. Antsilevich } 257dde8a05bSUgen J.S. Antsilevich splx(s); 258dde8a05bSUgen J.S. Antsilevich return 0; 259dde8a05bSUgen J.S. Antsilevich } 260dde8a05bSUgen J.S. Antsilevich splx(s); 261dde8a05bSUgen J.S. Antsilevich } 262dde8a05bSUgen J.S. Antsilevich if (n > s_tail) { 263dde8a05bSUgen J.S. Antsilevich from = (caddr_t) (snp->snp_buf + snp->snp_base); 264dde8a05bSUgen J.S. Antsilevich to = (caddr_t) (snp->snp_buf); 265dde8a05bSUgen J.S. Antsilevich len = snp->snp_len; 266dde8a05bSUgen J.S. Antsilevich bcopy(from, to, len); 267dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 268dde8a05bSUgen J.S. Antsilevich } 269dde8a05bSUgen J.S. Antsilevich to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len); 270dde8a05bSUgen J.S. Antsilevich bcopy(buf, to, n); 271dde8a05bSUgen J.S. Antsilevich snp->snp_len += n; 272dde8a05bSUgen J.S. Antsilevich 273dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_RWAIT) { 274dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 275dde8a05bSUgen J.S. Antsilevich wakeup((caddr_t) snp); 276dde8a05bSUgen J.S. Antsilevich } 277dde8a05bSUgen J.S. Antsilevich selwakeup(&snp->snp_sel); 278dde8a05bSUgen J.S. Antsilevich snp->snp_sel.si_pid = 0; 279dde8a05bSUgen J.S. Antsilevich 280dde8a05bSUgen J.S. Antsilevich return n; 281dde8a05bSUgen J.S. Antsilevich } 282dde8a05bSUgen J.S. Antsilevich 28387f6c662SJulian Elischer static int 284dde8a05bSUgen J.S. Antsilevich snpopen(dev, flag, mode, p) 285dde8a05bSUgen J.S. Antsilevich dev_t dev; 286dde8a05bSUgen J.S. Antsilevich int flag, mode; 287dde8a05bSUgen J.S. Antsilevich struct proc *p; 288dde8a05bSUgen J.S. Antsilevich { 289dde8a05bSUgen J.S. Antsilevich struct snoop *snp; 290dde8a05bSUgen J.S. Antsilevich register int unit, error; 291dde8a05bSUgen J.S. Antsilevich 292dde8a05bSUgen J.S. Antsilevich if (error = suser(p->p_ucred, &p->p_acflag)) 293dde8a05bSUgen J.S. Antsilevich return (error); 294dde8a05bSUgen J.S. Antsilevich 295dde8a05bSUgen J.S. Antsilevich if ((unit = minor(dev)) >= NSNP) 296dde8a05bSUgen J.S. Antsilevich return (ENXIO); 29777f77631SPaul Traina 298dde8a05bSUgen J.S. Antsilevich snp = &snoopsw[unit]; 29977f77631SPaul Traina 300dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OPEN) 301dde8a05bSUgen J.S. Antsilevich return (ENXIO); 30277f77631SPaul Traina 303019b4d63SUgen J.S. Antsilevich /* 304019b4d63SUgen J.S. Antsilevich * We intentionally do not OR flags with SNOOP_OPEN,but set them so 305019b4d63SUgen J.S. Antsilevich * all previous settings (especially SNOOP_OFLOW) will be cleared. 306019b4d63SUgen J.S. Antsilevich */ 307019b4d63SUgen J.S. Antsilevich snp->snp_flags = SNOOP_OPEN; 308dde8a05bSUgen J.S. Antsilevich 309dde8a05bSUgen J.S. Antsilevich snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK); 310dde8a05bSUgen J.S. Antsilevich snp->snp_blen = SNOOP_MINLEN; 311dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 312dde8a05bSUgen J.S. Antsilevich snp->snp_len = 0; 313dde8a05bSUgen J.S. Antsilevich 314dde8a05bSUgen J.S. Antsilevich /* 3150739a0dcSUgen J.S. Antsilevich * snp_tty == NULL is for inactive snoop devices. 316dde8a05bSUgen J.S. Antsilevich */ 3170739a0dcSUgen J.S. Antsilevich snp->snp_tty = NULL; 31877f77631SPaul Traina snp->snp_target = -1; 319dde8a05bSUgen J.S. Antsilevich return (0); 320dde8a05bSUgen J.S. Antsilevich } 321dde8a05bSUgen J.S. Antsilevich 322019b4d63SUgen J.S. Antsilevich 323019b4d63SUgen J.S. Antsilevich int 324019b4d63SUgen J.S. Antsilevich snp_detach(snp) 325019b4d63SUgen J.S. Antsilevich struct snoop *snp; 326019b4d63SUgen J.S. Antsilevich { 327019b4d63SUgen J.S. Antsilevich struct tty *tp; 328019b4d63SUgen J.S. Antsilevich 329019b4d63SUgen J.S. Antsilevich snp->snp_base = 0; 330019b4d63SUgen J.S. Antsilevich snp->snp_len = 0; 331019b4d63SUgen J.S. Antsilevich 332019b4d63SUgen J.S. Antsilevich /* 333019b4d63SUgen J.S. Antsilevich * If line disc. changed we do not touch this pointer,SLIP/PPP will 334019b4d63SUgen J.S. Antsilevich * change it anyway. 335019b4d63SUgen J.S. Antsilevich */ 336019b4d63SUgen J.S. Antsilevich 3370739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 338964587caSUgen J.S. Antsilevich goto detach_notty; 339019b4d63SUgen J.S. Antsilevich 3400739a0dcSUgen J.S. Antsilevich tp = snp->snp_tty; 341019b4d63SUgen J.S. Antsilevich 34277f77631SPaul Traina if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) && 343019b4d63SUgen J.S. Antsilevich (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { 344019b4d63SUgen J.S. Antsilevich tp->t_sc = NULL; 345019b4d63SUgen J.S. Antsilevich tp->t_state &= ~TS_SNOOP; 346019b4d63SUgen J.S. Antsilevich } else 347019b4d63SUgen J.S. Antsilevich printf("Snoop: bad attached tty data.\n"); 348019b4d63SUgen J.S. Antsilevich 3490739a0dcSUgen J.S. Antsilevich snp->snp_tty = NULL; 35077f77631SPaul Traina snp->snp_target = -1; 351019b4d63SUgen J.S. Antsilevich 352964587caSUgen J.S. Antsilevich detach_notty: 353019b4d63SUgen J.S. Antsilevich selwakeup(&snp->snp_sel); 354019b4d63SUgen J.S. Antsilevich snp->snp_sel.si_pid = 0; 355019b4d63SUgen J.S. Antsilevich 356019b4d63SUgen J.S. Antsilevich return (0); 357019b4d63SUgen J.S. Antsilevich } 358019b4d63SUgen J.S. Antsilevich 35987f6c662SJulian Elischer static int 36060039670SBruce Evans snpclose(dev, flags, fmt, p) 361dde8a05bSUgen J.S. Antsilevich dev_t dev; 36260039670SBruce Evans int flags; 36360039670SBruce Evans int fmt; 36460039670SBruce Evans struct proc *p; 365dde8a05bSUgen J.S. Antsilevich { 366dde8a05bSUgen J.S. Antsilevich register int unit = minor(dev); 367dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 368dde8a05bSUgen J.S. Antsilevich 369dde8a05bSUgen J.S. Antsilevich snp->snp_blen = 0; 370dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 371019b4d63SUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OPEN; 372dde8a05bSUgen J.S. Antsilevich 373019b4d63SUgen J.S. Antsilevich return (snp_detach(snp)); 374dde8a05bSUgen J.S. Antsilevich } 375dde8a05bSUgen J.S. Antsilevich 376964587caSUgen J.S. Antsilevich int 377964587caSUgen J.S. Antsilevich snpdown(snp) 378964587caSUgen J.S. Antsilevich struct snoop *snp; 379964587caSUgen J.S. Antsilevich { 380964587caSUgen J.S. Antsilevich snp->snp_blen = SNOOP_MINLEN; 381964587caSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 382964587caSUgen J.S. Antsilevich snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK); 383964587caSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_DOWN; 384dde8a05bSUgen J.S. Antsilevich 385964587caSUgen J.S. Antsilevich return (snp_detach(snp)); 386964587caSUgen J.S. Antsilevich } 387dde8a05bSUgen J.S. Antsilevich 388dde8a05bSUgen J.S. Antsilevich 38987f6c662SJulian Elischer static int 39060039670SBruce Evans snpioctl(dev, cmd, data, flags, p) 391dde8a05bSUgen J.S. Antsilevich dev_t dev; 392dde8a05bSUgen J.S. Antsilevich int cmd; 393dde8a05bSUgen J.S. Antsilevich caddr_t data; 39460039670SBruce Evans int flags; 39560039670SBruce Evans struct proc *p; 396dde8a05bSUgen J.S. Antsilevich { 397dde8a05bSUgen J.S. Antsilevich int unit = minor(dev), s; 39877f77631SPaul Traina dev_t tdev; 399dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 400dde8a05bSUgen J.S. Antsilevich struct tty *tp, *tpo; 401dde8a05bSUgen J.S. Antsilevich 402dde8a05bSUgen J.S. Antsilevich switch (cmd) { 403dde8a05bSUgen J.S. Antsilevich case SNPSTTY: 40477f77631SPaul Traina tdev = *((dev_t *) data); 40577f77631SPaul Traina if (tdev == -1) 406964587caSUgen J.S. Antsilevich return (snpdown(snp)); 407964587caSUgen J.S. Antsilevich 40877f77631SPaul Traina tp = devtotty(tdev); 40977f77631SPaul Traina if (!tp) 410dde8a05bSUgen J.S. Antsilevich return (EINVAL); 411dde8a05bSUgen J.S. Antsilevich 41277f77631SPaul Traina if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP)) 413dde8a05bSUgen J.S. Antsilevich return (EBUSY); 414dde8a05bSUgen J.S. Antsilevich 41577f77631SPaul Traina if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC)) 416dde8a05bSUgen J.S. Antsilevich return (EBUSY); 417dde8a05bSUgen J.S. Antsilevich 418dde8a05bSUgen J.S. Antsilevich s = spltty(); 41977f77631SPaul Traina 42077f77631SPaul Traina if (snp->snp_target == -1) { 4210739a0dcSUgen J.S. Antsilevich tpo = snp->snp_tty; 42277f77631SPaul Traina if (tpo) 423dde8a05bSUgen J.S. Antsilevich tpo->t_state &= ~TS_SNOOP; 424dde8a05bSUgen J.S. Antsilevich } 42577f77631SPaul Traina 426dde8a05bSUgen J.S. Antsilevich tp->t_sc = (caddr_t) snp; 427dde8a05bSUgen J.S. Antsilevich tp->t_state |= TS_SNOOP; 4280739a0dcSUgen J.S. Antsilevich snp->snp_tty = tp; 42977f77631SPaul Traina snp->snp_target = tdev; 43077f77631SPaul Traina 431964587caSUgen J.S. Antsilevich /* 432964587caSUgen J.S. Antsilevich * Clean overflow and down flags - 433964587caSUgen J.S. Antsilevich * we'll have a chance to get them in the future :))) 434964587caSUgen J.S. Antsilevich */ 435964587caSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OFLOW; 436019b4d63SUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_DOWN; 437dde8a05bSUgen J.S. Antsilevich splx(s); 438dde8a05bSUgen J.S. Antsilevich break; 43977f77631SPaul Traina 440dde8a05bSUgen J.S. Antsilevich case SNPGTTY: 4410739a0dcSUgen J.S. Antsilevich /* 4420739a0dcSUgen J.S. Antsilevich * We keep snp_target field specially to make 4430739a0dcSUgen J.S. Antsilevich * SNPGTTY happy,else we can't know what is device 4440739a0dcSUgen J.S. Antsilevich * major/minor for tty. 4450739a0dcSUgen J.S. Antsilevich */ 44677f77631SPaul Traina *((dev_t *) data) = snp->snp_target; 447dde8a05bSUgen J.S. Antsilevich break; 448dde8a05bSUgen J.S. Antsilevich 449dde8a05bSUgen J.S. Antsilevich case FIONBIO: 450dde8a05bSUgen J.S. Antsilevich if (*(int *) data) 451dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_NBIO; 452dde8a05bSUgen J.S. Antsilevich else 453dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_NBIO; 454dde8a05bSUgen J.S. Antsilevich break; 45577f77631SPaul Traina 456dde8a05bSUgen J.S. Antsilevich case FIOASYNC: 457dde8a05bSUgen J.S. Antsilevich if (*(int *) data) 458dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_ASYNC; 459dde8a05bSUgen J.S. Antsilevich else 460dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_ASYNC; 461dde8a05bSUgen J.S. Antsilevich break; 46277f77631SPaul Traina 463dde8a05bSUgen J.S. Antsilevich case FIONREAD: 464dde8a05bSUgen J.S. Antsilevich s = spltty(); 4650739a0dcSUgen J.S. Antsilevich if (snp->snp_tty != NULL) 466dde8a05bSUgen J.S. Antsilevich *(int *) data = snp->snp_len; 467dde8a05bSUgen J.S. Antsilevich else 468964587caSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_DOWN) { 469964587caSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OFLOW) 470964587caSUgen J.S. Antsilevich *(int *) data = SNP_OFLOW; 471964587caSUgen J.S. Antsilevich else 472964587caSUgen J.S. Antsilevich *(int *) data = SNP_TTYCLOSE; 473964587caSUgen J.S. Antsilevich } else { 474964587caSUgen J.S. Antsilevich *(int *) data = SNP_DETACH; 475964587caSUgen J.S. Antsilevich } 476dde8a05bSUgen J.S. Antsilevich splx(s); 477dde8a05bSUgen J.S. Antsilevich break; 47877f77631SPaul Traina 479dde8a05bSUgen J.S. Antsilevich default: 480dde8a05bSUgen J.S. Antsilevich return (ENOTTY); 481dde8a05bSUgen J.S. Antsilevich } 482dde8a05bSUgen J.S. Antsilevich return (0); 483dde8a05bSUgen J.S. Antsilevich } 484dde8a05bSUgen J.S. Antsilevich 485dde8a05bSUgen J.S. Antsilevich 48687f6c662SJulian Elischer static int 487dde8a05bSUgen J.S. Antsilevich snpselect(dev, rw, p) 488dde8a05bSUgen J.S. Antsilevich dev_t dev; 489dde8a05bSUgen J.S. Antsilevich int rw; 490dde8a05bSUgen J.S. Antsilevich struct proc *p; 491dde8a05bSUgen J.S. Antsilevich { 492a98ca469SPoul-Henning Kamp int unit = minor(dev); 493dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 494dde8a05bSUgen J.S. Antsilevich 49577f77631SPaul Traina if (rw != FREAD) 4960739a0dcSUgen J.S. Antsilevich return 1; 49777f77631SPaul Traina 49877f77631SPaul Traina if (snp->snp_len > 0) 499dde8a05bSUgen J.S. Antsilevich return 1; 50077f77631SPaul Traina 501019b4d63SUgen J.S. Antsilevich /* 502019b4d63SUgen J.S. Antsilevich * If snoop is down,we don't want to select() forever so we return 1. 503019b4d63SUgen J.S. Antsilevich * Caller should see if we down via FIONREAD ioctl().The last should 504019b4d63SUgen J.S. Antsilevich * return -1 to indicate down state. 505019b4d63SUgen J.S. Antsilevich */ 50677f77631SPaul Traina if (snp->snp_flags & SNOOP_DOWN) 507019b4d63SUgen J.S. Antsilevich return 1; 50877f77631SPaul Traina 509dde8a05bSUgen J.S. Antsilevich selrecord(p, &snp->snp_sel); 510dde8a05bSUgen J.S. Antsilevich return 0; 511dde8a05bSUgen J.S. Antsilevich } 512dde8a05bSUgen J.S. Antsilevich 51387f6c662SJulian Elischer static void *snp_devfs_token[NSNP]; 51453ac6efbSJulian Elischer static snp_devsw_installed = 0; 51553ac6efbSJulian Elischer 51687f6c662SJulian Elischer static void 51787f6c662SJulian Elischer snp_drvinit(void *unused) 51853ac6efbSJulian Elischer { 51953ac6efbSJulian Elischer dev_t dev; 52087f6c662SJulian Elischer char name[32]; 52187f6c662SJulian Elischer int i; 52253ac6efbSJulian Elischer 52353ac6efbSJulian Elischer if( ! snp_devsw_installed ) { 52453ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 52553ac6efbSJulian Elischer cdevsw_add(&dev,&snp_cdevsw, NULL); 52653ac6efbSJulian Elischer snp_devsw_installed = 1; 52753ac6efbSJulian Elischer #ifdef DEVFS 52887f6c662SJulian Elischer for ( i = 0 ; i < NSNP ; i++) { 52987f6c662SJulian Elischer sprintf(name,"snp%d",i); 53087f6c662SJulian Elischer snp_devfs_token[i] = 53187f6c662SJulian Elischer devfs_add_devsw( "/", name, &snp_cdevsw, i, 53287f6c662SJulian Elischer DV_CHR, 0, 0, 0600); 53353ac6efbSJulian Elischer } 53453ac6efbSJulian Elischer #endif 53553ac6efbSJulian Elischer } 5367198bf47SJulian Elischer } 53753ac6efbSJulian Elischer 53853ac6efbSJulian Elischer SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL) 53953ac6efbSJulian Elischer 54053ac6efbSJulian Elischer 541dde8a05bSUgen J.S. Antsilevich #endif 542