Example #1
0
static int
log_rsrv(queue_t *q)
{
	mblk_t *mp;
	char *msg, *msgid_start, *msgid_end;
	size_t idlen;

	while (canputnext(q) && (mp = getq(q)) != NULL) {
		if (log_msgid == 0) {
			/*
			 * Strip out the message ID.  If it's a kernel
			 * SL_CONSOLE message, replace msgid with "unix: ".
			 */
			msg = (char *)mp->b_cont->b_rptr;
			if ((msgid_start = strstr(msg, "[ID ")) != NULL &&
			    (msgid_end = strstr(msgid_start, "] ")) != NULL) {
				log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
				if ((lc->flags & SL_CONSOLE) &&
				    (lc->pri & LOG_FACMASK) == LOG_KERN)
					msgid_start = msg + snprintf(msg,
					    7, "unix: ");
				idlen = msgid_end + 2 - msgid_start;
				ovbcopy(msg, msg + idlen, msgid_start - msg);
				mp->b_cont->b_rptr += idlen;
			}
		}
		mp->b_band = 0;
		putnext(q, mp);
	}
	return (0);
}
Example #2
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);
}
Example #3
0
static void
t_wput(queue_t *q, mblk_t *mp)
{
	trace();
	if (mp->b_datap->db_type < QPCTL && (q->q_count || !canputnext(q)))
		putq(q, mp);
	else
		putnext(q, mp);
}
Example #4
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);
}
Example #5
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);
		}

	}
}
Example #6
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);
}
Example #7
0
int
m3ua_l_rput(queue_t *q, mblk_t *mp)
{
	int err;

	if (mp->b_datap->db_type < QPCTL && (q->q_count || !canputnext(q))) {
		putq(q, mp);
		return (0);
	}
	if ((err = m3ua_rd(q, mp)))
		return (m3ua_recover(q, mp, err));
	return (0);
}
Example #8
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);
	}
}
/*
 * sppp_dlprsendup()
 *
 * Description:
 *    For any valid promiscuous streams (marked with SPS_PROMISC and its
 *    sps_dlstate is DL_IDLE), send data upstream. The caller is expected
 *    to hold ppa_sib_lock when calling this procedure.
 */
void
sppp_dlprsendup(spppstr_t *sps, mblk_t *mp, t_scalar_t proto, boolean_t header)
{
	sppa_t	*ppa;
	mblk_t	*dmp;

	ASSERT(sps != NULL);
	ASSERT(mp != NULL && mp->b_rptr != NULL);
	ppa = sps->sps_ppa;
	ASSERT(ppa != NULL);

	/* NOTE: caller must hold ppa_sib_lock in RW_READER mode */
	ASSERT(RW_READ_HELD(&ppa->ppa_sib_lock));

	for (; sps != NULL; sps = sps->sps_nextsib) {
		/*
		 * We specifically test to ensure that the DLPI state for the
		 * promiscous stream is IDLE (DL_IDLE), since such state tells
		 * us that the promiscous stream has been bound to PPP_ALLSAP.
		 */
		if (IS_SPS_PROMISC(sps) && (sps->sps_dlstate == DL_IDLE) &&
		    canputnext(sps->sps_rq)) {
			if ((dmp = dupmsg(mp)) == NULL) {
				mutex_enter(&ppa->ppa_sta_lock);
				ppa->ppa_allocbfail++;
				mutex_exit(&ppa->ppa_sta_lock);
				continue;
			}
			if (header) {
				dmp->b_rptr += PPP_HDRLEN;
			}
			if (IS_SPS_RAWDATA(sps)) {
				/* function frees original message if fails */
				dmp = sppp_dladdether(sps, dmp, proto);
			} else {
				/* function frees original message if fails */
				dmp = sppp_dladdud(sps, dmp, proto, B_TRUE);
			}
			if (dmp != NULL) {
				putnext(sps->sps_rq, dmp);
			} else {
				mutex_enter(&ppa->ppa_sta_lock);
				ppa->ppa_allocbfail++;
				mutex_exit(&ppa->ppa_sta_lock);
			}
		}
	}
}
Example #10
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);
}
Example #11
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);
	}
}
Example #12
0
/*
 * move unrecognized stuff upward
 */
static int
parsersvc(
	  queue_t *q
	  )
{
	mblk_t *mp;
  
	while ((mp = getq(q)))
	{
		if (canputnext(q) || (mp->b_datap->db_type > QPCTL))
		{
			putnext(q, mp);
			pprintf(DD_RSVC, "parse: RSVC - putnext\n");
		}
		else
		{
			putbq(q, mp);
			pprintf(DD_RSVC, "parse: RSVC - flow control wait\n");
			break;
		}
	}
	return 0;
}
Example #13
0
/*
 * Add a new message to the socket
 */
int
rds_deliver_new_msg(mblk_t *mp, ipaddr_t local_addr, ipaddr_t rem_addr,
    in_port_t local_port, in_port_t rem_port, zoneid_t zoneid)
{
	rds_t *rds;
	struct  T_unitdata_ind  *tudi;
	int	udi_size;	/* Size of T_unitdata_ind */
	mblk_t *mp1;
	sin_t	*sin;
	int error = 0;

	local_port = htons(local_port);
	rem_port = htons(rem_port);

	ASSERT(mp->b_datap->db_type == M_DATA);
	rds = rds_fanout(local_addr, rem_addr, local_port, rem_port, zoneid);
	if (rds == NULL) {
		dprint(2, ("%s: rds_fanout failed: (0x%x 0x%x %d %d)", LABEL,
		    local_addr, rem_addr, ntohs(local_port), ntohs(rem_port)));
		freemsg(mp);
		return (error);
	}

	udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin_t);

	/* Allocate a message block for the T_UNITDATA_IND structure. */
	mp1 = allocb(udi_size, BPRI_MED);
	if (mp1 == NULL) {
		dprint(2, ("%s: allocb failed", LABEL));
		freemsg(mp);
		return (ENOMEM);
	}

	mp1->b_cont = mp;
	mp = mp1;
	mp->b_datap->db_type = M_PROTO;
	tudi = (struct T_unitdata_ind *)(uintptr_t)mp->b_rptr;
	mp->b_wptr = (uchar_t *)tudi + udi_size;
	tudi->PRIM_type = T_UNITDATA_IND;
	tudi->SRC_length = sizeof (sin_t);
	tudi->SRC_offset = sizeof (struct T_unitdata_ind);
	tudi->OPT_offset = sizeof (struct T_unitdata_ind) + sizeof (sin_t);
	udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin_t));
	tudi->OPT_length = udi_size;
	sin = (sin_t *)&tudi[1];
	sin->sin_addr.s_addr = rem_addr;
	sin->sin_port = ntohs(rem_port);
	sin->sin_family = rds->rds_family;
	*(uint32_t *)(uintptr_t)&sin->sin_zero[0] = 0;
	*(uint32_t *)(uintptr_t)&sin->sin_zero[4] = 0;

	putnext(rds->rds_ulpd, mp);

	/* check port quota */
	if (RDS_GET_RXPKTS_PEND() > rds_rx_pkts_pending_hwm) {
		ulong_t current_port_quota = RDS_GET_PORT_QUOTA();
		if (rds->rds_port_quota > current_port_quota) {
			/* this may result in stalling the port */
			rds->rds_port_quota = current_port_quota;
			(void) proto_set_rx_hiwat(rds->rds_ulpd, NULL,
			    rds->rds_port_quota * UserBufferSize);
			RDS_INCR_PORT_QUOTA_ADJUSTED();
		}
	}

	/*
	 * canputnext() check is done after putnext as the protocol does
	 * not allow dropping any received packet.
	 */
	if (!canputnext(rds->rds_ulpd)) {
		error = ENOSPC;
	}

	RDS_DEC_REF_CNT(rds);
	return (error);
}
Example #14
0
/*
 * Fusion output routine, called by tcp_output() and tcp_wput_proto().
 */
boolean_t
tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size)
{
	tcp_t *peer_tcp = tcp->tcp_loopback_peer;
	uint_t max_unread;
	boolean_t flow_stopped;
	boolean_t urgent = (DB_TYPE(mp) != M_DATA);

	ASSERT(tcp->tcp_fused);
	ASSERT(peer_tcp != NULL && peer_tcp->tcp_loopback_peer == tcp);
	ASSERT(tcp->tcp_connp->conn_sqp == peer_tcp->tcp_connp->conn_sqp);
	ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_PROTO ||
	    DB_TYPE(mp) == M_PCPROTO);

	max_unread = peer_tcp->tcp_fuse_rcv_unread_hiwater;

	/* If this connection requires IP, unfuse and use regular path */
	if (TCP_LOOPBACK_IP(tcp) || TCP_LOOPBACK_IP(peer_tcp) ||
	    IPP_ENABLED(IPP_LOCAL_OUT|IPP_LOCAL_IN)) {
		TCP_STAT(tcp_fusion_aborted);
		tcp_unfuse(tcp);
		return (B_FALSE);
	}

	if (send_size == 0) {
		freemsg(mp);
		return (B_TRUE);
	}

	/*
	 * Handle urgent data; we either send up SIGURG to the peer now
	 * or do it later when we drain, in case the peer is detached
	 * or if we're short of memory for M_PCSIG mblk.
	 */
	if (urgent) {
		/*
		 * We stop synchronous streams when we have urgent data
		 * queued to prevent tcp_fuse_rrw() from pulling it.  If
		 * for some reasons the urgent data can't be delivered
		 * below, synchronous streams will remain stopped until
		 * someone drains the tcp_rcv_list.
		 */
		TCP_FUSE_SYNCSTR_PLUG_DRAIN(peer_tcp);
		tcp_fuse_output_urg(tcp, mp);
	}

	mutex_enter(&peer_tcp->tcp_fuse_lock);
	/*
	 * Wake up and signal the peer; it is okay to do this before
	 * enqueueing because we are holding the lock.  One of the
	 * advantages of synchronous streams is the ability for us to
	 * find out when the application performs a read on the socket,
	 * by way of tcp_fuse_rrw() entry point being called.  Every
	 * data that gets enqueued onto the receiver is treated as if
	 * it has arrived at the receiving endpoint, thus generating
	 * SIGPOLL/SIGIO for asynchronous socket just as in the strrput()
	 * case.  However, we only wake up the application when necessary,
	 * i.e. during the first enqueue.  When tcp_fuse_rrw() is called
	 * it will send everything upstream.
	 */
	if (peer_tcp->tcp_direct_sockfs && !urgent &&
	    !TCP_IS_DETACHED(peer_tcp)) {
		if (peer_tcp->tcp_rcv_list == NULL)
			STR_WAKEUP_SET(STREAM(peer_tcp->tcp_rq));
		/* Update poll events and send SIGPOLL/SIGIO if necessary */
		STR_SENDSIG(STREAM(peer_tcp->tcp_rq));
	}

	/*
	 * Enqueue data into the peer's receive list; we may or may not
	 * drain the contents depending on the conditions below.
	 */
	tcp_rcv_enqueue(peer_tcp, mp, send_size);

	/* In case it wrapped around and also to keep it constant */
	peer_tcp->tcp_rwnd += send_size;

	/*
	 * Exercise flow-control when needed; we will get back-enabled
	 * in either tcp_accept_finish(), tcp_unfuse(), or tcp_fuse_rrw().
	 * If tcp_direct_sockfs is on or if the peer endpoint is detached,
	 * we emulate streams flow control by checking the peer's queue
	 * size and high water mark; otherwise we simply use canputnext()
	 * to decide if we need to stop our flow.
	 *
	 * The outstanding unread data block check does not apply for a
	 * detached receiver; this is to avoid unnecessary blocking of the
	 * sender while the accept is currently in progress and is quite
	 * similar to the regular tcp.
	 */
	if (TCP_IS_DETACHED(peer_tcp) || max_unread == 0)
		max_unread = UINT_MAX;

	flow_stopped = tcp->tcp_flow_stopped;
	if (!flow_stopped &&
	    (((peer_tcp->tcp_direct_sockfs || TCP_IS_DETACHED(peer_tcp)) &&
	    (peer_tcp->tcp_rcv_cnt >= peer_tcp->tcp_fuse_rcv_hiwater ||
	    ++peer_tcp->tcp_fuse_rcv_unread_cnt >= max_unread)) ||
	    (!peer_tcp->tcp_direct_sockfs &&
	    !TCP_IS_DETACHED(peer_tcp) && !canputnext(peer_tcp->tcp_rq)))) {
		tcp_setqfull(tcp);
		flow_stopped = B_TRUE;
		TCP_STAT(tcp_fusion_flowctl);
		DTRACE_PROBE4(tcp__fuse__output__flowctl, tcp_t *, tcp,
		    uint_t, send_size, uint_t, peer_tcp->tcp_rcv_cnt,
		    uint_t, peer_tcp->tcp_fuse_rcv_unread_cnt);
	} else if (flow_stopped &&
Example #15
0
/*
 * telmodrput:
 * Be sure to preserve data order.  If the daemon is waiting for additional
 * data (TEL_GETBLK state) forward new data.  Otherwise, apply normal
 * telnet protocol processing to M_DATA.  Take notice of TLI messages
 * indicating connection tear-down, and change them into M_HANGUP's.
 */
static void
telmodrput(queue_t *q, mblk_t *mp)
{
	mblk_t	*newmp;
	struct telmod_info    *tmip = (struct telmod_info *)q->q_ptr;
	union T_primitives *tip;

	if ((mp->b_datap->db_type < QPCTL) &&
	    ((q->q_first) || ((tmip->flags & TEL_STOPPED) &&
	    !(tmip->flags & TEL_GETBLK)) || !canputnext(q))) {
		(void) putq(q, mp);
		return;
	}

	switch (mp->b_datap->db_type) {
	case M_DATA:

		/*
		 * If the user level daemon requests for 1 more
		 * block of data (needs more data for protocol processing)
		 * create a M_CTL message block with the mp.
		 */
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;
		}
		/*
		 * call the protocol parsing routine which processes
		 * the data part of the message block first. Then it
		 * handles protocol and CR/LF processing.
		 * If an error is found inside allocb/dupb, recover
		 * routines inside rcv_parse will queue up the
		 * original message block in its service queue.
		 */
		(void) rcv_parse(q, mp);
		break;

	case M_FLUSH:
		/*
		 * Since M_FLUSH came from TCP, we mark it bound for
		 * daemon, not tty.  This only happens when TCP expects
		 * to do a connection reset.
		 */
		mp->b_flag |= MSGMARK;
		if (*mp->b_rptr & FLUSHR)
			flushq(q, FLUSHALL);
		putnext(q, mp);
		break;

	case M_PCSIG:
	case M_ERROR:
		if (tmip->flags & TEL_GETBLK)
			tmip->flags &= ~TEL_GETBLK;
		/* FALLTHRU */
	case M_IOCACK:
	case M_IOCNAK:
	case M_SETOPTS:
		putnext(q, mp);
		break;

	case M_PROTO:
	case M_PCPROTO:
		if (tmip->flags & TEL_GETBLK)
			tmip->flags &= ~TEL_GETBLK;

		tip = (union T_primitives *)mp->b_rptr;
		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_EXDATA_IND:
		case T_DATA_IND:	/* conform to TPI, but never happens */
			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,
			    "telmodrput: unexpected TLI primitive msg "
			    "type 0x%x", tip->type);
#endif
			freemsg(mp);
		}
		break;

	default:
#ifdef DEBUG
		cmn_err(CE_NOTE,
		    "telmodrput: unexpected msg type 0x%x",
		    mp->b_datap->db_type);
#endif
		freemsg(mp);
	}
}
Example #16
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);
		}
	}
}
Example #17
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;
	}
}
Example #18
0
/*
 * convert incoming data
 */
static int
parserput(
	  queue_t *q,
	  mblk_t *imp
	  )
{
	register unsigned char type;
	mblk_t *mp = imp;
  
	switch (type = mp->b_datap->db_type)
	{
	    default:
		/*
		 * anything we don't know will be put on queue
		 * the service routine will move it to the next one
		 */
		pprintf(DD_RPUT, "parse: parserput - forward type 0x%x\n", type);

		if (canputnext(q) || (mp->b_datap->db_type > QPCTL))
		{
			putnext(q, mp);
		}
		else
		    putq(q, mp);
		break;
      
	    case M_BREAK:
	    case M_DATA:
		    {
			    register parsestream_t * parse = (parsestream_t *)q->q_ptr;
			    register mblk_t *nmp;
			    register unsigned long ch;
			    timestamp_t c_time;
			    timespec_t hres_time;

			    /*
			     * get time on packet delivery
			     */
			    gethrestime(&hres_time);
			    c_time.tv.tv_sec  = hres_time.tv_sec;
			    c_time.tv.tv_usec = hres_time.tv_nsec / 1000;

			    if (!(parse->parse_status & PARSE_ENABLE))
			    {
				    pprintf(DD_RPUT, "parse: parserput - parser disabled - forward type 0x%x\n", type);
				    if (canputnext(q) || (mp->b_datap->db_type > QPCTL))
				    {
					    putnext(q, mp);
				    }
				    else
					putq(q, mp);
			    }
			    else
			    {
				    pprintf(DD_RPUT, "parse: parserput - M_%s\n", (type == M_DATA) ? "DATA" : "BREAK");
				    if (type == M_DATA)
				    {
					    /*
					     * parse packet looking for start an end characters
					     */
					    while (mp != (mblk_t *)NULL)
					    {
						    ch = rdchar(&mp);
						    if (ch != ~0 && parse_ioread(&parse->parse_io, (unsigned int)ch, &c_time))
						    {
							    /*
							     * up up and away (hopefully ...)
							     * don't press it if resources are tight or nobody wants it
							     */
							    nmp = (mblk_t *)NULL;
							    if (canputnext(parse->parse_queue) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
							    {
								    bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
								    nmp->b_wptr += sizeof(parsetime_t);
								    putnext(parse->parse_queue, nmp);
							    }
							    else
								if (nmp) freemsg(nmp);
							    parse_iodone(&parse->parse_io);
						    }
					    }	
				    }
				    else
				    {
					    if (parse_ioread(&parse->parse_io, (unsigned int)0, &c_time))
					    {
						    /*
						     * up up and away (hopefully ...)
						     * don't press it if resources are tight or nobody wants it
						     */
						    nmp = (mblk_t *)NULL;
						    if (canputnext(parse->parse_queue) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
						    {
							    bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
							    nmp->b_wptr += sizeof(parsetime_t);
							    putnext(parse->parse_queue, nmp);
						    }
						    else
							if (nmp) freemsg(nmp);
						    parse_iodone(&parse->parse_io);
					    }
					    freemsg(mp);
				    }
				    break;
			    }
		    }

		    /*
		     * CD PPS support for non direct ISR hack
		     */
	    case M_HANGUP:
	    case M_UNHANGUP:
		    {
			    register parsestream_t * parse = (parsestream_t *)q->q_ptr;
			    timestamp_t c_time;
			    timespec_t hres_time;
			    register mblk_t *nmp;
			    register int status = cd_invert ^ (type == M_UNHANGUP);

			    gethrestime(&hres_time);
			    c_time.tv.tv_sec  = hres_time.tv_sec;
			    c_time.tv.tv_usec = hres_time.tv_nsec / 1000;
	
			    pprintf(DD_RPUT, "parse: parserput - M_%sHANGUP\n", (type == M_HANGUP) ? "" : "UN");

			    if ((parse->parse_status & PARSE_ENABLE) &&
				parse_iopps(&parse->parse_io, status ? SYNC_ONE : SYNC_ZERO, &c_time))
			    {
				    nmp = (mblk_t *)NULL;
				    if (canputnext(parse->parse_queue) && (nmp = allocb(sizeof(parsetime_t), BPRI_MED)))
				    {
					    bcopy((caddr_t)&parse->parse_io.parse_dtime, (caddr_t)nmp->b_rptr, sizeof(parsetime_t));
					    nmp->b_wptr += sizeof(parsetime_t);
					    putnext(parse->parse_queue, nmp);
				    }
				    else
					if (nmp) freemsg(nmp);
				    parse_iodone(&parse->parse_io);
				    freemsg(mp);
			    }
			    else
				if (canputnext(q) || (mp->b_datap->db_type > QPCTL))
				{
					putnext(q, mp);
				}
				else
				    putq(q, mp);
	
			    if (status)
			    {
				    parse->parse_ppsclockev.tv = c_time.tv;
				    ++(parse->parse_ppsclockev.serial);
			    }
		    }
	}
	return 0;
}