int sendrecv(int function, struct msg *m, int dest) { struct msg mbuf; char iobuf[BUFLEN]; int ret; ret = -1; assert((dest >= 0 && dest < NPROC) || (function == RECV && dest == ANY)); assert(dest == ANY || ptable[dest].state != UNUSED); m->source = current - ptable; assert(m->source != dest); // mbuf is in kernel address space; if (function == SEND) { mbuf = *m; ret = sendmsg(&mbuf, dest); } else if (function == RECV) { ret = recvmsg(&mbuf, dest); *m = mbuf; } else if (function == BOTH) { mbuf = *m; mcopyin(iobuf, &mbuf, m); if ( (ret = sendmsg(&mbuf, dest)) != 0) return ret; ret = recvmsg(&mbuf, dest); mcopyout(&mbuf, m); *m = mbuf; } return ret; }
/* * 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; } }
/* * apush_iocdata() - * Handle the M_IOCDATA messages associated with * the autopush feature. */ static void apush_iocdata( queue_t *qp, /* pointer to write queue */ mblk_t *mp) /* message pointer */ { int i, ret; struct copyresp *csp; struct strapush *sap; struct autopush *ap; struct saddev *sadp; uint_t size; csp = (struct copyresp *)mp->b_rptr; if (csp->cp_rval) { /* if there was an error */ freemsg(mp); return; } if (mp->b_cont) /* sap needed only if mp->b_cont is set */ sap = (struct strapush *)mp->b_cont->b_rptr; switch (SAD_CMD(csp->cp_cmd)) { case SAD_CMD(SAD_SAP): switch ((long)csp->cp_private) { case GETSTRUCT: switch (sap->sap_cmd) { case SAP_ONE: case SAP_RANGE: case SAP_ALL: if ((sap->sap_npush == 0) || (sap->sap_npush > MAXAPUSH) || (sap->sap_npush > nstrpush)) { /* invalid number of modules to push */ miocnak(qp, mp, 0, EINVAL); break; } if (ret = valid_major(sap->sap_major)) { miocnak(qp, mp, 0, ret); break; } if ((sap->sap_cmd == SAP_RANGE) && (sap->sap_lastminor <= sap->sap_minor)) { /* bad range */ miocnak(qp, mp, 0, ERANGE); break; } /* * Validate that the specified list of * modules exist. */ for (i = 0; i < sap->sap_npush; i++) { sap->sap_list[i][FMNAMESZ] = '\0'; if (fmodsw_find(sap->sap_list[i], FMODSW_LOAD) == NULL) { miocnak(qp, mp, 0, EINVAL); return; } } mutex_enter(&sad_lock); if (ap_hfind(sap->sap_major, sap->sap_minor, sap->sap_lastminor, sap->sap_cmd)) { mutex_exit(&sad_lock); /* already configured */ miocnak(qp, mp, 0, EEXIST); break; } if ((ap = ap_alloc()) == NULL) { mutex_exit(&sad_lock); /* no autopush structures */ miocnak(qp, mp, 0, ENOSR); break; } ap->ap_cnt++; ap->ap_common = sap->sap_common; if (SAD_VER(csp->cp_cmd) > 0) ap->ap_anchor = sap->sap_anchor; else ap->ap_anchor = 0; for (i = 0; i < ap->ap_npush; i++) (void) strcpy(ap->ap_list[i], sap->sap_list[i]); ap_hadd(ap); mutex_exit(&sad_lock); miocack(qp, mp, 0, 0); break; case SAP_CLEAR: if (ret = valid_major(sap->sap_major)) { miocnak(qp, mp, 0, ret); break; } mutex_enter(&sad_lock); if ((ap = ap_hfind(sap->sap_major, sap->sap_minor, sap->sap_lastminor, sap->sap_cmd)) == NULL) { mutex_exit(&sad_lock); /* not configured */ miocnak(qp, mp, 0, ENODEV); break; } if ((ap->ap_type == SAP_RANGE) && (sap->sap_minor != ap->ap_minor)) { mutex_exit(&sad_lock); /* starting minors do not match */ miocnak(qp, mp, 0, ERANGE); break; } if ((ap->ap_type == SAP_ALL) && (sap->sap_minor != 0)) { mutex_exit(&sad_lock); /* SAP_ALL must have minor == 0 */ miocnak(qp, mp, 0, EINVAL); break; } ap_hrmv(ap); if (--(ap->ap_cnt) <= 0) ap_free(ap); mutex_exit(&sad_lock); miocack(qp, mp, 0, 0); break; default: miocnak(qp, mp, 0, EINVAL); break; } /* switch (sap_cmd) */ break; default: cmn_err(CE_WARN, "apush_iocdata: cp_private bad in SAD_SAP: %p", (void *)csp->cp_private); freemsg(mp); break; } /* switch (cp_private) */ break; case SAD_CMD(SAD_GAP): switch ((long)csp->cp_private) { case GETSTRUCT: { if (ret = valid_major(sap->sap_major)) { miocnak(qp, mp, 0, ret); break; } mutex_enter(&sad_lock); if ((ap = ap_hfind(sap->sap_major, sap->sap_minor, sap->sap_lastminor, SAP_ONE)) == NULL) { mutex_exit(&sad_lock); /* not configured */ miocnak(qp, mp, 0, ENODEV); break; } sap->sap_common = ap->ap_common; if (SAD_VER(csp->cp_cmd) > 0) sap->sap_anchor = ap->ap_anchor; for (i = 0; i < ap->ap_npush; i++) (void) strcpy(sap->sap_list[i], ap->ap_list[i]); for (; i < MAXAPUSH; i++) bzero(sap->sap_list[i], FMNAMESZ + 1); mutex_exit(&sad_lock); if (SAD_VER(csp->cp_cmd) == 1) size = STRAPUSH_V1_LEN; else size = STRAPUSH_V0_LEN; sadp = (struct saddev *)qp->q_ptr; mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, NULL); qreply(qp, mp); break; } case GETRESULT: miocack(qp, mp, 0, 0); break; default: cmn_err(CE_WARN, "apush_iocdata: cp_private bad case SAD_GAP: %p", (void *)csp->cp_private); freemsg(mp); break; } /* switch (cp_private) */ break; default: /* can't happen */ ASSERT(0); freemsg(mp); break; } /* switch (cp_cmd) */ }