4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This module implements the "fast path" processing for the telnet protocol.
31 * Since it only knows a very small number of the telnet protocol options,
32 * the daemon is required to assist this module. This module must be run
33 * underneath logindmux, which handles switching messages between the
34 * daemon and the pty master stream appropriately. When an unknown telnet
35 * option is received it is handled as a stop-and-wait operation. The
36 * module refuses to forward data in either direction, and waits for the
37 * daemon to deal with the option, and forward any unprocessed data back
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/stream.h>
44 #include <sys/stropts.h>
45 #include <sys/strsun.h>
47 #include <sys/errno.h>
49 #include <sys/sunddi.h>
50 #include <sys/tihdr.h>
52 #include <sys/logindmux.h>
53 #include <sys/telioctl.h>
54 #include <sys/termios.h>
55 #include <sys/debug.h>
57 #include <sys/modctl.h>
58 #include <sys/cmn_err.h>
59 #include <sys/cryptmod.h>
63 extern struct streamtab telmodinfo
;
66 #define SIMWAIT (1*hz)
71 #define TEL_IOCPASSTHRU 0x100
72 #define TEL_STOPPED 0x80
73 #define TEL_CRRCV 0x40
74 #define TEL_CRSND 0x20
75 #define TEL_GETBLK 0x10
78 * NOTE: values TEL_BINARY_IN and TEL_BINARY_OUT are defined in
79 * telioctl.h, passed in the TEL_IOC_MODE ioctl and stored (bitwise)
80 * in the module state flag. So those values are not available
81 * even though they are not defined here.
87 * Per queue instances are single-threaded since the q_ptr
88 * field of queues need to be shared among threads.
90 static struct fmodsw fsw
= {
97 * Module linkage information for the kernel.
100 static struct modlstrmod modlstrmod
= {
106 static struct modlinkage modlinkage
= {
107 MODREV_1
, &modlstrmod
, NULL
113 return (mod_install(&modlinkage
));
119 return (mod_remove(&modlinkage
));
123 _info(struct modinfo
*modinfop
)
125 return (mod_info(&modlinkage
, modinfop
));
128 static int telmodopen(queue_t
*, dev_t
*, int, int, cred_t
*);
129 static int telmodclose(queue_t
*, int, cred_t
*);
130 static void telmodrput(queue_t
*, mblk_t
*);
131 static void telmodrsrv(queue_t
*);
132 static void telmodwput(queue_t
*, mblk_t
*);
133 static void telmodwsrv(queue_t
*);
134 static int rcv_parse(queue_t
*q
, mblk_t
*mp
);
135 static int snd_parse(queue_t
*q
, mblk_t
*mp
);
136 static void telmod_timer(void *);
137 static void telmod_buffer(void *);
138 static void recover(queue_t
*, mblk_t
*, size_t);
140 static struct module_info telmodoinfo
= {
141 TELMOD_ID
, /* module id number */
142 "telmod", /* module name */
143 0, /* minimum packet size */
144 INFPSZ
, /* maximum packet size */
145 512, /* hi-water mark */
146 256 /* lo-water mark */
149 static struct qinit telmodrinit
= {
150 (int (*)())telmodrput
,
151 (int (*)())telmodrsrv
,
159 static struct qinit telmodwinit
= {
160 (int (*)())telmodwput
,
161 (int (*)())telmodwsrv
,
169 struct streamtab telmodinfo
= {
177 * Per-instance state struct for the telnet module.
181 bufcall_id_t wbufcid
;
182 bufcall_id_t rbufcid
;
183 timeout_id_t wtimoutid
;
184 timeout_id_t rtimoutid
;
191 dummy_callback(void *arg
)
196 * A variety of telnet options can never really be processed in the
197 * kernel. For example, TELOPT_TTYPE, must be based in the TERM
198 * environment variable to the login process. Also, data may already
199 * have reached the stream head before telmod was pushed on the stream.
200 * So when telmod is opened, it begins in stopped state, preventing
201 * further data passing either direction through it. It sends a
202 * T_DATA_REQ messages up toward the daemon. This is so the daemon
203 * can be sure that all data which was not processed by telmod
204 * (because it wasn't yet pushed) has been received at the stream head.
208 telmodopen(queue_t
*q
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*credp
)
210 struct telmod_info
*tmip
;
212 union T_primitives
*tp
;
215 if (sflag
!= MODOPEN
)
218 if (q
->q_ptr
!= NULL
) {
219 /* It's already attached. */
223 * Allocate state structure.
225 tmip
= kmem_zalloc(sizeof (*tmip
), KM_SLEEP
);
234 tmip
->flags
|= TEL_STOPPED
;
238 * Since TCP operates in the TLI-inspired brain-dead fashion,
239 * the connection will revert to bound state if the connection
240 * is reset by the client. We must send a T_UNBIND_REQ in
241 * that case so the port doesn't get "wedged" (preventing
242 * inetd from being able to restart the listener). Allocate
243 * it here, so that we don't need to worry about allocb()
246 while ((tmip
->unbind_mp
= allocb(sizeof (union T_primitives
),
248 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
249 BPRI_HI
, dummy_callback
, NULL
);
257 tmip
->unbind_mp
->b_wptr
= tmip
->unbind_mp
->b_rptr
+
258 sizeof (struct T_unbind_req
);
259 tmip
->unbind_mp
->b_datap
->db_type
= M_PROTO
;
260 tp
= (union T_primitives
*)tmip
->unbind_mp
->b_rptr
;
261 tp
->type
= T_UNBIND_REQ
;
263 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
264 * read queue since only write queue can get T_DATA_REQ).
265 * Readstream routine in telnet daemon will do a getmsg() till
266 * it receives this proto message
268 while ((bp
= allocb(sizeof (union T_primitives
), BPRI_HI
)) == NULL
) {
269 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
270 BPRI_HI
, dummy_callback
, NULL
);
278 bp
->b_datap
->db_type
= M_PROTO
;
279 bp
->b_wptr
= bp
->b_rptr
+ sizeof (union T_primitives
);
280 tp
= (union T_primitives
*)bp
->b_rptr
;
281 tp
->type
= T_DATA_REQ
;
282 tp
->data_req
.MORE_flag
= 0;
289 if (tmip
->unbind_mp
!= NULL
) {
290 freemsg(tmip
->unbind_mp
);
292 kmem_free(tmip
, sizeof (struct telmod_info
));
300 * telmodclose - just the normal streams clean-up is required.
305 telmodclose(queue_t
*q
, int flag
, cred_t
*credp
)
307 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
311 * Flush any write-side data downstream. Ignoring flow
312 * control at this point is known to be safe because the
313 * M_HANGUP below poisons the stream such that no modules can
316 while (mp
= getq(WR(q
)))
319 /* Poison the stream head so that we can't be pushed again. */
320 (void) putnextctl(q
, M_HANGUP
);
324 qunbufcall(q
, tmip
->wbufcid
);
328 qunbufcall(q
, tmip
->rbufcid
);
331 if (tmip
->wtimoutid
) {
332 (void) quntimeout(q
, tmip
->wtimoutid
);
335 if (tmip
->rtimoutid
) {
336 (void) quntimeout(q
, tmip
->rtimoutid
);
339 if (tmip
->unbind_mp
!= NULL
) {
340 freemsg(tmip
->unbind_mp
);
343 kmem_free(q
->q_ptr
, sizeof (struct telmod_info
));
344 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
350 * Be sure to preserve data order. If the daemon is waiting for additional
351 * data (TEL_GETBLK state) forward new data. Otherwise, apply normal
352 * telnet protocol processing to M_DATA. Take notice of TLI messages
353 * indicating connection tear-down, and change them into M_HANGUP's.
356 telmodrput(queue_t
*q
, mblk_t
*mp
)
359 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
360 union T_primitives
*tip
;
362 if ((mp
->b_datap
->db_type
< QPCTL
) &&
363 ((q
->q_first
) || ((tmip
->flags
& TEL_STOPPED
) &&
364 !(tmip
->flags
& TEL_GETBLK
)) || !canputnext(q
))) {
369 switch (mp
->b_datap
->db_type
) {
373 * If the user level daemon requests for 1 more
374 * block of data (needs more data for protocol processing)
375 * create a M_CTL message block with the mp.
378 if (tmip
->flags
& TEL_GETBLK
) {
379 if ((newmp
= allocb(sizeof (char), BPRI_MED
)) == NULL
) {
380 recover(q
, mp
, msgdsize(mp
));
383 newmp
->b_datap
->db_type
= M_CTL
;
384 newmp
->b_wptr
= newmp
->b_rptr
+ 1;
385 *(newmp
->b_rptr
) = M_CTL_MAGIC_NUMBER
;
387 tmip
->flags
&= ~TEL_GETBLK
;
389 tmip
->flags
|= TEL_STOPPED
;
396 * call the protocol parsing routine which processes
397 * the data part of the message block first. Then it
398 * handles protocol and CR/LF processing.
399 * If an error is found inside allocb/dupb, recover
400 * routines inside rcv_parse will queue up the
401 * original message block in its service queue.
403 (void) rcv_parse(q
, mp
);
408 * Since M_FLUSH came from TCP, we mark it bound for
409 * daemon, not tty. This only happens when TCP expects
410 * to do a connection reset.
412 mp
->b_flag
|= MSGMARK
;
413 if (*mp
->b_rptr
& FLUSHR
)
420 if (tmip
->flags
& TEL_GETBLK
)
421 tmip
->flags
&= ~TEL_GETBLK
;
431 if (tmip
->flags
& TEL_GETBLK
)
432 tmip
->flags
&= ~TEL_GETBLK
;
434 tip
= (union T_primitives
*)mp
->b_rptr
;
439 /* Make into M_HANGUP and putnext */
440 ASSERT(mp
->b_cont
== NULL
);
441 mp
->b_datap
->db_type
= M_HANGUP
;
442 mp
->b_wptr
= mp
->b_rptr
;
448 * If we haven't already, send T_UNBIND_REQ to prevent
449 * TCP from going into "BOUND" state and locking up the
452 if (tip
->type
== T_DISCON_IND
&& tmip
->unbind_mp
!=
455 qreply(q
, tmip
->unbind_mp
);
456 tmip
->unbind_mp
= NULL
;
463 case T_DATA_IND
: /* conform to TPI, but never happens */
468 ASSERT(mp
->b_datap
->db_type
== M_DATA
);
469 if (msgdsize(mp
) != 0) {
477 * We only get T_OK_ACK when we issue the unbind, and it can
481 ASSERT(tmip
->unbind_mp
== NULL
);
488 "telmodrput: unexpected TLI primitive msg "
489 "type 0x%x", tip
->type
);
498 "telmodrput: unexpected msg type 0x%x",
499 mp
->b_datap
->db_type
);
507 * Mostly we end up here because of M_DATA processing delayed due to flow
508 * control or lack of memory. XXX.sparker: TLI primitives here?
511 telmodrsrv(queue_t
*q
)
514 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
515 union T_primitives
*tip
;
517 while ((mp
= getq(q
)) != NULL
) {
518 if (((tmip
->flags
& TEL_STOPPED
) &&
519 !(tmip
->flags
& TEL_GETBLK
)) || !canputnext(q
)) {
523 switch (mp
->b_datap
->db_type
) {
527 if (tmip
->flags
& TEL_GETBLK
) {
528 if ((newmp
= allocb(sizeof (char),
529 BPRI_MED
)) == NULL
) {
530 recover(q
, mp
, msgdsize(mp
));
533 newmp
->b_datap
->db_type
= M_CTL
;
534 newmp
->b_wptr
= newmp
->b_rptr
+ 1;
535 *(newmp
->b_rptr
) = M_CTL_MAGIC_NUMBER
;
537 tmip
->flags
&= ~TEL_GETBLK
;
539 tmip
->flags
|= TEL_STOPPED
;
545 if (!rcv_parse(q
, mp
)) {
552 tip
= (union T_primitives
*)mp
->b_rptr
;
555 * Unless the M_PROTO message indicates data, clear
556 * TEL_GETBLK so that we stop passing our messages
557 * up to the telnet daemon.
559 if (tip
->type
!= T_DATA_IND
&&
560 tip
->type
!= T_EXDATA_IND
)
561 tmip
->flags
&= ~TEL_GETBLK
;
566 /* Make into M_HANGUP and putnext */
567 ASSERT(mp
->b_cont
== NULL
);
568 mp
->b_datap
->db_type
= M_HANGUP
;
569 mp
->b_wptr
= mp
->b_rptr
;
575 * If we haven't already, send T_UNBIND_REQ
576 * to prevent TCP from going into "BOUND"
577 * state and locking up the port.
579 if (tip
->type
== T_DISCON_IND
&&
580 tmip
->unbind_mp
!= NULL
) {
582 qreply(q
, tmip
->unbind_mp
);
583 tmip
->unbind_mp
= NULL
;
589 case T_DATA_IND
: /* conform to TPI, but never happens */
595 ASSERT(mp
->b_datap
->db_type
== M_DATA
);
596 if (msgdsize(mp
) != 0) {
604 * We only get T_OK_ACK when we issue the unbind, and
605 * it can be ignored safely.
608 ASSERT(tmip
->unbind_mp
== NULL
);
615 "telmodrsrv: unexpected TLI primitive "
616 "msg type 0x%x", tip
->type
);
629 "telmodrsrv: unexpected msg type 0x%x",
630 mp
->b_datap
->db_type
);
639 * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon
640 * to process something. M_CTL's are data from the daemon bound for the
641 * network. We forward them immediately. There are two classes of ioctl's
642 * we must handle here also. One is ioctl's forwarded by ptem which we
643 * ignore. The other is ioctl's issued by the daemon to control us.
644 * Process them appropriately. M_PROTO's we pass along, figuring they are
645 * are TPI operations for TCP. M_FLUSH requires careful processing, since
646 * telnet cannot tolerate flushing its protocol requests. Also the flushes
647 * can be running either daemon<->TCP or application<->telmod. We must
648 * carefully deal with this.
652 queue_t
*q
, /* Pointer to the read queue */
653 mblk_t
*mp
) /* Pointer to current message block */
655 struct telmod_info
*tmip
;
661 tmip
= (struct telmod_info
*)q
->q_ptr
;
663 switch (mp
->b_datap
->db_type
) {
665 if (!canputnext(q
) || (tmip
->flags
& TEL_STOPPED
) ||
672 * This routine parses data generating from ptm side.
673 * Insert a null character if carraige return
674 * is not followed by line feed unless we are in binary mode.
675 * Also, duplicate IAC if found in the data.
677 (void) snd_parse(q
, mp
);
681 if (((mp
->b_wptr
- mp
->b_rptr
) == 1) &&
682 (*(mp
->b_rptr
) == M_CTL_MAGIC_NUMBER
)) {
691 ioc
= (struct iocblk
*)mp
->b_rptr
;
692 switch (ioc
->ioc_cmd
) {
695 * This ioctl is issued by user level daemon to
696 * request one more message block to process protocol
699 if (!(tmip
->flags
& TEL_STOPPED
)) {
700 miocnak(q
, mp
, 0, EINVAL
);
703 tmip
->flags
|= TEL_GETBLK
;
707 miocack(q
, mp
, 0, 0);
711 * This ioctl is issued by user level daemon to reenable the
712 * read and write queues. This is issued during startup time
713 * after setting up the mux links and also after processing
714 * the protocol. It is also issued after each time an
715 * an unrecognized telnet option is forwarded to the daemon.
720 * Send negative ack if TEL_STOPPED flag is not set
722 if (!(tmip
->flags
& TEL_STOPPED
)) {
723 miocnak(q
, mp
, 0, EINVAL
);
726 tmip
->flags
&= ~TEL_STOPPED
;
728 (void) putbq(RD(q
), mp
->b_cont
);
737 miocack(q
, mp
, 0, 0);
741 * Set binary/normal mode for input and output
742 * according to the instructions from the daemon.
745 error
= miocpullup(mp
, sizeof (uchar_t
));
747 miocnak(q
, mp
, 0, error
);
750 tmip
->flags
|= *(mp
->b_cont
->b_rptr
) &
751 (TEL_BINARY_IN
|TEL_BINARY_OUT
);
752 miocack(q
, mp
, 0, 0);
765 miocnak(q
, mp
, 0, EINVAL
);
769 error
= miocpullup(mp
, sizeof (uchar_t
));
771 miocnak(q
, mp
, 0, error
);
774 if (*(mp
->b_cont
->b_rptr
) == 0x01)
775 tmip
->flags
|= TEL_IOCPASSTHRU
;
777 tmip
->flags
&= ~TEL_IOCPASSTHRU
;
779 miocack(q
, mp
, 0, 0);
783 if (tmip
->flags
& TEL_IOCPASSTHRU
) {
788 "telmodwput: unexpected ioctl type 0x%x",
791 miocnak(q
, mp
, 0, EINVAL
);
799 * Flushing is tricky: We try to flush all we can, but certain
800 * data cannot be flushed. Telnet protocol sequences cannot
801 * be flushed. So, TCP's queues cannot be flushed since we
802 * cannot tell what might be telnet protocol data. Then we
803 * must take care to create and forward out-of-band data
804 * indicating the flush to the far side.
809 * We cannot flush our read queue, since there may
810 * be telnet protocol bits in the queue, awaiting
811 * processing. However, once it leaves this module
812 * it's guaranteed that all protocol data is in
813 * M_CTL, so we do flush read data beyond us, expecting
814 * them (actually logindmux) to do FLUSHDATAs also.
816 *mp
->b_rptr
= rw
& ~FLUSHW
;
823 * Since all telnet protocol data comes from the
824 * daemon, stored as M_CTL messages, flushq will
825 * do exactly what's needed: Flush bytes which do
826 * not have telnet protocol data.
828 flushq(q
, FLUSHDATA
);
837 /* We may receive T_DISCON_REQ from the mux */
838 if (!canputnext(q
) || q
->q_first
!= NULL
)
847 "telmodwput: unexpected msg type 0x%x",
848 mp
->b_datap
->db_type
);
856 * telmodwsrv - module write service procedure
859 telmodwsrv(queue_t
*q
)
863 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
865 while ((mp
= getq(q
)) != NULL
) {
866 if (!canputnext(q
)) {
867 ASSERT(mp
->b_datap
->db_type
< QPCTL
);
871 switch (mp
->b_datap
->db_type
) {
874 if (tmip
->flags
& TEL_STOPPED
) {
879 * Insert a null character if carraige return
880 * is not followed by line feed
882 if (!snd_parse(q
, mp
)) {
888 if (((mp
->b_wptr
- mp
->b_rptr
) == 1) &&
889 (*(mp
->b_rptr
) == M_CTL_MAGIC_NUMBER
)) {
904 "telmodwsrv: unexpected msg type 0x%x",
905 mp
->b_datap
->db_type
);
914 * This routine is called from read put/service procedure and parses
915 * message block to check for telnet protocol by detecting an IAC.
916 * The routine processes the data part of the message block first and
917 * then sends protocol followed after IAC to the telnet daemon. The
918 * routine also processes CR/LF by eliminating LF/NULL followed after CR.
920 * Since the code to do this with streams mblks is complicated, some
921 * explanations are in order. If an IAC is found, a dupb() is done,
922 * and the pointers are adjusted to create two streams message. The
923 * (possibly empty) first message contains preceeding data, and the
924 * second begins with the IAC and contains the rest of the streams
928 * datamp: Points to the head of a chain of mblks containing data
929 * which requires no expansion, and can be forwarded directly
931 * prevmp: Points to the last mblk on the datamp chain, used to add
932 * to the chain headed by datamp.
933 * newmp: When an M_CTL header is required, this pointer references
934 * that "header" mblk.
935 * protomp: When an IAC is discovered, a dupb() is done on the first mblk
936 * containing an IAC. protomp points to this dup'ed mblk.
937 * This mblk is eventually forwarded to the daemon.
940 rcv_parse(queue_t
*q
, mblk_t
*mp
)
942 mblk_t
*protomp
, *newmp
, *datamp
, *prevmp
;
946 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
949 prevmp
= protomp
= 0;
953 * If the mblk is empty, just continue scanning.
955 if (mp
->b_rptr
== mp
->b_wptr
) {
961 * First check to see if we have received CR and are checking
962 * for a following LF/NULL. If so, do what's necessary to
963 * trim the LF/NULL. This case is for when the LF/NULL is
964 * at the beginning of a subsequent mblk.
966 if (!(tmip
->flags
& TEL_BINARY_IN
) &&
967 (tmip
->flags
& TEL_CRRCV
)) {
968 if ((*mp
->b_rptr
== '\n') || (*mp
->b_rptr
== NULL
)) {
969 if (mp
->b_wptr
== (mp
->b_rptr
+ 1)) {
970 tmip
->flags
&= ~TEL_CRRCV
;
972 prevmp
->b_cont
= mp
->b_cont
;
979 if (datamp
== NULL
) {
983 * a '\r' in a previous
987 * nothing to putnext.
998 tmip
->flags
&= ~TEL_CRRCV
;
1002 * Now scan through the entire message block, for IACs
1003 * and CR characters, which need processing.
1005 while (tmp
< mp
->b_wptr
) {
1007 if (tmp
[0] == IAC
) {
1009 * Telnet protocol - parse it now
1010 * process data part of mblk
1011 * before sending the protocol.
1013 if (tmp
> mp
->b_rptr
) {
1014 if ((protomp
= dupb(mp
)) == NULL
) {
1015 msgsize
= msgdsize(datamp
);
1016 recover(q
, datamp
, msgsize
);
1019 ASSERT(tmp
>= mp
->b_datap
->db_base
);
1020 ASSERT(tmp
<= mp
->b_datap
->db_lim
);
1022 protomp
->b_datap
->db_base
);
1023 ASSERT(tmp
<= protomp
->b_datap
->db_lim
);
1025 protomp
->b_rptr
= tmp
;
1026 protomp
->b_cont
= mp
->b_cont
;
1030 prevmp
->b_cont
= mp
;
1044 * create a 1 byte M_CTL message block with
1045 * protomp and send it down.
1048 if ((newmp
= allocb(sizeof (char),
1049 BPRI_MED
)) == NULL
) {
1051 * Save the dup'ed mp containing
1052 * the protocol information which
1053 * we couldn't get an M_CTL header
1056 msgsize
= msgdsize(protomp
);
1057 recover(q
, protomp
, msgsize
);
1060 newmp
->b_datap
->db_type
= M_CTL
;
1061 newmp
->b_wptr
= newmp
->b_rptr
+ 1;
1062 *(newmp
->b_rptr
) = M_CTL_MAGIC_NUMBER
;
1063 newmp
->b_cont
= protomp
;
1065 tmip
->flags
|= TEL_STOPPED
;
1070 if (!(tmip
->flags
& TEL_BINARY_IN
)) {
1072 * Set TEL_CRRCV flag if last character is CR
1074 if ((tmp
== (mp
->b_wptr
- 1)) &&
1076 tmip
->flags
|= TEL_CRRCV
;
1081 * If CR is followed by LF/NULL, get rid of
1082 * LF/NULL and realign the message block.
1084 if ((tmp
[0] == '\r') && ((tmp
[1] == '\n') ||
1085 (tmp
[1] == NULL
))) {
1087 * If CR is in the middle of a block,
1088 * we need to get rid of LF and join
1089 * the two pieces together.
1091 if (mp
->b_wptr
> (tmp
+ 2)) {
1092 bcopy(tmp
+ 2, tmp
+ 1,
1093 (mp
->b_wptr
- tmp
- 2));
1096 mp
->b_wptr
= tmp
+ 1;
1100 prevmp
->b_cont
= mp
;
1114 * This routine is called from write put/service procedures and processes
1115 * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are
1116 * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk.
1117 * This routine is pessimistic: It pre-allocates a buffer twice the size
1118 * of the incoming message, which is the maximum size a message can become
1119 * after IAC expansion.
1121 * savemp: Points at the original message, so it can be freed when
1122 * processing is complete.
1123 * mp: The current point of scanning the message.
1124 * newmp: New message being created with the processed output.
1127 snd_parse(queue_t
*q
, mblk_t
*mp
)
1129 unsigned char *tmp
, *tmp1
;
1130 mblk_t
*newmp
, *savemp
;
1131 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1132 size_t size
= msgdsize(mp
);
1142 * Extra byte to allocb() takes care of the case when there was
1143 * a '\r' at the end of the previous message and there's a '\r'
1144 * at the beginning of the current message.
1146 if ((newmp
= allocb((2 * size
)+1, BPRI_MED
)) == NULL
) {
1147 recover(q
, mp
, (2 * size
)+1);
1150 newmp
->b_datap
->db_type
= M_DATA
;
1152 tmp1
= newmp
->b_rptr
;
1154 if (!(tmip
->flags
& TEL_BINARY_OUT
) &&
1155 (tmip
->flags
& TEL_CRSND
)) {
1156 if (*(mp
->b_rptr
) != '\n')
1158 tmip
->flags
&= ~TEL_CRSND
;
1161 while (tmp
< mp
->b_wptr
) {
1162 if (!(tmip
->flags
& TEL_BINARY_OUT
)) {
1164 if ((tmp
== (mp
->b_wptr
- 1)) &&
1166 tmip
->flags
|= TEL_CRSND
;
1169 if ((tmp
[0] == '\r') &&
1170 (tmp1
== newmp
->b_wptr
)) {
1171 /* XXX.sparker: can't happen */
1172 tmip
->flags
|= TEL_CRSND
;
1175 if ((tmp
[0] == '\r') && (tmp
[1] != '\n')) {
1181 if (tmp
[0] == IAC
) {
1189 newmp
->b_wptr
= tmp1
;
1197 telmod_timer(void *arg
)
1200 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1204 if (q
->q_flag
& QREADR
) {
1205 ASSERT(tmip
->rtimoutid
);
1206 tmip
->rtimoutid
= 0;
1208 ASSERT(tmip
->wtimoutid
);
1209 tmip
->wtimoutid
= 0;
1216 telmod_buffer(void *arg
)
1219 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1223 if (q
->q_flag
& QREADR
) {
1224 ASSERT(tmip
->rbufcid
);
1227 ASSERT(tmip
->wbufcid
);
1235 recover(queue_t
*q
, mblk_t
*mp
, size_t size
)
1239 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1241 ASSERT(mp
->b_datap
->db_type
< QPCTL
);
1243 (void) putbq(q
, mp
);
1246 * Make sure there is at most one outstanding request per queue.
1248 if (q
->q_flag
& QREADR
) {
1249 if (tmip
->rtimoutid
|| tmip
->rbufcid
) {
1253 if (tmip
->wtimoutid
|| tmip
->wbufcid
) {
1257 if (!(bid
= qbufcall(RD(q
), size
, BPRI_MED
, telmod_buffer
, q
))) {
1258 tid
= qtimeout(RD(q
), telmod_timer
, q
, SIMWAIT
);
1259 if (q
->q_flag
& QREADR
)
1260 tmip
->rtimoutid
= tid
;
1262 tmip
->wtimoutid
= tid
;
1264 if (q
->q_flag
& QREADR
)
1265 tmip
->rbufcid
= bid
;
1267 tmip
->wbufcid
= bid
;