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> 2271455815SBruce Evans #include <sys/filio.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 #include <sys/tty.h> 263ac4d1efSBruce Evans #include <sys/fcntl.h> 27dde8a05bSUgen J.S. Antsilevich #include <sys/conf.h> 28659ffb48SPeter Wemm #include <sys/poll.h> 29dde8a05bSUgen J.S. Antsilevich #include <sys/uio.h> 30dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h> 31dde8a05bSUgen J.S. Antsilevich #include <sys/malloc.h> 3253ac6efbSJulian Elischer #ifdef DEVFS 3353ac6efbSJulian Elischer #include <sys/devfsext.h> 3453ac6efbSJulian Elischer #endif /*DEVFS*/ 3587f6c662SJulian Elischer 3687f6c662SJulian Elischer #include <sys/snoop.h> 3787f6c662SJulian Elischer 3887f6c662SJulian Elischer static d_open_t snpopen; 3987f6c662SJulian Elischer static d_close_t snpclose; 4087f6c662SJulian Elischer static d_read_t snpread; 4187f6c662SJulian Elischer static d_write_t snpwrite; 4287f6c662SJulian Elischer static d_ioctl_t snpioctl; 43659ffb48SPeter Wemm static d_poll_t snppoll; 4487f6c662SJulian Elischer 4553ac6efbSJulian Elischer #define CDEV_MAJOR 53 46d2f265faSPoul-Henning Kamp static struct cdevsw snp_cdevsw = 4787f6c662SJulian Elischer { snpopen, snpclose, snpread, snpwrite, /*53*/ 4887f6c662SJulian Elischer snpioctl, nostop, nullreset, nodevtotty,/* snoop */ 49659ffb48SPeter Wemm snppoll, nommap, NULL, "snp", NULL, -1 }; 5087f6c662SJulian Elischer 5153ac6efbSJulian Elischer 52dde8a05bSUgen J.S. Antsilevich #ifndef MIN 53dde8a05bSUgen J.S. Antsilevich #define MIN(a,b) (((a)<(b))?(a):(b)) 54dde8a05bSUgen J.S. Antsilevich #endif 55dde8a05bSUgen J.S. Antsilevich 56dde8a05bSUgen J.S. Antsilevich static struct snoop snoopsw[NSNP]; 57dde8a05bSUgen J.S. Antsilevich 58444f003cSBruce Evans static struct tty *snpdevtotty __P((dev_t dev)); 5987b6de2bSPoul-Henning Kamp static int snp_detach __P((struct snoop *snp)); 6098d93822SBruce Evans 6177f77631SPaul Traina static struct tty * 62444f003cSBruce Evans snpdevtotty (dev) 6377f77631SPaul Traina dev_t dev; 6477f77631SPaul Traina { 65444f003cSBruce Evans struct cdevsw *cdp; 66444f003cSBruce Evans int maj; 6777f77631SPaul Traina 68444f003cSBruce Evans maj = major(dev); 69444f003cSBruce Evans if ((u_int)maj >= nchrdev) 70444f003cSBruce Evans return (NULL); 71444f003cSBruce Evans cdp = cdevsw[maj]; 72444f003cSBruce Evans if (cdp == NULL) 73444f003cSBruce Evans return (NULL); 74444f003cSBruce Evans return ((*cdp->d_devtotty)(dev)); 7577f77631SPaul Traina } 7677f77631SPaul Traina 770739a0dcSUgen J.S. Antsilevich #define SNP_INPUT_BUF 5 /* This is even too much,the maximal 780739a0dcSUgen J.S. Antsilevich * interactive mode write is 3 bytes 790739a0dcSUgen J.S. Antsilevich * length for function keys... 800739a0dcSUgen J.S. Antsilevich */ 810739a0dcSUgen J.S. Antsilevich 8287f6c662SJulian Elischer static int 830739a0dcSUgen J.S. Antsilevich snpwrite(dev, uio, flag) 840739a0dcSUgen J.S. Antsilevich dev_t dev; 850739a0dcSUgen J.S. Antsilevich struct uio *uio; 860739a0dcSUgen J.S. Antsilevich int flag; 870739a0dcSUgen J.S. Antsilevich { 880739a0dcSUgen J.S. Antsilevich int unit = minor(dev), len, i, error; 890739a0dcSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 900739a0dcSUgen J.S. Antsilevich struct tty *tp; 910739a0dcSUgen J.S. Antsilevich char c[SNP_INPUT_BUF]; 920739a0dcSUgen J.S. Antsilevich 930739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 940739a0dcSUgen J.S. Antsilevich return (EIO); 950739a0dcSUgen J.S. Antsilevich 960739a0dcSUgen J.S. Antsilevich tp = snp->snp_tty; 970739a0dcSUgen J.S. Antsilevich 980739a0dcSUgen J.S. Antsilevich if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) && 990739a0dcSUgen J.S. Antsilevich (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) 1000739a0dcSUgen J.S. Antsilevich goto tty_input; 1010739a0dcSUgen J.S. Antsilevich 1020739a0dcSUgen J.S. Antsilevich printf("Snoop: attempt to write to bad tty.\n"); 1030739a0dcSUgen J.S. Antsilevich return (EIO); 1040739a0dcSUgen J.S. Antsilevich 1050739a0dcSUgen J.S. Antsilevich tty_input: 1060739a0dcSUgen J.S. Antsilevich if (!(tp->t_state & TS_ISOPEN)) 1070739a0dcSUgen J.S. Antsilevich return (EIO); 1080739a0dcSUgen J.S. Antsilevich 1090739a0dcSUgen J.S. Antsilevich while (uio->uio_resid > 0) { 1100739a0dcSUgen J.S. Antsilevich len = MIN(uio->uio_resid,SNP_INPUT_BUF); 1110739a0dcSUgen J.S. Antsilevich if ((error = uiomove(c, len, uio)) != 0) 1120739a0dcSUgen J.S. Antsilevich return (error); 1130739a0dcSUgen J.S. Antsilevich for (i=0;i<len;i++) { 1140739a0dcSUgen J.S. Antsilevich if (ttyinput(c[i] , tp)) 1150739a0dcSUgen J.S. Antsilevich return (EIO); 1160739a0dcSUgen J.S. Antsilevich } 1170739a0dcSUgen J.S. Antsilevich } 1180739a0dcSUgen J.S. Antsilevich return 0; 1190739a0dcSUgen J.S. Antsilevich 1200739a0dcSUgen J.S. Antsilevich } 1210739a0dcSUgen J.S. Antsilevich 1220739a0dcSUgen J.S. Antsilevich 12387f6c662SJulian Elischer static int 124dde8a05bSUgen J.S. Antsilevich snpread(dev, uio, flag) 125dde8a05bSUgen J.S. Antsilevich dev_t dev; 126dde8a05bSUgen J.S. Antsilevich struct uio *uio; 127dde8a05bSUgen J.S. Antsilevich int flag; 128dde8a05bSUgen J.S. Antsilevich { 129dde8a05bSUgen J.S. Antsilevich int unit = minor(dev), s; 130dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 131dde8a05bSUgen J.S. Antsilevich int len, n, nblen, error = 0; 132dde8a05bSUgen J.S. Antsilevich caddr_t from; 133dde8a05bSUgen J.S. Antsilevich char *nbuf; 134dde8a05bSUgen J.S. Antsilevich 135dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC 136dde8a05bSUgen J.S. Antsilevich if ((snp->snp_len + snp->snp_base) > snp->snp_blen) 137dde8a05bSUgen J.S. Antsilevich panic("snoop buffer error"); 138dde8a05bSUgen J.S. Antsilevich #endif 13977f77631SPaul Traina 1400739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 141dde8a05bSUgen J.S. Antsilevich return (EIO); 142dde8a05bSUgen J.S. Antsilevich 143dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 144dde8a05bSUgen J.S. Antsilevich 145dde8a05bSUgen J.S. Antsilevich do { 146dde8a05bSUgen J.S. Antsilevich if (snp->snp_len == 0) { 147dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_NBIO) { 148dde8a05bSUgen J.S. Antsilevich return EWOULDBLOCK; 149dde8a05bSUgen J.S. Antsilevich } 150dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_RWAIT; 151dde8a05bSUgen J.S. Antsilevich tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0); 152dde8a05bSUgen J.S. Antsilevich } 153dde8a05bSUgen J.S. Antsilevich } while (snp->snp_len == 0); 154dde8a05bSUgen J.S. Antsilevich 155019b4d63SUgen J.S. Antsilevich n = snp->snp_len; 156dde8a05bSUgen J.S. Antsilevich 157dde8a05bSUgen J.S. Antsilevich while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { 158dde8a05bSUgen J.S. Antsilevich len = MIN(uio->uio_resid, snp->snp_len); 159dde8a05bSUgen J.S. Antsilevich from = (caddr_t) (snp->snp_buf + snp->snp_base); 160dde8a05bSUgen J.S. Antsilevich if (len == 0) 161dde8a05bSUgen J.S. Antsilevich break; 162dde8a05bSUgen J.S. Antsilevich 163dde8a05bSUgen J.S. Antsilevich error = uiomove(from, len, uio); 164dde8a05bSUgen J.S. Antsilevich snp->snp_base += len; 165dde8a05bSUgen J.S. Antsilevich snp->snp_len -= len; 166dde8a05bSUgen J.S. Antsilevich } 167019b4d63SUgen J.S. Antsilevich if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) { 168dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OFLOW; 169019b4d63SUgen J.S. Antsilevich } 170dde8a05bSUgen J.S. Antsilevich s = spltty(); 171dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen; 172dde8a05bSUgen J.S. Antsilevich if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) { 173dde8a05bSUgen J.S. Antsilevich while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN)) 174dde8a05bSUgen J.S. Antsilevich nblen = nblen / 2; 175dde8a05bSUgen J.S. Antsilevich if (nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) { 176dde8a05bSUgen J.S. Antsilevich bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 177dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 178dde8a05bSUgen J.S. Antsilevich snp->snp_buf = nbuf; 179dde8a05bSUgen J.S. Antsilevich snp->snp_blen = nblen; 180dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 181dde8a05bSUgen J.S. Antsilevich } 182dde8a05bSUgen J.S. Antsilevich } 183dde8a05bSUgen J.S. Antsilevich splx(s); 184dde8a05bSUgen J.S. Antsilevich 185dde8a05bSUgen J.S. Antsilevich return error; 186dde8a05bSUgen J.S. Antsilevich } 187dde8a05bSUgen J.S. Antsilevich 1880739a0dcSUgen J.S. Antsilevich int 1890739a0dcSUgen J.S. Antsilevich snpinc(snp, c) 1900739a0dcSUgen J.S. Antsilevich struct snoop *snp; 1910739a0dcSUgen J.S. Antsilevich char c; 1920739a0dcSUgen J.S. Antsilevich { 1930739a0dcSUgen J.S. Antsilevich char buf[1]; 1940739a0dcSUgen J.S. Antsilevich 1950739a0dcSUgen J.S. Antsilevich buf[0]=c; 1960739a0dcSUgen J.S. Antsilevich return (snpin(snp,buf,1)); 1970739a0dcSUgen J.S. Antsilevich } 1980739a0dcSUgen J.S. Antsilevich 199dde8a05bSUgen J.S. Antsilevich 200dde8a05bSUgen J.S. Antsilevich int 201dde8a05bSUgen J.S. Antsilevich snpin(snp, buf, n) 202dde8a05bSUgen J.S. Antsilevich struct snoop *snp; 203dde8a05bSUgen J.S. Antsilevich char *buf; 204dde8a05bSUgen J.S. Antsilevich int n; 205dde8a05bSUgen J.S. Antsilevich { 206dde8a05bSUgen J.S. Antsilevich int s_free, s_tail; 207dde8a05bSUgen J.S. Antsilevich int s, len, nblen; 208dde8a05bSUgen J.S. Antsilevich caddr_t from, to; 209dde8a05bSUgen J.S. Antsilevich char *nbuf; 210dde8a05bSUgen J.S. Antsilevich 211dde8a05bSUgen J.S. Antsilevich 212dde8a05bSUgen J.S. Antsilevich if (n == 0) 213dde8a05bSUgen J.S. Antsilevich return 0; 214dde8a05bSUgen J.S. Antsilevich 215dde8a05bSUgen J.S. Antsilevich #ifdef DIAGNOSTIC 216dde8a05bSUgen J.S. Antsilevich if (n < 0) 217dde8a05bSUgen J.S. Antsilevich panic("bad snoop char count"); 218dde8a05bSUgen J.S. Antsilevich 219019b4d63SUgen J.S. Antsilevich if (!(snp->snp_flags & SNOOP_OPEN)) { 220019b4d63SUgen J.S. Antsilevich printf("Snoop: data coming to closed device.\n"); 221019b4d63SUgen J.S. Antsilevich return 0; 222dde8a05bSUgen J.S. Antsilevich } 223019b4d63SUgen J.S. Antsilevich #endif 224019b4d63SUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_DOWN) { 225019b4d63SUgen J.S. Antsilevich printf("Snoop: more data to down interface.\n"); 226019b4d63SUgen J.S. Antsilevich return 0; 227019b4d63SUgen J.S. Antsilevich } 228964587caSUgen J.S. Antsilevich 229019b4d63SUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OFLOW) { 230019b4d63SUgen J.S. Antsilevich printf("Snoop: buffer overflow.\n"); 231019b4d63SUgen J.S. Antsilevich /* 232019b4d63SUgen J.S. Antsilevich * On overflow we just repeat the standart close 233019b4d63SUgen J.S. Antsilevich * procedure...yes , this is waste of space but.. Then next 234019b4d63SUgen J.S. Antsilevich * read from device will fail if one would recall he is 235019b4d63SUgen J.S. Antsilevich * snooping and retry... 236019b4d63SUgen J.S. Antsilevich */ 237dde8a05bSUgen J.S. Antsilevich 238964587caSUgen J.S. Antsilevich return (snpdown(snp)); 239019b4d63SUgen J.S. Antsilevich } 240019b4d63SUgen J.S. Antsilevich s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base); 241019b4d63SUgen J.S. Antsilevich s_free = snp->snp_blen - snp->snp_len; 242dde8a05bSUgen J.S. Antsilevich 243dde8a05bSUgen J.S. Antsilevich 244dde8a05bSUgen J.S. Antsilevich if (n > s_free) { 245dde8a05bSUgen J.S. Antsilevich s = spltty(); 246dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen; 247dde8a05bSUgen J.S. Antsilevich while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) { 248dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen * 2; 249dde8a05bSUgen J.S. Antsilevich s_free = nblen - (snp->snp_len + snp->snp_base); 250dde8a05bSUgen J.S. Antsilevich } 251dde8a05bSUgen J.S. Antsilevich if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) { 252dde8a05bSUgen J.S. Antsilevich bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 253dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 254dde8a05bSUgen J.S. Antsilevich snp->snp_buf = nbuf; 255dde8a05bSUgen J.S. Antsilevich snp->snp_blen = nblen; 256dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 257dde8a05bSUgen J.S. Antsilevich } else { 258dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_OFLOW; 259dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_RWAIT) { 260dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 261dde8a05bSUgen J.S. Antsilevich wakeup((caddr_t) snp); 262dde8a05bSUgen J.S. Antsilevich } 263dde8a05bSUgen J.S. Antsilevich splx(s); 264dde8a05bSUgen J.S. Antsilevich return 0; 265dde8a05bSUgen J.S. Antsilevich } 266dde8a05bSUgen J.S. Antsilevich splx(s); 267dde8a05bSUgen J.S. Antsilevich } 268dde8a05bSUgen J.S. Antsilevich if (n > s_tail) { 269dde8a05bSUgen J.S. Antsilevich from = (caddr_t) (snp->snp_buf + snp->snp_base); 270dde8a05bSUgen J.S. Antsilevich to = (caddr_t) (snp->snp_buf); 271dde8a05bSUgen J.S. Antsilevich len = snp->snp_len; 272dde8a05bSUgen J.S. Antsilevich bcopy(from, to, len); 273dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 274dde8a05bSUgen J.S. Antsilevich } 275dde8a05bSUgen J.S. Antsilevich to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len); 276dde8a05bSUgen J.S. Antsilevich bcopy(buf, to, n); 277dde8a05bSUgen J.S. Antsilevich snp->snp_len += n; 278dde8a05bSUgen J.S. Antsilevich 279dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_RWAIT) { 280dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 281dde8a05bSUgen J.S. Antsilevich wakeup((caddr_t) snp); 282dde8a05bSUgen J.S. Antsilevich } 283dde8a05bSUgen J.S. Antsilevich selwakeup(&snp->snp_sel); 284dde8a05bSUgen J.S. Antsilevich snp->snp_sel.si_pid = 0; 285dde8a05bSUgen J.S. Antsilevich 286dde8a05bSUgen J.S. Antsilevich return n; 287dde8a05bSUgen J.S. Antsilevich } 288dde8a05bSUgen J.S. Antsilevich 28987f6c662SJulian Elischer static int 290dde8a05bSUgen J.S. Antsilevich snpopen(dev, flag, mode, p) 291dde8a05bSUgen J.S. Antsilevich dev_t dev; 292dde8a05bSUgen J.S. Antsilevich int flag, mode; 293dde8a05bSUgen J.S. Antsilevich struct proc *p; 294dde8a05bSUgen J.S. Antsilevich { 295dde8a05bSUgen J.S. Antsilevich struct snoop *snp; 296dde8a05bSUgen J.S. Antsilevich register int unit, error; 297dde8a05bSUgen J.S. Antsilevich 298dde8a05bSUgen J.S. Antsilevich if (error = suser(p->p_ucred, &p->p_acflag)) 299dde8a05bSUgen J.S. Antsilevich return (error); 300dde8a05bSUgen J.S. Antsilevich 301dde8a05bSUgen J.S. Antsilevich if ((unit = minor(dev)) >= NSNP) 302dde8a05bSUgen J.S. Antsilevich return (ENXIO); 30377f77631SPaul Traina 304dde8a05bSUgen J.S. Antsilevich snp = &snoopsw[unit]; 30577f77631SPaul Traina 306dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OPEN) 307dde8a05bSUgen J.S. Antsilevich return (ENXIO); 30877f77631SPaul Traina 309019b4d63SUgen J.S. Antsilevich /* 310019b4d63SUgen J.S. Antsilevich * We intentionally do not OR flags with SNOOP_OPEN,but set them so 311019b4d63SUgen J.S. Antsilevich * all previous settings (especially SNOOP_OFLOW) will be cleared. 312019b4d63SUgen J.S. Antsilevich */ 313019b4d63SUgen J.S. Antsilevich snp->snp_flags = SNOOP_OPEN; 314dde8a05bSUgen J.S. Antsilevich 315dde8a05bSUgen J.S. Antsilevich snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK); 316dde8a05bSUgen J.S. Antsilevich snp->snp_blen = SNOOP_MINLEN; 317dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 318dde8a05bSUgen J.S. Antsilevich snp->snp_len = 0; 319dde8a05bSUgen J.S. Antsilevich 320dde8a05bSUgen J.S. Antsilevich /* 3210739a0dcSUgen J.S. Antsilevich * snp_tty == NULL is for inactive snoop devices. 322dde8a05bSUgen J.S. Antsilevich */ 3230739a0dcSUgen J.S. Antsilevich snp->snp_tty = NULL; 32477f77631SPaul Traina snp->snp_target = -1; 325dde8a05bSUgen J.S. Antsilevich return (0); 326dde8a05bSUgen J.S. Antsilevich } 327dde8a05bSUgen J.S. Antsilevich 328019b4d63SUgen J.S. Antsilevich 32987b6de2bSPoul-Henning Kamp static int 330019b4d63SUgen J.S. Antsilevich snp_detach(snp) 331019b4d63SUgen J.S. Antsilevich struct snoop *snp; 332019b4d63SUgen J.S. Antsilevich { 333019b4d63SUgen J.S. Antsilevich struct tty *tp; 334019b4d63SUgen J.S. Antsilevich 335019b4d63SUgen J.S. Antsilevich snp->snp_base = 0; 336019b4d63SUgen J.S. Antsilevich snp->snp_len = 0; 337019b4d63SUgen J.S. Antsilevich 338019b4d63SUgen J.S. Antsilevich /* 339019b4d63SUgen J.S. Antsilevich * If line disc. changed we do not touch this pointer,SLIP/PPP will 340019b4d63SUgen J.S. Antsilevich * change it anyway. 341019b4d63SUgen J.S. Antsilevich */ 342019b4d63SUgen J.S. Antsilevich 3430739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 344964587caSUgen J.S. Antsilevich goto detach_notty; 345019b4d63SUgen J.S. Antsilevich 3460739a0dcSUgen J.S. Antsilevich tp = snp->snp_tty; 347019b4d63SUgen J.S. Antsilevich 34877f77631SPaul Traina if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) && 349019b4d63SUgen J.S. Antsilevich (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { 350019b4d63SUgen J.S. Antsilevich tp->t_sc = NULL; 351019b4d63SUgen J.S. Antsilevich tp->t_state &= ~TS_SNOOP; 352019b4d63SUgen J.S. Antsilevich } else 353019b4d63SUgen J.S. Antsilevich printf("Snoop: bad attached tty data.\n"); 354019b4d63SUgen J.S. Antsilevich 3550739a0dcSUgen J.S. Antsilevich snp->snp_tty = NULL; 35677f77631SPaul Traina snp->snp_target = -1; 357019b4d63SUgen J.S. Antsilevich 358964587caSUgen J.S. Antsilevich detach_notty: 359019b4d63SUgen J.S. Antsilevich selwakeup(&snp->snp_sel); 360019b4d63SUgen J.S. Antsilevich snp->snp_sel.si_pid = 0; 361019b4d63SUgen J.S. Antsilevich 362019b4d63SUgen J.S. Antsilevich return (0); 363019b4d63SUgen J.S. Antsilevich } 364019b4d63SUgen J.S. Antsilevich 36587f6c662SJulian Elischer static int 36660039670SBruce Evans snpclose(dev, flags, fmt, p) 367dde8a05bSUgen J.S. Antsilevich dev_t dev; 36860039670SBruce Evans int flags; 36960039670SBruce Evans int fmt; 37060039670SBruce Evans struct proc *p; 371dde8a05bSUgen J.S. Antsilevich { 372dde8a05bSUgen J.S. Antsilevich register int unit = minor(dev); 373dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 374dde8a05bSUgen J.S. Antsilevich 375dde8a05bSUgen J.S. Antsilevich snp->snp_blen = 0; 376dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 377019b4d63SUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OPEN; 378dde8a05bSUgen J.S. Antsilevich 379019b4d63SUgen J.S. Antsilevich return (snp_detach(snp)); 380dde8a05bSUgen J.S. Antsilevich } 381dde8a05bSUgen J.S. Antsilevich 382964587caSUgen J.S. Antsilevich int 383964587caSUgen J.S. Antsilevich snpdown(snp) 384964587caSUgen J.S. Antsilevich struct snoop *snp; 385964587caSUgen J.S. Antsilevich { 386964587caSUgen J.S. Antsilevich snp->snp_blen = SNOOP_MINLEN; 387964587caSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 388964587caSUgen J.S. Antsilevich snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK); 389964587caSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_DOWN; 390dde8a05bSUgen J.S. Antsilevich 391964587caSUgen J.S. Antsilevich return (snp_detach(snp)); 392964587caSUgen J.S. Antsilevich } 393dde8a05bSUgen J.S. Antsilevich 394dde8a05bSUgen J.S. Antsilevich 39587f6c662SJulian Elischer static int 39660039670SBruce Evans snpioctl(dev, cmd, data, flags, p) 397dde8a05bSUgen J.S. Antsilevich dev_t dev; 398dde8a05bSUgen J.S. Antsilevich int cmd; 399dde8a05bSUgen J.S. Antsilevich caddr_t data; 40060039670SBruce Evans int flags; 40160039670SBruce Evans struct proc *p; 402dde8a05bSUgen J.S. Antsilevich { 403dde8a05bSUgen J.S. Antsilevich int unit = minor(dev), s; 40477f77631SPaul Traina dev_t tdev; 405dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 406dde8a05bSUgen J.S. Antsilevich struct tty *tp, *tpo; 407dde8a05bSUgen J.S. Antsilevich 408dde8a05bSUgen J.S. Antsilevich switch (cmd) { 409dde8a05bSUgen J.S. Antsilevich case SNPSTTY: 41077f77631SPaul Traina tdev = *((dev_t *) data); 41177f77631SPaul Traina if (tdev == -1) 412964587caSUgen J.S. Antsilevich return (snpdown(snp)); 413964587caSUgen J.S. Antsilevich 414444f003cSBruce Evans tp = snpdevtotty(tdev); 41577f77631SPaul Traina if (!tp) 416dde8a05bSUgen J.S. Antsilevich return (EINVAL); 417dde8a05bSUgen J.S. Antsilevich 41877f77631SPaul Traina if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP)) 419dde8a05bSUgen J.S. Antsilevich return (EBUSY); 420dde8a05bSUgen J.S. Antsilevich 42177f77631SPaul Traina if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC)) 422dde8a05bSUgen J.S. Antsilevich return (EBUSY); 423dde8a05bSUgen J.S. Antsilevich 424dde8a05bSUgen J.S. Antsilevich s = spltty(); 42577f77631SPaul Traina 42677f77631SPaul Traina if (snp->snp_target == -1) { 4270739a0dcSUgen J.S. Antsilevich tpo = snp->snp_tty; 42877f77631SPaul Traina if (tpo) 429dde8a05bSUgen J.S. Antsilevich tpo->t_state &= ~TS_SNOOP; 430dde8a05bSUgen J.S. Antsilevich } 43177f77631SPaul Traina 432dde8a05bSUgen J.S. Antsilevich tp->t_sc = (caddr_t) snp; 433dde8a05bSUgen J.S. Antsilevich tp->t_state |= TS_SNOOP; 4340739a0dcSUgen J.S. Antsilevich snp->snp_tty = tp; 43577f77631SPaul Traina snp->snp_target = tdev; 43677f77631SPaul Traina 437964587caSUgen J.S. Antsilevich /* 438964587caSUgen J.S. Antsilevich * Clean overflow and down flags - 439964587caSUgen J.S. Antsilevich * we'll have a chance to get them in the future :))) 440964587caSUgen J.S. Antsilevich */ 441964587caSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OFLOW; 442019b4d63SUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_DOWN; 443dde8a05bSUgen J.S. Antsilevich splx(s); 444dde8a05bSUgen J.S. Antsilevich break; 44577f77631SPaul Traina 446dde8a05bSUgen J.S. Antsilevich case SNPGTTY: 4470739a0dcSUgen J.S. Antsilevich /* 4480739a0dcSUgen J.S. Antsilevich * We keep snp_target field specially to make 4490739a0dcSUgen J.S. Antsilevich * SNPGTTY happy,else we can't know what is device 4500739a0dcSUgen J.S. Antsilevich * major/minor for tty. 4510739a0dcSUgen J.S. Antsilevich */ 45277f77631SPaul Traina *((dev_t *) data) = snp->snp_target; 453dde8a05bSUgen J.S. Antsilevich break; 454dde8a05bSUgen J.S. Antsilevich 455dde8a05bSUgen J.S. Antsilevich case FIONBIO: 456dde8a05bSUgen J.S. Antsilevich if (*(int *) data) 457dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_NBIO; 458dde8a05bSUgen J.S. Antsilevich else 459dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_NBIO; 460dde8a05bSUgen J.S. Antsilevich break; 46177f77631SPaul Traina 462dde8a05bSUgen J.S. Antsilevich case FIOASYNC: 463dde8a05bSUgen J.S. Antsilevich if (*(int *) data) 464dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_ASYNC; 465dde8a05bSUgen J.S. Antsilevich else 466dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_ASYNC; 467dde8a05bSUgen J.S. Antsilevich break; 46877f77631SPaul Traina 469dde8a05bSUgen J.S. Antsilevich case FIONREAD: 470dde8a05bSUgen J.S. Antsilevich s = spltty(); 4710739a0dcSUgen J.S. Antsilevich if (snp->snp_tty != NULL) 472dde8a05bSUgen J.S. Antsilevich *(int *) data = snp->snp_len; 473dde8a05bSUgen J.S. Antsilevich else 474964587caSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_DOWN) { 475964587caSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OFLOW) 476964587caSUgen J.S. Antsilevich *(int *) data = SNP_OFLOW; 477964587caSUgen J.S. Antsilevich else 478964587caSUgen J.S. Antsilevich *(int *) data = SNP_TTYCLOSE; 479964587caSUgen J.S. Antsilevich } else { 480964587caSUgen J.S. Antsilevich *(int *) data = SNP_DETACH; 481964587caSUgen J.S. Antsilevich } 482dde8a05bSUgen J.S. Antsilevich splx(s); 483dde8a05bSUgen J.S. Antsilevich break; 48477f77631SPaul Traina 485dde8a05bSUgen J.S. Antsilevich default: 486dde8a05bSUgen J.S. Antsilevich return (ENOTTY); 487dde8a05bSUgen J.S. Antsilevich } 488dde8a05bSUgen J.S. Antsilevich return (0); 489dde8a05bSUgen J.S. Antsilevich } 490dde8a05bSUgen J.S. Antsilevich 491dde8a05bSUgen J.S. Antsilevich 49287f6c662SJulian Elischer static int 493659ffb48SPeter Wemm snppoll(dev, events, p) 494dde8a05bSUgen J.S. Antsilevich dev_t dev; 495659ffb48SPeter Wemm int events; 496dde8a05bSUgen J.S. Antsilevich struct proc *p; 497dde8a05bSUgen J.S. Antsilevich { 498a98ca469SPoul-Henning Kamp int unit = minor(dev); 499dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 500659ffb48SPeter Wemm int revents = 0; 501dde8a05bSUgen J.S. Antsilevich 50277f77631SPaul Traina 503019b4d63SUgen J.S. Antsilevich /* 504659ffb48SPeter Wemm * If snoop is down,we don't want to poll() forever so we return 1. 505019b4d63SUgen J.S. Antsilevich * Caller should see if we down via FIONREAD ioctl().The last should 506019b4d63SUgen J.S. Antsilevich * return -1 to indicate down state. 507019b4d63SUgen J.S. Antsilevich */ 508659ffb48SPeter Wemm if (events & (POLLIN | POLLRDNORM)) 509659ffb48SPeter Wemm if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0) 510659ffb48SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 511659ffb48SPeter Wemm else 512dde8a05bSUgen J.S. Antsilevich selrecord(p, &snp->snp_sel); 513659ffb48SPeter Wemm 514659ffb48SPeter Wemm return (revents); 515dde8a05bSUgen J.S. Antsilevich } 516dde8a05bSUgen J.S. Antsilevich 517734daefcSMarc G. Fournier #ifdef DEVFS 51887f6c662SJulian Elischer static void *snp_devfs_token[NSNP]; 519734daefcSMarc G. Fournier #endif 52053ac6efbSJulian Elischer static snp_devsw_installed = 0; 52153ac6efbSJulian Elischer 52287f6c662SJulian Elischer static void 52387f6c662SJulian Elischer snp_drvinit(void *unused) 52453ac6efbSJulian Elischer { 52553ac6efbSJulian Elischer dev_t dev; 526734daefcSMarc G. Fournier #ifdef DEVFS 52787f6c662SJulian Elischer int i; 528734daefcSMarc G. Fournier #endif 52953ac6efbSJulian Elischer 53053ac6efbSJulian Elischer if( ! snp_devsw_installed ) { 53153ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 53253ac6efbSJulian Elischer cdevsw_add(&dev,&snp_cdevsw, NULL); 53353ac6efbSJulian Elischer snp_devsw_installed = 1; 53453ac6efbSJulian Elischer #ifdef DEVFS 53587f6c662SJulian Elischer for ( i = 0 ; i < NSNP ; i++) { 53687f6c662SJulian Elischer snp_devfs_token[i] = 537734daefcSMarc G. Fournier devfs_add_devswf(&snp_cdevsw, i, DV_CHR, 0, 0, 538734daefcSMarc G. Fournier 0600, "snp%d", i); 53953ac6efbSJulian Elischer } 54053ac6efbSJulian Elischer #endif 54153ac6efbSJulian Elischer } 5427198bf47SJulian Elischer } 54353ac6efbSJulian Elischer 54453ac6efbSJulian Elischer SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL) 54553ac6efbSJulian Elischer 54653ac6efbSJulian Elischer 547dde8a05bSUgen J.S. Antsilevich #endif 548