Exemplo n.º 1
0
/*
 * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called.
 */
static void
ptioc(queue_t *q, mblk_t *mp, int qside)
{
	struct ptem *tp;
	struct iocblk *iocp;
	struct winsize *wb;
	struct jwinsize *jwb;
	mblk_t *tmp;
	mblk_t *pckt_msgp;	/* message sent to the PCKT module */
	int error;

	iocp = (struct iocblk *)mp->b_rptr;
	tp = (struct ptem *)q->q_ptr;

	switch (iocp->ioc_cmd) {

	case JWINSIZE:
		/*
		 * For compatibility:  If all zeros, NAK the message for dumb
		 * terminals.
		 */
		if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
		    (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
			miocnak(q, mp, 0, EINVAL);
			return;
		}

		tmp = allocb(sizeof (struct jwinsize), BPRI_MED);
		if (tmp == NULL) {
			miocnak(q, mp, 0, EAGAIN);
			return;
		}

		if (iocp->ioc_count == TRANSPARENT)
			mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp);
		else
			mioc2ack(mp, tmp, sizeof (struct jwinsize), 0);

		jwb = (struct jwinsize *)mp->b_cont->b_rptr;
		jwb->bytesx = tp->wsz.ws_col;
		jwb->bytesy = tp->wsz.ws_row;
		jwb->bitsx = tp->wsz.ws_xpixel;
		jwb->bitsy = tp->wsz.ws_ypixel;

		qreply(q, mp);
		return;

	case TIOCGWINSZ:
		/*
		 * If all zeros NAK the message for dumb terminals.
		 */
		if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) &&
		    (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) {
			miocnak(q, mp, 0, EINVAL);
			return;
		}

		tmp = allocb(sizeof (struct winsize), BPRI_MED);
		if (tmp == NULL) {
			miocnak(q, mp, 0, EAGAIN);
			return;
		}

		mioc2ack(mp, tmp, sizeof (struct winsize), 0);

		wb = (struct winsize *)mp->b_cont->b_rptr;
		wb->ws_row = tp->wsz.ws_row;
		wb->ws_col = tp->wsz.ws_col;
		wb->ws_xpixel = tp->wsz.ws_xpixel;
		wb->ws_ypixel = tp->wsz.ws_ypixel;

		qreply(q, mp);
		return;

	case TIOCSWINSZ:
		error = miocpullup(mp, sizeof (struct winsize));
		if (error != 0) {
			miocnak(q, mp, 0, error);
			return;
		}

		wb = (struct winsize *)mp->b_cont->b_rptr;
		/*
		 * Send a SIGWINCH signal if the row/col information has
		 * changed.
		 */
		if ((tp->wsz.ws_row != wb->ws_row) ||
		    (tp->wsz.ws_col != wb->ws_col) ||
		    (tp->wsz.ws_xpixel != wb->ws_xpixel) ||
		    (tp->wsz.ws_ypixel != wb->ws_xpixel)) {
			/*
			 * SIGWINCH is always sent upstream.
			 */
			if (qside == WRSIDE)
				(void) putnextctl1(RD(q), M_SIG, SIGWINCH);
			else if (qside == RDSIDE)
				(void) putnextctl1(q, M_SIG, SIGWINCH);
			/*
			 * Message may have come in as an M_IOCDATA; pass it
			 * to the master side as an M_IOCTL.
			 */
			mp->b_datap->db_type = M_IOCTL;
			if (qside == WRSIDE) {
				/*
				 * Need a copy of this message to pass on to
				 * the PCKT module, only if the M_IOCTL
				 * orginated from the slave side.
				 */
				if ((pckt_msgp = copymsg(mp)) == NULL) {
					miocnak(q, mp, 0, EAGAIN);
					return;
				}
				putnext(q, pckt_msgp);
			}
			tp->wsz.ws_row = wb->ws_row;
			tp->wsz.ws_col = wb->ws_col;
			tp->wsz.ws_xpixel = wb->ws_xpixel;
			tp->wsz.ws_ypixel = wb->ws_ypixel;
		}

		mioc2ack(mp, NULL, 0, 0);
		qreply(q, mp);
		return;

	case TIOCSIGNAL: {
		/*
		 * This ioctl can emanate from the master side in remote
		 * mode only.
		 */
		int	sig;

		if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) {
			error = miocpullup(mp, sizeof (int));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				return;
			}
		}

		if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT)
			sig = *(int *)mp->b_cont->b_rptr;
		else
			sig = (int)*(intptr_t *)mp->b_cont->b_rptr;

		if (sig < 1 || sig >= NSIG) {
			miocnak(q, mp, 0, EINVAL);
			return;
		}

		/*
		 * Send an M_PCSIG message up the slave's read side and
		 * respond back to the master with an ACK or NAK as
		 * appropriate.
		 */
		if (putnextctl1(q, M_PCSIG, sig) == 0) {
			miocnak(q, mp, 0, EAGAIN);
			return;
		}

		mioc2ack(mp, NULL, 0, 0);
		qreply(q, mp);
		return;
	    }

	case TIOCREMOTE: {
		int	onoff;
		mblk_t	*mctlp;

		if (DB_TYPE(mp) == M_IOCTL) {
			error = miocpullup(mp, sizeof (int));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				return;
			}
		}

		onoff = *(int *)mp->b_cont->b_rptr;

		/*
		 * Send M_CTL up using the iocblk format.
		 */
		mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON);
		if (mctlp == NULL) {
			miocnak(q, mp, 0, EAGAIN);
			return;
		}
		mctlp->b_datap->db_type = M_CTL;
		putnext(q, mctlp);

		/*
		 * ACK the ioctl.
		 */
		mioc2ack(mp, NULL, 0, 0);
		qreply(q, mp);

		/*
		 * Record state change.
		 */
		if (onoff)
			tp->state |= REMOTEMODE;
		else
			tp->state &= ~REMOTEMODE;
		return;
	    }

	default:
		putnext(q, mp);
		return;
	}
}
Exemplo n.º 2
0
/*
 * This routine is called from both ptemwput and ptemwsrv to do the
 * actual work of dealing with mp.  ptmewput will have already
 * dealt with high priority messages.
 *
 * Return 1 if the message was processed completely and 0 if not.
 */
static int
ptemwmsg(queue_t *q, mblk_t *mp)
{
	struct ptem *ntp = (struct ptem *)q->q_ptr;
	struct iocblk *iocp;	/* outgoing ioctl structure */
	struct termio *termiop;
	struct termios *termiosp;
	mblk_t *dack_ptr;		/* disconnect message ACK block */
	mblk_t *pckt_msgp;		/* message sent to the PCKT module */
	mblk_t *dp;			/* ioctl reply data */
	tcflag_t cflags;
	int error;

	switch (mp->b_datap->db_type) {

	case M_IOCTL:
		/*
		 * Note:  for each "set" type operation a copy
		 * of the M_IOCTL message is made and passed
		 * downstream.  Eventually the PCKT module, if
		 * it has been pushed, should pick up this message.
		 * If the PCKT module has not been pushed the master
		 * side stream head will free it.
		 */
		iocp = (struct iocblk *)mp->b_rptr;
		switch (iocp->ioc_cmd) {

		case TCSETAF:
		case TCSETSF:
			/*
			 * Flush the read queue.
			 */
			if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			/* FALLTHROUGH */

		case TCSETA:
		case TCSETAW:
		case TCSETS:
		case TCSETSW:

			switch (iocp->ioc_cmd) {
			case TCSETAF:
			case TCSETA:
			case TCSETAW:
				error = miocpullup(mp, sizeof (struct termio));
				if (error != 0) {
					miocnak(q, mp, 0, error);
					goto out;
				}
				cflags = ((struct termio *)
				    mp->b_cont->b_rptr)->c_cflag;
				ntp->cflags =
				    (ntp->cflags & 0xffff0000 | cflags);
				break;

			case TCSETSF:
			case TCSETS:
			case TCSETSW:
				error = miocpullup(mp, sizeof (struct termios));
				if (error != 0) {
					miocnak(q, mp, 0, error);
					goto out;
				}
				cflags = ((struct termios *)
				    mp->b_cont->b_rptr)->c_cflag;
				ntp->cflags = cflags;
				break;
			}

			if ((cflags & CBAUD) == B0) {
				/*
				 * Hang-up: Send a zero length message.
				 */
				dack_ptr = ntp->dack_ptr;

				if (dack_ptr) {
					ntp->dack_ptr = NULL;
					/*
					 * Send a zero length message
					 * downstream.
					 */
					putnext(q, dack_ptr);
				}
			} else {
				/*
				 * Make a copy of this message and pass it on
				 * to the PCKT module.
				 */
				if ((pckt_msgp = copymsg(mp)) == NULL) {
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
				putnext(q, pckt_msgp);
			}
			/*
			 * Send ACK upstream.
			 */
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
out:
			break;

		case TCGETA:
			dp = allocb(sizeof (struct termio), BPRI_MED);
			if (dp == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			termiop = (struct termio *)dp->b_rptr;
			termiop->c_cflag = (ushort_t)ntp->cflags;
			mioc2ack(mp, dp, sizeof (struct termio), 0);
			qreply(q, mp);
			break;

		case TCGETS:
			dp = allocb(sizeof (struct termios), BPRI_MED);
			if (dp == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			termiosp = (struct termios *)dp->b_rptr;
			termiosp->c_cflag = ntp->cflags;
			mioc2ack(mp, dp, sizeof (struct termios), 0);
			qreply(q, mp);
			break;

		case TCSBRK:
			error = miocpullup(mp, sizeof (int));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				break;
			}

			/*
			 * Need a copy of this message to pass it on to
			 * the PCKT module.
			 */
			if ((pckt_msgp = copymsg(mp)) == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			/*
			 * Send a copy of the M_IOCTL to the PCKT module.
			 */
			putnext(q, pckt_msgp);

			/*
			 * TCSBRK meaningful if data part of message is 0
			 * cf. termio(7).
			 */
			if (!(*(int *)mp->b_cont->b_rptr))
				(void) putnextctl(q, M_BREAK);
			/*
			 * ACK the ioctl.
			 */
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		case JWINSIZE:
		case TIOCGWINSZ:
		case TIOCSWINSZ:
			ptioc(q, mp, WRSIDE);
			break;

		case TIOCSTI:
			/*
			 * Simulate typing of a character at the terminal.  In
			 * all cases, we acknowledge the ioctl and pass a copy
			 * of it along for the PCKT module to encapsulate.  If
			 * not in remote mode, we also process the ioctl
			 * itself, looping the character given as its argument
			 * back around to the read side.
			 */

			/*
			 * Need a copy of this message to pass on to the PCKT
			 * module.
			 */
			if ((pckt_msgp = copymsg(mp)) == NULL) {
				miocnak(q, mp, 0, EAGAIN);
				break;
			}
			if ((ntp->state & REMOTEMODE) == 0) {
				mblk_t *bp;

				error = miocpullup(mp, sizeof (char));
				if (error != 0) {
					freemsg(pckt_msgp);
					miocnak(q, mp, 0, error);
					break;
				}

				/*
				 * The permission checking has already been
				 * done at the stream head, since it has to be
				 * done in the context of the process doing
				 * the call.
				 */
				if ((bp = allocb(1, BPRI_MED)) == NULL) {
					freemsg(pckt_msgp);
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
				/*
				 * XXX:	Is EAGAIN really the right response to
				 *	flow control blockage?
				 */
				if (!bcanputnext(RD(q), mp->b_band)) {
					freemsg(bp);
					freemsg(pckt_msgp);
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
				*bp->b_wptr++ = *mp->b_cont->b_rptr;
				qreply(q, bp);
			}

			putnext(q, pckt_msgp);
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		case PTSSTTY:
			if (ntp->state & IS_PTSTTY) {
				miocnak(q, mp, 0, EEXIST);
			} else {
				ntp->state |= IS_PTSTTY;
				mioc2ack(mp, NULL, 0, 0);
				qreply(q, mp);
			}
			break;

		default:
			/*
			 * End of the line.  The slave driver doesn't see any
			 * ioctls that we don't explicitly pass along to it.
			 */
			miocnak(q, mp, 0, EINVAL);
			break;
		}
		break;

	case M_DELAY: /* tty delays not supported */
		freemsg(mp);
		break;

	case M_DATA:
		if ((mp->b_wptr - mp->b_rptr) < 0) {
			/*
			 * Free all bad length messages.
			 */
			freemsg(mp);
			break;
		} else if ((mp->b_wptr - mp->b_rptr) == 0) {
			if (!(ntp->state & IS_PTSTTY)) {
				freemsg(mp);
				break;
			}
		}
		if (ntp->state & OFLOW_CTL)
			return (0);

	default:
		putnext(q, mp);
		break;

	}

	return (1);
}
Exemplo n.º 3
0
/**
 * ptem_r_msg - process a message on the read side
 * @q: read queue
 * @mp: the message to process
 *
 * Returns 1 when the caller (putp or srvp) needs to queue or requeue the
 * message.  Returns 0 when the message has been disposed and the caller must
 * release its reference to mp.
 *
 * Keep this away from the fast path.
 */
static streams_noinline __unlikely void
ptem_r_msg(queue_t *q, mblk_t *mp)
{
	struct iocblk *ioc = (typeof(ioc)) mp->b_rptr;
	int error = EINVAL;
	int count = 0;
	int rval = 0;
	mblk_t *bp;

	/* The Stream head is set to recognized all transparent terminal input-output controls and
	   pass them downstream as though they were I_STR input-output controls.  There is also the 
	   opportunity to register input-output controls with the Stream head using the TIOC_REPLY
	   message. */
	if (unlikely(ioc->ioc_count == TRANSPARENT)) {
		__swerr();
		goto nak;
	}
	if (!(bp = mp->b_cont))
		goto nak;

	switch (ioc->ioc_cmd) {
	case TCSBRK:
		/* When the ptem module receives an M_IOCTL message of type TCSBRK on its read-side 
		   queue, it sends an M_IOCACK message downstream and an M_BREAK message upstream. */
		if (!pullupmsg(bp, sizeof(int)))
			goto nak;
		if (!putnextctl(q, M_BREAK)) {
			error = EAGAIN;
			goto nak;
		}
		goto ack;
	case TIOCGWINSZ:
	{
		/* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE,
		   input-output control commands. */
		struct ptem *p = PTEM_PRIV(q);
		extern void __struct_winsize_is_too_large_for_fastbuf(void);

		if (!(p->flags & PTEM_HAVE_WINSIZE))
			goto nak;
		if (FASTBUF < sizeof(struct winsize)) {
			__struct_winsize_is_too_large_for_fastbuf();
		}
		/* always have room in a fastbuf */
		count = sizeof(p->ws);
		bp->b_rptr = bp->b_datap->db_base;
		bp->b_wptr = bp->b_rptr + count;
		*(struct winsize *) bp->b_rptr = p->ws;
		goto ack;
	}
#ifdef JWINSIZE
	case JWINSIZE:
		/* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE,
		   input-output control commands. */
	{
		struct ptem *p = PTEM_PRIV(q);
		struct jwinsize *jws;

		if (!(p->flags & PTEM_HAVE_WINSIZE))
			goto nak;
		if (FASTBUF < sizeof(struct jwinsize))
			__undefined_call_makes_compile_fail();
		/* always have room in a fastbuf */
		count = sizeof(*jws);
		bp->b_rptr = bp->b_datap->db_base;
		bp->b_wptr = bp->b_rptr + count;
		jws = (typeof(jws)) bp->b_rptr;
		jws->bytesx = p->ws.ws_col;
		jws->bytesy = p->ws.ws_row;
		jws->bitsx = p->ws.ws_xpixel;
		jws->bitsy = p->ws.ws_ypixel;
		goto ack;
	}
#endif				/* JWINSIZE */
	case TIOCSWINSZ:
		/* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE,
		   input-output control commands. */
	{
		struct ptem *p = PTEM_PRIV(q);
		struct winsize *ws;
		int changed = 0;
		int zeroed = !(p->flags & PTEM_HAVE_WINSIZE);
		mblk_t *mb;

		if (!pullupmsg(bp, sizeof(*ws)))
			goto nak;
		if (!(mb = allocb(1, BPRI_MED))) {
			error = EAGAIN;
			goto nak;
		}
		ws = (typeof(ws)) bp->b_rptr;
		if (ws->ws_col != p->ws.ws_col) {
			if ((p->ws.ws_col = ws->ws_col))
				zeroed = 0;
			changed = 1;
		}
		if (ws->ws_row != p->ws.ws_row) {
			if ((p->ws.ws_row = ws->ws_row))
				zeroed = 0;
			changed = 1;
		}
		if (ws->ws_xpixel != p->ws.ws_xpixel) {
			if ((p->ws.ws_xpixel = ws->ws_xpixel))
				zeroed = 0;
			changed = 1;
		}
		if (ws->ws_ypixel != p->ws.ws_ypixel) {
			if ((p->ws.ws_ypixel = ws->ws_ypixel))
				zeroed = 0;
			changed = 1;
		}
		if (zeroed)
			p->flags &= ~PTEM_HAVE_WINSIZE;
		else
			p->flags |= PTEM_HAVE_WINSIZE;
		if (changed) {
			mb->b_datap->db_type = M_SIG;
			*mb->b_wptr++ = SIGWINCH;
			putnext(q, mb);
		} else
			freeb(mb);
		count = 0;
		goto ack;
	}
#ifdef TIOCSIGNAL
	case TIOCSIGNAL:
#endif				/* TIOCSIGNAL */
#ifdef O_TIOCSIGNAL
	case O_TIOCSIGNAL:
#endif				/* O_TIOCSIGNAL */
	{
		uint s;

		if (!pullupmsg(bp, sizeof(s)))
			goto nak;
		if ((s = *(uint *) bp->b_rptr) > _NSIG || s == 0)
			goto nak;
		if (!putnextctl1(q, M_PCSIG, s)) {
			error = EAGAIN;
			goto nak;
		}
		count = 0;
		goto ack;
	}
#ifdef TIOCREMOTE
	case TIOCREMOTE:
#endif				/* TIOCREMOTE */
#ifdef O_TIOCREMOTE
	case O_TIOCREMOTE:
#endif				/* O_TIOCREMOTE */
	{
		struct ptem *p = PTEM_PRIV(q);
		struct iocblk *ctl;
		mblk_t *mb;

		if (!pullupmsg(bp, sizeof(uint)))
			goto nak;
		if (!(mb = allocb(sizeof(*ctl), BPRI_MED))) {
			error = EAGAIN;
			goto nak;
		}
		mb->b_datap->db_type = M_CTL;
		ctl = (typeof(ctl)) mb->b_rptr;
		mb->b_wptr += sizeof(*ctl);
		bzero(ctl, sizeof(ctl));
		if (*(uint *) bp->b_rptr) {
			ctl->ioc_cmd = MC_NO_CANON;
			p->flags |= PTEM_REMOTE_MODE;
		} else {
			ctl->ioc_cmd = MC_DO_CANON;
			p->flags &= ~PTEM_REMOTE_MODE;
		}
		putnext(q, mb);
		count = 0;
		goto ack;
	}
	default:
		break;
	}
	putnext(q, mp);
	return;

      ack:
	mp->b_datap->db_type = M_IOCNAK;
	ioc->ioc_error = error;
	ioc->ioc_rval = -1;
	ioc->ioc_count = 0;
      reply:
	qreply(q, mp);
	return;
      nak:
	mp->b_datap->db_type = M_IOCACK;
	ioc->ioc_error = error;
	ioc->ioc_rval = rval;
	ioc->ioc_count = count;
	goto reply;
}
Exemplo n.º 4
0
/*
 * cvc_win_resize()
 *	cvc_win_resize will read winsize data from the CONC IOSRAM chunk and set
 *	the console window size accordingly.  If indicated by the caller, CONC's
 *	data_valid flag will also be cleared.  The flag isn't cleared in all
 *	cases because we need to process winsize data at startup without waiting
 *	for a command.
 */
static void
cvc_win_resize(int clear_flag)
{
	int		rval;
	uint16_t	rows;
	uint16_t	cols;
	uint16_t	xpixels;
	uint16_t	ypixels;
	tty_common_t	*tty;
	cvc_t		*cp;
	struct winsize	ws;

	/*
	 * Start by reading the new window size out of the CONC chunk and, if
	 * requested, clearing CONC's data_valid flag.  If any of that fails,
	 * return immediately.  (Note that the rather bulky condition in the
	 * two "if" statements takes advantage of C's short-circuit logic
	 * evaluation)
	 */
	if (((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_rows),
	    CVC_CTL_SIZE(winsize_rows), (caddr_t)&rows)) != 0) ||
	    ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_cols),
	    CVC_CTL_SIZE(winsize_cols), (caddr_t)&cols)) != 0) ||
	    ((rval = iosram_rd(IOSRAM_KEY_CONC,
	    CVC_CTL_OFFSET(winsize_xpixels), CVC_CTL_SIZE(winsize_xpixels),
	    (caddr_t)&xpixels)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC,
	    CVC_CTL_OFFSET(winsize_ypixels), CVC_CTL_SIZE(winsize_ypixels),
	    (caddr_t)&ypixels)) != 0)) {
		if (rval != EAGAIN) {
			cmn_err(CE_WARN,
			    "cvc_win_resize: read for ctlbuf ret %d", rval);
		}
		return;
	}

	if (clear_flag && ((rval = iosram_set_flag(IOSRAM_KEY_CONC,
	    IOSRAM_DATA_INVALID, IOSRAM_INT_NONE)) != 0)) {
		if (rval != EAGAIN) {
			cmn_err(CE_WARN,
			    "cvc_win_resize: set_flag for ctlbuf ret %d", rval);
		}
		return;
	}

	/*
	 * Copy the parameters from IOSRAM to a winsize struct.
	 */
	ws.ws_row = rows;
	ws.ws_col = cols;
	ws.ws_xpixel = xpixels;
	ws.ws_ypixel = ypixels;

	/*
	 * This code was taken from Starfire, and it appears to work correctly.
	 * However, since the original developer felt it necessary to add the
	 * following comment, it's probably worth preserving:
	 *
	 * XXX I hope this is safe...
	 */
	cp = cvcinput_q->q_ptr;
	tty = &cp->cvc_tty;
	mutex_enter(&tty->t_excl);
	if (bcmp((caddr_t)&tty->t_size, (caddr_t)&ws,
	    sizeof (struct winsize))) {
		tty->t_size = ws;
		mutex_exit(&tty->t_excl);
		(void) putnextctl1(cvcinput_q, M_PCSIG,
			SIGWINCH);
	} else {
		mutex_exit(&tty->t_excl);
	}
}
Exemplo n.º 5
0
/**
 * ptem_w_msg - process a message on the write side
 * @q: write queue
 * @mp: message to process
 *
 * Returns 1 when the caller (putp or srvp) needs to queue or requeue the
 * message.  Returns 0 when the message has been disposed and the caller must
 * release its reference to mp.
 *
 * Keep this function out of the way of the fastpath.
 */
static streams_noinline int
ptem_w_msg(queue_t *q, mblk_t *mp)
{
	struct ptem *p = PTEM_PRIV(q);

	/* fast path */
	if (likely(mp->b_datap->db_type == M_DATA)) {
	      m_data:
		if ((p->flags & PTEM_OUTPUT_STOPPED)
		    || (q->q_first != NULL)
		    || (q->q_flag & QSVCBUSY)
		    || (!bcanputnext(q, mp->b_band)))
			return (1);
		putnext(q, mp);
		return (0);
	}

	switch (mp->b_datap->db_type) {
	case M_DATA:
		goto m_data;
	case M_IOCTL:
	{
		struct iocblk *ioc = (struct iocblk *) mp->b_rptr;
		int error = EINVAL;
		int rval = 0;
		int count = 0;
		mblk_t *bp, *cp;

		/* The Stream head is set to recognized all transparent terminal input-output
		   controls and pass them downstream as though they were I_STR input-output
		   controls.  There is also the opportunity to register input-output controls with
		   the Stream head using the TIOC_REPLY message. */
		if (ioc->ioc_count == TRANSPARENT) {
			__swerr();
			goto nak;
		}

		if ((bp = mp->b_cont) == NULL)
			goto nak;

		switch (ioc->ioc_cmd) {
		case TCSETAF:
			/* Note, if properly handled the M_FLUSH message will never be queued and
			   upon successful return from this function, we have already processed the
			   read-side flush along the entire Stream. */
			if (!putnextctl1(q, M_FLUSH, FLUSHR)) {
				error = EAGAIN;
				goto nak;
			}
			/* fall through */
		case TCSETAW:
			/* Note, output should have already drained. */
			/* fall through */
		case TCSETA:
		{
			struct termio *c;
			mblk_t *zp;

			if (!pullupmsg(bp, sizeof(struct termio)))
				goto nak;

			c = (typeof(c)) bp->b_rptr;

			if ((c->c_cflag & CBAUD) == B0) {
				/* slave hangup */
				if ((zp = xchg(&p->zero, NULL)))
					putnext(q, zp);
			} else {
				if (!(cp = copymsg(mp))) {
					error = EAGAIN;
					goto nak;
				}

				p->c.c_iflag = (p->c.c_iflag & 0xffff0000) | c->c_iflag;
				p->c.c_oflag = (p->c.c_oflag & 0xffff0000) | c->c_oflag;
				p->c.c_cflag = (p->c.c_cflag & 0xffff0000) | c->c_cflag;
				p->c.c_lflag = (p->c.c_lflag & 0xffff0000) | c->c_lflag;
				p->c.c_line = c->c_line;
				bcopy(c->c_cc, p->c.c_cc, NCC);

				putnext(q, cp);
			}
			goto ack;
		}

		case TCSETSF:
			/* Note, if properly handled the M_FLUSH message will never be queued and
			   upon successful return from this function, we have already processed the
			   read-side flush along the entire Stream. */
			if (!putnextctl1(q, M_FLUSH, FLUSHR)) {
				error = EAGAIN;
				goto nak;
			}
			/* fall through */
		case TCSETSW:
			/* Note, output should have already drained. */
			/* fall through */
		case TCSETS:
		{
			struct termios *c;
			mblk_t *zp;

			if (!pullupmsg(bp, sizeof(struct termios)))
				goto nak;

			c = (typeof(c)) bp->b_rptr;

			if ((c->c_cflag & CBAUD) == B0) {
				/* slave hangup */
				if ((zp = xchg(&p->zero, NULL)))
					putnext(q, zp);
			} else {
				if (!(cp = copymsg(mp))) {
					error = EAGAIN;
					goto nak;
				}

				p->c = *c;

				putnext(q, cp);
			}
			goto ack;
		}

		case TCGETA:
		{
			struct termio *c;
			extern void __struct_termio_is_too_large_for_fastbuf(void);

			if (FASTBUF < sizeof(struct termio))
				__struct_termio_is_too_large_for_fastbuf();
			count = sizeof(*c);
			bp->b_rptr = bp->b_datap->db_base;
			bp->b_wptr = bp->b_rptr + count;
			c = (typeof(c)) bp->b_rptr;

			c->c_iflag = p->c.c_iflag;
			c->c_oflag = p->c.c_oflag;
			c->c_cflag = p->c.c_cflag;
			c->c_lflag = p->c.c_lflag;
			c->c_line = p->c.c_line;
			bcopy(p->c.c_cc, p->c.c_cc, NCC);

			goto ack;
		}
		case TCGETS:
		{
			extern void __struct_termios_is_too_large_for_fastbuf(void);

			if (FASTBUF < sizeof(struct termios))
				__struct_termios_is_too_large_for_fastbuf();
			count = sizeof(p->c);
			bp->b_rptr = bp->b_datap->db_base;
			bp->b_wptr = bp->b_rptr + count;
			*((struct termios *) bp->b_rptr) = p->c;
			goto ack;
		}
		case TIOCGWINSZ:
		{
			extern void __struct_winsize_is_too_large_for_fastbuf(void);

			if (!(p->flags & PTEM_HAVE_WINSIZE))
				goto nak;
			if (FASTBUF < sizeof(struct winsize))
				__struct_winsize_is_too_large_for_fastbuf();
			count = sizeof(p->ws);
			bp->b_rptr = bp->b_datap->db_base;
			bp->b_wptr = bp->b_rptr + count;
			*((struct winsize *) bp->b_rptr) = p->ws;
			goto ack;
		}
#ifdef JWINSIZE
		case JWINSIZE:
		{
			struct jwinsize *jws;
			extern void __struct_jwinsize_is_too_large_for_fastbuf(void);

			if (!(p->flags & PTEM_HAVE_WINSIZE))
				goto nak;
			if (FASTBUF < sizeof(struct jwinsize))
				__struct_jwinsize_is_too_large_for_fastbuf();
			/* always have room in a fastbuf */
			count = sizeof(*jws);
			bp->b_rptr = bp->b_datap->db_base;
			bp->b_wptr = bp->b_rptr + count;
			jws = (typeof(jws)) bp->b_rptr;

			jws->bytesx = p->ws.ws_col;
			jws->bytesy = p->ws.ws_row;
			jws->bitsx = p->ws.ws_xpixel;
			jws->bitsy = p->ws.ws_ypixel;

			goto ack;
		}
#endif				/* JWINSIZE */
		case TIOCSWINSZ:
		{
			struct winsize *ws;
			int changed = 0;
			int zeroed = !(p->flags & PTEM_HAVE_WINSIZE);
			mblk_t *mb;

			if (!pullupmsg(bp, sizeof(*ws)))
				goto nak;
			if (!(cp = copymsg(mp))) {
				error = EAGAIN;
				goto nak;
			}
			if (!(mb = allocb(1, BPRI_MED))) {
				freemsg(cp);
				error = EAGAIN;
				goto nak;
			}
			ws = (typeof(ws)) bp->b_rptr;
			if (ws->ws_col != p->ws.ws_col) {
				if ((p->ws.ws_col = ws->ws_col))
					zeroed = 0;
				changed = 1;
			}
			if (ws->ws_row != p->ws.ws_row) {
				if ((p->ws.ws_row = ws->ws_row))
					zeroed = 0;
				changed = 1;
			}
			if (ws->ws_xpixel != p->ws.ws_xpixel) {
				if ((p->ws.ws_xpixel = ws->ws_xpixel))
					zeroed = 0;
				changed = 1;
			}
			if (ws->ws_ypixel != p->ws.ws_ypixel) {
				if ((p->ws.ws_ypixel = ws->ws_ypixel))
					zeroed = 0;
				changed = 1;
			}
			if (zeroed)
				p->flags &= ~PTEM_HAVE_WINSIZE;
			else
				p->flags |= PTEM_HAVE_WINSIZE;
			if (changed) {
				mb->b_datap->db_type = M_SIG;
				*mb->b_wptr++ = SIGWINCH;
				qreply(q, mb);
			} else
				freeb(mb);
			putnext(q, cp);	/* copy for pctk(4) */
			count = 0;
			goto ack;
		}
		case TCSBRK:
			if (!(cp = copymsg(mp))) {
				error = EAGAIN;
				goto nak;
			}
			putnext(q, cp);
			count = 0;
			goto ack;
		default:
			goto nak;
		}
		break;
	      ack:
		mp->b_datap->db_type = M_IOCACK;
		ioc->ioc_error = 0;
		ioc->ioc_rval = rval;
		ioc->ioc_count = count;
		goto reply;
	      nak:
		mp->b_datap->db_type = M_IOCNAK;
		ioc->ioc_error = error;
		ioc->ioc_rval = -1;
		ioc->ioc_count = 0;
	      reply:
		qreply(q, mp);
		break;
	}
	case M_FLUSH:
		if (mp->b_rptr[0] & FLUSHW) {
			if (mp->b_rptr[0] & FLUSHBAND)
				flushband(q, mp->b_rptr[1], FLUSHDATA);
			else
				flushq(q, FLUSHDATA);
		}
		putnext(q, mp);
		break;
	default:
		if (mp->b_datap->db_type < QPCTL) {
			if ((q->q_first != NULL)
			    || (q->q_flag & QSVCBUSY)
			    || (!bcanputnext(q, mp->b_band)))
				return (1);	/* (re)queue */
		}
		putnext(q, mp);
		break;
	}
	return (0);
}