/* * dm2s_start - Start transmission function. * * Send all queued messages. If the mailbox is busy, then * start a timeout as a polling mechanism. The timeout is useful * to not rely entirely on the SCF_MB_SPACE event. */ void dm2s_start(queue_t *wq, dm2s_t *dm2sp) { mblk_t *mp; int ret; DPRINTF(DBG_DRV, ("dm2s_start: called\n")); ASSERT(dm2sp != NULL); ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); while ((mp = getq(wq)) != NULL) { switch (mp->b_datap->db_type) { case M_DATA: ret = dm2s_transmit(wq, mp, dm2sp->ms_target, dm2sp->ms_key); if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) { DPRINTF(DBG_MBOX, ("dm2s_start: recoverable err=%d\n", ret)); /* * Start a timeout to retry again. */ if (dm2sp->ms_wq_timeoutid == 0) { DTRACE_PROBE1(dm2s_wqtimeout__start, dm2s_t, dm2sp); dm2sp->ms_wq_timeoutid = qtimeout(wq, dm2s_wq_timeout, (void *)dm2sp, dm2s_timeout_val(ret)); } return; } else if (ret != 0) { mutex_exit(&dm2sp->ms_lock); /* * An error occurred with the transmission, * flush pending messages and initiate a * hangup. */ flushq(wq, FLUSHDATA); (void) putnextctl(RD(wq), M_HANGUP); DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); DPRINTF(DBG_WARN, ("dm2s_start: hangup transmit err=%d\n", ret)); mutex_enter(&dm2sp->ms_lock); } break; default: /* * At this point, we don't expect any other messages. */ freemsg(mp); break; } } }
/* * cvc_redir() * called from cvcredir:cvcr_wput() to handle console input * data. This routine puts the cvcredir write (downstream) data * onto the cvc read (upstream) queues. */ int cvc_redir(mblk_t *mp) { register struct iocblk *iocp; int rv = 1; /* * This function shouldn't be called if cvcredir hasn't registered yet. */ if (cvcinput_q == NULL) { /* * Need to let caller know that it may be necessary for them to * free the message buffer, so return 0. */ CVC_DBG0(CVC_DBG_REDIR, "redirection not enabled"); cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!"); return (0); } CVC_DBG1(CVC_DBG_REDIR, "type 0x%x", mp->b_datap->db_type); if (mp->b_datap->db_type == M_DATA) { /* * XXX - should canputnext be called here? Starfire's cvc * doesn't do that, and it appears to work anyway. */ CVC_DBG1(CVC_DBG_NETWORK_RD, "Sending mp 0x%x", mp); (void) putnext(cvcinput_q, mp); } else if (mp->b_datap->db_type == M_IOCTL) { /* * The cvcredir driver filters out ioctl mblks we wouldn't * understand, so we don't have to check for every conceivable * ioc_cmd. However, additional ioctls may be supported (again) * some day, so the code is structured to check the value even * though there's only one that is currently supported. */ iocp = (struct iocblk *)mp->b_rptr; if (iocp->ioc_cmd == CVC_DISCONNECT) { (void) putnextctl(cvcinput_q, M_HANGUP); } } else { /* * Since we don't know what this mblk is, we're not going to * process it. */ CVC_DBG1(CVC_DBG_REDIR, "unrecognized mblk type: %d", mp->b_datap->db_type); rv = 0; } return (rv); }
/* ARGSUSED */ int dm2s_close(queue_t *rq, int flag, cred_t *cred) { dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; DPRINTF(DBG_DRV, ("dm2s_close: called\n")); if (dm2sp == NULL) { /* Already closed once */ return (ENODEV); } /* Close the lower layer first */ mutex_enter(&dm2sp->ms_lock); (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); dm2s_mbox_fini(dm2sp); mutex_exit(&dm2sp->ms_lock); /* * Now we can assume that no asynchronous callbacks exist. * Poison the stream head so that we can't be pushed again. */ (void) putnextctl(rq, M_HANGUP); qprocsoff(rq); if (dm2sp->ms_rbufcid != 0) { qunbufcall(rq, dm2sp->ms_rbufcid); dm2sp->ms_rbufcid = 0; } if (dm2sp->ms_rq_timeoutid != 0) { DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); dm2sp->ms_rq_timeoutid = 0; } if (dm2sp->ms_wq_timeoutid != 0) { DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); dm2sp->ms_wq_timeoutid = 0; } /* * Now we can really mark it closed. */ mutex_enter(&dm2sp->ms_lock); dm2sp->ms_rq = dm2sp->ms_wq = NULL; dm2sp->ms_state &= ~DM2S_OPENED; mutex_exit(&dm2sp->ms_lock); rq->q_ptr = WR(rq)->q_ptr = NULL; (void) qassociate(rq, -1); DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); return (0); }
/*ARGSUSED*/ static int telmodclose(queue_t *q, int flag, cred_t *credp) { struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; mblk_t *mp; /* * Flush any write-side data downstream. Ignoring flow * control at this point is known to be safe because the * M_HANGUP below poisons the stream such that no modules can * be pushed again. */ while (mp = getq(WR(q))) putnext(WR(q), mp); /* Poison the stream head so that we can't be pushed again. */ (void) putnextctl(q, M_HANGUP); qprocsoff(q); if (tmip->wbufcid) { qunbufcall(q, tmip->wbufcid); tmip->wbufcid = 0; } if (tmip->rbufcid) { qunbufcall(q, tmip->rbufcid); tmip->rbufcid = 0; } if (tmip->wtimoutid) { (void) quntimeout(q, tmip->wtimoutid); tmip->wtimoutid = 0; } if (tmip->rtimoutid) { (void) quntimeout(q, tmip->rtimoutid); tmip->rtimoutid = 0; } if (tmip->unbind_mp != NULL) { freemsg(tmip->unbind_mp); } kmem_free(q->q_ptr, sizeof (struct telmod_info)); q->q_ptr = WR(q)->q_ptr = NULL; return (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); }
/* * 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; } }
/* * dm2s_receive - Read all messages from the mailbox. * * This function is called from the read service procedure, to * receive the messages awaiting in the mailbox. */ void dm2s_receive(dm2s_t *dm2sp) { queue_t *rq = dm2sp->ms_rq; mblk_t *mp; int ret; uint32_t len; DPRINTF(DBG_DRV, ("dm2s_receive: called\n")); ASSERT(dm2sp != NULL); ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); if (rq == NULL) { return; } /* * As the number of messages in the mailbox are pretty limited, * it is safe to process all messages in one loop. */ while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target, dm2sp->ms_key, &len)) == 0)) { DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len)); if (len == 0) { break; } mp = allocb(len, BPRI_MED); if (mp == NULL) { DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n")); /* * Start a bufcall so that we can retry again * when memory becomes available. */ dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED, dm2s_bufcall_rcv, dm2sp); if (dm2sp->ms_rbufcid == 0) { DPRINTF(DBG_WARN, ("dm2s_receive: qbufcall failed\n")); /* * if bufcall fails, start a timeout to * initiate a re-try after some time. */ DTRACE_PROBE1(dm2s_rqtimeout__start, dm2s_t, dm2sp); dm2sp->ms_rq_timeoutid = qtimeout(rq, dm2s_rq_timeout, (void *)dm2sp, drv_usectohz(DM2S_SM_TOUT)); } break; } /* * Only a single scatter/gather element is enough here. */ dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr; dm2sp->ms_sg_rcv.msc_len = len; DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n")); ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1, &dm2sp->ms_sg_rcv, 0); DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret)); if (ret != 0) { freemsg(mp); break; } DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv); mp->b_wptr += len; /* * Queue the messages in the rq, so that the service * procedure handles sending the messages up the stream. */ putq(rq, mp); } if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) { /* * Some thing went wrong, flush pending messages * and initiate a hangup. * Note: flushing the wq initiates a faster close. */ mutex_exit(&dm2sp->ms_lock); flushq(WR(rq), FLUSHDATA); (void) putnextctl(rq, M_HANGUP); DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); mutex_enter(&dm2sp->ms_lock); DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown " "condition - hangup ret=%d\n", ret)); } }
/* * cvc_iosram_ops() * Process commands sent to cvc from netcon_server via IOSRAM */ static void cvc_iosram_ops(uint8_t op) { int rval = ESUCCESS; static uint8_t stale_op = 0; ASSERT(MUTEX_HELD(&cvc_iosram_input_mutex)); CVC_DBG1(CVC_DBG_IOSRAM_CNTL, "cntl msg 0x%x", op); /* * If this is a repeated notice of a command that was previously * processed but couldn't be cleared due to EAGAIN (tunnel switch in * progress), just clear the data_valid flag and return. */ if (op == stale_op) { if (iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID, IOSRAM_INT_NONE) == 0) { stale_op = 0; } return; } stale_op = 0; switch (op) { case CVC_IOSRAM_BREAK: /* A console break (L1-A) */ abort_sequence_enter((char *)NULL); break; case CVC_IOSRAM_DISCONNECT: /* Break connection, hang up */ if (cvcinput_q) (void) putnextctl(cvcinput_q, M_HANGUP); break; case CVC_IOSRAM_VIA_NET: /* console via network */ via_iosram = 0; break; case CVC_IOSRAM_VIA_IOSRAM: /* console via iosram */ via_iosram = 1; /* * Tell cvcd to close any network connection it has. */ rw_enter(&cvclock, RW_READER); if (cvcoutput_q != NULL) { (void) putnextctl(cvcoutput_q, M_HANGUP); } rw_exit(&cvclock); break; case CVC_IOSRAM_WIN_RESIZE: /* console window size data */ /* * In the case of window resizing, we don't want to * record a stale_op value because we should always use * the most recent winsize info, which could change * between the time that we fail to clear the flag and * the next time we try to process the command. So, * we'll just let cvc_win_resize clear the data_valid * flag itself (hence the TRUE parameter) and not worry * about whether or not it succeeds. */ cvc_win_resize(TRUE); return; /* NOTREACHED */ default: cmn_err(CE_WARN, "cvc: unknown IOSRAM opcode %d", op); break; } /* * Clear CONC's data_valid flag to indicate that the chunk is available * for further communications. If the flag can't be cleared due to an * error, record the op value so we'll know to ignore it when we see it * on the next poll. */ rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID, IOSRAM_INT_NONE); if (rval != 0) { stale_op = op; if (rval != EAGAIN) { cmn_err(CE_WARN, "cvc_iosram_ops: set flag for cntlbuf ret %d", rval); } } }
/** * 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; }
/** * sl_w_ioctl: - process M_IOCTL message * @q: active queue (upper write queue) * @mp: the message * * Linking of streams: streams are linked under the multiplexing driver by opening an upper stream * and then linking a signalling link stream under the multiplexing driver. Then the SL_SETLINK * input-output control is used with the multiplexer id to set the global-PPA and CLEI associated * with the signalling link. The SL_GETLINK input-output control can be used at a later date to * determine the multiplexer id for a given signalling link stream. */ static struct int sl_w_ioctl(queue_t *q, mblk_t *mp) { struct iocblk *ioc = (struct iocblk *) mp->b_rptr; switch (ioc->ioc_cmd) { case I_LINK: case I_PLINK: { struct linkblk *l; if (!mp->b_cont) mi_copy_done(q, mp, EINVAL); l = (struct linkblk *) mp->b_cont->b_rptr; if (!(bot = kmem_alloc(sizeof(*bot), KM_NOSLEEP))) mi_copy_done(q, mp, ENOMEM); write_lock_str(&mux_lock, flags); bot->next = mux_links; bpt->prev = &mux_links; mux_links = bot; bot->dev = l->l_index; bot->rq = RD(l->l_qtop); bot->wq = l->l_qtop; bot->other = NULL; noenable(bot->rq); l->l_qtop->q_ptr = RD(l->l_qtop)->q_ptr = (void *) bot; write_unlock_str(&mux_lock, flags); mi_copy_done(q, mp, 0); return (0); } case I_UNLINK: case I_PUNLINK: { struct linkblk *l; if (!mp->b_cont) mi_copy_done(q, mp, EINVAL); l = (struct linkblk *) mp->b_cont->b_rptr; write_lock_str(&mux_lock, flags); for (bot = mux_list; bot; bot = bot->next) if (bot->dev == l->l_index) break; if (!bot) { write_unlock_str(&mux_lock, flags); mi_copy_done(q, mp, EINVAL); return (0); } /* Note that the lower multiplex driver put and service procedures must be prepared to be invoked event after the M_IOCACK for the I_UNLINK or I_PUNLINK ioctl has been returned. THis is because the setq(9) back to the Stream head is not performed until after the acknowledgement has been received. We set q->q_ptr to a null multiplex structure to keep the lower Stream functioning until the setq(9) is performed. */ l->l_qtop->q_ptr = RD(l->l_qtop)->q_ptr = &no_mux; if ((*bot->prev = bot->next)) { bot->next = NULL; bot->prev = &bot->next; } bot->other = NULL; kmem_free(bot, sizeof(*bot)); /* hang up all upper streams that feed this lower stream */ for (top = mux_opens; top; top = top->next) { if (top->other == bot) { putnextctl(top->rq, M_HANGUP); top->other = NULL; } } write_unlock_str(&mux_lock, flags); mi_copy_done(q, mp, 0); return (0); } case SL_SETLINK: { struct sl_mux_ppa *sm; /* This input-output control is used to set the global-PPA and CLEI associated with a lower multiplex stream. The argument is an sl_mux_ppa structure that contains the multiplex id, the 32-bit PPA, and a CLEI string of up to 32 characters in length. */ mi_copyin(q, mp, NULL, sizeof(struct sl_mux_ppa)); return (0); } case SL_GETLINK: { /* This input-output control is used to obtain the multiplex-id assocated with a lower multiplex stream. The argument is an sl_mux_ppa structure that contains a 32-bit PPA or CLEI string of up to 32 characters in length. It returns the multiplex id in the same structure. */ mi_copyin(q, mp, NULL, sizeof(struct sl_mux_ppa)); return (0); } default: if (mux->other && mux->other->rq) { if (bcanputnext(mux->other->rq, mp->b_band)) { putnext(mux->other->rq, mp); return (0); } return (-EBUSY); } break; } mi_copy_done(q, mp, EINVAL); return (0); }