Exemplo n.º 1
0
/*
 *  SSCOP RSRV - Queued message from below.
 *
 *  If the message is a priority message we attempt to process it immediately
 *  and without flow control.  If the message is a non-priority message and
 *  the next queue is flow controlled, we put the message back on the queue
 *  and wait.  If we cannot process a priority message immediately we cannot
 *  place it back on the queue and discard it.  We requeue non-priority
 *  messages which cannot be processed immediately.  Unrecognized messages are
 *  passed down-queue.
 */
STATIC int
sscop_rsrv(queue_t *q)
{
	mblk_t *mp;
	int err = -EOPNOTSUPP;

	while ((mp = getq(q))) {
		if (mp->b_datap->db_type < QPCTL && !canputnext(q)) {
			putbq(q, mp);
			return (0);
		}
		switch (mp->b_datap->db_type) {
		case M_DATA:
			if ((err = sscop_r_data(q, mp)))
				break;
			goto rsrv_continue;
		case M_PROTO:
			if ((err = sscop_r_proto(q, mp)))
				break;
			goto rsrv_continue;
		case M_PCPROTO:
			if ((err = sscop_r_pcproto(q, mp)))
				break;
			goto rsrv_continue;
		case M_CTL:
			if ((err = sscop_r_ctl(q, mp)))
				break;
			goto rsrv_continue;
		}
		switch (err) {
		case -EAGAIN:
			if (mp->b_datap->db_type < QPCTL) {
				putbq(q, mp);
				return (0);
			}
		case -EOPNOTSUPP:
			if (q->q_next) {
				putnext(q, mp);
				goto rsrv_continue;
			}
			break;
		}
		freemsg(mp);
	      rsrv_continue:
		/* 
		 *  NOTE:-  I have removed and processed a message from the
		 *  receive queue, so I should check for receive congestion
		 *  abatement.  If receive congestion has abated below the
		 *  accept threshold, I should signal MTP that there is no
		 *  longer any receive congestion.
		 */
		continue;
	}
	return (0);
}
Exemplo n.º 2
0
/*
 * telmodwsrv - module write service procedure
 */
static void
telmodwsrv(queue_t *q)
{
	mblk_t	*mp, *savemp;

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

	while ((mp = getq(q)) != NULL) {
		if (!canputnext(q)) {
			ASSERT(mp->b_datap->db_type < QPCTL);
			(void) putbq(q, mp);
			return;
		}
		switch (mp->b_datap->db_type) {

		case M_DATA:
			if (tmip->flags & TEL_STOPPED) {
				(void) putbq(q, mp);
				return;
			}
			/*
			 * Insert a null character if carraige return
			 * is not followed by line feed
			 */
			if (!snd_parse(q, mp)) {
				return;
			}
			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_PROTO:
			putnext(q, mp);
			break;

		default:
#ifdef DEBUG
			cmn_err(CE_NOTE,
			    "telmodwsrv: unexpected msg type 0x%x",
			    mp->b_datap->db_type);
#endif
			freemsg(mp);
		}

	}
}
Exemplo n.º 3
0
/*
 *  SSCOP WSRV = Queued message from above.
 *
 *  If the message is a priority message we attempt to process it immediately
 *  and without flow control.  If the message is a non-priority message and
 *  the next queue is flow controlled, we put the message back on the queue
 *  and wait.  If we cannot process a priority message immediately we cannot
 *  place it back on the queue, we discard it.  We requeue non-priority
 *  messages which cannot be processed immediately.  Unrecognized messages are
 *  passed down-queue.
 */
STATIC int
sscop_wsrv(queue_t *q)
{
	int err = -EOPNOTSUPP;
	mblk_t *mp;

	while ((mp = getq(q))) {
		if (q->q_next && mp->b_datap->db_type < QPCTL && !canputnext(q)) {
			putbq(q, mp);
			return (0);
		}
		switch (mp->b_datap->db_type) {
		case M_DATA:
			if ((err = sscop_w_data(q, mp)))
				break;
			goto wsrv_continue;
		case M_PROTO:
			if ((err = sscop_w_proto(q, mp)))
				break;
			goto wsrv_continue;
		case M_PCPROTO:
			if ((err = sscop_w_pcproto(q, mp)))
				break;
			goto wsrv_continue;
		case M_CTL:
			if ((err = sscop_w_ctl(q, mp)))
				break;
			goto wsrv_continue;
		}
		switch (err) {
		case -EAGAIN:
			if (mp->b_datap->db_type < QPCTL) {
				putbq(q, mp);
				return (0);
			}
		case -EOPNOTSUPP:
			if (q->q_next) {
				putnext(q, mp);
				goto wsrv_continue;
			}
		}
		freemsg(mp);
	      wsrv_continue:
		/* 
		 *  NOTE:-   I have removed a message from the queue, so I
		 *  should check for band congestion abatement for the data
		 *  band to see if transmit congestion has abated.  If it has,
		 *  I should notify MTP3 of transmit abatement.
		 */
		continue;
	}
	return (0);
}
Exemplo n.º 4
0
/*
 * dm2s_rsrv - Streams read side service procedure.
 *
 * All messages are received in the service procedure
 * only. This is done to simplify the streams synchronization.
 */
int
dm2s_rsrv(queue_t *rq)
{
	mblk_t *mp;
	dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;

	DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n"));
	ASSERT(dm2sp != NULL);
	mutex_enter(&dm2sp->ms_lock);

	/* Receive if there are any messages waiting in the mailbox. */
	dm2s_receive(dm2sp);
	mutex_exit(&dm2sp->ms_lock);

	/* Send the received messages up the stream. */
	while ((mp = getq(rq)) != NULL) {
		if (canputnext(rq)) {
			putnext(rq, mp);
		} else {
			putbq(rq, mp);
			break;
		}
	}
	DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n"));
	return (0);
}
Exemplo n.º 5
0
/*
 * Returns 1 if the caller should stop processing messages
 */
static int
mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
{
	mblk_t *bp;
	mblk_t *next;

	bp = mp;
	do {
		while (bp->b_rptr < bp->b_wptr) {
			/*
			 * Detect an attempt to reset the mouse.  Lock out any
			 * further mouse writes until the reset has completed.
			 */
			if (*bp->b_rptr == MSERESET) {

				/*
				 * If we couldn't allocate memory and we
				 * we couldn't register a bufcall,
				 * mouse8042_initiate_reset returns 0 and
				 * has already used the message to send an
				 * error reply back upstream, so there is no
				 * need to deallocate or put this message back
				 * on the queue.
				 */
				if (mouse8042_initiate_reset(q, bp, state) == 0)
					return (1);

				/*
				 * If there's no data remaining in this block,
				 * free this block and put the following blocks
				 * of this message back on the queue. If putting
				 * the rest of the message back on the queue
				 * fails, free the the message.
				 */
				if (MBLKL(bp) == 0) {
					next = bp->b_cont;
					freeb(bp);
					bp = next;
				}
				if (bp != NULL) {
					if (!putbq(q, bp))
						freemsg(bp);
				}

				return (1);

			}
			ddi_put8(state->ms_handle,
			    state->ms_addr + I8042_INT_OUTPUT_DATA,
			    *bp->b_rptr++);
		}
		next = bp->b_cont;
		freeb(bp);
	} while ((bp = next) != NULL);

	return (0);
}
Exemplo n.º 6
0
/*
 * ptem write queue service procedure.
 */
static void
ptemwsrv(queue_t *q)
{
	mblk_t *mp;

	while ((mp = getq(q)) != NULL) {
		if (!bcanputnext(q, mp->b_band) || !ptemwmsg(q, mp)) {
			(void) putbq(q, mp);
			break;
		}
	}
}
Exemplo n.º 7
0
static void
m3ua_rsrv(queue_t *q)
{
	mblk_t *mp;
	int err = EOPNOTSUPP;

	trace();
	while ((mp = getq(q))) {
		if (mp->b_datap->db_type < QPCTL && !canputnext(q)) {
			putbq(q, mp);
			return;
		}
		switch (mp->b_datap->db_type) {
		case M_DATA:
			if ((err = m3ua_m_data(q, mp)))
				break;
			continue;
		case M_CTL:
		case M_PROTO:
		case M_PCPROTO:
			if ((err = m3ua_m_proto(q, mp)))
				break;
			continue;
		}
		switch (err) {
		case EAGAIN:
			if (mp->b_datap->db_type < QPCTL) {
				putbq(q, mp);
				return;
			}
			break;
		case EOPNOTSUPP:
			if (q->q_next) {
				putnext(q, mp);
				return;
			}
		}
		freemsg(mp);
	}
}
Exemplo n.º 8
0
/*
 * Through message handle for read side stream
 *
 * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
 *  -. uinst_t->lock   : M [RW_READER]
 *  -. uinst_t->u_lock : A
 *  -. uinst_t->l_lock : P
 *  -. uinst_t->c_lock : P
 */
int
oplmsu_rcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag)
{
	lpath_t	*lpath;
	ctrl_t	*ctrl;
	queue_t	*dst_queue = NULL;
	int	act_flag;

	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));

	mutex_enter(&oplmsu_uinst->l_lock);
	lpath = (lpath_t *)q->q_ptr;
	if (lpath->uinst != NULL) {
		act_flag = ACTIVE_RES;
	} else {
		act_flag = NOT_ACTIVE_RES;
	}
	mutex_exit(&oplmsu_uinst->l_lock);

	mutex_enter(&oplmsu_uinst->c_lock);
	if (((ctrl = oplmsu_uinst->user_ctrl) != NULL) &&
	    (((mp->b_datap->db_type == M_IOCACK) ||
	    (mp->b_datap->db_type == M_IOCNAK)) || (act_flag == ACTIVE_RES))) {
		dst_queue = RD(ctrl->queue);
	} else {
		mutex_exit(&oplmsu_uinst->c_lock);
		freemsg(mp);
		return (SUCCESS);
	}

	if (pri_flag == MSU_HIGH) {
		putq(dst_queue, mp);
	} else {
		if (canput(dst_queue)) {
			putq(dst_queue, mp);
		} else {
			/*
			 * Place a normal priority message at the head of
			 * read queue
			 */

			ctrl = (ctrl_t *)dst_queue->q_ptr;
			ctrl->lrq_flag = 1;
			ctrl->lrq_queue = q;
			mutex_exit(&oplmsu_uinst->c_lock);
			putbq(q, mp);
			return (FAILURE);
		}
	}
	mutex_exit(&oplmsu_uinst->c_lock);
	return (SUCCESS);
}
Exemplo n.º 9
0
static streamscall int
zap_rsrv(queue_t *q)
{
	mblk_t *mp;

	while ((mp = getq(q))) {
		if (zap_r_msg(q, mp)) {
			putbq(q, mp);
			break;
		}
	}
	return (0);
}
Exemplo n.º 10
0
static streamscall int
ptem_wsrv(queue_t *q)
{
	mblk_t *mp;

	/* Simply drain and process them all. */
	while ((mp = getq(q))) {
		if (ptem_w_msg(q, mp)) {
			putbq(q, mp);
			break;
		}
	}
	return (0);
}
Exemplo n.º 11
0
static void
t_wsrv(queue_t *q)
{
	mblk_t *mp;

	trace();
	while ((mp = getq(q))) {
		if (mp->b_datap->db_type < QPCTL && !canputnext(q)) {
			putbq(q, mp);
			return;
		}
		putnext(q, mp);
	}
}
Exemplo n.º 12
0
/*
 * putbq() function for normal priority message of write stream
 *
 * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
 *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
 *  -. uinst_t->u_lock : A
 *  -. uinst_t->l_lock : P
 *  -. uinst_t->c_lock : P
 */
void
oplmsu_wcmn_norm_putbq(queue_t *uwq, mblk_t *mp, queue_t *dq)
{
	lpath_t	*lpath;

	ASSERT(mp != NULL);
	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));

	mutex_enter(&oplmsu_uinst->l_lock);
	lpath = (lpath_t *)dq->q_ptr;
	lpath->uwq_flag = 1;
	lpath->uwq_queue = uwq;
	mutex_exit(&oplmsu_uinst->l_lock);
	putbq(uwq, mp);
}
Exemplo n.º 13
0
STATIC streamscall int
srvmod_srv(queue_t *q)
{
	mblk_t *mp;

	while ((mp = getq(q))) {
		if (likely(mp->b_datap->db_type >= QPCTL || bcanputnext(q, mp->b_band))) {
			putnext(q, mp);
			continue;
		}
		putbq(q, mp);
		break;
	}
	return (0);
}
Exemplo n.º 14
0
static inline int
m3ua_reservice(queue_t *q, mblk_t *mp, int err)
{
	if (mp->b_datap->db_type < QPCTL)
		switch (err) {
		case -EBUSY:
		case -EAGAIN:
		case -ENOMEM:
		case -ENOBUFS:
			putbq(q, mp);
			return (0);
		}
	freemsg(mp);
	return (err);
}
Exemplo n.º 15
0
/************************************************************************
 *
 * Function Name: ip2xinet_lwsrv
 * Title: IP2XINET Lower Write Service routine
 *
 * Description:
 *      Send all of the messages on this queue down to the next driver.
 *      If we discover that we can't do a put, then stop the Linux
 *      devices from sending us stuff.
 *
 ************************************************************************/
STATIC streamscall int
ip2xinet_lwsrv(queue_t *q)
{
	mblk_t *mp;
	int allsent = 1;
	int i;
	struct ip2xinet_dev *dev = ip2xinet_devs;
	struct ip2xinet_priv *privp;

	while ((mp = getq(q))) {
		/* M_PROTO's should be last on the list.  If it is something else, then it should
		   be ahead, and we can just go ahead and put it down. */
		if (mp->b_datap->db_type == M_PROTO) {
			if (canputnext(q)) {
				putnext(q, mp);
			} else {
				noenable(q);
				if (!putbq(q, mp))
					freemsg(mp);	/* FIXME */
				enableok(q);
				allsent = 0;
				break;
			}
		} else {
			putnext(q, mp);
		}
	}

	/* Handle the flow control.  If we were able to send everything then it is ok for the
	   kernel to send us more stuff.  Otherwise it is not ok.  Go through all of the devices
	   and set the appropriate state. */
	spin_lock(&ip2xinet_lock);
	for (i = 0; i < NUMIP2XINET; i++, dev++) {
		privp = &dev->priv;
		if (privp->state == 1 && ip2xinet_status.ip2x_dlstate == DL_IDLE) {
			if (allsent) {
				netif_start_queue(&dev->dev);	/* kernel can transmit */
			} else {
				netif_stop_queue(&dev->dev);	/* We are flow controlled. */
			}
		}
	}
	spin_unlock(&ip2xinet_lock);

	return (0);
}
Exemplo n.º 16
0
static streamscall int
ll_rsrv(queue_t *q)
{
	caddr_t priv;

	if ((priv = mi_trylock(q)) != NULL) {
		mblk_t *mp;

		while ((mp = getq(q))) {
			if (ll_r_msg_srv(q, mp)) {
				putbq(q, mp);
				break;
			}
		}
		mi_unlock(priv);
	}
	return (0);
}
Exemplo n.º 17
0
static streamscall int
pckt_rsrv(queue_t *q)
{
	mblk_t *mp;

	while ((mp = getq(q))) {
		if (mp->b_datap->db_type < QPCTL) {
			if (!bcanputnext(q, mp->b_band))
				goto put_back;
		}
		if (pckt_r_msg(q, mp))
			continue;
	      put_back:
		if (!putbq(q, mp))
			freemsg(mp);
		break;
	}
	return (0);
}
Exemplo n.º 18
0
/*
 * This routine is symmetric for master and slave, so it handles both without
 * splitting up the codepath.
 *
 * If there are messages on this queue that can be sent to the other, send
 * them via putnext(). Else, if queued messages cannot be sent, leave them
 * on this queue.
 */
static void
zc_wsrv(queue_t *qp)
{
	mblk_t *mp;

	DBG1("zc_wsrv master (%s) side", zc_side(qp));

	/*
	 * Partner has no read queue, so take the data, and throw it away.
	 */
	if (zc_switch(RD(qp)) == NULL) {
		DBG("zc_wsrv: other side isn't listening");
		while ((mp = getq(qp)) != NULL) {
			if (mp->b_datap->db_type == M_IOCTL)
				miocnak(qp, mp, 0, 0);
			else
				freemsg(mp);
		}
		flushq(qp, FLUSHALL);
		return;
	}

	/*
	 * while there are messages on this write queue...
	 */
	while ((mp = getq(qp)) != NULL) {
		/*
		 * Due to the way zc_wput is implemented, we should never
		 * see a control message here.
		 */
		ASSERT(mp->b_datap->db_type < QPCTL);

		if (bcanputnext(RD(zc_switch(qp)), mp->b_band)) {
			DBG("wsrv: send message to other side\n");
			putnext(RD(zc_switch(qp)), mp);
		} else {
			DBG("wsrv: putting msg back on queue\n");
			(void) putbq(qp, mp);
			break;
		}
	}
}
Exemplo n.º 19
0
/**
 * ch_srvp: - service procedure.
 * @q: queue to service
 *
 * Simple draining service procedure.
 */
static streamscall __hot_get int
ch_srvp(queue_t *q, mblk_t *mp)
{
	mblk_t *mp;

	if (likely((mp = getq(q)))) {
		do {
			if (ch_msg(q, mp)) {
				if (putbq(q, mp)) {
					swerr();
					freemsg(mp);
				}
				break;
			}
		} while (unlikely((mp = getq(q))));
	}
	if (_WR(q)->q_first)
		qenable(_WR(q));
	return (0);
}
Exemplo n.º 20
0
/*
 * move unrecognized stuff upward
 */
static int
parsersvc(
	queue_t *q
	)
{
	mblk_t *mp;

	while ((mp = getq(q)))
	{
		if (canput(q->q_next) || (mp->b_datap->db_type > QPCTL))
		{
			putnext(q, mp);
			parseprintf(DD_RSVC,("parse: RSVC - putnext\n"));
		}
		else
		{
			putbq(q, mp);
			parseprintf(DD_RSVC,("parse: RSVC - flow control wait\n"));
			break;
		}
	}
	return 0;
}
Exemplo n.º 21
0
static void
recover(queue_t *q, mblk_t *mp, size_t size)
{
	bufcall_id_t bid;
	timeout_id_t tid;
	struct	telmod_info	*tmip = (struct telmod_info *)q->q_ptr;

	ASSERT(mp->b_datap->db_type < QPCTL);
	noenable(q);
	(void) putbq(q, mp);

	/*
	 * Make sure there is at most one outstanding request per queue.
	 */
	if (q->q_flag & QREADR) {
		if (tmip->rtimoutid || tmip->rbufcid) {
			return;
		}
	} else {
		if (tmip->wtimoutid || tmip->wbufcid) {
			return;
		}
	}
	if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) {
		tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT);
		if (q->q_flag & QREADR)
			tmip->rtimoutid = tid;
		else
			tmip->wtimoutid = tid;
	} else	{
		if (q->q_flag & QREADR)
			tmip->rbufcid = bid;
		else
			tmip->wbufcid = bid;
	}
}
Exemplo n.º 22
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;
	}
}
Exemplo n.º 23
0
/*
 * bufcall request
 *
 * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
 *  -. uinst_t->lock   : M [RW_READER]
 *  -. uinst_t->u_lock : A
 *  -. uinst_t->l_lock : P
 *  -. uinst_t->c_lock : P
 */
void
oplmsu_cmn_bufcall(queue_t *q, mblk_t *mp, size_t size, int rw_flag)
{

	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));

	if (rw_flag == MSU_WRITE_SIDE) {
		ctrl_t	*ctrl;

		putbq(q, mp);

		mutex_enter(&oplmsu_uinst->c_lock);
		ctrl = (ctrl_t *)q->q_ptr;
		if (ctrl->wbuf_id != 0) {
			mutex_exit(&oplmsu_uinst->c_lock);
			return;
		}

		ctrl->wbuftbl->q = q;
		ctrl->wbuftbl->rw_flag = rw_flag;
		ctrl->wbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
		    (void *)ctrl->wbuftbl);

		if (ctrl->wbuf_id == 0) {
			if (ctrl->wtout_id != 0) {
				mutex_exit(&oplmsu_uinst->c_lock);
				return;
			}

			ctrl->wtout_id = timeout(oplmsu_cmn_bufcb,
			    (void *)ctrl->wbuftbl, drv_usectohz(MSU_TM_500MS));
		}
		mutex_exit(&oplmsu_uinst->c_lock);
	} else if (rw_flag == MSU_READ_SIDE) {
		lpath_t	*lpath;
		mblk_t	*wrk_msg;

		mutex_enter(&oplmsu_uinst->l_lock);
		lpath = (lpath_t *)q->q_ptr;
		if (mp->b_datap->db_type >= QPCTL) {
			if (lpath->first_lpri_hi == NULL) {
				lpath->last_lpri_hi = mp;
				mp->b_next = NULL;
			} else {
				wrk_msg = lpath->first_lpri_hi;
				wrk_msg->b_prev = mp;
				mp->b_next = wrk_msg;
			}
			mp->b_prev = NULL;
			lpath->first_lpri_hi = mp;
		} else {
			putbq(q, mp);
		}

		if (lpath->rbuf_id != 0) {
			mutex_exit(&oplmsu_uinst->l_lock);
			return;
		}

		lpath->rbuftbl->q = q;
		lpath->rbuftbl->rw_flag = rw_flag;
		lpath->rbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
		    (void *)lpath->rbuftbl);

		if (lpath->rbuf_id == 0) {
			if (lpath->rtout_id != 0) {
				mutex_exit(&oplmsu_uinst->l_lock);
				return;
			}

			lpath->rtout_id = timeout(oplmsu_cmn_bufcb,
			    (void *)lpath->rbuftbl, drv_usectohz(MSU_TM_500MS));
		}
		mutex_exit(&oplmsu_uinst->l_lock);
	}
}
Exemplo n.º 24
0
/*
 * cvc_wsrv()
 *	cvc_wsrv handles mblks that have been queued by cvc_wput either because
 *	the IOSRAM path was selected or the queue contained preceding mblks.  To
 *	optimize processing (particularly if the IOSRAM path is selected), all
 *	mblks are pulled off of the queue and chained together.  Then, if there
 *	are any mblks on the chain, they are either forwarded to cvcredir or
 *	sent for IOSRAM processing as appropriate given current circumstances.
 *	IOSRAM processing may not be able to handle all of the data in the
 *	chain, in which case the remaining data is placed back on the queue and
 *	a timeout routine is registered to reschedule cvc_wsrv in the future.
 *	Automatic scheduling of the queue is disabled (noenable(q)) while
 *	cvc_wsrv is running to avoid superfluous calls.
 */
static int
cvc_wsrv(queue_t *q)
{
	mblk_t *total_mp = NULL;
	mblk_t *mp;

	if (cvc_stopped == 1 || cvc_suspended == 1) {
		return (0);
	}

	rw_enter(&cvclock, RW_READER);
	noenable(q);

	/*
	 * If there's already a timeout registered for scheduling this routine
	 * in the future, it's a safe bet that we don't want to run right now.
	 */
	if (cvc_timeout_id != (timeout_id_t)-1) {
		enableok(q);
		rw_exit(&cvclock);
		return (0);
	}

	/*
	 * Start by linking all of the queued M_DATA mblks into a single chain
	 * so we can flush as much as possible to IOSRAM (if we choose that
	 * route).
	 */
	while ((mp = getq(q)) != NULL) {
		/*
		 * Technically, certain IOCTLs are supposed to be processed only
		 * after all preceding data has completely "drained".  In an
		 * attempt to support that, we delay processing of those IOCTLs
		 * until this point.  It is still possible that an IOCTL will be
		 * processed before all preceding data is drained, for instance
		 * in the case where not all of the preceding data would fit
		 * into IOSRAM and we have to place it back on the queue.
		 * However, since none of these IOCTLs really appear to have any
		 * relevance for cvc, and we weren't supporting delayed
		 * processing at _all_ previously, this partial implementation
		 * should suffice.  (Fully implementing the delayed IOCTL
		 * processing would be unjustifiably difficult given the nature
		 * of the underlying IOSRAM console protocol.)
		 */
		if (mp->b_datap->db_type == M_IOCTL) {
			cvc_ioctl(q, mp);
			continue;
		}

		/*
		 * We know that only M_IOCTL and M_DATA blocks are placed on our
		 * queue.  Since this block isn't an M_IOCTL, it must be M_DATA.
		 */
		if (total_mp != NULL) {
			linkb(total_mp, mp);
		} else {
			total_mp = mp;
		}
	}

	/*
	 * Do we actually have anything to do?
	 */
	if (total_mp == NULL) {
		enableok(q);
		rw_exit(&cvclock);
		return (0);
	}

	/*
	 * Yes, we do, so send the data to either cvcredir or IOSRAM as
	 * appropriate.  In the latter case, we might not be able to transmit
	 * everything right now, so re-queue the remainder.
	 */
	if (cvcoutput_q != NULL && !via_iosram) {
		CVC_DBG0(CVC_DBG_NETWORK_WR, "Sending to cvcredir.");
		/*
		 * XXX - should canputnext be called here?  Starfire's cvc
		 * doesn't do that, and it appears to work anyway.
		 */
		(void) putnext(cvcoutput_q, total_mp);
	} else {
		CVC_DBG0(CVC_DBG_IOSRAM_WR, "Send to IOSRAM.");
		cvc_send_to_iosram(&total_mp);
		if (total_mp != NULL) {
			(void) putbq(q, total_mp);
		}
	}

	/*
	 * If there is still data queued at this point, make sure the queue
	 * gets scheduled again after an appropriate delay (which has been
	 * somewhat arbitrarily selected as half of the SC's input polling
	 * frequency).
	 */
	enableok(q);
	if (q->q_first != NULL) {
		if (cvc_timeout_id == (timeout_id_t)-1) {
			cvc_timeout_id = timeout(cvc_flush_queue,
			    NULL, drv_usectohz(CVC_IOSRAM_POLL_USECS / 2));
		}
	}
	rw_exit(&cvclock);
	return (0);
}
Exemplo n.º 25
0
/*
 * telmodrsrv:
 * Mostly we end up here because of M_DATA processing delayed due to flow
 * control or lack of memory.  XXX.sparker: TLI primitives here?
 */
static void
telmodrsrv(queue_t *q)
{
	mblk_t	*mp, *newmp;
	struct telmod_info    *tmip = (struct telmod_info *)q->q_ptr;
	union T_primitives *tip;

	while ((mp = getq(q)) != NULL) {
		if (((tmip->flags & TEL_STOPPED) &&
		    !(tmip->flags & TEL_GETBLK)) || !canputnext(q)) {
			(void) putbq(q, mp);
			return;
		}
		switch (mp->b_datap->db_type) {

		case M_DATA:
is_mdata:
			if (tmip->flags & TEL_GETBLK) {
				if ((newmp = allocb(sizeof (char),
				    BPRI_MED)) == NULL) {
					recover(q, mp, msgdsize(mp));
					return;
				}
				newmp->b_datap->db_type = M_CTL;
				newmp->b_wptr = newmp->b_rptr + 1;
				*(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
				newmp->b_cont = mp;
				tmip->flags &= ~TEL_GETBLK;
				noenable(q);
				tmip->flags |= TEL_STOPPED;

				putnext(q, newmp);

				break;
			}
			if (!rcv_parse(q, mp)) {
				return;
			}
			break;

		case M_PROTO:

			tip = (union T_primitives *)mp->b_rptr;

			/*
			 * Unless the M_PROTO message indicates data, clear
			 * TEL_GETBLK so that we stop passing our messages
			 * up to the telnet daemon.
			 */
			if (tip->type != T_DATA_IND &&
			    tip->type != T_EXDATA_IND)
				tmip->flags &= ~TEL_GETBLK;

			switch (tip->type) {
			case T_ORDREL_IND:
			case T_DISCON_IND:
			/* Make into M_HANGUP and putnext */
				ASSERT(mp->b_cont == NULL);
				mp->b_datap->db_type = M_HANGUP;
				mp->b_wptr = mp->b_rptr;
				if (mp->b_cont) {
					freemsg(mp->b_cont);
					mp->b_cont = NULL;
				}
				/*
				 * If we haven't already, send T_UNBIND_REQ
				 * to prevent TCP from going into "BOUND"
				 * state and locking up the port.
				 */
				if (tip->type == T_DISCON_IND &&
				    tmip->unbind_mp != NULL) {
					putnext(q, mp);
					qreply(q, tmip->unbind_mp);
					tmip->unbind_mp = NULL;
				} else {
					putnext(q, mp);
				}
				break;

			case T_DATA_IND: /* conform to TPI, but never happens */
			case T_EXDATA_IND:
				newmp = mp->b_cont;
				freeb(mp);
				mp = newmp;
				if (mp) {
					ASSERT(mp->b_datap->db_type == M_DATA);
					if (msgdsize(mp) != 0) {
						goto is_mdata;
					}
					freemsg(mp);
				}
				break;

			/*
			 * We only get T_OK_ACK when we issue the unbind, and
			 * it can be ignored safely.
			 */
			case T_OK_ACK:
				ASSERT(tmip->unbind_mp == NULL);
				freemsg(mp);
				break;

			default:
#ifdef DEBUG
				cmn_err(CE_NOTE,
				    "telmodrsrv: unexpected TLI primitive "
				    "msg type 0x%x", tip->type);
#endif
				freemsg(mp);
			}
			break;

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

		default:
#ifdef DEBUG
			cmn_err(CE_NOTE,
			    "telmodrsrv: unexpected msg type 0x%x",
			    mp->b_datap->db_type);
#endif
			freemsg(mp);
		}
	}
}
Exemplo n.º 26
0
/*
 * dm2s_transmit - Transmit a message.
 */
int
dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key)
{
	dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
	int ret;
	uint32_t len;
	uint32_t numsg;

	DPRINTF(DBG_DRV, ("dm2s_transmit: called\n"));
	ASSERT(dm2sp != NULL);
	ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
	/*
	 * Free the message if the mailbox is not in the connected state.
	 */
	if (!DM2S_MBOX_READY(dm2sp)) {
		DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n"));
		freemsg(mp);
		return (EIO);
	}

	len = msgdsize(mp);
	if (len > dm2sp->ms_mtu) {
		/*
		 * Size is too big to send, free the message.
		 */
		DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n"));
		DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len);
		freemsg(mp);
		return (0);
	}

	if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx,
	    DM2S_MAX_SG)) != 0) {
		DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n"));
		putbq(wq, mp);
		return (EAGAIN);
	}
	DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n",
	    numsg, len));
	ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0);
	if (ret == EBUSY || ret == ENOSPC) {
		DPRINTF(DBG_MBOX,
		    ("dm2s_transmit: mailbox busy ret=%d\n", ret));
		if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) {
			/*
			 * If maximum retries are reached, then free the
			 * message.
			 */
			DPRINTF(DBG_MBOX,
			    ("dm2s_transmit: freeing msg after max retries\n"));
			DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret);
			freemsg(mp);
			dm2sp->ms_retries = 0;
			return (0);
		}
		DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret);
		/*
		 * Queue it back, so that we can retry again.
		 */
		putbq(wq, mp);
		return (ret);
	}
	DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx);
	dm2sp->ms_retries = 0;
	freemsg(mp);
	DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret));
	return (ret);
}