17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * This module implements the "fast path" processing for the telnet protocol.
297c478bd9Sstevel@tonic-gate * Since it only knows a very small number of the telnet protocol options,
307c478bd9Sstevel@tonic-gate * the daemon is required to assist this module. This module must be run
317c478bd9Sstevel@tonic-gate * underneath logindmux, which handles switching messages between the
327c478bd9Sstevel@tonic-gate * daemon and the pty master stream appropriately. When an unknown telnet
337c478bd9Sstevel@tonic-gate * option is received it is handled as a stop-and-wait operation. The
347c478bd9Sstevel@tonic-gate * module refuses to forward data in either direction, and waits for the
357c478bd9Sstevel@tonic-gate * daemon to deal with the option, and forward any unprocessed data back
367c478bd9Sstevel@tonic-gate * to the daemon.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/stream.h>
427c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
437c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
447c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
457c478bd9Sstevel@tonic-gate #include <sys/errno.h>
467c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
497c478bd9Sstevel@tonic-gate #include <sys/ptem.h>
507c478bd9Sstevel@tonic-gate #include <sys/logindmux.h>
517c478bd9Sstevel@tonic-gate #include <sys/telioctl.h>
527c478bd9Sstevel@tonic-gate #include <sys/termios.h>
537c478bd9Sstevel@tonic-gate #include <sys/debug.h>
547c478bd9Sstevel@tonic-gate #include <sys/conf.h>
557c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
567c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
577c478bd9Sstevel@tonic-gate #include <sys/cryptmod.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #define IAC 255
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate extern struct streamtab telmodinfo;
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate #define TELMOD_ID 105
647c478bd9Sstevel@tonic-gate #define SIMWAIT (1*hz)
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate * Module state flags
687c478bd9Sstevel@tonic-gate */
697c478bd9Sstevel@tonic-gate #define TEL_IOCPASSTHRU 0x100
707c478bd9Sstevel@tonic-gate #define TEL_STOPPED 0x80
717c478bd9Sstevel@tonic-gate #define TEL_CRRCV 0x40
727c478bd9Sstevel@tonic-gate #define TEL_CRSND 0x20
737c478bd9Sstevel@tonic-gate #define TEL_GETBLK 0x10
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * NOTE: values TEL_BINARY_IN and TEL_BINARY_OUT are defined in
777c478bd9Sstevel@tonic-gate * telioctl.h, passed in the TEL_IOC_MODE ioctl and stored (bitwise)
787c478bd9Sstevel@tonic-gate * in the module state flag. So those values are not available
797c478bd9Sstevel@tonic-gate * even though they are not defined here.
807c478bd9Sstevel@tonic-gate */
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate * Per queue instances are single-threaded since the q_ptr
867c478bd9Sstevel@tonic-gate * field of queues need to be shared among threads.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
897c478bd9Sstevel@tonic-gate "telmod",
907c478bd9Sstevel@tonic-gate &telmodinfo,
917c478bd9Sstevel@tonic-gate D_MTQPAIR | D_MP
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
967c478bd9Sstevel@tonic-gate */
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
997c478bd9Sstevel@tonic-gate &mod_strmodops,
1007c478bd9Sstevel@tonic-gate "telnet module",
1017c478bd9Sstevel@tonic-gate &fsw
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1057c478bd9Sstevel@tonic-gate MODREV_1, &modlstrmod, NULL
1067c478bd9Sstevel@tonic-gate };
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate int
_init()1097c478bd9Sstevel@tonic-gate _init()
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage));
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate int
_fini()1157c478bd9Sstevel@tonic-gate _fini()
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage));
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1217c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate static int telmodopen(queue_t *, dev_t *, int, int, cred_t *);
1277c478bd9Sstevel@tonic-gate static int telmodclose(queue_t *, int, cred_t *);
128*c97b1070SToomas Soome static int telmodrput(queue_t *, mblk_t *);
129*c97b1070SToomas Soome static int telmodrsrv(queue_t *);
130*c97b1070SToomas Soome static int telmodwput(queue_t *, mblk_t *);
131*c97b1070SToomas Soome static int telmodwsrv(queue_t *);
1327c478bd9Sstevel@tonic-gate static int rcv_parse(queue_t *q, mblk_t *mp);
1337c478bd9Sstevel@tonic-gate static int snd_parse(queue_t *q, mblk_t *mp);
1347c478bd9Sstevel@tonic-gate static void telmod_timer(void *);
1357c478bd9Sstevel@tonic-gate static void telmod_buffer(void *);
1367c478bd9Sstevel@tonic-gate static void recover(queue_t *, mblk_t *, size_t);
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate static struct module_info telmodoinfo = {
1397c478bd9Sstevel@tonic-gate TELMOD_ID, /* module id number */
1407c478bd9Sstevel@tonic-gate "telmod", /* module name */
1417c478bd9Sstevel@tonic-gate 0, /* minimum packet size */
1427c478bd9Sstevel@tonic-gate INFPSZ, /* maximum packet size */
1437c478bd9Sstevel@tonic-gate 512, /* hi-water mark */
1447c478bd9Sstevel@tonic-gate 256 /* lo-water mark */
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate static struct qinit telmodrinit = {
148*c97b1070SToomas Soome telmodrput,
149*c97b1070SToomas Soome telmodrsrv,
1507c478bd9Sstevel@tonic-gate telmodopen,
1517c478bd9Sstevel@tonic-gate telmodclose,
1527c478bd9Sstevel@tonic-gate nulldev,
1537c478bd9Sstevel@tonic-gate &telmodoinfo,
1547c478bd9Sstevel@tonic-gate NULL
1557c478bd9Sstevel@tonic-gate };
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate static struct qinit telmodwinit = {
158*c97b1070SToomas Soome telmodwput,
159*c97b1070SToomas Soome telmodwsrv,
1607c478bd9Sstevel@tonic-gate NULL,
1617c478bd9Sstevel@tonic-gate NULL,
1627c478bd9Sstevel@tonic-gate nulldev,
1637c478bd9Sstevel@tonic-gate &telmodoinfo,
1647c478bd9Sstevel@tonic-gate NULL
1657c478bd9Sstevel@tonic-gate };
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate struct streamtab telmodinfo = {
1687c478bd9Sstevel@tonic-gate &telmodrinit,
1697c478bd9Sstevel@tonic-gate &telmodwinit,
1707c478bd9Sstevel@tonic-gate NULL,
1717c478bd9Sstevel@tonic-gate NULL
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate * Per-instance state struct for the telnet module.
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate struct telmod_info {
1787c478bd9Sstevel@tonic-gate int flags;
1797c478bd9Sstevel@tonic-gate bufcall_id_t wbufcid;
1807c478bd9Sstevel@tonic-gate bufcall_id_t rbufcid;
1817c478bd9Sstevel@tonic-gate timeout_id_t wtimoutid;
1827c478bd9Sstevel@tonic-gate timeout_id_t rtimoutid;
1837c478bd9Sstevel@tonic-gate mblk_t *unbind_mp;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate };
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1887c478bd9Sstevel@tonic-gate static void
dummy_callback(void * arg)1897c478bd9Sstevel@tonic-gate dummy_callback(void *arg)
1907c478bd9Sstevel@tonic-gate {}
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate * telmodopen -
1947c478bd9Sstevel@tonic-gate * A variety of telnet options can never really be processed in the
1957c478bd9Sstevel@tonic-gate * kernel. For example, TELOPT_TTYPE, must be based in the TERM
1967c478bd9Sstevel@tonic-gate * environment variable to the login process. Also, data may already
1977c478bd9Sstevel@tonic-gate * have reached the stream head before telmod was pushed on the stream.
1987c478bd9Sstevel@tonic-gate * So when telmod is opened, it begins in stopped state, preventing
1997c478bd9Sstevel@tonic-gate * further data passing either direction through it. It sends a
2007c478bd9Sstevel@tonic-gate * T_DATA_REQ messages up toward the daemon. This is so the daemon
2017c478bd9Sstevel@tonic-gate * can be sure that all data which was not processed by telmod
2027c478bd9Sstevel@tonic-gate * (because it wasn't yet pushed) has been received at the stream head.
2037c478bd9Sstevel@tonic-gate */
2047c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2057c478bd9Sstevel@tonic-gate static int
telmodopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * credp)2067c478bd9Sstevel@tonic-gate telmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate struct telmod_info *tmip;
2097c478bd9Sstevel@tonic-gate mblk_t *bp;
2107c478bd9Sstevel@tonic-gate union T_primitives *tp;
2117c478bd9Sstevel@tonic-gate int error;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate if (sflag != MODOPEN)
2147c478bd9Sstevel@tonic-gate return (EINVAL);
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate if (q->q_ptr != NULL) {
2177c478bd9Sstevel@tonic-gate /* It's already attached. */
2187c478bd9Sstevel@tonic-gate return (0);
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate * Allocate state structure.
2227c478bd9Sstevel@tonic-gate */
2237c478bd9Sstevel@tonic-gate tmip = kmem_zalloc(sizeof (*tmip), KM_SLEEP);
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate * Cross-link.
2277c478bd9Sstevel@tonic-gate */
2287c478bd9Sstevel@tonic-gate q->q_ptr = tmip;
2297c478bd9Sstevel@tonic-gate WR(q)->q_ptr = tmip;
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate noenable(q);
2327c478bd9Sstevel@tonic-gate tmip->flags |= TEL_STOPPED;
2337c478bd9Sstevel@tonic-gate qprocson(q);
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate * Since TCP operates in the TLI-inspired brain-dead fashion,
2377c478bd9Sstevel@tonic-gate * the connection will revert to bound state if the connection
2387c478bd9Sstevel@tonic-gate * is reset by the client. We must send a T_UNBIND_REQ in
2397c478bd9Sstevel@tonic-gate * that case so the port doesn't get "wedged" (preventing
2407c478bd9Sstevel@tonic-gate * inetd from being able to restart the listener). Allocate
2417c478bd9Sstevel@tonic-gate * it here, so that we don't need to worry about allocb()
2427c478bd9Sstevel@tonic-gate * failures later.
2437c478bd9Sstevel@tonic-gate */
2447c478bd9Sstevel@tonic-gate while ((tmip->unbind_mp = allocb(sizeof (union T_primitives),
2457c478bd9Sstevel@tonic-gate BPRI_HI)) == NULL) {
2467c478bd9Sstevel@tonic-gate bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
2477c478bd9Sstevel@tonic-gate BPRI_HI, dummy_callback, NULL);
2487c478bd9Sstevel@tonic-gate if (!qwait_sig(q)) {
2497c478bd9Sstevel@tonic-gate qunbufcall(q, id);
2507c478bd9Sstevel@tonic-gate error = EINTR;
2517c478bd9Sstevel@tonic-gate goto fail;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate qunbufcall(q, id);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate tmip->unbind_mp->b_wptr = tmip->unbind_mp->b_rptr +
2567c478bd9Sstevel@tonic-gate sizeof (struct T_unbind_req);
2577c478bd9Sstevel@tonic-gate tmip->unbind_mp->b_datap->db_type = M_PROTO;
2587c478bd9Sstevel@tonic-gate tp = (union T_primitives *)tmip->unbind_mp->b_rptr;
2597c478bd9Sstevel@tonic-gate tp->type = T_UNBIND_REQ;
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
2627c478bd9Sstevel@tonic-gate * read queue since only write queue can get T_DATA_REQ).
2637c478bd9Sstevel@tonic-gate * Readstream routine in telnet daemon will do a getmsg() till
2647c478bd9Sstevel@tonic-gate * it receives this proto message
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) {
2677c478bd9Sstevel@tonic-gate bufcall_id_t id = qbufcall(q, sizeof (union T_primitives),
2687c478bd9Sstevel@tonic-gate BPRI_HI, dummy_callback, NULL);
2697c478bd9Sstevel@tonic-gate if (!qwait_sig(q)) {
2707c478bd9Sstevel@tonic-gate qunbufcall(q, id);
2717c478bd9Sstevel@tonic-gate error = EINTR;
2727c478bd9Sstevel@tonic-gate goto fail;
2737c478bd9Sstevel@tonic-gate }
2747c478bd9Sstevel@tonic-gate qunbufcall(q, id);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate bp->b_datap->db_type = M_PROTO;
2777c478bd9Sstevel@tonic-gate bp->b_wptr = bp->b_rptr + sizeof (union T_primitives);
2787c478bd9Sstevel@tonic-gate tp = (union T_primitives *)bp->b_rptr;
2797c478bd9Sstevel@tonic-gate tp->type = T_DATA_REQ;
2807c478bd9Sstevel@tonic-gate tp->data_req.MORE_flag = 0;
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate putnext(q, bp);
2837c478bd9Sstevel@tonic-gate return (0);
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate fail:
2867c478bd9Sstevel@tonic-gate qprocsoff(q);
2877c478bd9Sstevel@tonic-gate if (tmip->unbind_mp != NULL) {
2887c478bd9Sstevel@tonic-gate freemsg(tmip->unbind_mp);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate kmem_free(tmip, sizeof (struct telmod_info));
2917c478bd9Sstevel@tonic-gate q->q_ptr = NULL;
2927c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL;
2937c478bd9Sstevel@tonic-gate return (error);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate * telmodclose - just the normal streams clean-up is required.
2997c478bd9Sstevel@tonic-gate */
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3027c478bd9Sstevel@tonic-gate static int
telmodclose(queue_t * q,int flag,cred_t * credp)3037c478bd9Sstevel@tonic-gate telmodclose(queue_t *q, int flag, cred_t *credp)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
3067c478bd9Sstevel@tonic-gate mblk_t *mp;
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate * Flush any write-side data downstream. Ignoring flow
3107c478bd9Sstevel@tonic-gate * control at this point is known to be safe because the
3117c478bd9Sstevel@tonic-gate * M_HANGUP below poisons the stream such that no modules can
3127c478bd9Sstevel@tonic-gate * be pushed again.
3137c478bd9Sstevel@tonic-gate */
3147c478bd9Sstevel@tonic-gate while (mp = getq(WR(q)))
3157c478bd9Sstevel@tonic-gate putnext(WR(q), mp);
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /* Poison the stream head so that we can't be pushed again. */
3187c478bd9Sstevel@tonic-gate (void) putnextctl(q, M_HANGUP);
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate qprocsoff(q);
3217c478bd9Sstevel@tonic-gate if (tmip->wbufcid) {
3227c478bd9Sstevel@tonic-gate qunbufcall(q, tmip->wbufcid);
3237c478bd9Sstevel@tonic-gate tmip->wbufcid = 0;
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate if (tmip->rbufcid) {
3267c478bd9Sstevel@tonic-gate qunbufcall(q, tmip->rbufcid);
3277c478bd9Sstevel@tonic-gate tmip->rbufcid = 0;
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate if (tmip->wtimoutid) {
3307c478bd9Sstevel@tonic-gate (void) quntimeout(q, tmip->wtimoutid);
3317c478bd9Sstevel@tonic-gate tmip->wtimoutid = 0;
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate if (tmip->rtimoutid) {
3347c478bd9Sstevel@tonic-gate (void) quntimeout(q, tmip->rtimoutid);
3357c478bd9Sstevel@tonic-gate tmip->rtimoutid = 0;
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate if (tmip->unbind_mp != NULL) {
3387c478bd9Sstevel@tonic-gate freemsg(tmip->unbind_mp);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate kmem_free(q->q_ptr, sizeof (struct telmod_info));
3427c478bd9Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL;
3437c478bd9Sstevel@tonic-gate return (0);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate /*
3477c478bd9Sstevel@tonic-gate * telmodrput:
3487c478bd9Sstevel@tonic-gate * Be sure to preserve data order. If the daemon is waiting for additional
3497c478bd9Sstevel@tonic-gate * data (TEL_GETBLK state) forward new data. Otherwise, apply normal
3507c478bd9Sstevel@tonic-gate * telnet protocol processing to M_DATA. Take notice of TLI messages
3517c478bd9Sstevel@tonic-gate * indicating connection tear-down, and change them into M_HANGUP's.
3527c478bd9Sstevel@tonic-gate */
353*c97b1070SToomas Soome static int
telmodrput(queue_t * q,mblk_t * mp)3547c478bd9Sstevel@tonic-gate telmodrput(queue_t *q, mblk_t *mp)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate mblk_t *newmp;
3577c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
3587c478bd9Sstevel@tonic-gate union T_primitives *tip;
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate if ((mp->b_datap->db_type < QPCTL) &&
3617c478bd9Sstevel@tonic-gate ((q->q_first) || ((tmip->flags & TEL_STOPPED) &&
3627c478bd9Sstevel@tonic-gate !(tmip->flags & TEL_GETBLK)) || !canputnext(q))) {
3637c478bd9Sstevel@tonic-gate (void) putq(q, mp);
364*c97b1070SToomas Soome return (0);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
3687c478bd9Sstevel@tonic-gate case M_DATA:
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate * If the user level daemon requests for 1 more
3727c478bd9Sstevel@tonic-gate * block of data (needs more data for protocol processing)
3737c478bd9Sstevel@tonic-gate * create a M_CTL message block with the mp.
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate is_mdata:
3767c478bd9Sstevel@tonic-gate if (tmip->flags & TEL_GETBLK) {
3777c478bd9Sstevel@tonic-gate if ((newmp = allocb(sizeof (char), BPRI_MED)) == NULL) {
3787c478bd9Sstevel@tonic-gate recover(q, mp, msgdsize(mp));
379*c97b1070SToomas Soome return (0);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL;
3827c478bd9Sstevel@tonic-gate newmp->b_wptr = newmp->b_rptr + 1;
3837c478bd9Sstevel@tonic-gate *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
3847c478bd9Sstevel@tonic-gate newmp->b_cont = mp;
3857c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_GETBLK;
3867c478bd9Sstevel@tonic-gate noenable(q);
3877c478bd9Sstevel@tonic-gate tmip->flags |= TEL_STOPPED;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate putnext(q, newmp);
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate break;
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate * call the protocol parsing routine which processes
3957c478bd9Sstevel@tonic-gate * the data part of the message block first. Then it
3967c478bd9Sstevel@tonic-gate * handles protocol and CR/LF processing.
3977c478bd9Sstevel@tonic-gate * If an error is found inside allocb/dupb, recover
3987c478bd9Sstevel@tonic-gate * routines inside rcv_parse will queue up the
3997c478bd9Sstevel@tonic-gate * original message block in its service queue.
4007c478bd9Sstevel@tonic-gate */
4017c478bd9Sstevel@tonic-gate (void) rcv_parse(q, mp);
4027c478bd9Sstevel@tonic-gate break;
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate case M_FLUSH:
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate * Since M_FLUSH came from TCP, we mark it bound for
4077c478bd9Sstevel@tonic-gate * daemon, not tty. This only happens when TCP expects
4087c478bd9Sstevel@tonic-gate * to do a connection reset.
4097c478bd9Sstevel@tonic-gate */
4107c478bd9Sstevel@tonic-gate mp->b_flag |= MSGMARK;
4117c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR)
4127c478bd9Sstevel@tonic-gate flushq(q, FLUSHALL);
4137c478bd9Sstevel@tonic-gate putnext(q, mp);
4147c478bd9Sstevel@tonic-gate break;
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate case M_PCSIG:
4177c478bd9Sstevel@tonic-gate case M_ERROR:
4187c478bd9Sstevel@tonic-gate if (tmip->flags & TEL_GETBLK)
4197c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_GETBLK;
4207c478bd9Sstevel@tonic-gate /* FALLTHRU */
4217c478bd9Sstevel@tonic-gate case M_IOCACK:
4227c478bd9Sstevel@tonic-gate case M_IOCNAK:
4237c478bd9Sstevel@tonic-gate case M_SETOPTS:
4247c478bd9Sstevel@tonic-gate putnext(q, mp);
4257c478bd9Sstevel@tonic-gate break;
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate case M_PROTO:
4287c478bd9Sstevel@tonic-gate case M_PCPROTO:
4297c478bd9Sstevel@tonic-gate if (tmip->flags & TEL_GETBLK)
4307c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_GETBLK;
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate tip = (union T_primitives *)mp->b_rptr;
4337c478bd9Sstevel@tonic-gate switch (tip->type) {
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate case T_ORDREL_IND:
4367c478bd9Sstevel@tonic-gate case T_DISCON_IND:
4377c478bd9Sstevel@tonic-gate /* Make into M_HANGUP and putnext */
4387c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont == NULL);
4397c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_HANGUP;
4407c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr;
4417c478bd9Sstevel@tonic-gate if (mp->b_cont) {
4427c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
4437c478bd9Sstevel@tonic-gate mp->b_cont = NULL;
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate * If we haven't already, send T_UNBIND_REQ to prevent
4477c478bd9Sstevel@tonic-gate * TCP from going into "BOUND" state and locking up the
4487c478bd9Sstevel@tonic-gate * port.
4497c478bd9Sstevel@tonic-gate */
4507c478bd9Sstevel@tonic-gate if (tip->type == T_DISCON_IND && tmip->unbind_mp !=
4517c478bd9Sstevel@tonic-gate NULL) {
4527c478bd9Sstevel@tonic-gate putnext(q, mp);
4537c478bd9Sstevel@tonic-gate qreply(q, tmip->unbind_mp);
4547c478bd9Sstevel@tonic-gate tmip->unbind_mp = NULL;
4557c478bd9Sstevel@tonic-gate } else {
4567c478bd9Sstevel@tonic-gate putnext(q, mp);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate break;
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate case T_EXDATA_IND:
4617c478bd9Sstevel@tonic-gate case T_DATA_IND: /* conform to TPI, but never happens */
4627c478bd9Sstevel@tonic-gate newmp = mp->b_cont;
4637c478bd9Sstevel@tonic-gate freeb(mp);
4647c478bd9Sstevel@tonic-gate mp = newmp;
4657c478bd9Sstevel@tonic-gate if (mp) {
4667c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA);
4677c478bd9Sstevel@tonic-gate if (msgdsize(mp) != 0) {
4687c478bd9Sstevel@tonic-gate goto is_mdata;
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate freemsg(mp);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate break;
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate /*
4757c478bd9Sstevel@tonic-gate * We only get T_OK_ACK when we issue the unbind, and it can
4767c478bd9Sstevel@tonic-gate * be ignored safely.
4777c478bd9Sstevel@tonic-gate */
4787c478bd9Sstevel@tonic-gate case T_OK_ACK:
4797c478bd9Sstevel@tonic-gate ASSERT(tmip->unbind_mp == NULL);
4807c478bd9Sstevel@tonic-gate freemsg(mp);
4817c478bd9Sstevel@tonic-gate break;
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate default:
4847c478bd9Sstevel@tonic-gate #ifdef DEBUG
4857c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
4867c478bd9Sstevel@tonic-gate "telmodrput: unexpected TLI primitive msg "
4877c478bd9Sstevel@tonic-gate "type 0x%x", tip->type);
4887c478bd9Sstevel@tonic-gate #endif
4897c478bd9Sstevel@tonic-gate freemsg(mp);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate break;
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate default:
4947c478bd9Sstevel@tonic-gate #ifdef DEBUG
4957c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
4967c478bd9Sstevel@tonic-gate "telmodrput: unexpected msg type 0x%x",
4977c478bd9Sstevel@tonic-gate mp->b_datap->db_type);
4987c478bd9Sstevel@tonic-gate #endif
4997c478bd9Sstevel@tonic-gate freemsg(mp);
5007c478bd9Sstevel@tonic-gate }
501*c97b1070SToomas Soome return (0);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * telmodrsrv:
5067c478bd9Sstevel@tonic-gate * Mostly we end up here because of M_DATA processing delayed due to flow
5077c478bd9Sstevel@tonic-gate * control or lack of memory. XXX.sparker: TLI primitives here?
5087c478bd9Sstevel@tonic-gate */
509*c97b1070SToomas Soome static int
telmodrsrv(queue_t * q)5107c478bd9Sstevel@tonic-gate telmodrsrv(queue_t *q)
5117c478bd9Sstevel@tonic-gate {
5127c478bd9Sstevel@tonic-gate mblk_t *mp, *newmp;
5137c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
5147c478bd9Sstevel@tonic-gate union T_primitives *tip;
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
5177c478bd9Sstevel@tonic-gate if (((tmip->flags & TEL_STOPPED) &&
5187c478bd9Sstevel@tonic-gate !(tmip->flags & TEL_GETBLK)) || !canputnext(q)) {
5197c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
520*c97b1070SToomas Soome return (0);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate case M_DATA:
5257c478bd9Sstevel@tonic-gate is_mdata:
5267c478bd9Sstevel@tonic-gate if (tmip->flags & TEL_GETBLK) {
5277c478bd9Sstevel@tonic-gate if ((newmp = allocb(sizeof (char),
5287c478bd9Sstevel@tonic-gate BPRI_MED)) == NULL) {
5297c478bd9Sstevel@tonic-gate recover(q, mp, msgdsize(mp));
530*c97b1070SToomas Soome return (0);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL;
5337c478bd9Sstevel@tonic-gate newmp->b_wptr = newmp->b_rptr + 1;
5347c478bd9Sstevel@tonic-gate *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
5357c478bd9Sstevel@tonic-gate newmp->b_cont = mp;
5367c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_GETBLK;
5377c478bd9Sstevel@tonic-gate noenable(q);
5387c478bd9Sstevel@tonic-gate tmip->flags |= TEL_STOPPED;
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate putnext(q, newmp);
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate break;
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate if (!rcv_parse(q, mp)) {
545*c97b1070SToomas Soome return (0);
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate break;
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate case M_PROTO:
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate tip = (union T_primitives *)mp->b_rptr;
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate * Unless the M_PROTO message indicates data, clear
5557c478bd9Sstevel@tonic-gate * TEL_GETBLK so that we stop passing our messages
5567c478bd9Sstevel@tonic-gate * up to the telnet daemon.
5577c478bd9Sstevel@tonic-gate */
5587c478bd9Sstevel@tonic-gate if (tip->type != T_DATA_IND &&
5597c478bd9Sstevel@tonic-gate tip->type != T_EXDATA_IND)
5607c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_GETBLK;
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate switch (tip->type) {
5637c478bd9Sstevel@tonic-gate case T_ORDREL_IND:
5647c478bd9Sstevel@tonic-gate case T_DISCON_IND:
5657c478bd9Sstevel@tonic-gate /* Make into M_HANGUP and putnext */
5667c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont == NULL);
5677c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_HANGUP;
5687c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr;
5697c478bd9Sstevel@tonic-gate if (mp->b_cont) {
5707c478bd9Sstevel@tonic-gate freemsg(mp->b_cont);
5717c478bd9Sstevel@tonic-gate mp->b_cont = NULL;
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate * If we haven't already, send T_UNBIND_REQ
5757c478bd9Sstevel@tonic-gate * to prevent TCP from going into "BOUND"
5767c478bd9Sstevel@tonic-gate * state and locking up the port.
5777c478bd9Sstevel@tonic-gate */
5787c478bd9Sstevel@tonic-gate if (tip->type == T_DISCON_IND &&
5797c478bd9Sstevel@tonic-gate tmip->unbind_mp != NULL) {
5807c478bd9Sstevel@tonic-gate putnext(q, mp);
5817c478bd9Sstevel@tonic-gate qreply(q, tmip->unbind_mp);
5827c478bd9Sstevel@tonic-gate tmip->unbind_mp = NULL;
5837c478bd9Sstevel@tonic-gate } else {
5847c478bd9Sstevel@tonic-gate putnext(q, mp);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate break;
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate case T_DATA_IND: /* conform to TPI, but never happens */
5897c478bd9Sstevel@tonic-gate case T_EXDATA_IND:
5907c478bd9Sstevel@tonic-gate newmp = mp->b_cont;
5917c478bd9Sstevel@tonic-gate freeb(mp);
5927c478bd9Sstevel@tonic-gate mp = newmp;
5937c478bd9Sstevel@tonic-gate if (mp) {
5947c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_type == M_DATA);
5957c478bd9Sstevel@tonic-gate if (msgdsize(mp) != 0) {
5967c478bd9Sstevel@tonic-gate goto is_mdata;
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate freemsg(mp);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate break;
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate /*
6037c478bd9Sstevel@tonic-gate * We only get T_OK_ACK when we issue the unbind, and
6047c478bd9Sstevel@tonic-gate * it can be ignored safely.
6057c478bd9Sstevel@tonic-gate */
6067c478bd9Sstevel@tonic-gate case T_OK_ACK:
6077c478bd9Sstevel@tonic-gate ASSERT(tmip->unbind_mp == NULL);
6087c478bd9Sstevel@tonic-gate freemsg(mp);
6097c478bd9Sstevel@tonic-gate break;
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate default:
6127c478bd9Sstevel@tonic-gate #ifdef DEBUG
6137c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
6147c478bd9Sstevel@tonic-gate "telmodrsrv: unexpected TLI primitive "
6157c478bd9Sstevel@tonic-gate "msg type 0x%x", tip->type);
6167c478bd9Sstevel@tonic-gate #endif
6177c478bd9Sstevel@tonic-gate freemsg(mp);
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate break;
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate case M_SETOPTS:
6227c478bd9Sstevel@tonic-gate putnext(q, mp);
6237c478bd9Sstevel@tonic-gate break;
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate default:
6267c478bd9Sstevel@tonic-gate #ifdef DEBUG
6277c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
6287c478bd9Sstevel@tonic-gate "telmodrsrv: unexpected msg type 0x%x",
6297c478bd9Sstevel@tonic-gate mp->b_datap->db_type);
6307c478bd9Sstevel@tonic-gate #endif
6317c478bd9Sstevel@tonic-gate freemsg(mp);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate }
634*c97b1070SToomas Soome return (0);
6357c478bd9Sstevel@tonic-gate }
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate /*
6387c478bd9Sstevel@tonic-gate * telmodwput:
6397c478bd9Sstevel@tonic-gate * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon
6407c478bd9Sstevel@tonic-gate * to process something. M_CTL's are data from the daemon bound for the
6417c478bd9Sstevel@tonic-gate * network. We forward them immediately. There are two classes of ioctl's
6427c478bd9Sstevel@tonic-gate * we must handle here also. One is ioctl's forwarded by ptem which we
6437c478bd9Sstevel@tonic-gate * ignore. The other is ioctl's issued by the daemon to control us.
6447c478bd9Sstevel@tonic-gate * Process them appropriately. M_PROTO's we pass along, figuring they are
6457c478bd9Sstevel@tonic-gate * are TPI operations for TCP. M_FLUSH requires careful processing, since
6467c478bd9Sstevel@tonic-gate * telnet cannot tolerate flushing its protocol requests. Also the flushes
6477c478bd9Sstevel@tonic-gate * can be running either daemon<->TCP or application<->telmod. We must
6487c478bd9Sstevel@tonic-gate * carefully deal with this.
6497c478bd9Sstevel@tonic-gate */
650*c97b1070SToomas Soome static int
telmodwput(queue_t * q,mblk_t * mp)6517c478bd9Sstevel@tonic-gate telmodwput(
6527c478bd9Sstevel@tonic-gate queue_t *q, /* Pointer to the read queue */
6537c478bd9Sstevel@tonic-gate mblk_t *mp) /* Pointer to current message block */
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate struct telmod_info *tmip;
6567c478bd9Sstevel@tonic-gate struct iocblk *ioc;
6577c478bd9Sstevel@tonic-gate mblk_t *savemp;
6587c478bd9Sstevel@tonic-gate int rw;
6597c478bd9Sstevel@tonic-gate int error;
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate tmip = (struct telmod_info *)q->q_ptr;
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
6647c478bd9Sstevel@tonic-gate case M_DATA:
6657c478bd9Sstevel@tonic-gate if (!canputnext(q) || (tmip->flags & TEL_STOPPED) ||
6667c478bd9Sstevel@tonic-gate (q->q_first)) {
6677c478bd9Sstevel@tonic-gate noenable(q);
6687c478bd9Sstevel@tonic-gate (void) putq(q, mp);
6697c478bd9Sstevel@tonic-gate break;
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate * This routine parses data generating from ptm side.
6737c478bd9Sstevel@tonic-gate * Insert a null character if carraige return
6747c478bd9Sstevel@tonic-gate * is not followed by line feed unless we are in binary mode.
6757c478bd9Sstevel@tonic-gate * Also, duplicate IAC if found in the data.
6767c478bd9Sstevel@tonic-gate */
6777c478bd9Sstevel@tonic-gate (void) snd_parse(q, mp);
6787c478bd9Sstevel@tonic-gate break;
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate case M_CTL:
6817c478bd9Sstevel@tonic-gate if (((mp->b_wptr - mp->b_rptr) == 1) &&
6827c478bd9Sstevel@tonic-gate (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) {
6837c478bd9Sstevel@tonic-gate savemp = mp->b_cont;
6847c478bd9Sstevel@tonic-gate freeb(mp);
6857c478bd9Sstevel@tonic-gate mp = savemp;
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate putnext(q, mp);
6887c478bd9Sstevel@tonic-gate break;
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate case M_IOCTL:
6917c478bd9Sstevel@tonic-gate ioc = (struct iocblk *)mp->b_rptr;
6927c478bd9Sstevel@tonic-gate switch (ioc->ioc_cmd) {
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate * This ioctl is issued by user level daemon to
6967c478bd9Sstevel@tonic-gate * request one more message block to process protocol
6977c478bd9Sstevel@tonic-gate */
6987c478bd9Sstevel@tonic-gate case TEL_IOC_GETBLK:
6997c478bd9Sstevel@tonic-gate if (!(tmip->flags & TEL_STOPPED)) {
7007c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
7017c478bd9Sstevel@tonic-gate break;
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate tmip->flags |= TEL_GETBLK;
7047c478bd9Sstevel@tonic-gate qenable(RD(q));
7057c478bd9Sstevel@tonic-gate enableok(RD(q));
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0);
7087c478bd9Sstevel@tonic-gate break;
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate * This ioctl is issued by user level daemon to reenable the
7127c478bd9Sstevel@tonic-gate * read and write queues. This is issued during startup time
7137c478bd9Sstevel@tonic-gate * after setting up the mux links and also after processing
7147c478bd9Sstevel@tonic-gate * the protocol. It is also issued after each time an
7157c478bd9Sstevel@tonic-gate * an unrecognized telnet option is forwarded to the daemon.
7167c478bd9Sstevel@tonic-gate */
7177c478bd9Sstevel@tonic-gate case TEL_IOC_ENABLE:
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate * Send negative ack if TEL_STOPPED flag is not set
7217c478bd9Sstevel@tonic-gate */
7227c478bd9Sstevel@tonic-gate if (!(tmip->flags & TEL_STOPPED)) {
7237c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
7247c478bd9Sstevel@tonic-gate break;
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_STOPPED;
7277c478bd9Sstevel@tonic-gate if (mp->b_cont) {
7287c478bd9Sstevel@tonic-gate (void) putbq(RD(q), mp->b_cont);
7297c478bd9Sstevel@tonic-gate mp->b_cont = 0;
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate qenable(RD(q));
7337c478bd9Sstevel@tonic-gate enableok(RD(q));
7347c478bd9Sstevel@tonic-gate qenable(q);
7357c478bd9Sstevel@tonic-gate enableok(q);
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0);
7387c478bd9Sstevel@tonic-gate break;
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate * Set binary/normal mode for input and output
7427c478bd9Sstevel@tonic-gate * according to the instructions from the daemon.
7437c478bd9Sstevel@tonic-gate */
7447c478bd9Sstevel@tonic-gate case TEL_IOC_MODE:
7457c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uchar_t));
7467c478bd9Sstevel@tonic-gate if (error != 0) {
7477c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error);
7487c478bd9Sstevel@tonic-gate break;
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate tmip->flags |= *(mp->b_cont->b_rptr) &
7517c478bd9Sstevel@tonic-gate (TEL_BINARY_IN|TEL_BINARY_OUT);
7527c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0);
7537c478bd9Sstevel@tonic-gate break;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate #ifdef DEBUG
7567c478bd9Sstevel@tonic-gate case TCSETAF:
7577c478bd9Sstevel@tonic-gate case TCSETSF:
7587c478bd9Sstevel@tonic-gate case TCSETA:
7597c478bd9Sstevel@tonic-gate case TCSETAW:
7607c478bd9Sstevel@tonic-gate case TCSETS:
7617c478bd9Sstevel@tonic-gate case TCSETSW:
7627c478bd9Sstevel@tonic-gate case TCSBRK:
7637c478bd9Sstevel@tonic-gate case TIOCSTI:
7647c478bd9Sstevel@tonic-gate case TIOCSWINSZ:
7657c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
7667c478bd9Sstevel@tonic-gate break;
7677c478bd9Sstevel@tonic-gate #endif
7687c478bd9Sstevel@tonic-gate case CRYPTPASSTHRU:
7697c478bd9Sstevel@tonic-gate error = miocpullup(mp, sizeof (uchar_t));
7707c478bd9Sstevel@tonic-gate if (error != 0) {
7717c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, error);
7727c478bd9Sstevel@tonic-gate break;
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate if (*(mp->b_cont->b_rptr) == 0x01)
7757c478bd9Sstevel@tonic-gate tmip->flags |= TEL_IOCPASSTHRU;
7767c478bd9Sstevel@tonic-gate else
7777c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_IOCPASSTHRU;
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate miocack(q, mp, 0, 0);
7807c478bd9Sstevel@tonic-gate break;
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate default:
7837c478bd9Sstevel@tonic-gate if (tmip->flags & TEL_IOCPASSTHRU) {
7847c478bd9Sstevel@tonic-gate putnext(q, mp);
7857c478bd9Sstevel@tonic-gate } else {
7867c478bd9Sstevel@tonic-gate #ifdef DEBUG
7877c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
7887c478bd9Sstevel@tonic-gate "telmodwput: unexpected ioctl type 0x%x",
7897c478bd9Sstevel@tonic-gate ioc->ioc_cmd);
7907c478bd9Sstevel@tonic-gate #endif
7917c478bd9Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate break;
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate break;
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate case M_FLUSH:
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate * Flushing is tricky: We try to flush all we can, but certain
8007c478bd9Sstevel@tonic-gate * data cannot be flushed. Telnet protocol sequences cannot
8017c478bd9Sstevel@tonic-gate * be flushed. So, TCP's queues cannot be flushed since we
8027c478bd9Sstevel@tonic-gate * cannot tell what might be telnet protocol data. Then we
8037c478bd9Sstevel@tonic-gate * must take care to create and forward out-of-band data
8047c478bd9Sstevel@tonic-gate * indicating the flush to the far side.
8057c478bd9Sstevel@tonic-gate */
8067c478bd9Sstevel@tonic-gate rw = *mp->b_rptr;
8077c478bd9Sstevel@tonic-gate if (rw & FLUSHR) {
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate * We cannot flush our read queue, since there may
8107c478bd9Sstevel@tonic-gate * be telnet protocol bits in the queue, awaiting
8117c478bd9Sstevel@tonic-gate * processing. However, once it leaves this module
8127c478bd9Sstevel@tonic-gate * it's guaranteed that all protocol data is in
8137c478bd9Sstevel@tonic-gate * M_CTL, so we do flush read data beyond us, expecting
8147c478bd9Sstevel@tonic-gate * them (actually logindmux) to do FLUSHDATAs also.
8157c478bd9Sstevel@tonic-gate */
8167c478bd9Sstevel@tonic-gate *mp->b_rptr = rw & ~FLUSHW;
8177c478bd9Sstevel@tonic-gate qreply(q, mp);
8187c478bd9Sstevel@tonic-gate } else {
8197c478bd9Sstevel@tonic-gate freemsg(mp);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate if (rw & FLUSHW) {
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate * Since all telnet protocol data comes from the
8247c478bd9Sstevel@tonic-gate * daemon, stored as M_CTL messages, flushq will
8257c478bd9Sstevel@tonic-gate * do exactly what's needed: Flush bytes which do
8267c478bd9Sstevel@tonic-gate * not have telnet protocol data.
8277c478bd9Sstevel@tonic-gate */
8287c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate break;
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate case M_PCPROTO:
8337c478bd9Sstevel@tonic-gate putnext(q, mp);
8347c478bd9Sstevel@tonic-gate break;
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate case M_PROTO:
8377c478bd9Sstevel@tonic-gate /* We may receive T_DISCON_REQ from the mux */
8387c478bd9Sstevel@tonic-gate if (!canputnext(q) || q->q_first != NULL)
8397c478bd9Sstevel@tonic-gate (void) putq(q, mp);
8407c478bd9Sstevel@tonic-gate else
8417c478bd9Sstevel@tonic-gate putnext(q, mp);
8427c478bd9Sstevel@tonic-gate break;
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate default:
8457c478bd9Sstevel@tonic-gate #ifdef DEBUG
8467c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
8477c478bd9Sstevel@tonic-gate "telmodwput: unexpected msg type 0x%x",
8487c478bd9Sstevel@tonic-gate mp->b_datap->db_type);
8497c478bd9Sstevel@tonic-gate #endif
8507c478bd9Sstevel@tonic-gate freemsg(mp);
8517c478bd9Sstevel@tonic-gate break;
8527c478bd9Sstevel@tonic-gate }
853*c97b1070SToomas Soome return (0);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate
8567c478bd9Sstevel@tonic-gate /*
8577c478bd9Sstevel@tonic-gate * telmodwsrv - module write service procedure
8587c478bd9Sstevel@tonic-gate */
859*c97b1070SToomas Soome static int
telmodwsrv(queue_t * q)8607c478bd9Sstevel@tonic-gate telmodwsrv(queue_t *q)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate mblk_t *mp, *savemp;
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
8677c478bd9Sstevel@tonic-gate if (!canputnext(q)) {
8687c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_type < QPCTL);
8697c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
870*c97b1070SToomas Soome return (0);
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate case M_DATA:
8757c478bd9Sstevel@tonic-gate if (tmip->flags & TEL_STOPPED) {
8767c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
877*c97b1070SToomas Soome return (0);
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate /*
8807c478bd9Sstevel@tonic-gate * Insert a null character if carraige return
8817c478bd9Sstevel@tonic-gate * is not followed by line feed
8827c478bd9Sstevel@tonic-gate */
8837c478bd9Sstevel@tonic-gate if (!snd_parse(q, mp)) {
884*c97b1070SToomas Soome return (0);
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate break;
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate case M_CTL:
8897c478bd9Sstevel@tonic-gate if (((mp->b_wptr - mp->b_rptr) == 1) &&
8907c478bd9Sstevel@tonic-gate (*(mp->b_rptr) == M_CTL_MAGIC_NUMBER)) {
8917c478bd9Sstevel@tonic-gate savemp = mp->b_cont;
8927c478bd9Sstevel@tonic-gate freeb(mp);
8937c478bd9Sstevel@tonic-gate mp = savemp;
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate putnext(q, mp);
8967c478bd9Sstevel@tonic-gate break;
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate case M_PROTO:
8997c478bd9Sstevel@tonic-gate putnext(q, mp);
9007c478bd9Sstevel@tonic-gate break;
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate default:
9037c478bd9Sstevel@tonic-gate #ifdef DEBUG
9047c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
9057c478bd9Sstevel@tonic-gate "telmodwsrv: unexpected msg type 0x%x",
9067c478bd9Sstevel@tonic-gate mp->b_datap->db_type);
9077c478bd9Sstevel@tonic-gate #endif
9087c478bd9Sstevel@tonic-gate freemsg(mp);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate }
912*c97b1070SToomas Soome return (0);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /*
9167c478bd9Sstevel@tonic-gate * This routine is called from read put/service procedure and parses
9177c478bd9Sstevel@tonic-gate * message block to check for telnet protocol by detecting an IAC.
9187c478bd9Sstevel@tonic-gate * The routine processes the data part of the message block first and
9197c478bd9Sstevel@tonic-gate * then sends protocol followed after IAC to the telnet daemon. The
9207c478bd9Sstevel@tonic-gate * routine also processes CR/LF by eliminating LF/NULL followed after CR.
9217c478bd9Sstevel@tonic-gate *
9227c478bd9Sstevel@tonic-gate * Since the code to do this with streams mblks is complicated, some
9237c478bd9Sstevel@tonic-gate * explanations are in order. If an IAC is found, a dupb() is done,
9247c478bd9Sstevel@tonic-gate * and the pointers are adjusted to create two streams message. The
9257c478bd9Sstevel@tonic-gate * (possibly empty) first message contains preceeding data, and the
9267c478bd9Sstevel@tonic-gate * second begins with the IAC and contains the rest of the streams
9277c478bd9Sstevel@tonic-gate * message.
9287c478bd9Sstevel@tonic-gate *
9297c478bd9Sstevel@tonic-gate * The variables:
9307c478bd9Sstevel@tonic-gate * datamp: Points to the head of a chain of mblks containing data
9317c478bd9Sstevel@tonic-gate * which requires no expansion, and can be forwarded directly
9327c478bd9Sstevel@tonic-gate * to the pty.
9337c478bd9Sstevel@tonic-gate * prevmp: Points to the last mblk on the datamp chain, used to add
9347c478bd9Sstevel@tonic-gate * to the chain headed by datamp.
9357c478bd9Sstevel@tonic-gate * newmp: When an M_CTL header is required, this pointer references
9367c478bd9Sstevel@tonic-gate * that "header" mblk.
9377c478bd9Sstevel@tonic-gate * protomp: When an IAC is discovered, a dupb() is done on the first mblk
9387c478bd9Sstevel@tonic-gate * containing an IAC. protomp points to this dup'ed mblk.
9397c478bd9Sstevel@tonic-gate * This mblk is eventually forwarded to the daemon.
9407c478bd9Sstevel@tonic-gate */
9417c478bd9Sstevel@tonic-gate static int
rcv_parse(queue_t * q,mblk_t * mp)9427c478bd9Sstevel@tonic-gate rcv_parse(queue_t *q, mblk_t *mp)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate mblk_t *protomp, *newmp, *datamp, *prevmp;
9457c478bd9Sstevel@tonic-gate unsigned char *tmp;
9467c478bd9Sstevel@tonic-gate size_t msgsize;
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate datamp = mp;
9517c478bd9Sstevel@tonic-gate prevmp = protomp = 0;
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate while (mp) {
9547c478bd9Sstevel@tonic-gate /*
9557c478bd9Sstevel@tonic-gate * If the mblk is empty, just continue scanning.
9567c478bd9Sstevel@tonic-gate */
9577c478bd9Sstevel@tonic-gate if (mp->b_rptr == mp->b_wptr) {
9587c478bd9Sstevel@tonic-gate prevmp = mp;
9597c478bd9Sstevel@tonic-gate mp = mp->b_cont;
9607c478bd9Sstevel@tonic-gate continue;
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate /*
9637c478bd9Sstevel@tonic-gate * First check to see if we have received CR and are checking
9647c478bd9Sstevel@tonic-gate * for a following LF/NULL. If so, do what's necessary to
9657c478bd9Sstevel@tonic-gate * trim the LF/NULL. This case is for when the LF/NULL is
9667c478bd9Sstevel@tonic-gate * at the beginning of a subsequent mblk.
9677c478bd9Sstevel@tonic-gate */
9687c478bd9Sstevel@tonic-gate if (!(tmip->flags & TEL_BINARY_IN) &&
9697c478bd9Sstevel@tonic-gate (tmip->flags & TEL_CRRCV)) {
970c86160f0SToomas Soome if ((*mp->b_rptr == '\n') || (*mp->b_rptr == '\0')) {
9717c478bd9Sstevel@tonic-gate if (mp->b_wptr == (mp->b_rptr + 1)) {
9727c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_CRRCV;
9737c478bd9Sstevel@tonic-gate if (prevmp) {
9747c478bd9Sstevel@tonic-gate prevmp->b_cont = mp->b_cont;
9757c478bd9Sstevel@tonic-gate freeb(mp);
9767c478bd9Sstevel@tonic-gate mp = prevmp->b_cont;
9777c478bd9Sstevel@tonic-gate continue;
9787c478bd9Sstevel@tonic-gate } else {
9797c478bd9Sstevel@tonic-gate datamp = mp->b_cont;
9807c478bd9Sstevel@tonic-gate freeb(mp);
9817c478bd9Sstevel@tonic-gate if (datamp == NULL) {
9827c478bd9Sstevel@tonic-gate /*
9837c478bd9Sstevel@tonic-gate * Message contained
9847c478bd9Sstevel@tonic-gate * only a '\0' after
9857c478bd9Sstevel@tonic-gate * a '\r' in a previous
9867c478bd9Sstevel@tonic-gate * message, so we can
9877c478bd9Sstevel@tonic-gate * read more, even
9887c478bd9Sstevel@tonic-gate * though we have
9897c478bd9Sstevel@tonic-gate * nothing to putnext.
9907c478bd9Sstevel@tonic-gate */
9917c478bd9Sstevel@tonic-gate return (1);
9927c478bd9Sstevel@tonic-gate } else {
9937c478bd9Sstevel@tonic-gate mp = datamp;
9947c478bd9Sstevel@tonic-gate continue;
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate }
9987c478bd9Sstevel@tonic-gate mp->b_rptr += 1;
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_CRRCV;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate tmp = mp->b_rptr;
10037c478bd9Sstevel@tonic-gate /*
10047c478bd9Sstevel@tonic-gate * Now scan through the entire message block, for IACs
10057c478bd9Sstevel@tonic-gate * and CR characters, which need processing.
10067c478bd9Sstevel@tonic-gate */
10077c478bd9Sstevel@tonic-gate while (tmp < mp->b_wptr) {
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate if (tmp[0] == IAC) {
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate * Telnet protocol - parse it now
10127c478bd9Sstevel@tonic-gate * process data part of mblk
10137c478bd9Sstevel@tonic-gate * before sending the protocol.
10147c478bd9Sstevel@tonic-gate */
10157c478bd9Sstevel@tonic-gate if (tmp > mp->b_rptr) {
10167c478bd9Sstevel@tonic-gate if ((protomp = dupb(mp)) == NULL) {
10177c478bd9Sstevel@tonic-gate msgsize = msgdsize(datamp);
10187c478bd9Sstevel@tonic-gate recover(q, datamp, msgsize);
10197c478bd9Sstevel@tonic-gate return (0);
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate ASSERT(tmp >= mp->b_datap->db_base);
10227c478bd9Sstevel@tonic-gate ASSERT(tmp <= mp->b_datap->db_lim);
10237c478bd9Sstevel@tonic-gate ASSERT(tmp >=
10247c478bd9Sstevel@tonic-gate protomp->b_datap->db_base);
10257c478bd9Sstevel@tonic-gate ASSERT(tmp <= protomp->b_datap->db_lim);
10267c478bd9Sstevel@tonic-gate mp->b_wptr = tmp;
10277c478bd9Sstevel@tonic-gate protomp->b_rptr = tmp;
10287c478bd9Sstevel@tonic-gate protomp->b_cont = mp->b_cont;
10297c478bd9Sstevel@tonic-gate mp->b_cont = 0;
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate if (prevmp)
10327c478bd9Sstevel@tonic-gate prevmp->b_cont = mp;
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate } else {
10357c478bd9Sstevel@tonic-gate protomp = mp;
10367c478bd9Sstevel@tonic-gate
10377c478bd9Sstevel@tonic-gate if (prevmp)
10387c478bd9Sstevel@tonic-gate prevmp->b_cont = 0;
10397c478bd9Sstevel@tonic-gate else
10407c478bd9Sstevel@tonic-gate datamp = 0;
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate if (datamp) {
10437c478bd9Sstevel@tonic-gate putnext(q, datamp);
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate * create a 1 byte M_CTL message block with
10477c478bd9Sstevel@tonic-gate * protomp and send it down.
10487c478bd9Sstevel@tonic-gate */
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate if ((newmp = allocb(sizeof (char),
10517c478bd9Sstevel@tonic-gate BPRI_MED)) == NULL) {
10527c478bd9Sstevel@tonic-gate /*
10537c478bd9Sstevel@tonic-gate * Save the dup'ed mp containing
10547c478bd9Sstevel@tonic-gate * the protocol information which
10557c478bd9Sstevel@tonic-gate * we couldn't get an M_CTL header
10567c478bd9Sstevel@tonic-gate * for.
10577c478bd9Sstevel@tonic-gate */
10587c478bd9Sstevel@tonic-gate msgsize = msgdsize(protomp);
10597c478bd9Sstevel@tonic-gate recover(q, protomp, msgsize);
10607c478bd9Sstevel@tonic-gate return (0);
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_CTL;
10637c478bd9Sstevel@tonic-gate newmp->b_wptr = newmp->b_rptr + 1;
10647c478bd9Sstevel@tonic-gate *(newmp->b_rptr) = M_CTL_MAGIC_NUMBER;
10657c478bd9Sstevel@tonic-gate newmp->b_cont = protomp;
10667c478bd9Sstevel@tonic-gate noenable(q);
10677c478bd9Sstevel@tonic-gate tmip->flags |= TEL_STOPPED;
10687c478bd9Sstevel@tonic-gate putnext(q, newmp);
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate return (0);
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate if (!(tmip->flags & TEL_BINARY_IN)) {
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate * Set TEL_CRRCV flag if last character is CR
10757c478bd9Sstevel@tonic-gate */
10767c478bd9Sstevel@tonic-gate if ((tmp == (mp->b_wptr - 1)) &&
10777c478bd9Sstevel@tonic-gate (tmp[0] == '\r')) {
10787c478bd9Sstevel@tonic-gate tmip->flags |= TEL_CRRCV;
10797c478bd9Sstevel@tonic-gate break;
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate
10827c478bd9Sstevel@tonic-gate /*
10837c478bd9Sstevel@tonic-gate * If CR is followed by LF/NULL, get rid of
10847c478bd9Sstevel@tonic-gate * LF/NULL and realign the message block.
10857c478bd9Sstevel@tonic-gate */
10867c478bd9Sstevel@tonic-gate if ((tmp[0] == '\r') && ((tmp[1] == '\n') ||
1087c86160f0SToomas Soome (tmp[1] == '\0'))) {
10887c478bd9Sstevel@tonic-gate /*
10897c478bd9Sstevel@tonic-gate * If CR is in the middle of a block,
10907c478bd9Sstevel@tonic-gate * we need to get rid of LF and join
10917c478bd9Sstevel@tonic-gate * the two pieces together.
10927c478bd9Sstevel@tonic-gate */
10937c478bd9Sstevel@tonic-gate if (mp->b_wptr > (tmp + 2)) {
10947c478bd9Sstevel@tonic-gate bcopy(tmp + 2, tmp + 1,
10957c478bd9Sstevel@tonic-gate (mp->b_wptr - tmp - 2));
10967c478bd9Sstevel@tonic-gate mp->b_wptr -= 1;
10977c478bd9Sstevel@tonic-gate } else {
10987c478bd9Sstevel@tonic-gate mp->b_wptr = tmp + 1;
10997c478bd9Sstevel@tonic-gate }
11007c478bd9Sstevel@tonic-gate
11017c478bd9Sstevel@tonic-gate if (prevmp)
11027c478bd9Sstevel@tonic-gate prevmp->b_cont = mp;
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate tmp++;
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate prevmp = mp;
11087c478bd9Sstevel@tonic-gate mp = mp->b_cont;
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate putnext(q, datamp);
11117c478bd9Sstevel@tonic-gate
11127c478bd9Sstevel@tonic-gate return (1);
11137c478bd9Sstevel@tonic-gate }
11147c478bd9Sstevel@tonic-gate
11157c478bd9Sstevel@tonic-gate /*
11167c478bd9Sstevel@tonic-gate * This routine is called from write put/service procedures and processes
11177c478bd9Sstevel@tonic-gate * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are
11187c478bd9Sstevel@tonic-gate * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk.
11197c478bd9Sstevel@tonic-gate * This routine is pessimistic: It pre-allocates a buffer twice the size
11207c478bd9Sstevel@tonic-gate * of the incoming message, which is the maximum size a message can become
11217c478bd9Sstevel@tonic-gate * after IAC expansion.
11227c478bd9Sstevel@tonic-gate *
11237c478bd9Sstevel@tonic-gate * savemp: Points at the original message, so it can be freed when
11247c478bd9Sstevel@tonic-gate * processing is complete.
11257c478bd9Sstevel@tonic-gate * mp: The current point of scanning the message.
11267c478bd9Sstevel@tonic-gate * newmp: New message being created with the processed output.
11277c478bd9Sstevel@tonic-gate */
11287c478bd9Sstevel@tonic-gate static int
snd_parse(queue_t * q,mblk_t * mp)11297c478bd9Sstevel@tonic-gate snd_parse(queue_t *q, mblk_t *mp)
11307c478bd9Sstevel@tonic-gate {
11317c478bd9Sstevel@tonic-gate unsigned char *tmp, *tmp1;
11327c478bd9Sstevel@tonic-gate mblk_t *newmp, *savemp;
11337c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
11347c478bd9Sstevel@tonic-gate size_t size = msgdsize(mp);
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate savemp = mp;
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate if (size == 0) {
11397c478bd9Sstevel@tonic-gate putnext(q, mp);
11407c478bd9Sstevel@tonic-gate return (1);
11417c478bd9Sstevel@tonic-gate }
11427c478bd9Sstevel@tonic-gate
11437c478bd9Sstevel@tonic-gate /*
11447c478bd9Sstevel@tonic-gate * Extra byte to allocb() takes care of the case when there was
11457c478bd9Sstevel@tonic-gate * a '\r' at the end of the previous message and there's a '\r'
11467c478bd9Sstevel@tonic-gate * at the beginning of the current message.
11477c478bd9Sstevel@tonic-gate */
11487c478bd9Sstevel@tonic-gate if ((newmp = allocb((2 * size)+1, BPRI_MED)) == NULL) {
11497c478bd9Sstevel@tonic-gate recover(q, mp, (2 * size)+1);
11507c478bd9Sstevel@tonic-gate return (0);
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_DATA;
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate tmp1 = newmp->b_rptr;
11557c478bd9Sstevel@tonic-gate while (mp) {
11567c478bd9Sstevel@tonic-gate if (!(tmip->flags & TEL_BINARY_OUT) &&
11577c478bd9Sstevel@tonic-gate (tmip->flags & TEL_CRSND)) {
11587c478bd9Sstevel@tonic-gate if (*(mp->b_rptr) != '\n')
1159c86160f0SToomas Soome *tmp1++ = '\0';
11607c478bd9Sstevel@tonic-gate tmip->flags &= ~TEL_CRSND;
11617c478bd9Sstevel@tonic-gate }
11627c478bd9Sstevel@tonic-gate tmp = mp->b_rptr;
11637c478bd9Sstevel@tonic-gate while (tmp < mp->b_wptr) {
11647c478bd9Sstevel@tonic-gate if (!(tmip->flags & TEL_BINARY_OUT)) {
11657c478bd9Sstevel@tonic-gate *tmp1++ = *tmp;
11667c478bd9Sstevel@tonic-gate if ((tmp == (mp->b_wptr - 1)) &&
11677c478bd9Sstevel@tonic-gate (tmp[0] == '\r')) {
11687c478bd9Sstevel@tonic-gate tmip->flags |= TEL_CRSND;
11697c478bd9Sstevel@tonic-gate break;
11707c478bd9Sstevel@tonic-gate }
11717c478bd9Sstevel@tonic-gate if ((tmp[0] == '\r') &&
11727c478bd9Sstevel@tonic-gate (tmp1 == newmp->b_wptr)) {
11737c478bd9Sstevel@tonic-gate /* XXX.sparker: can't happen */
11747c478bd9Sstevel@tonic-gate tmip->flags |= TEL_CRSND;
11757c478bd9Sstevel@tonic-gate break;
11767c478bd9Sstevel@tonic-gate }
11777c478bd9Sstevel@tonic-gate if ((tmp[0] == '\r') && (tmp[1] != '\n')) {
1178c86160f0SToomas Soome *tmp1++ = '\0';
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate } else
11817c478bd9Sstevel@tonic-gate *tmp1++ = *tmp;
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate if (tmp[0] == IAC) {
11847c478bd9Sstevel@tonic-gate *tmp1++ = IAC;
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate tmp++;
11877c478bd9Sstevel@tonic-gate }
11887c478bd9Sstevel@tonic-gate mp = mp->b_cont;
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate newmp->b_wptr = tmp1;
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate putnext(q, newmp);
11947c478bd9Sstevel@tonic-gate freemsg(savemp);
11957c478bd9Sstevel@tonic-gate return (1);
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate static void
telmod_timer(void * arg)11997c478bd9Sstevel@tonic-gate telmod_timer(void *arg)
12007c478bd9Sstevel@tonic-gate {
12017c478bd9Sstevel@tonic-gate queue_t *q = arg;
12027c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate ASSERT(tmip);
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) {
12077c478bd9Sstevel@tonic-gate ASSERT(tmip->rtimoutid);
12087c478bd9Sstevel@tonic-gate tmip->rtimoutid = 0;
12097c478bd9Sstevel@tonic-gate } else {
12107c478bd9Sstevel@tonic-gate ASSERT(tmip->wtimoutid);
12117c478bd9Sstevel@tonic-gate tmip->wtimoutid = 0;
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate enableok(q);
12147c478bd9Sstevel@tonic-gate qenable(q);
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate
12177c478bd9Sstevel@tonic-gate static void
telmod_buffer(void * arg)12187c478bd9Sstevel@tonic-gate telmod_buffer(void *arg)
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate queue_t *q = arg;
12217c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate ASSERT(tmip);
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) {
12267c478bd9Sstevel@tonic-gate ASSERT(tmip->rbufcid);
12277c478bd9Sstevel@tonic-gate tmip->rbufcid = 0;
12287c478bd9Sstevel@tonic-gate } else {
12297c478bd9Sstevel@tonic-gate ASSERT(tmip->wbufcid);
12307c478bd9Sstevel@tonic-gate tmip->wbufcid = 0;
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate enableok(q);
12337c478bd9Sstevel@tonic-gate qenable(q);
12347c478bd9Sstevel@tonic-gate }
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate static void
recover(queue_t * q,mblk_t * mp,size_t size)12377c478bd9Sstevel@tonic-gate recover(queue_t *q, mblk_t *mp, size_t size)
12387c478bd9Sstevel@tonic-gate {
12397c478bd9Sstevel@tonic-gate bufcall_id_t bid;
12407c478bd9Sstevel@tonic-gate timeout_id_t tid;
12417c478bd9Sstevel@tonic-gate struct telmod_info *tmip = (struct telmod_info *)q->q_ptr;
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_type < QPCTL);
12447c478bd9Sstevel@tonic-gate noenable(q);
12457c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate /*
12487c478bd9Sstevel@tonic-gate * Make sure there is at most one outstanding request per queue.
12497c478bd9Sstevel@tonic-gate */
12507c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR) {
12517c478bd9Sstevel@tonic-gate if (tmip->rtimoutid || tmip->rbufcid) {
12527c478bd9Sstevel@tonic-gate return;
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate } else {
12557c478bd9Sstevel@tonic-gate if (tmip->wtimoutid || tmip->wbufcid) {
12567c478bd9Sstevel@tonic-gate return;
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate if (!(bid = qbufcall(RD(q), size, BPRI_MED, telmod_buffer, q))) {
12607c478bd9Sstevel@tonic-gate tid = qtimeout(RD(q), telmod_timer, q, SIMWAIT);
12617c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR)
12627c478bd9Sstevel@tonic-gate tmip->rtimoutid = tid;
12637c478bd9Sstevel@tonic-gate else
12647c478bd9Sstevel@tonic-gate tmip->wtimoutid = tid;
12657c478bd9Sstevel@tonic-gate } else {
12667c478bd9Sstevel@tonic-gate if (q->q_flag & QREADR)
12677c478bd9Sstevel@tonic-gate tmip->rbufcid = bid;
12687c478bd9Sstevel@tonic-gate else
12697c478bd9Sstevel@tonic-gate tmip->wbufcid = bid;
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate }
1272