Пример #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;
	}
}
Пример #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);
}
Пример #3
0
/*
 * ptemrput - Module read queue put procedure.
 *
 * This is called from the module or driver downstream.
 */
static void
ptemrput(queue_t *q, mblk_t *mp)
{
	struct iocblk *iocp;	/* M_IOCTL data */
	struct copyresp *resp;	/* transparent ioctl response struct */
	int error;

	switch (mp->b_datap->db_type) {
	case M_DELAY:
	case M_READ:
		freemsg(mp);
		break;

	case M_IOCTL:
		iocp = (struct iocblk *)mp->b_rptr;

		switch (iocp->ioc_cmd) {
		case TCSBRK:
			/*
			 * Send a break message upstream.
			 *
			 * XXX:	Shouldn't the argument come into play in
			 *	determining whether or not so send an M_BREAK?
			 *	It certainly does in the write-side direction.
			 */
			error = miocpullup(mp, sizeof (int));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				break;
			}
			if (!(*(int *)mp->b_cont->b_rptr)) {
				if (!putnextctl(q, M_BREAK)) {
					/*
					 * Send an NAK reply back
					 */
					miocnak(q, mp, 0, EAGAIN);
					break;
				}
			}
			/*
			 * ACK it.
			 */
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

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

		case TIOCSIGNAL:
			/*
			 * The following subtle logic is due to the fact that
			 * `mp' may be in any one of three distinct formats:
			 *
			 *	1. A transparent M_IOCTL with an intptr_t-sized
			 *	   payload containing the signal number.
			 *
			 *	2. An I_STR M_IOCTL with an int-sized payload
			 *	   containing the signal number.
			 *
			 *	3. An M_IOCDATA with an int-sized payload
			 *	   containing the signal number.
			 */
			if (iocp->ioc_count == TRANSPARENT) {
				intptr_t sig = *(intptr_t *)mp->b_cont->b_rptr;

				if (sig < 1 || sig >= NSIG) {
					/*
					 * it's transparent with pointer
					 * to the arg
					 */
					mcopyin(mp, NULL, sizeof (int), NULL);
					qreply(q, mp);
					break;
				}
			}
			ptioc(q, mp, RDSIDE);
			break;

		case TIOCREMOTE:
			if (iocp->ioc_count != TRANSPARENT)
				ptioc(q, mp, RDSIDE);
			else {
				mcopyin(mp, NULL, sizeof (int), NULL);
				qreply(q, mp);
			}
			break;

		default:
			putnext(q, mp);
			break;
		}
		break;

	case M_IOCDATA:
		resp = (struct copyresp *)mp->b_rptr;
		if (resp->cp_rval) {
			/*
			 * Just free message on failure.
			 */
			freemsg(mp);
			break;
		}

		/*
		 * Only need to copy data for the SET case.
		 */
		switch (resp->cp_cmd) {

		case TIOCSWINSZ:
		case TIOCSIGNAL:
		case TIOCREMOTE:
			ptioc(q, mp, RDSIDE);
			break;

		case JWINSIZE:
		case TIOCGWINSZ:
			mp->b_datap->db_type = M_IOCACK;
			mioc2ack(mp, NULL, 0, 0);
			qreply(q, mp);
			break;

		default:
			freemsg(mp);
			break;
	}
	break;

	case M_IOCACK:
	case M_IOCNAK:
		/*
		 * We only pass write-side ioctls through to the master that
		 * we've already ACKed or NAKed to the stream head.  Thus, we
		 * discard ones arriving from below, since they're redundant
		 * from the point of view of modules above us.
		 */
		freemsg(mp);
		break;

	case M_HANGUP:
		/*
		 * clear blocked state.
		 */
		{
			struct ptem *ntp = (struct ptem *)q->q_ptr;
			if (ntp->state & OFLOW_CTL) {
				ntp->state &= ~OFLOW_CTL;
				qenable(WR(q));
			}
		}
	default:
		putnext(q, mp);
		break;
	}
}
Пример #4
0
/*
 * telmodwput:
 * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon
 * to process something.  M_CTL's are data from the daemon bound for the
 * network.  We forward them immediately.  There are two classes of ioctl's
 * we must handle here also.  One is ioctl's forwarded by ptem which we
 * ignore.  The other is ioctl's issued by the daemon to control us.
 * Process them appropriately.  M_PROTO's we pass along, figuring they are
 * are TPI operations for TCP.  M_FLUSH requires careful processing, since
 * telnet cannot tolerate flushing its protocol requests.  Also the flushes
 * can be running either daemon<->TCP or application<->telmod.  We must
 * carefully deal with this.
 */
static void
telmodwput(
	queue_t *q,	/* Pointer to the read queue */
	mblk_t *mp)	/* Pointer to current message block */
{
	struct telmod_info	*tmip;
	struct iocblk *ioc;
	mblk_t *savemp;
	int rw;
	int error;

	tmip = (struct telmod_info *)q->q_ptr;

	switch (mp->b_datap->db_type) {
	case M_DATA:
		if (!canputnext(q) || (tmip->flags & TEL_STOPPED) ||
			(q->q_first)) {
			noenable(q);
			(void) putq(q, mp);
			break;
		}
		/*
		 * This routine parses data generating from ptm side.
		 * Insert a null character if carraige return
		 * is not followed by line feed unless we are in binary mode.
		 * Also, duplicate IAC if found in the data.
		 */
		(void) snd_parse(q, mp);
		break;

	case M_CTL:
		if (((mp->b_wptr - mp->b_rptr) == 1) &&
			(*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) {
			savemp = mp->b_cont;
			freeb(mp);
			mp = savemp;
		}
		putnext(q, mp);
		break;

	case M_IOCTL:
		ioc = (struct iocblk *)mp->b_rptr;
		switch (ioc->ioc_cmd) {

		/*
		 * This ioctl is issued by user level daemon to
		 * request one more message block to process protocol
		 */
		case TEL_IOC_GETBLK:
			if (!(tmip->flags & TEL_STOPPED)) {
				miocnak(q, mp, 0, EINVAL);
				break;
			}
			tmip->flags |= TEL_GETBLK;
			qenable(RD(q));
			enableok(RD(q));

			miocack(q, mp, 0, 0);
			break;

		/*
		 * This ioctl is issued by user level daemon to reenable the
		 * read and write queues. This is issued during startup time
		 * after setting up the mux links and also after processing
		 * the protocol.  It is also issued after each time an
		 * an unrecognized telnet option is forwarded to the daemon.
		 */
		case TEL_IOC_ENABLE:

			/*
			 * Send negative ack if TEL_STOPPED flag is not set
			 */
			if (!(tmip->flags & TEL_STOPPED)) {
				miocnak(q, mp, 0, EINVAL);
				break;
			}
			tmip->flags &= ~TEL_STOPPED;
			if (mp->b_cont) {
				(void) putbq(RD(q), mp->b_cont);
				mp->b_cont = 0;
			}

			qenable(RD(q));
			enableok(RD(q));
			qenable(q);
			enableok(q);

			miocack(q, mp, 0, 0);
			break;

		/*
		 * Set binary/normal mode for input and output
		 * according to the instructions from the daemon.
		 */
		case TEL_IOC_MODE:
			error = miocpullup(mp, sizeof (uchar_t));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				break;
			}
			tmip->flags |= *(mp->b_cont->b_rptr) &
			    (TEL_BINARY_IN|TEL_BINARY_OUT);
			miocack(q, mp, 0, 0);
			break;

#ifdef DEBUG
		case TCSETAF:
		case TCSETSF:
		case TCSETA:
		case TCSETAW:
		case TCSETS:
		case TCSETSW:
		case TCSBRK:
		case TIOCSTI:
		case TIOCSWINSZ:
			miocnak(q, mp, 0, EINVAL);
			break;
#endif
		case CRYPTPASSTHRU:
			error = miocpullup(mp, sizeof (uchar_t));
			if (error != 0) {
				miocnak(q, mp, 0, error);
				break;
			}
			if (*(mp->b_cont->b_rptr) == 0x01)
				tmip->flags |= TEL_IOCPASSTHRU;
			else
				tmip->flags &= ~TEL_IOCPASSTHRU;

			miocack(q, mp, 0, 0);
			break;

		default:
			if (tmip->flags & TEL_IOCPASSTHRU) {
				putnext(q, mp);
			} else {
#ifdef DEBUG
				cmn_err(CE_NOTE,
				"telmodwput: unexpected ioctl type 0x%x",
					ioc->ioc_cmd);
#endif
				miocnak(q, mp, 0, EINVAL);
			}
			break;
		}
		break;

	case M_FLUSH:
		/*
		 * Flushing is tricky:  We try to flush all we can, but certain
		 * data cannot be flushed.  Telnet protocol sequences cannot
		 * be flushed.  So, TCP's queues cannot be flushed since we
		 * cannot tell what might be telnet protocol data.  Then we
		 * must take care to create and forward out-of-band data
		 * indicating the flush to the far side.
		 */
		rw = *mp->b_rptr;
		if (rw & FLUSHR) {
			/*
			 * We cannot flush our read queue, since there may
			 * be telnet protocol bits in the queue, awaiting
			 * processing.  However, once it leaves this module
			 * it's guaranteed that all protocol data is in
			 * M_CTL, so we do flush read data beyond us, expecting
			 * them (actually logindmux) to do FLUSHDATAs also.
			 */
			*mp->b_rptr = rw & ~FLUSHW;
			qreply(q, mp);
		} else {
			freemsg(mp);
		}
		if (rw & FLUSHW) {
			/*
			 * Since all telnet protocol data comes from the
			 * daemon, stored as M_CTL messages, flushq will
			 * do exactly what's needed:  Flush bytes which do
			 * not have telnet protocol data.
			 */
			flushq(q, FLUSHDATA);
		}
		break;

	case M_PCPROTO:
		putnext(q, mp);
		break;

	case M_PROTO:
		/* We may receive T_DISCON_REQ from the mux */
		if (!canputnext(q) || q->q_first != NULL)
			(void) putq(q, mp);
		else
			putnext(q, mp);
		break;

	default:
#ifdef DEBUG
		cmn_err(CE_NOTE,
		    "telmodwput: unexpected msg type 0x%x",
		    mp->b_datap->db_type);
#endif
		freemsg(mp);
		break;
	}
}
Пример #5
0
static void
kb8042_ioctlmsg(struct kb8042 *kb8042, queue_t *qp, mblk_t *mp)
{
	struct iocblk	*iocp;
	mblk_t		*datap;
	int		error;
	int		tmp;

	iocp = (struct iocblk *)mp->b_rptr;

	switch (iocp->ioc_cmd) {

	case CONSOPENPOLLEDIO:
		error = miocpullup(mp, sizeof (struct cons_polledio *));
		if (error != 0) {
			miocnak(qp, mp, 0, error);
			return;
		}

		/*
		 * We are given an appropriate-sized data block,
		 * and return a pointer to our structure in it.
		 */
		*(struct cons_polledio **)mp->b_cont->b_rptr =
		    &kb8042->polledio;
		mp->b_datap->db_type = M_IOCACK;
		iocp->ioc_error = 0;
		qreply(qp, mp);
		break;

	case CONSCLOSEPOLLEDIO:
		miocack(qp, mp, 0, 0);
		break;

	case CONSSETABORTENABLE:
		if (iocp->ioc_count != TRANSPARENT) {
			miocnak(qp, mp, 0, EINVAL);
			return;
		}

		kb8042->debugger.enabled = *(intptr_t *)mp->b_cont->b_rptr;
		miocack(qp, mp, 0, 0);
		break;

	/*
	 * Valid only in TR_UNTRANS_MODE mode.
	 */
	case CONSSETKBDTYPE:
		error = miocpullup(mp, sizeof (int));
		if (error != 0) {
			miocnak(qp, mp, 0, error);
			return;
		}
		tmp =  *(int *)mp->b_cont->b_rptr;
		if (tmp != KB_PC && tmp != KB_USB) {
			miocnak(qp, mp, 0, EINVAL);
			break;
		}
		kb8042->simulated_kbd_type = tmp;
		miocack(qp, mp, 0, 0);
		break;

	case KIOCLAYOUT:
		if (kb8042->w_kblayout == -1) {
			miocnak(qp, mp, 0, EINVAL);
			return;
		}

		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
			miocnak(qp, mp, 0, ENOMEM);
			return;
		}

		if (kb8042->simulated_kbd_type == KB_USB)
			*(int *)datap->b_wptr = KBTRANS_USBKB_DEFAULT_LAYOUT;
		else
			*(int *)datap->b_wptr = kb8042->w_kblayout;

		datap->b_wptr += sizeof (int);
		if (mp->b_cont)
			freemsg(mp->b_cont);
		mp->b_cont = datap;
		iocp->ioc_count = sizeof (int);
		mp->b_datap->db_type = M_IOCACK;
		iocp->ioc_error = 0;
		qreply(qp, mp);
		break;

	case KIOCSLAYOUT:
		if (iocp->ioc_count != TRANSPARENT) {
			miocnak(qp, mp, 0, EINVAL);
			return;
		}

		kb8042->w_kblayout = *(intptr_t *)mp->b_cont->b_rptr;
		miocack(qp, mp, 0, 0);
		break;

	case KIOCCMD:
		error = miocpullup(mp, sizeof (int));
		if (error != 0) {
			miocnak(qp, mp, 0, error);
			return;
		}

		kb8042_type4_cmd(kb8042, *(int *)mp->b_cont->b_rptr);
		miocack(qp, mp, 0, 0);
		break;

	default:
#ifdef DEBUG1
		cmn_err(CE_NOTE, "!kb8042_ioctlmsg %x", iocp->ioc_cmd);
#endif
		miocnak(qp, mp, 0, EINVAL);
		return;
	}
}
Пример #6
0
/*
 * Handle write-side M_IOCTL messages.
 */
static void
pfioctl(queue_t *wq, mblk_t *mp)
{
	struct	epacketfilt	*pfp = (struct epacketfilt *)wq->q_ptr;
	struct	Pf_ext_packetfilt	*upfp;
	struct	packetfilt	*opfp;
	ushort_t	*fwp;
	int	arg;
	int	maxoff = 0;
	int	maxoffreg = 0;
	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
	int	error;

	switch (iocp->ioc_cmd) {
	case PFIOCSETF:
		/*
		 * Verify argument length. Since the size of packet filter
		 * got increased (ENMAXFILTERS was bumped up to 2047), to
		 * maintain backwards binary compatibility, we need to
		 * check for both possible sizes.
		 */
		switch (iocp->ioc_count) {
		case sizeof (struct Pf_ext_packetfilt):
			error = miocpullup(mp,
			    sizeof (struct Pf_ext_packetfilt));
			if (error != 0) {
				miocnak(wq, mp, 0, error);
				return;
			}
			upfp = (struct Pf_ext_packetfilt *)mp->b_cont->b_rptr;
			if (upfp->Pf_FilterLen > PF_MAXFILTERS) {
				miocnak(wq, mp, 0, EINVAL);
				return;
			}

			bcopy(upfp, pfp, sizeof (struct Pf_ext_packetfilt));
			pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen];
			break;

		case sizeof (struct packetfilt):
			error = miocpullup(mp, sizeof (struct packetfilt));
			if (error != 0) {
				miocnak(wq, mp, 0, error);
				return;
			}
			opfp = (struct packetfilt *)mp->b_cont->b_rptr;
			/* this strange comparison keeps gcc from complaining */
			if (opfp->Pf_FilterLen - 1 >= ENMAXFILTERS) {
				miocnak(wq, mp, 0, EINVAL);
				return;
			}

			pfp->pf.Pf_Priority = opfp->Pf_Priority;
			pfp->pf.Pf_FilterLen = (unsigned int)opfp->Pf_FilterLen;

			bcopy(opfp->Pf_Filter, pfp->pf.Pf_Filter,
			    sizeof (opfp->Pf_Filter));
			pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen];
			break;

		default:
			miocnak(wq, mp, 0, EINVAL);
			return;
		}

		/*
		 * Find and record maximum byte offset that the
		 * filter users.  We use this when executing the
		 * filter to determine how much of the packet
		 * body to pull up.  This code depends on the
		 * filter encoding.
		 */
		for (fwp = pfp->pf_Filter; fwp < pfp->pf_FilterEnd; fwp++) {
			arg = *fwp & ((1 << ENF_NBPA) - 1);
			switch (arg) {
			default:
				if ((arg -= ENF_PUSHWORD) > maxoff)
					maxoff = arg;
				break;

			case ENF_LOAD_OFFSET:
				/* Point to the offset */
				fwp++;
				if (*fwp > maxoffreg)
					maxoffreg = *fwp;
				break;

			case ENF_PUSHLIT:
			case ENF_BRTR:
			case ENF_BRFL:
				/* Skip over the literal. */
				fwp++;
				break;

			case ENF_PUSHZERO:
			case ENF_PUSHONE:
			case ENF_PUSHFFFF:
			case ENF_PUSHFF00:
			case ENF_PUSH00FF:
			case ENF_NOPUSH:
			case ENF_POP:
				break;
			}
		}

		/*
		 * Convert word offset to length in bytes.
		 */
		pfp->pf_PByteLen = (maxoff + maxoffreg + 1) * sizeof (ushort_t);
		miocack(wq, mp, 0, 0);
		break;

	default:
		putnext(wq, mp);
		break;
	}
}