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.
28 * This module implements the "fast path" processing for the telnet protocol.
29 * Since it only knows a very small number of the telnet protocol options,
30 * the daemon is required to assist this module. This module must be run
31 * underneath logindmux, which handles switching messages between the
32 * daemon and the pty master stream appropriately. When an unknown telnet
33 * option is received it is handled as a stop-and-wait operation. The
34 * module refuses to forward data in either direction, and waits for the
35 * daemon to deal with the option, and forward any unprocessed data back
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/stream.h>
42 #include <sys/stropts.h>
43 #include <sys/strsun.h>
45 #include <sys/errno.h>
47 #include <sys/sunddi.h>
48 #include <sys/tihdr.h>
50 #include <sys/logindmux.h>
51 #include <sys/telioctl.h>
52 #include <sys/termios.h>
53 #include <sys/debug.h>
55 #include <sys/modctl.h>
56 #include <sys/cmn_err.h>
57 #include <sys/cryptmod.h>
61 extern struct streamtab telmodinfo
;
64 #define SIMWAIT (1*hz)
69 #define TEL_IOCPASSTHRU 0x100
70 #define TEL_STOPPED 0x80
71 #define TEL_CRRCV 0x40
72 #define TEL_CRSND 0x20
73 #define TEL_GETBLK 0x10
76 * NOTE: values TEL_BINARY_IN and TEL_BINARY_OUT are defined in
77 * telioctl.h, passed in the TEL_IOC_MODE ioctl and stored (bitwise)
78 * in the module state flag. So those values are not available
79 * even though they are not defined here.
85 * Per queue instances are single-threaded since the q_ptr
86 * field of queues need to be shared among threads.
88 static struct fmodsw fsw
= {
95 * Module linkage information for the kernel.
98 static struct modlstrmod modlstrmod
= {
104 static struct modlinkage modlinkage
= {
105 MODREV_1
, &modlstrmod
, NULL
111 return (mod_install(&modlinkage
));
117 return (mod_remove(&modlinkage
));
121 _info(struct modinfo
*modinfop
)
123 return (mod_info(&modlinkage
, modinfop
));
126 static int telmodopen(queue_t
*, dev_t
*, int, int, cred_t
*);
127 static int telmodclose(queue_t
*, int, cred_t
*);
128 static void telmodrput(queue_t
*, mblk_t
*);
129 static void telmodrsrv(queue_t
*);
130 static void telmodwput(queue_t
*, mblk_t
*);
131 static void telmodwsrv(queue_t
*);
132 static int rcv_parse(queue_t
*q
, mblk_t
*mp
);
133 static int snd_parse(queue_t
*q
, mblk_t
*mp
);
134 static void telmod_timer(void *);
135 static void telmod_buffer(void *);
136 static void recover(queue_t
*, mblk_t
*, size_t);
138 static struct module_info telmodoinfo
= {
139 TELMOD_ID
, /* module id number */
140 "telmod", /* module name */
141 0, /* minimum packet size */
142 INFPSZ
, /* maximum packet size */
143 512, /* hi-water mark */
144 256 /* lo-water mark */
147 static struct qinit telmodrinit
= {
148 (int (*)())telmodrput
,
149 (int (*)())telmodrsrv
,
157 static struct qinit telmodwinit
= {
158 (int (*)())telmodwput
,
159 (int (*)())telmodwsrv
,
167 struct streamtab telmodinfo
= {
175 * Per-instance state struct for the telnet module.
179 bufcall_id_t wbufcid
;
180 bufcall_id_t rbufcid
;
181 timeout_id_t wtimoutid
;
182 timeout_id_t rtimoutid
;
189 dummy_callback(void *arg
)
194 * A variety of telnet options can never really be processed in the
195 * kernel. For example, TELOPT_TTYPE, must be based in the TERM
196 * environment variable to the login process. Also, data may already
197 * have reached the stream head before telmod was pushed on the stream.
198 * So when telmod is opened, it begins in stopped state, preventing
199 * further data passing either direction through it. It sends a
200 * T_DATA_REQ messages up toward the daemon. This is so the daemon
201 * can be sure that all data which was not processed by telmod
202 * (because it wasn't yet pushed) has been received at the stream head.
206 telmodopen(queue_t
*q
, dev_t
*devp
, int oflag
, int sflag
, cred_t
*credp
)
208 struct telmod_info
*tmip
;
210 union T_primitives
*tp
;
213 if (sflag
!= MODOPEN
)
216 if (q
->q_ptr
!= NULL
) {
217 /* It's already attached. */
221 * Allocate state structure.
223 tmip
= kmem_zalloc(sizeof (*tmip
), KM_SLEEP
);
232 tmip
->flags
|= TEL_STOPPED
;
236 * Since TCP operates in the TLI-inspired brain-dead fashion,
237 * the connection will revert to bound state if the connection
238 * is reset by the client. We must send a T_UNBIND_REQ in
239 * that case so the port doesn't get "wedged" (preventing
240 * inetd from being able to restart the listener). Allocate
241 * it here, so that we don't need to worry about allocb()
244 while ((tmip
->unbind_mp
= allocb(sizeof (union T_primitives
),
246 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
247 BPRI_HI
, dummy_callback
, NULL
);
255 tmip
->unbind_mp
->b_wptr
= tmip
->unbind_mp
->b_rptr
+
256 sizeof (struct T_unbind_req
);
257 tmip
->unbind_mp
->b_datap
->db_type
= M_PROTO
;
258 tp
= (union T_primitives
*)tmip
->unbind_mp
->b_rptr
;
259 tp
->type
= T_UNBIND_REQ
;
261 * Send a M_PROTO msg of type T_DATA_REQ (this is unique for
262 * read queue since only write queue can get T_DATA_REQ).
263 * Readstream routine in telnet daemon will do a getmsg() till
264 * it receives this proto message
266 while ((bp
= allocb(sizeof (union T_primitives
), BPRI_HI
)) == NULL
) {
267 bufcall_id_t id
= qbufcall(q
, sizeof (union T_primitives
),
268 BPRI_HI
, dummy_callback
, NULL
);
276 bp
->b_datap
->db_type
= M_PROTO
;
277 bp
->b_wptr
= bp
->b_rptr
+ sizeof (union T_primitives
);
278 tp
= (union T_primitives
*)bp
->b_rptr
;
279 tp
->type
= T_DATA_REQ
;
280 tp
->data_req
.MORE_flag
= 0;
287 if (tmip
->unbind_mp
!= NULL
) {
288 freemsg(tmip
->unbind_mp
);
290 kmem_free(tmip
, sizeof (struct telmod_info
));
298 * telmodclose - just the normal streams clean-up is required.
303 telmodclose(queue_t
*q
, int flag
, cred_t
*credp
)
305 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
309 * Flush any write-side data downstream. Ignoring flow
310 * control at this point is known to be safe because the
311 * M_HANGUP below poisons the stream such that no modules can
314 while (mp
= getq(WR(q
)))
317 /* Poison the stream head so that we can't be pushed again. */
318 (void) putnextctl(q
, M_HANGUP
);
322 qunbufcall(q
, tmip
->wbufcid
);
326 qunbufcall(q
, tmip
->rbufcid
);
329 if (tmip
->wtimoutid
) {
330 (void) quntimeout(q
, tmip
->wtimoutid
);
333 if (tmip
->rtimoutid
) {
334 (void) quntimeout(q
, tmip
->rtimoutid
);
337 if (tmip
->unbind_mp
!= NULL
) {
338 freemsg(tmip
->unbind_mp
);
341 kmem_free(q
->q_ptr
, sizeof (struct telmod_info
));
342 q
->q_ptr
= WR(q
)->q_ptr
= NULL
;
348 * Be sure to preserve data order. If the daemon is waiting for additional
349 * data (TEL_GETBLK state) forward new data. Otherwise, apply normal
350 * telnet protocol processing to M_DATA. Take notice of TLI messages
351 * indicating connection tear-down, and change them into M_HANGUP's.
354 telmodrput(queue_t
*q
, mblk_t
*mp
)
357 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
358 union T_primitives
*tip
;
360 if ((mp
->b_datap
->db_type
< QPCTL
) &&
361 ((q
->q_first
) || ((tmip
->flags
& TEL_STOPPED
) &&
362 !(tmip
->flags
& TEL_GETBLK
)) || !canputnext(q
))) {
367 switch (mp
->b_datap
->db_type
) {
371 * If the user level daemon requests for 1 more
372 * block of data (needs more data for protocol processing)
373 * create a M_CTL message block with the mp.
376 if (tmip
->flags
& TEL_GETBLK
) {
377 if ((newmp
= allocb(sizeof (char), BPRI_MED
)) == NULL
) {
378 recover(q
, mp
, msgdsize(mp
));
381 newmp
->b_datap
->db_type
= M_CTL
;
382 newmp
->b_wptr
= newmp
->b_rptr
+ 1;
383 *(newmp
->b_rptr
) = M_CTL_MAGIC_NUMBER
;
385 tmip
->flags
&= ~TEL_GETBLK
;
387 tmip
->flags
|= TEL_STOPPED
;
394 * call the protocol parsing routine which processes
395 * the data part of the message block first. Then it
396 * handles protocol and CR/LF processing.
397 * If an error is found inside allocb/dupb, recover
398 * routines inside rcv_parse will queue up the
399 * original message block in its service queue.
401 (void) rcv_parse(q
, mp
);
406 * Since M_FLUSH came from TCP, we mark it bound for
407 * daemon, not tty. This only happens when TCP expects
408 * to do a connection reset.
410 mp
->b_flag
|= MSGMARK
;
411 if (*mp
->b_rptr
& FLUSHR
)
418 if (tmip
->flags
& TEL_GETBLK
)
419 tmip
->flags
&= ~TEL_GETBLK
;
429 if (tmip
->flags
& TEL_GETBLK
)
430 tmip
->flags
&= ~TEL_GETBLK
;
432 tip
= (union T_primitives
*)mp
->b_rptr
;
437 /* Make into M_HANGUP and putnext */
438 ASSERT(mp
->b_cont
== NULL
);
439 mp
->b_datap
->db_type
= M_HANGUP
;
440 mp
->b_wptr
= mp
->b_rptr
;
446 * If we haven't already, send T_UNBIND_REQ to prevent
447 * TCP from going into "BOUND" state and locking up the
450 if (tip
->type
== T_DISCON_IND
&& tmip
->unbind_mp
!=
453 qreply(q
, tmip
->unbind_mp
);
454 tmip
->unbind_mp
= NULL
;
461 case T_DATA_IND
: /* conform to TPI, but never happens */
466 ASSERT(mp
->b_datap
->db_type
== M_DATA
);
467 if (msgdsize(mp
) != 0) {
475 * We only get T_OK_ACK when we issue the unbind, and it can
479 ASSERT(tmip
->unbind_mp
== NULL
);
486 "telmodrput: unexpected TLI primitive msg "
487 "type 0x%x", tip
->type
);
496 "telmodrput: unexpected msg type 0x%x",
497 mp
->b_datap
->db_type
);
505 * Mostly we end up here because of M_DATA processing delayed due to flow
506 * control or lack of memory. XXX.sparker: TLI primitives here?
509 telmodrsrv(queue_t
*q
)
512 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
513 union T_primitives
*tip
;
515 while ((mp
= getq(q
)) != NULL
) {
516 if (((tmip
->flags
& TEL_STOPPED
) &&
517 !(tmip
->flags
& TEL_GETBLK
)) || !canputnext(q
)) {
521 switch (mp
->b_datap
->db_type
) {
525 if (tmip
->flags
& TEL_GETBLK
) {
526 if ((newmp
= allocb(sizeof (char),
527 BPRI_MED
)) == NULL
) {
528 recover(q
, mp
, msgdsize(mp
));
531 newmp
->b_datap
->db_type
= M_CTL
;
532 newmp
->b_wptr
= newmp
->b_rptr
+ 1;
533 *(newmp
->b_rptr
) = M_CTL_MAGIC_NUMBER
;
535 tmip
->flags
&= ~TEL_GETBLK
;
537 tmip
->flags
|= TEL_STOPPED
;
543 if (!rcv_parse(q
, mp
)) {
550 tip
= (union T_primitives
*)mp
->b_rptr
;
553 * Unless the M_PROTO message indicates data, clear
554 * TEL_GETBLK so that we stop passing our messages
555 * up to the telnet daemon.
557 if (tip
->type
!= T_DATA_IND
&&
558 tip
->type
!= T_EXDATA_IND
)
559 tmip
->flags
&= ~TEL_GETBLK
;
564 /* Make into M_HANGUP and putnext */
565 ASSERT(mp
->b_cont
== NULL
);
566 mp
->b_datap
->db_type
= M_HANGUP
;
567 mp
->b_wptr
= mp
->b_rptr
;
573 * If we haven't already, send T_UNBIND_REQ
574 * to prevent TCP from going into "BOUND"
575 * state and locking up the port.
577 if (tip
->type
== T_DISCON_IND
&&
578 tmip
->unbind_mp
!= NULL
) {
580 qreply(q
, tmip
->unbind_mp
);
581 tmip
->unbind_mp
= NULL
;
587 case T_DATA_IND
: /* conform to TPI, but never happens */
593 ASSERT(mp
->b_datap
->db_type
== M_DATA
);
594 if (msgdsize(mp
) != 0) {
602 * We only get T_OK_ACK when we issue the unbind, and
603 * it can be ignored safely.
606 ASSERT(tmip
->unbind_mp
== NULL
);
613 "telmodrsrv: unexpected TLI primitive "
614 "msg type 0x%x", tip
->type
);
627 "telmodrsrv: unexpected msg type 0x%x",
628 mp
->b_datap
->db_type
);
637 * M_DATA is processed and forwarded if we aren't stopped awaiting the daemon
638 * to process something. M_CTL's are data from the daemon bound for the
639 * network. We forward them immediately. There are two classes of ioctl's
640 * we must handle here also. One is ioctl's forwarded by ptem which we
641 * ignore. The other is ioctl's issued by the daemon to control us.
642 * Process them appropriately. M_PROTO's we pass along, figuring they are
643 * are TPI operations for TCP. M_FLUSH requires careful processing, since
644 * telnet cannot tolerate flushing its protocol requests. Also the flushes
645 * can be running either daemon<->TCP or application<->telmod. We must
646 * carefully deal with this.
650 queue_t
*q
, /* Pointer to the read queue */
651 mblk_t
*mp
) /* Pointer to current message block */
653 struct telmod_info
*tmip
;
659 tmip
= (struct telmod_info
*)q
->q_ptr
;
661 switch (mp
->b_datap
->db_type
) {
663 if (!canputnext(q
) || (tmip
->flags
& TEL_STOPPED
) ||
670 * This routine parses data generating from ptm side.
671 * Insert a null character if carraige return
672 * is not followed by line feed unless we are in binary mode.
673 * Also, duplicate IAC if found in the data.
675 (void) snd_parse(q
, mp
);
679 if (((mp
->b_wptr
- mp
->b_rptr
) == 1) &&
680 (*(mp
->b_rptr
) == M_CTL_MAGIC_NUMBER
)) {
689 ioc
= (struct iocblk
*)mp
->b_rptr
;
690 switch (ioc
->ioc_cmd
) {
693 * This ioctl is issued by user level daemon to
694 * request one more message block to process protocol
697 if (!(tmip
->flags
& TEL_STOPPED
)) {
698 miocnak(q
, mp
, 0, EINVAL
);
701 tmip
->flags
|= TEL_GETBLK
;
705 miocack(q
, mp
, 0, 0);
709 * This ioctl is issued by user level daemon to reenable the
710 * read and write queues. This is issued during startup time
711 * after setting up the mux links and also after processing
712 * the protocol. It is also issued after each time an
713 * an unrecognized telnet option is forwarded to the daemon.
718 * Send negative ack if TEL_STOPPED flag is not set
720 if (!(tmip
->flags
& TEL_STOPPED
)) {
721 miocnak(q
, mp
, 0, EINVAL
);
724 tmip
->flags
&= ~TEL_STOPPED
;
726 (void) putbq(RD(q
), mp
->b_cont
);
735 miocack(q
, mp
, 0, 0);
739 * Set binary/normal mode for input and output
740 * according to the instructions from the daemon.
743 error
= miocpullup(mp
, sizeof (uchar_t
));
745 miocnak(q
, mp
, 0, error
);
748 tmip
->flags
|= *(mp
->b_cont
->b_rptr
) &
749 (TEL_BINARY_IN
|TEL_BINARY_OUT
);
750 miocack(q
, mp
, 0, 0);
763 miocnak(q
, mp
, 0, EINVAL
);
767 error
= miocpullup(mp
, sizeof (uchar_t
));
769 miocnak(q
, mp
, 0, error
);
772 if (*(mp
->b_cont
->b_rptr
) == 0x01)
773 tmip
->flags
|= TEL_IOCPASSTHRU
;
775 tmip
->flags
&= ~TEL_IOCPASSTHRU
;
777 miocack(q
, mp
, 0, 0);
781 if (tmip
->flags
& TEL_IOCPASSTHRU
) {
786 "telmodwput: unexpected ioctl type 0x%x",
789 miocnak(q
, mp
, 0, EINVAL
);
797 * Flushing is tricky: We try to flush all we can, but certain
798 * data cannot be flushed. Telnet protocol sequences cannot
799 * be flushed. So, TCP's queues cannot be flushed since we
800 * cannot tell what might be telnet protocol data. Then we
801 * must take care to create and forward out-of-band data
802 * indicating the flush to the far side.
807 * We cannot flush our read queue, since there may
808 * be telnet protocol bits in the queue, awaiting
809 * processing. However, once it leaves this module
810 * it's guaranteed that all protocol data is in
811 * M_CTL, so we do flush read data beyond us, expecting
812 * them (actually logindmux) to do FLUSHDATAs also.
814 *mp
->b_rptr
= rw
& ~FLUSHW
;
821 * Since all telnet protocol data comes from the
822 * daemon, stored as M_CTL messages, flushq will
823 * do exactly what's needed: Flush bytes which do
824 * not have telnet protocol data.
826 flushq(q
, FLUSHDATA
);
835 /* We may receive T_DISCON_REQ from the mux */
836 if (!canputnext(q
) || q
->q_first
!= NULL
)
845 "telmodwput: unexpected msg type 0x%x",
846 mp
->b_datap
->db_type
);
854 * telmodwsrv - module write service procedure
857 telmodwsrv(queue_t
*q
)
861 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
863 while ((mp
= getq(q
)) != NULL
) {
864 if (!canputnext(q
)) {
865 ASSERT(mp
->b_datap
->db_type
< QPCTL
);
869 switch (mp
->b_datap
->db_type
) {
872 if (tmip
->flags
& TEL_STOPPED
) {
877 * Insert a null character if carraige return
878 * is not followed by line feed
880 if (!snd_parse(q
, mp
)) {
886 if (((mp
->b_wptr
- mp
->b_rptr
) == 1) &&
887 (*(mp
->b_rptr
) == M_CTL_MAGIC_NUMBER
)) {
902 "telmodwsrv: unexpected msg type 0x%x",
903 mp
->b_datap
->db_type
);
912 * This routine is called from read put/service procedure and parses
913 * message block to check for telnet protocol by detecting an IAC.
914 * The routine processes the data part of the message block first and
915 * then sends protocol followed after IAC to the telnet daemon. The
916 * routine also processes CR/LF by eliminating LF/NULL followed after CR.
918 * Since the code to do this with streams mblks is complicated, some
919 * explanations are in order. If an IAC is found, a dupb() is done,
920 * and the pointers are adjusted to create two streams message. The
921 * (possibly empty) first message contains preceeding data, and the
922 * second begins with the IAC and contains the rest of the streams
926 * datamp: Points to the head of a chain of mblks containing data
927 * which requires no expansion, and can be forwarded directly
929 * prevmp: Points to the last mblk on the datamp chain, used to add
930 * to the chain headed by datamp.
931 * newmp: When an M_CTL header is required, this pointer references
932 * that "header" mblk.
933 * protomp: When an IAC is discovered, a dupb() is done on the first mblk
934 * containing an IAC. protomp points to this dup'ed mblk.
935 * This mblk is eventually forwarded to the daemon.
938 rcv_parse(queue_t
*q
, mblk_t
*mp
)
940 mblk_t
*protomp
, *newmp
, *datamp
, *prevmp
;
944 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
947 prevmp
= protomp
= 0;
951 * If the mblk is empty, just continue scanning.
953 if (mp
->b_rptr
== mp
->b_wptr
) {
959 * First check to see if we have received CR and are checking
960 * for a following LF/NULL. If so, do what's necessary to
961 * trim the LF/NULL. This case is for when the LF/NULL is
962 * at the beginning of a subsequent mblk.
964 if (!(tmip
->flags
& TEL_BINARY_IN
) &&
965 (tmip
->flags
& TEL_CRRCV
)) {
966 if ((*mp
->b_rptr
== '\n') || (*mp
->b_rptr
== 0)) {
967 if (mp
->b_wptr
== (mp
->b_rptr
+ 1)) {
968 tmip
->flags
&= ~TEL_CRRCV
;
970 prevmp
->b_cont
= mp
->b_cont
;
977 if (datamp
== NULL
) {
981 * a '\r' in a previous
985 * nothing to putnext.
996 tmip
->flags
&= ~TEL_CRRCV
;
1000 * Now scan through the entire message block, for IACs
1001 * and CR characters, which need processing.
1003 while (tmp
< mp
->b_wptr
) {
1005 if (tmp
[0] == IAC
) {
1007 * Telnet protocol - parse it now
1008 * process data part of mblk
1009 * before sending the protocol.
1011 if (tmp
> mp
->b_rptr
) {
1012 if ((protomp
= dupb(mp
)) == NULL
) {
1013 msgsize
= msgdsize(datamp
);
1014 recover(q
, datamp
, msgsize
);
1017 ASSERT(tmp
>= mp
->b_datap
->db_base
);
1018 ASSERT(tmp
<= mp
->b_datap
->db_lim
);
1020 protomp
->b_datap
->db_base
);
1021 ASSERT(tmp
<= protomp
->b_datap
->db_lim
);
1023 protomp
->b_rptr
= tmp
;
1024 protomp
->b_cont
= mp
->b_cont
;
1028 prevmp
->b_cont
= mp
;
1042 * create a 1 byte M_CTL message block with
1043 * protomp and send it down.
1046 if ((newmp
= allocb(sizeof (char),
1047 BPRI_MED
)) == NULL
) {
1049 * Save the dup'ed mp containing
1050 * the protocol information which
1051 * we couldn't get an M_CTL header
1054 msgsize
= msgdsize(protomp
);
1055 recover(q
, protomp
, msgsize
);
1058 newmp
->b_datap
->db_type
= M_CTL
;
1059 newmp
->b_wptr
= newmp
->b_rptr
+ 1;
1060 *(newmp
->b_rptr
) = M_CTL_MAGIC_NUMBER
;
1061 newmp
->b_cont
= protomp
;
1063 tmip
->flags
|= TEL_STOPPED
;
1068 if (!(tmip
->flags
& TEL_BINARY_IN
)) {
1070 * Set TEL_CRRCV flag if last character is CR
1072 if ((tmp
== (mp
->b_wptr
- 1)) &&
1074 tmip
->flags
|= TEL_CRRCV
;
1079 * If CR is followed by LF/NULL, get rid of
1080 * LF/NULL and realign the message block.
1082 if ((tmp
[0] == '\r') && ((tmp
[1] == '\n') ||
1083 (tmp
[1] == '\0'))) {
1085 * If CR is in the middle of a block,
1086 * we need to get rid of LF and join
1087 * the two pieces together.
1089 if (mp
->b_wptr
> (tmp
+ 2)) {
1090 bcopy(tmp
+ 2, tmp
+ 1,
1091 (mp
->b_wptr
- tmp
- 2));
1094 mp
->b_wptr
= tmp
+ 1;
1098 prevmp
->b_cont
= mp
;
1112 * This routine is called from write put/service procedures and processes
1113 * CR-LF. If CR is not followed by LF, it inserts a NULL character if we are
1114 * in non binary mode. Also, duplicate IAC(0xFF) if found in the mblk.
1115 * This routine is pessimistic: It pre-allocates a buffer twice the size
1116 * of the incoming message, which is the maximum size a message can become
1117 * after IAC expansion.
1119 * savemp: Points at the original message, so it can be freed when
1120 * processing is complete.
1121 * mp: The current point of scanning the message.
1122 * newmp: New message being created with the processed output.
1125 snd_parse(queue_t
*q
, mblk_t
*mp
)
1127 unsigned char *tmp
, *tmp1
;
1128 mblk_t
*newmp
, *savemp
;
1129 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1130 size_t size
= msgdsize(mp
);
1140 * Extra byte to allocb() takes care of the case when there was
1141 * a '\r' at the end of the previous message and there's a '\r'
1142 * at the beginning of the current message.
1144 if ((newmp
= allocb((2 * size
)+1, BPRI_MED
)) == NULL
) {
1145 recover(q
, mp
, (2 * size
)+1);
1148 newmp
->b_datap
->db_type
= M_DATA
;
1150 tmp1
= newmp
->b_rptr
;
1152 if (!(tmip
->flags
& TEL_BINARY_OUT
) &&
1153 (tmip
->flags
& TEL_CRSND
)) {
1154 if (*(mp
->b_rptr
) != '\n')
1156 tmip
->flags
&= ~TEL_CRSND
;
1159 while (tmp
< mp
->b_wptr
) {
1160 if (!(tmip
->flags
& TEL_BINARY_OUT
)) {
1162 if ((tmp
== (mp
->b_wptr
- 1)) &&
1164 tmip
->flags
|= TEL_CRSND
;
1167 if ((tmp
[0] == '\r') &&
1168 (tmp1
== newmp
->b_wptr
)) {
1169 /* XXX.sparker: can't happen */
1170 tmip
->flags
|= TEL_CRSND
;
1173 if ((tmp
[0] == '\r') && (tmp
[1] != '\n')) {
1179 if (tmp
[0] == IAC
) {
1187 newmp
->b_wptr
= tmp1
;
1195 telmod_timer(void *arg
)
1198 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1202 if (q
->q_flag
& QREADR
) {
1203 ASSERT(tmip
->rtimoutid
);
1204 tmip
->rtimoutid
= 0;
1206 ASSERT(tmip
->wtimoutid
);
1207 tmip
->wtimoutid
= 0;
1214 telmod_buffer(void *arg
)
1217 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1221 if (q
->q_flag
& QREADR
) {
1222 ASSERT(tmip
->rbufcid
);
1225 ASSERT(tmip
->wbufcid
);
1233 recover(queue_t
*q
, mblk_t
*mp
, size_t size
)
1237 struct telmod_info
*tmip
= (struct telmod_info
*)q
->q_ptr
;
1239 ASSERT(mp
->b_datap
->db_type
< QPCTL
);
1241 (void) putbq(q
, mp
);
1244 * Make sure there is at most one outstanding request per queue.
1246 if (q
->q_flag
& QREADR
) {
1247 if (tmip
->rtimoutid
|| tmip
->rbufcid
) {
1251 if (tmip
->wtimoutid
|| tmip
->wbufcid
) {
1255 if (!(bid
= qbufcall(RD(q
), size
, BPRI_MED
, telmod_buffer
, q
))) {
1256 tid
= qtimeout(RD(q
), telmod_timer
, q
, SIMWAIT
);
1257 if (q
->q_flag
& QREADR
)
1258 tmip
->rtimoutid
= tid
;
1260 tmip
->wtimoutid
= tid
;
1262 if (q
->q_flag
& QREADR
)
1263 tmip
->rbufcid
= bid
;
1265 tmip
->wbufcid
= bid
;