/* * 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; } }
/* * 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; } }
/* * 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; } }
static void kb8042_ioctlmsg(struct kb8042 *kb8042, queue_t *qp, mblk_t *mp) { struct iocblk *iocp; mblk_t *datap; int error; int tmp; iocp = (struct iocblk *)mp->b_rptr; switch (iocp->ioc_cmd) { case CONSOPENPOLLEDIO: error = miocpullup(mp, sizeof (struct cons_polledio *)); if (error != 0) { miocnak(qp, mp, 0, error); return; } /* * We are given an appropriate-sized data block, * and return a pointer to our structure in it. */ *(struct cons_polledio **)mp->b_cont->b_rptr = &kb8042->polledio; mp->b_datap->db_type = M_IOCACK; iocp->ioc_error = 0; qreply(qp, mp); break; case CONSCLOSEPOLLEDIO: miocack(qp, mp, 0, 0); break; case CONSSETABORTENABLE: if (iocp->ioc_count != TRANSPARENT) { miocnak(qp, mp, 0, EINVAL); return; } kb8042->debugger.enabled = *(intptr_t *)mp->b_cont->b_rptr; miocack(qp, mp, 0, 0); break; /* * Valid only in TR_UNTRANS_MODE mode. */ case CONSSETKBDTYPE: error = miocpullup(mp, sizeof (int)); if (error != 0) { miocnak(qp, mp, 0, error); return; } tmp = *(int *)mp->b_cont->b_rptr; if (tmp != KB_PC && tmp != KB_USB) { miocnak(qp, mp, 0, EINVAL); break; } kb8042->simulated_kbd_type = tmp; miocack(qp, mp, 0, 0); break; case KIOCLAYOUT: if (kb8042->w_kblayout == -1) { miocnak(qp, mp, 0, EINVAL); return; } if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) { miocnak(qp, mp, 0, ENOMEM); return; } if (kb8042->simulated_kbd_type == KB_USB) *(int *)datap->b_wptr = KBTRANS_USBKB_DEFAULT_LAYOUT; else *(int *)datap->b_wptr = kb8042->w_kblayout; datap->b_wptr += sizeof (int); if (mp->b_cont) freemsg(mp->b_cont); mp->b_cont = datap; iocp->ioc_count = sizeof (int); mp->b_datap->db_type = M_IOCACK; iocp->ioc_error = 0; qreply(qp, mp); break; case KIOCSLAYOUT: if (iocp->ioc_count != TRANSPARENT) { miocnak(qp, mp, 0, EINVAL); return; } kb8042->w_kblayout = *(intptr_t *)mp->b_cont->b_rptr; miocack(qp, mp, 0, 0); break; case KIOCCMD: error = miocpullup(mp, sizeof (int)); if (error != 0) { miocnak(qp, mp, 0, error); return; } kb8042_type4_cmd(kb8042, *(int *)mp->b_cont->b_rptr); miocack(qp, mp, 0, 0); break; default: #ifdef DEBUG1 cmn_err(CE_NOTE, "!kb8042_ioctlmsg %x", iocp->ioc_cmd); #endif miocnak(qp, mp, 0, EINVAL); return; } }
/* * Handle write-side M_IOCTL messages. */ static void pfioctl(queue_t *wq, mblk_t *mp) { struct epacketfilt *pfp = (struct epacketfilt *)wq->q_ptr; struct Pf_ext_packetfilt *upfp; struct packetfilt *opfp; ushort_t *fwp; int arg; int maxoff = 0; int maxoffreg = 0; struct iocblk *iocp = (struct iocblk *)mp->b_rptr; int error; switch (iocp->ioc_cmd) { case PFIOCSETF: /* * Verify argument length. Since the size of packet filter * got increased (ENMAXFILTERS was bumped up to 2047), to * maintain backwards binary compatibility, we need to * check for both possible sizes. */ switch (iocp->ioc_count) { case sizeof (struct Pf_ext_packetfilt): error = miocpullup(mp, sizeof (struct Pf_ext_packetfilt)); if (error != 0) { miocnak(wq, mp, 0, error); return; } upfp = (struct Pf_ext_packetfilt *)mp->b_cont->b_rptr; if (upfp->Pf_FilterLen > PF_MAXFILTERS) { miocnak(wq, mp, 0, EINVAL); return; } bcopy(upfp, pfp, sizeof (struct Pf_ext_packetfilt)); pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen]; break; case sizeof (struct packetfilt): error = miocpullup(mp, sizeof (struct packetfilt)); if (error != 0) { miocnak(wq, mp, 0, error); return; } opfp = (struct packetfilt *)mp->b_cont->b_rptr; /* this strange comparison keeps gcc from complaining */ if (opfp->Pf_FilterLen - 1 >= ENMAXFILTERS) { miocnak(wq, mp, 0, EINVAL); return; } pfp->pf.Pf_Priority = opfp->Pf_Priority; pfp->pf.Pf_FilterLen = (unsigned int)opfp->Pf_FilterLen; bcopy(opfp->Pf_Filter, pfp->pf.Pf_Filter, sizeof (opfp->Pf_Filter)); pfp->pf_FilterEnd = &pfp->pf_Filter[pfp->pf_FilterLen]; break; default: miocnak(wq, mp, 0, EINVAL); return; } /* * Find and record maximum byte offset that the * filter users. We use this when executing the * filter to determine how much of the packet * body to pull up. This code depends on the * filter encoding. */ for (fwp = pfp->pf_Filter; fwp < pfp->pf_FilterEnd; fwp++) { arg = *fwp & ((1 << ENF_NBPA) - 1); switch (arg) { default: if ((arg -= ENF_PUSHWORD) > maxoff) maxoff = arg; break; case ENF_LOAD_OFFSET: /* Point to the offset */ fwp++; if (*fwp > maxoffreg) maxoffreg = *fwp; break; case ENF_PUSHLIT: case ENF_BRTR: case ENF_BRFL: /* Skip over the literal. */ fwp++; break; case ENF_PUSHZERO: case ENF_PUSHONE: case ENF_PUSHFFFF: case ENF_PUSHFF00: case ENF_PUSH00FF: case ENF_NOPUSH: case ENF_POP: break; } } /* * Convert word offset to length in bytes. */ pfp->pf_PByteLen = (maxoff + maxoffreg + 1) * sizeof (ushort_t); miocack(wq, mp, 0, 0); break; default: putnext(wq, mp); break; } }