1 /* COMMADPT.C   (c) Copyright Roger Bowler & Others, 2002-2011       */
2 /*              (c) Copyright, MHP, 2007-2008 (see below)            */
3 /*              Hercules Communication Line Driver                   */
4 
5 /*-------------------------------------------------------------------*/
6 /* Hercules Communication Line Driver                                */
7 /* (c) 1999-2006 Roger Bowler & Others                               */
8 /* Use of this program is governed by the QPL License                */
9 /* Original Author : Ivan Warren                                     */
10 /* Prime Maintainer : Ivan Warren                                    */
11 /*-------------------------------------------------------------------*/
12 
13 /* ********************************************************************
14 
15    TTY Mode Additions (c) Copyright, 2007 MHP <ikj1234i at yahoo dot com>
16 
17    Feb. 2007- Add support for 2703 Telegraph Terminal Control Type II
18    (for use with TTY ASR 33/35 or compatible terminals).
19 
20    To enable TTY mode for a particular port, specify ``LNCTL=ASYNC'' in the
21    hercules conf file.
22 
23    The host sends and receives bytes directly in ASCII, but bits are
24    reversed from standard ASCII bit order.  Lookup tables are used to
25    perform the reversals on each byte, to make even parity for sending
26    toward the host, and to skip certain noxious characters emitted by
27    TSO/TCAM.
28 
29    This code contains minimal TELNET support.  It accepts TELNET
30    IP (Interrupt Process) which is mapped and transmitted to the host
31    as a BREAK (ATTN) sequence.  All TELNET commands are responded
32    negatively.
33 
34    *****************************************************************
35 
36    2741 Mode Additions (c) Copyright, 2008 MHP <ikj1234i at yahoo dot com>
37 
38    2741 mode is now working, though imperfectly as of yet.
39 
40    There is a new param (term=tty|2741) in the conf file to select termtype.
41 
42    Specify code=ebcd for EBCD, or code=corr for correspondence code.
43    Also code=none to disable all translation.  The code= option applies to
44    2741 mode only.
45 
46    Another new param (skip=) is a byte string, specified in hex, to specify
47    "garbage" code points that are to be suppressed in output processing.
48    This allows distinct lists to be used for different terminal types.
49 
50    Automatic translation to Uppercase is enabled by setting uctrans=yes .
51    This is for both 2741 and TTY terminals.
52 
53    You can specify lnctl=tele2 for TTY and lnctl=ibm1 for 2741.
54 
55    Samples:
56      0045 2703 lport=32003 dial=IN lnctl=ibm1 term=2741 skip=5EDE code=ebcd
57      0045 2703 lport=32003 dial=IN lnctl=tele2 uctrans=yes term=tty skip=88C9DF
58 
59    For TCAM, if you are zapping device UCB's, the following type values
60    seem to work:
61    55 10 40 13 - 2741
62    51 10 40 53 - TTY (3335)
63 
64    When running TCAM in 2741 mode if you experience A00 abends, the following
65    zap (to member IEDQTCAM in 'SYS1.LINKLIB') may help
66 
67    NAME IEDQTCAM IEDQKA01
68    VER 0E38 012C
69    REP 0E38 0101
70 
71    The 2741 mode enables ordinary remote ASCII TELNET clients to connect.
72    The translate tables were lifted from IEDQ27 and IEDQ28.  Instead of
73    translating directly between ASCII and the host's 2741-correspondence code,
74    we add an intermediate EBCDIC step.  This enables use of all pre-
75    existing tables so I don't have to code any new ones :)
76 
77    Also, 2740 OS consoles should work.  It may be necessary to modify the
78    driver to end READ CCWs even when no data has been received (see comment)
79 
80    *****************************************************************
81 
82    Some TTY Fixes - 2012-01-30 MHP <ikj1234i at yahoo dot com>
83 
84    This async/2703 driver release contains several bug fixes and minor
85    enhancements (primarily to fix windows telnet clients).  In addition
86    there are three new configuration parameters (iskip=, bs=dumb, break=dumb)
87 
88    When using windows telnet, it's recommended to set bs=dumb and break=dumb .
89 
90    The new iskip= option is analogous to the skip= option, except that
91    it chooses input ASCII characters to suppress (the skip= option is used
92    to suppress characters in output processing).  Note that while both options
93    are entered as hex bytes, the skip= option uses S/370 mainframe code
94    points (either byte-reversed ASCII for TTY or correspondence code/EBCD for
95    2741), whereas the iskip= option requires ASCII code points.  Here's an
96    example:
97    0045 2703 lport=32003 dial=IN lnctl=tele2 uctrans=yes term=tty skip=88C9DF iskip=0A
98    Here's an example, for windows telnet clients
99    0046 2703 lport=32003 dial=IN lnctl=tele2 uctrans=yes term=tty skip=88C9DF iskip=0A bs=dumb break=dumb
100 
101    *****************************************************************
102 
103    driver mods for APL\360 December 2012 MHP <ikj1234i at yahoo dot com>
104    - circumvention for several race conditions
105    - new "eol" parameter specifies a byte value (ASCII), default 0x0D,
106      which when received marks the end of the input line
107    - new "prepend" and "append" parameters to specify zero to four
108      bytes to be prepended and appended (respectively) to input lines
109      that have been received from terminals before being sent to the
110      mainframe OS.  Typical use is to add Circle D and C around each
111      input transmission (2741's for APL\360).  Bytes must be specified in
112      S/370 channel format, not in ASCII.
113    - new terminal type "rxvt4apl" with 8-bit and character translation
114      support for rxvt4apl in 2741 mode. Use the following conf definition entry
115      0402 2703 dial=in lport=57413 lnctl=ibm1 term=rxvt4apl skip=5EDE code=ebcd
116         iskip=0D0A prepend=16 append=5B1F eol=0A binary=yes crlf=yes sendcr=yes
117           [all on a single line]
118    - negotiation to telnet binary mode when using rxvt4apl ("binary" parameter)
119    - send CR back to terminal when input line received ("sendcr" parameter)
120    - option to map 2741 NL to TTY CRLF sequence ("crlf" parameter)
121    - increase Hercules MAX_ARGS
122 
123 ******************************************************************** */
124 
125 #include "hstdinc.h"
126 #include "hercules.h"
127 #include "devtype.h"
128 #include "parser.h"
129 #include "commadpt.h"
130 
131 #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
132   SYSBLK *psysblk;
133   #define sysblk (*psysblk)
134 #endif
135 
136  /*-------------------------------------------------------------------*/
137  /* Ivan Warren 20040227                                              */
138  /* This table is used by channel.c to determine if a CCW code is an  */
139  /* immediate command or not                                          */
140  /* The tape is addressed in the DEVHND structure as 'DEVIMM immed'   */
141  /* 0 : Command is NOT an immediate command                           */
142  /* 1 : Command is an immediate command                               */
143  /* Note : An immediate command is defined as a command which returns */
144  /* CE (channel end) during initialisation (that is, no data is       */
145  /* actually transfered. In this case, IL is not indicated for a CCW  */
146  /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in     */
147  /* effect                                                            */
148  /*-------------------------------------------------------------------*/
149 
150 static BYTE commadpt_immed_command[256]=
151 { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
152   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
153   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
154   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
155   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
156   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
157   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
158   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
159   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
160   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
161   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
162   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
163   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
164   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
165   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
166   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
167 
168 COMMADPT_PEND_TEXT;     /* Defined in commadpt.h                     */
169                         /* Defines commadpt_pendccw_text array       */
170 
171 /*---------------------------------------------------------------*/
172 /* PARSER TABLES                                                 */
173 /*---------------------------------------------------------------*/
174 static PARSER ptab[]={
175     {"lport","%s"},
176     {"lhost","%s"},
177     {"rport","%s"},
178     {"rhost","%s"},
179     {"dial","%s"},
180     {"rto","%s"},
181     {"pto","%s"},
182     {"eto","%s"},
183     {"switched","%s"},
184     {"lnctl","%s"},
185     {"term","%s"},
186     {"code","%s"},
187     {"uctrans","%s"},
188     {"skip","%s"},
189     {"iskip","%s"},
190     {"bs","%s"},
191     {"break","%s"},
192     {"prepend","%s"},
193     {"append","%s"},
194     {"eol","%s"},
195     {"crlf","%s"},
196     {"sendcr","%s"},
197     {"binary","%s"},
198     {NULL,NULL}
199 };
200 
201 enum {
202     COMMADPT_KW_LPORT=1,
203     COMMADPT_KW_LHOST,
204     COMMADPT_KW_RPORT,
205     COMMADPT_KW_RHOST,
206     COMMADPT_KW_DIAL,
207     COMMADPT_KW_READTO,
208     COMMADPT_KW_POLLTO,
209     COMMADPT_KW_ENABLETO,
210     COMMADPT_KW_SWITCHED,
211     COMMADPT_KW_LNCTL,
212     COMMADPT_KW_TERM,
213     COMMADPT_KW_CODE,
214     COMMADPT_KW_UCTRANS,
215     COMMADPT_KW_SKIP,
216     COMMADPT_KW_ISKIP,
217     COMMADPT_KW_BS,
218     COMMADPT_KW_BREAK,
219     COMMADPT_KW_PREPEND,
220     COMMADPT_KW_APPEND,
221     COMMADPT_KW_EOL,
222     COMMADPT_KW_CRLF,
223     COMMADPT_KW_SENDCR,
224     COMMADPT_KW_BINARY,
225 } commadpt_kw;
226 
227 static BYTE byte_reverse_table[256] = {
228     0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
229     0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
230     0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
231     0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
232     0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
233     0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
234     0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
235     0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
236     0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
237     0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
238     0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
239     0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
240     0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
241     0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
242     0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
243     0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
244 };
245 
246 static BYTE telnet_binary[6] = { 0xff, 0xfd, 0x00, 0xff, 0xfb, 0x00 };
247 
248 BYTE overstrike_2741_pairs[] = {
249     0x93, 0xA6, /* nor */
250     0xC9, 0xCC, /* rotate */
251     0xCC, 0xCF, /* log */
252     0xC9, 0xEE, /* grade down */
253     0xC3, 0xE7, /* lamp */
254     0xC5, 0xC6, /* quote quad */
255     0x93, 0xA6, /* nand */
256     0xA3, 0xCC, /* transpose */
257     0xA6, 0xEE, /* locked fn */
258     0xC9, 0xF0, /* grade up */
259     0x76, 0xC5, /* exclamation */
260     0xCA, 0xE4, /* ibeam */
261     0xC6, 0xE1, /* domino */
262 };
263 
264 BYTE overstrike_rxvt4apl_chars[] = {
265     /* must match overstrike_2741_pairs */
266     0xe5,
267     0xe8,
268     0x89,
269     0x9d,
270     0xa6,
271     0x97,
272     0xea,
273     0xed,
274     0xa1, /* locked fn - no exact match for this */
275     0x93,
276     0x21,
277     0x84,
278     0x98,
279 };
280 
281 static BYTE overstrike_map [256] = {
282     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
283     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
284     0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
285     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
286     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
287     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
288     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
289     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
290     0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
291     0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0,
292     0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296     0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0,
297     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
298 };
299 
300 static BYTE rxvt4apl_from_2741[256] = {
301     0x3f, 0x20, 0x31, 0x3f, 0x32, 0x3f, 0x3f, 0x33, 0x34, 0x3f, 0x3f, 0x35, 0x3f, 0x36, 0x37, 0x3f,
302     0x38, 0x3f, 0x3f, 0x39, 0x3f, 0x30, 0x5d, 0x3f, 0x3f, 0x3f, 0x95, 0x3f, 0x96, 0x3f, 0x3f, 0x04,
303     0x90, 0x3f, 0x3f, 0x2f, 0x3f, 0x53, 0x54, 0x3f, 0x3f, 0x55, 0x56, 0x3f, 0x57, 0x3f, 0x3f, 0x58,
304     0x3f, 0x59, 0x5a, 0x3f, 0x3f, 0x3f, 0x3f, 0x2c, 0x84, 0x3f, 0x3f, 0x0a, 0x3f, 0x17, 0x1b, 0x3f,
305     0x2b, 0x3f, 0x3f, 0x4a, 0x3f, 0x4b, 0x4c, 0x3f, 0x3f, 0x4d, 0x4e, 0x3f, 0x4f, 0x3f, 0x3f, 0x50,
306     0x3f, 0x51, 0x52, 0x3f, 0x3f, 0x3f, 0x3f, 0x5b, 0x9d, 0x3f, 0x3f, 0x0d, 0x3f, 0x08, 0x87, 0x3f,
307     0x3f, 0x92, 0x41, 0x3f, 0x42, 0x3f, 0x3f, 0x43, 0x44, 0x3f, 0x3f, 0x45, 0x3f, 0x46, 0x47, 0x3f,
308     0x48, 0x3f, 0x3f, 0x49, 0x3f, 0x3f, 0x2e, 0x3f, 0x3f, 0x3f, 0x09, 0x3f, 0x86, 0x3f, 0x3f, 0x7f,
309     0x3f, 0x20, 0x9a, 0x3f, 0xfd, 0x3f, 0x3f, 0x3c, 0xf3, 0x3f, 0x3f, 0x3d, 0x3f, 0xf2, 0x3e, 0x3f,
310     0x86, 0x3f, 0x3f, 0xfa, 0x3f, 0x5e, 0x29, 0x3f, 0x3f, 0x3f, 0x95, 0x3f, 0x96, 0x3f, 0x3f, 0x3f,
311     0x85, 0x3f, 0x3f, 0x5c, 0x3f, 0x8d, 0x7e, 0x3f, 0x3f, 0x8b, 0xfc, 0x3f, 0xf7, 0x3f, 0x3f, 0x83,
312     0x3f, 0x8c, 0x82, 0x3f, 0x3f, 0x3f, 0x3f, 0x3b, 0x84, 0x3f, 0x3f, 0x0a, 0x3f, 0x17, 0x1b, 0x3f,
313     0x2d, 0x3f, 0x3f, 0xf8, 0x3f, 0x27, 0x95, 0x3f, 0x3f, 0x7c, 0xe7, 0x3f, 0xf9, 0x3f, 0x3f, 0x2a,
314     0x3f, 0x3f, 0xfb, 0x3f, 0x3f, 0x3f, 0x3f, 0x28, 0x9d, 0x3f, 0x3f, 0x0d, 0x3f, 0x08, 0x87, 0x3f,
315     0x3f, 0xf6, 0xe0, 0x3f, 0xe6, 0x3f, 0x3f, 0xef, 0x8f, 0x3f, 0x3f, 0xee, 0x3f, 0x5f, 0xec, 0x3f,
316     0x91, 0x3f, 0x3f, 0xe2, 0x3f, 0x3f, 0x3a, 0x3f, 0x3f, 0x3f, 0x09, 0x3f, 0x86, 0x3f, 0x3f, 0x7f,
317 };
318 
319 static BYTE rxvt4apl_to_2741[256] = {
320     0x88, 0x88, 0x88, 0x88, 0x1f, 0x88, 0x88, 0x88, 0x5d, 0x7a, 0x3b, 0x88, 0x88, 0x5b, 0x88, 0x88,
321     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x5e, 0x88, 0x88, 0x88, 0x88, 0x3e, 0x88, 0x88, 0x88, 0x88,
322     0x01, 0xb7, 0x96, 0x16, 0x57, 0x8b, 0x61, 0xc5, 0xd7, 0x96, 0xcf, 0x40, 0x37, 0xc0, 0x76, 0x23,
323     0x15, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e, 0x10, 0x13, 0xf6, 0xb7, 0x87, 0x8b, 0x8e, 0xd1,
324     0x20, 0xe2, 0xe4, 0xe7, 0xe8, 0xeb, 0xed, 0xee, 0xf0, 0xf3, 0xc3, 0xc5, 0xc6, 0xc9, 0xca, 0xcc,
325     0xcf, 0xd1, 0xd2, 0xa5, 0xa6, 0xa9, 0xaa, 0xac, 0xaf, 0xb1, 0xb2, 0x57, 0xa3, 0x16, 0x95, 0xed,
326     0x88, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e, 0x70, 0x73, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c,
327     0x4f, 0x51, 0x52, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f, 0x31, 0x32, 0x88, 0xc9, 0x88, 0xa6, 0x88,
328     0x88, 0x88, 0xb2, 0xaf, 0x88, 0xa0, 0x90, 0x88, 0x88, 0x88, 0x88, 0xa9, 0xb1, 0xa5, 0x88, 0xe8,
329     0x20, 0xf0, 0x61, 0x88, 0x88, 0xc6, 0x88, 0x88, 0x88, 0x88, 0x82, 0x88, 0x88, 0x88, 0x88, 0x88,
330     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
331     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
332     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
333     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
334     0xe2, 0x88, 0xf3, 0x88, 0x88, 0x88, 0xe4, 0xca, 0x88, 0x88, 0x88, 0x88, 0xee, 0x88, 0xeb, 0xe7,
335     0x88, 0x88, 0x8d, 0x88, 0x88, 0x88, 0xe1, 0xac, 0xc3, 0xcc, 0x93, 0xd2, 0xaa, 0x84, 0x88, 0x88,
336 };
337 
338 /* 2741 EBCD code tables */
339 /* directly copied from mvs src file iedq27 */
340 static BYTE xlate_table_ebcd_toebcdic[256] = {
341     0x3F, 0x40, 0xF1, 0x3F, 0xF2, 0x3F, 0x3F, 0xF3, 0xF4, 0x3F, 0x3F, 0xF5, 0x3F, 0xF6, 0xF7, 0x3F,
342     0xF8, 0x3F, 0x3F, 0xF9, 0x3F, 0xF0, 0x7B, 0x3F, 0x3F, 0x3F, 0x35, 0x3F, 0x36, 0x3F, 0x3F, 0x37,
343     0x7C, 0x3F, 0x3F, 0x61, 0x3F, 0xA2, 0xA3, 0x3F, 0x3F, 0xA4, 0xA5, 0x3F, 0xA6, 0x3F, 0x3F, 0xA7,
344     0x3F, 0xA8, 0xA9, 0x3F, 0x3F, 0x3F, 0x3F, 0x6B, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x26, 0x27, 0x3F,
345     0x60, 0x3F, 0x3F, 0x91, 0x3F, 0x92, 0x93, 0x3F, 0x3F, 0x94, 0x95, 0x3F, 0x96, 0x3F, 0x3F, 0x97,
346     0x3F, 0x98, 0x99, 0x3F, 0x3F, 0x3F, 0x3F, 0x5B, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x17, 0x3F,
347     0x3F, 0x50, 0x81, 0x3F, 0x82, 0x3F, 0x3F, 0x83, 0x84, 0x3F, 0x3F, 0x85, 0x3F, 0x86, 0x87, 0x3F,
348     0x88, 0x3F, 0x3F, 0x89, 0x3F, 0x3F, 0x4B, 0x3F, 0x3F, 0x3F, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x07,
349     0x3F, 0x40, 0x7E, 0x3F, 0x4C, 0x3F, 0x3F, 0x5E, 0x7A, 0x3F, 0x3F, 0x6C, 0x3F, 0x7D, 0x6E, 0x3F,
350     0x5C, 0x3F, 0x3F, 0x4D, 0x3F, 0x5D, 0x7F, 0x3F, 0x3F, 0x3F, 0x35, 0x3F, 0x36, 0x3F, 0x3F, 0x3F,
351     0x4A, 0x3F, 0x3F, 0x6F, 0x3F, 0xE2, 0xE3, 0x3F, 0x3F, 0xE4, 0xE5, 0x3F, 0xE6, 0x3F, 0x3F, 0xE7,
352     0x3F, 0xE8, 0xE9, 0x3F, 0x3F, 0x3F, 0x3F, 0x4F, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x26, 0x27, 0x3F,
353     0x6D, 0x3F, 0x3F, 0xD1, 0x3F, 0xD2, 0xD3, 0x3F, 0x3F, 0xD4, 0xD5, 0x3F, 0xD6, 0x3F, 0x3F, 0xD7,
354     0x3F, 0xD8, 0xD9, 0x3F, 0x3F, 0x3F, 0x3F, 0x5A, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x17, 0x3F,
355     0x3F, 0x4E, 0xC1, 0x3F, 0xC2, 0x3F, 0x3F, 0xC3, 0xC4, 0x3F, 0x3F, 0xC5, 0x3F, 0xC6, 0xC7, 0x3F,
356     0xC8, 0x3F, 0x3F, 0xC9, 0x3F, 0x3F, 0x5F, 0x3F, 0x3F, 0x3F, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x07
357 };
358 
359 static BYTE xlate_table_ebcd_fromebcdic[256] = {
360     0x88, 0x88, 0x88, 0x88, 0x88, 0x7A, 0x7C, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x5B, 0x88, 0x88,
361     0x88, 0x88, 0x88, 0x88, 0x58, 0x5B, 0x5D, 0x5E, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
362     0x88, 0x88, 0x88, 0x88, 0x38, 0x3B, 0x88, 0x3E, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
363     0x88, 0x88, 0x5E, 0x88, 0x88, 0x88, 0x1C, 0x1F, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
364     0x01, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xA0, 0x76, 0x84, 0x93, 0xE1, 0xB7,
365     0x61, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xD7, 0x57, 0x90, 0x95, 0x87, 0xF6,
366     0x40, 0x23, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x37, 0x8B, 0xC0, 0x8E, 0xA3,
367     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x16, 0x20, 0x8D, 0x82, 0x96,
368     0x88, 0x62, 0x64, 0x67, 0x68, 0x6B, 0x6D, 0x6E, 0x70, 0x73, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
369     0x88, 0x43, 0x45, 0x46, 0x49, 0x4A, 0x4C, 0x4F, 0x51, 0x52, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
370     0x88, 0x88, 0x25, 0x26, 0x29, 0x2A, 0x2C, 0x2F, 0x31, 0x32, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
371     0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
372     0x88, 0xE2, 0xE4, 0xE7, 0xE8, 0xEB, 0xED, 0xEE, 0xF0, 0xF3, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
373     0x88, 0xC3, 0xC5, 0xC6, 0xC9, 0xCA, 0xCC, 0xCF, 0xD1, 0xD2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
374     0x88, 0x88, 0xA5, 0xA6, 0xA9, 0xAA, 0xAC, 0xAF, 0xB1, 0xB2, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
375     0x15, 0x02, 0x04, 0x07, 0x08, 0x0B, 0x0D, 0x0E, 0x10, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88
376 };
377 
378 /* 2741 correspondence code tables */
379 /* directly copied from mvs src file iedq28 */
380 static BYTE xlate_table_cc_toebcdic[256] = {
381     0x3F, 0x40, 0xF1, 0x3F, 0xF2, 0x3F, 0x3F, 0xF3, 0xF5, 0x3F, 0x3F, 0xF7, 0x3F, 0xF6, 0xF8, 0x3F,
382     0xF4, 0x3F, 0x3F, 0xF0, 0x3F, 0xA9, 0xF9, 0x3F, 0x3F, 0x34, 0x35, 0x3F, 0x36, 0x3F, 0x3F, 0x37,
383     0xA3, 0x3F, 0x3F, 0xA7, 0x3F, 0x95, 0xA4, 0x3F, 0x3F, 0x85, 0x84, 0x3F, 0x92, 0x3F, 0x3F, 0x83,
384     0x3F, 0x93, 0x88, 0x3F, 0x3F, 0x3F, 0x3F, 0x82, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x26, 0x27, 0x3F,
385     0x5A, 0x3F, 0x3F, 0x94, 0x3F, 0x4B, 0xA5, 0x3F, 0x3F, 0x7D, 0x99, 0x3F, 0x89, 0x3F, 0x3F, 0x81,
386     0x3F, 0x96, 0xA2, 0x3F, 0x3F, 0x3F, 0x3F, 0xA6, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x17, 0x3F,
387     0x3F, 0x91, 0x87, 0x3F, 0x7E, 0x3F, 0x3F, 0x86, 0x97, 0x3F, 0x3F, 0x5E, 0x3F, 0x98, 0x6B, 0x3F,
388     0x61, 0x3F, 0x3F, 0xA8, 0x3F, 0x3F, 0x60, 0x3F, 0x3F, 0x04, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x07,
389     0x3F, 0x40, 0x4F, 0x3F, 0x7C, 0x3F, 0x3F, 0x7B, 0x6C, 0x3F, 0x3F, 0x50, 0x3F, 0x4C, 0x5C, 0x3F,
390     0x5B, 0x3F, 0x3F, 0x5D, 0x3F, 0xE9, 0x4D, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x36, 0x3F, 0x3F, 0x37,
391     0xE3, 0x3F, 0x3F, 0xE7, 0x3F, 0xD5, 0xE4, 0x3F, 0x3F, 0xC5, 0xC4, 0x3F, 0xD2, 0x3F, 0x3F, 0xC3,
392     0x3F, 0xD3, 0xC8, 0x3F, 0x3F, 0x3F, 0x3F, 0xC2, 0x24, 0x3F, 0x3F, 0x25, 0x3F, 0x3F, 0x27, 0x3F,
393     0x6E, 0x3F, 0x3F, 0xD4, 0x3F, 0x4B, 0xE5, 0x3F, 0x3F, 0x7F, 0xD9, 0x3F, 0xC9, 0x3F, 0x3F, 0xC1,
394     0x3F, 0xD6, 0xE2, 0x3F, 0x3F, 0x3F, 0x3F, 0xE6, 0x14, 0x3F, 0x3F, 0x15, 0x3F, 0x16, 0x3F, 0x3F,
395     0x3F, 0xD1, 0xC7, 0x3F, 0x4E, 0x3F, 0x3F, 0xC6, 0xD7, 0x3F, 0x3F, 0x7A, 0x3F, 0xD8, 0x6B, 0x3F,
396     0x6F, 0x3F, 0x3F, 0xE8, 0x3F, 0x3F, 0x6D, 0x3F, 0x3F, 0x3F, 0x05, 0x3F, 0x06, 0x3F, 0x3F, 0x3F,
397 };
398 
399 static BYTE xlate_table_cc_fromebcdic[256] = {
400     0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x7A, 0x7C, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x5B, 0xEB, 0xEB,
401     0xEB, 0xEB, 0xEB, 0xEB, 0x58, 0x5B, 0x5D, 0x5E, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
402     0xEB, 0xEB, 0xEB, 0xEB, 0x38, 0x3B, 0xEB, 0x3E, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
403     0xEB, 0xEB, 0x5E, 0xEB, 0x19, 0x1A, 0x1C, 0x1F, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
404     0x01, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x45, 0x8D, 0x96, 0xE4, 0x82,
405     0x8B, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x40, 0x90, 0x8E, 0x93, 0x6B, 0xEB,
406     0x76, 0x70, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x6E, 0x88, 0xF6, 0xC0, 0xF0,
407     0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0x87, 0x84, 0x49, 0x64, 0xC9,
408     0xEB, 0x4F, 0x37, 0x2F, 0x2A, 0x29, 0x67, 0x62, 0x32, 0x4C, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
409     0xEB, 0x61, 0x2C, 0x31, 0x43, 0x25, 0x51, 0x68, 0x6D, 0x4A, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
410     0xEB, 0xEB, 0x52, 0x20, 0x26, 0x46, 0x57, 0x23, 0x73, 0x15, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
411     0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
412     0xEB, 0xCF, 0xB7, 0xAF, 0xAA, 0xA9, 0xE7, 0xE2, 0xB2, 0xCC, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
413     0xEB, 0xE1, 0xAC, 0xB1, 0xC3, 0xA5, 0xD1, 0xE8, 0xED, 0xCA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
414     0xEB, 0xEB, 0xD2, 0xA0, 0xA6, 0xC6, 0xD7, 0xA3, 0xF3, 0x95, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
415     0x13, 0x02, 0x04, 0x07, 0x10, 0x08, 0x0D, 0x0B, 0x0E, 0x16, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
416 };
417 
418 #define CIRCLE_C 0x1F
419 #define CIRCLE_D 0x16
420 
421 static BYTE byte_parity_table [128] = {
422 /* value: 0 = even parity, 1 = odd parity */
423     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
424     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
425     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
426     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
427     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
428     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
429     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
430     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
431 };
432 
logdump(char * txt,DEVBLK * dev,BYTE * bfr,size_t sz)433 static void logdump(char *txt,DEVBLK *dev,BYTE *bfr,size_t sz)
434 {
435     size_t i;
436     if ( !dev->ccwtrace )
437     {
438         return;
439     }
440     logmsg(_("HHCCA300D %4.4X:%s : Status = TEXT=%s, TRANS=%s, TWS=%s\n"),
441             dev->devnum,
442             txt,
443             dev->commadpt->in_textmode?"YES":"NO",
444             dev->commadpt->in_xparmode?"YES":"NO",
445             dev->commadpt->xparwwait?"YES":"NO");
446     logmsg(_("HHCCA300D %4.4X:%s : Dump of %d (%x) byte(s)\n"),dev->devnum,txt,sz,sz);
447     for( i=0; i<sz; i++ )
448     {
449         if( i%16 == 0 )
450         {
451             if( i !=0 )
452             {
453                 logmsg("\n");
454             }
455             logmsg(_("HHCCA300D %4.4X:%s : %4.4X:"),dev->devnum,txt,i);
456         }
457         if( i%4 == 0 )
458         {
459             logmsg(" ");
460         }
461         logmsg("%2.2X",bfr[i]);
462     }
463     logmsg("\n");
464 }
465 /*-------------------------------------------------------------------*/
466 /* Handler utility routines                                          */
467 /*-------------------------------------------------------------------*/
468 
469 /*-------------------------------------------------------------------*/
470 /* Buffer ring management                                            */
471 /*-------------------------------------------------------------------*/
472 
473 /*-------------------------------------------------------------------*/
474 /* Buffer ring management : Init a buffer ring                       */
475 /*-------------------------------------------------------------------*/
commadpt_ring_init(COMMADPT_RING * ring,size_t sz,int trace)476 void commadpt_ring_init(COMMADPT_RING *ring,size_t sz,int trace)
477 {
478     ring->bfr=malloc(sz);
479     ring->sz=sz;
480     ring->hi=0;
481     ring->lo=0;
482     ring->havedata=0;
483     ring->overflow=0;
484     if(trace)
485     {
486         logmsg("HCCCA999D : Ring buffer for ring %p allocated at %p\n",
487             ring,
488             ring->bfr);
489     }
490 }
491 /*-------------------------------------------------------------------*/
492 /* Buffer ring management : Free a buffer ring                       */
493 /*-------------------------------------------------------------------*/
commadpt_ring_terminate(COMMADPT_RING * ring,int trace)494 static void commadpt_ring_terminate(COMMADPT_RING *ring,int trace)
495 {
496     if(trace)
497     {
498         logmsg("HCCCA999D : Ring buffer for ring %p at %p freed\n",
499             ring,
500             ring->bfr);
501     }
502     if(ring->bfr!=NULL)
503     {
504         free(ring->bfr);
505         ring->bfr=NULL;
506     }
507     ring->sz=0;
508     ring->hi=0;
509     ring->lo=0;
510     ring->havedata=0;
511     ring->overflow=0;
512 }
513 /*-------------------------------------------------------------------*/
514 /* Buffer ring management : Flush a buffer ring                      */
515 /*-------------------------------------------------------------------*/
commadpt_ring_flush(COMMADPT_RING * ring)516 static void commadpt_ring_flush(COMMADPT_RING *ring)
517 {
518     ring->hi=0;
519     ring->lo=0;
520     ring->havedata=0;
521     ring->overflow=0;
522 }
523 /*-------------------------------------------------------------------*/
524 /* Buffer ring management : Queue a byte in the ring                 */
525 /*-------------------------------------------------------------------*/
commadpt_ring_push(COMMADPT_RING * ring,BYTE b)526 inline static void commadpt_ring_push(COMMADPT_RING *ring,BYTE b)
527 {
528     ring->bfr[ring->hi++]=b;
529     if(ring->hi>=ring->sz)
530     {
531         ring->hi=0;
532     }
533     if(ring->hi==ring->lo)
534     {
535         ring->overflow=1;
536     }
537     ring->havedata=1;
538 }
539 /*-------------------------------------------------------------------*/
540 /* Buffer ring management : Queue a byte array in the ring           */
541 /*-------------------------------------------------------------------*/
commadpt_ring_pushbfr(COMMADPT_RING * ring,BYTE * b,size_t sz)542 inline static void commadpt_ring_pushbfr(COMMADPT_RING *ring,BYTE *b,size_t sz)
543 {
544     size_t i;
545     for(i=0;i<sz;i++)
546     {
547         commadpt_ring_push(ring,b[i]);
548     }
549 }
550 /*-------------------------------------------------------------------*/
551 /* Buffer ring management : Retrieve a byte from the ring            */
552 /*-------------------------------------------------------------------*/
commadpt_ring_pop(COMMADPT_RING * ring)553 inline static BYTE commadpt_ring_pop(COMMADPT_RING *ring)
554 {
555     register BYTE b;
556     b=ring->bfr[ring->lo++];
557     if(ring->lo>=ring->sz)
558     {
559         ring->lo=0;
560     }
561     if(ring->hi==ring->lo)
562     {
563         ring->havedata=0;
564     }
565     return b;
566 }
567 
568 /*-------------------------------------------------------------------*/
569 /* Buffer ring management : Retrive a byte array from the ring       */
570 /*-------------------------------------------------------------------*/
commadpt_ring_popbfr(COMMADPT_RING * ring,BYTE * b,size_t sz)571 inline static size_t commadpt_ring_popbfr(COMMADPT_RING *ring,BYTE *b,size_t sz)
572 {
573     size_t i;
574     for(i=0;i<sz && ring->havedata;i++)
575     {
576         b[i]=commadpt_ring_pop(ring);
577     }
578     return i;
579 }
580 /*-------------------------------------------------------------------*/
581 /* Free all private structures and buffers                           */
582 /*-------------------------------------------------------------------*/
commadpt_clean_device(DEVBLK * dev)583 static void commadpt_clean_device(DEVBLK *dev)
584 {
585     if(!dev)
586     {
587         /*
588          * Shouldn't happen.. But during shutdown, some weird
589          * things happen !
590          */
591         return;
592     }
593     if(dev->commadpt!=NULL)
594     {
595         commadpt_ring_terminate(&dev->commadpt->inbfr,dev->ccwtrace);
596         commadpt_ring_terminate(&dev->commadpt->outbfr,dev->ccwtrace);
597         commadpt_ring_terminate(&dev->commadpt->rdwrk,dev->ccwtrace);
598         commadpt_ring_terminate(&dev->commadpt->pollbfr,dev->ccwtrace);
599         commadpt_ring_terminate(&dev->commadpt->ttybuf,dev->ccwtrace);
600         /* release the CA lock */
601         release_lock(&dev->commadpt->lock);
602         free(dev->commadpt);
603         dev->commadpt=NULL;
604         if(dev->ccwtrace)
605         {
606             logmsg(_("HHCCA300D %4.4X:clean : Control block freed\n"),
607                 dev->devnum);
608         }
609     }
610     else
611     {
612         if(dev->ccwtrace)
613         {
614             logmsg(_("HHCCA300D %4.4X:clean : Control block not freed : not allocated\n"),dev->devnum);
615         }
616     }
617     return;
618 }
619 
620 /*-------------------------------------------------------------------*/
621 /* Allocate initial private structures                               */
622 /*-------------------------------------------------------------------*/
commadpt_alloc_device(DEVBLK * dev)623 static int commadpt_alloc_device(DEVBLK *dev)
624 {
625     dev->commadpt=malloc(sizeof(COMMADPT));
626     if(dev->commadpt==NULL)
627     {
628         logmsg(_("HHCCA020E %4.4X:Memory allocation failure for main control block\n"),
629                 dev->devnum);
630         return -1;
631     }
632     memset(dev->commadpt,0,sizeof(COMMADPT));
633     commadpt_ring_init(&dev->commadpt->inbfr,4096,dev->ccwtrace);
634     commadpt_ring_init(&dev->commadpt->outbfr,4096,dev->ccwtrace);
635     commadpt_ring_init(&dev->commadpt->pollbfr,4096,dev->ccwtrace);
636     commadpt_ring_init(&dev->commadpt->rdwrk,65536,dev->ccwtrace);
637     commadpt_ring_init(&dev->commadpt->ttybuf,TTYLINE_SZ,dev->ccwtrace);
638     dev->commadpt->dev=dev;
639     return 0;
640 }
641 /*-------------------------------------------------------------------*/
642 /* Parsing utilities                                                 */
643 /*-------------------------------------------------------------------*/
644 /*-------------------------------------------------------------------*/
645 /* commadpt_getport : returns a port number or -1                    */
646 /*-------------------------------------------------------------------*/
commadpt_getport(char * txt)647 static int commadpt_getport(char *txt)
648 {
649     int pno;
650     struct servent *se;
651     pno=atoi(txt);
652     if(pno==0)
653     {
654         se=getservbyname(txt,"tcp");
655         if(se==NULL)
656         {
657             return -1;
658         }
659         pno=se->s_port;
660     }
661     return(pno);
662 }
663 /*-------------------------------------------------------------------*/
664 /* commadpt_getaddr : set an in_addr_t if ok, else return -1         */
665 /*-------------------------------------------------------------------*/
commadpt_getaddr(in_addr_t * ia,char * txt)666 static int commadpt_getaddr(in_addr_t *ia,char *txt)
667 {
668     struct hostent *he;
669     he=gethostbyname(txt);
670     if(he==NULL)
671     {
672         return(-1);
673     }
674     memcpy(ia,he->h_addr_list[0],4);
675     return(0);
676 }
677 /*-------------------------------------------------------------------*/
678 /* commadpt_connout : make a tcp outgoing call                       */
679 /* return values : 0 -> call succeeded or initiated                  */
680 /*                <0 -> call failed                                  */
681 /*-------------------------------------------------------------------*/
commadpt_connout(COMMADPT * ca)682 static int commadpt_connout(COMMADPT *ca)
683 {
684     int rc;
685     char        wbfr[256];
686     struct      sockaddr_in     sin;
687     struct      in_addr intmp;
688     sin.sin_family=AF_INET;
689     sin.sin_addr.s_addr=ca->rhost;
690     sin.sin_port=htons(ca->rport);
691     if(socket_is_socket(ca->sfd))
692     {
693         close_socket(ca->sfd);
694         ca->connect=0;
695     }
696     ca->sfd=socket(AF_INET,SOCK_STREAM,0);
697     /* set socket to NON-blocking mode */
698     socket_set_blocking_mode(ca->sfd,0);
699     rc=connect(ca->sfd,(struct sockaddr *)&sin,sizeof(sin));
700     if(rc<0)
701     {
702         if(HSO_errno==HSO_EINPROGRESS)
703         {
704             return(0);
705         }
706         else
707         {
708             strerror_r(HSO_errno,wbfr,256);
709             intmp.s_addr=ca->rhost;
710             logmsg(_("HHCCA001I %4.4X:Connect out to %s:%d failed during initial status : %s\n"),
711                     ca->devnum,
712                     inet_ntoa(intmp),
713                     ca->rport,
714                     wbfr);
715             close_socket(ca->sfd);
716             ca->connect=0;
717             return(-1);
718         }
719     }
720     ca->connect=1;
721     return(0);
722 }
723 /*-------------------------------------------------------------------*/
724 /* commadpt_initiate_userdial : interpret DIAL data and initiate call*/
725 /* return values : 0 -> call succeeded or initiated                  */
726 /*                <0 -> call failed                                  */
727 /*-------------------------------------------------------------------*/
commadpt_initiate_userdial(COMMADPT * ca)728 static int     commadpt_initiate_userdial(COMMADPT *ca)
729 {
730     int dotcount;       /* Number of seps (the 4th is the port separator) */
731     int i;              /* work                                           */
732     int cur;            /* Current section                                */
733     in_addr_t   destip; /* Destination IP address                         */
734     U16 destport;       /* Destination TCP port                           */
735     int incdata;        /* Incorrect dial data found                      */
736     int goteon;         /* EON presence flag                              */
737 
738    /* See the DIAL CCW portion in execute_ccw for dial format information */
739 
740     incdata=0;
741     goteon=0;
742     dotcount=0;
743     cur=0;
744     destip=0;
745     for(i=0;i<ca->dialcount;i++)
746     {
747         if(goteon)
748         {
749             /* EON MUST be last data byte */
750             if(ca->dev->ccwtrace)
751             {
752                 logmsg(_("HHCCA300D %4.4x : Found data beyond EON\n"),ca->devnum);
753             }
754             incdata=1;
755             break;
756         }
757         switch(ca->dialdata[i]&0x0f)
758         {
759             case 0x0d:  /* SEP */
760                 if(dotcount<4)
761                 {
762                     if(cur>255)
763                     {
764                         incdata=1;
765                         if(ca->dev->ccwtrace)
766                         {
767                             logmsg(_("HHCCA300D %4.4x : Found incorrect IP address section at position %d\n"),ca->devnum,dotcount+1);
768                             logmsg(_("HHCCA300D %4.4x : %d greater than 255\n"),ca->devnum,cur);
769                         }
770                         break;
771                     }
772                     destip<<=8;
773                     destip+=cur;
774                     cur=0;
775                     dotcount++;
776                 }
777                 else
778                 {
779                     incdata=1;
780                     if(ca->dev->ccwtrace)
781                     {
782                         logmsg(_("HHCCA300D %4.4x : Too many separators in dial data\n"),ca->devnum);
783                     }
784                     break;
785                 }
786                 break;
787             case 0x0c: /* EON */
788                 goteon=1;
789                 break;
790 
791                 /* A,B,E,F not valid */
792             case 0x0a:
793             case 0x0b:
794             case 0x0e:
795             case 0x0f:
796                 incdata=1;
797                 if(ca->dev->ccwtrace)
798                 {
799                     logmsg(_("HHCCA300D %4.4x : Incorrect dial data byte %2.2x\n"),ca->devnum,ca->dialdata[i]);
800                 }
801                 break;
802             default:
803                 cur*=10;
804                 cur+=ca->dialdata[i]&0x0f;
805                 break;
806         }
807         if(incdata)
808         {
809             break;
810         }
811     }
812     if(incdata)
813     {
814         return -1;
815     }
816     if(dotcount<4)
817     {
818         if(ca->dev->ccwtrace)
819         {
820             logmsg(_("HHCCA300D %4.4x : Not enough separators (only %d found) in dial data\n"),ca->devnum,dotcount);
821         }
822         return -1;
823     }
824     if(cur>65535)
825     {
826         if(ca->dev->ccwtrace)
827         {
828             logmsg(_("HHCCA300D %4.4x : Destination TCP port %d exceeds maximum of 65535\n"),ca->devnum,cur);
829         }
830         return -1;
831     }
832     destport=cur;
833     /* Update RHOST/RPORT */
834     ca->rport=destport;
835     ca->rhost=destip;
836     return(commadpt_connout(ca));
837 }
838 
connect_message(int sfd,int devnum,int term,int binary_opt)839 static void connect_message(int sfd, int devnum, int term, int binary_opt)
840 {
841     int rc;
842     struct sockaddr_in client;
843     socklen_t namelen;
844     char *ipaddr;
845     char msgtext[256];
846     namelen = sizeof(client);
847     rc = getpeername (sfd, (struct sockaddr *)&client, &namelen);
848     ipaddr = inet_ntoa(client.sin_addr);
849     sprintf(msgtext, "%s:%d TERMINAL CONNECTED CUA=%4.4X TERM=%s", ipaddr, (int)ntohs(client.sin_port), devnum, (term == COMMADPT_TERM_TTY) ? "TTY" : "2741");
850     logmsg( _("%s\n"), msgtext);
851     write(sfd, msgtext, strlen(msgtext));
852     write(sfd, "\r\n", 2);
853     if (binary_opt)
854         write(sfd, telnet_binary, sizeof(telnet_binary));
855 }
856 
857 /*-------------------------------------------------------------------*/
858 /* Communication Thread - Read socket data (after POLL request       */
859 /*-------------------------------------------------------------------*/
commadpt_read_poll(COMMADPT * ca)860 static int commadpt_read_poll(COMMADPT *ca)
861 {
862     BYTE b;
863     int rc;
864     while((rc=read_socket(ca->sfd,&b,1))>0)
865     {
866         if(b==0x32)
867         {
868             continue;
869         }
870         if(b==0x37)
871         {
872             return(1);
873         }
874     }
875     if(rc>0)
876     {
877         /* Store POLL IX in bfr followed by byte */
878         commadpt_ring_push(&ca->inbfr,ca->pollix);
879         commadpt_ring_push(&ca->inbfr,b);
880         return(2);
881     }
882     return(0);
883 }
884 
commadpt_read_tty(COMMADPT * ca,BYTE * bfr,int len)885 static void commadpt_read_tty(COMMADPT *ca, BYTE * bfr, int len)
886 {
887     BYTE        bfr3[3];
888     BYTE        c;
889     BYTE        dump_buf[TTYLINE_SZ];
890     int         dump_bp=0;
891     BYTE        tty_buf[TTYLINE_SZ];
892     int         tty_bp=0;
893     int i1;
894     u_int j;
895     int crflag = 0;
896     for (i1 = 0; i1 < len; i1++)
897     {
898         c = (unsigned char) bfr[i1];
899         if (ca->telnet_opt)
900         {
901             ca->telnet_opt = 0;
902             if(ca->dev->ccwtrace)
903                 logmsg(_("HHCCA300D %4.4X: Received TELNET CMD 0x%02x 0x%02x\n"),
904                         ca->dev->devnum,
905                         ca->telnet_cmd, c);
906             if (c == 0x00 && ca->binary_opt)
907                 continue; /* for binary: assume it's a response, so don't answer */
908             bfr3[0] = 0xff;  /* IAC */
909         /* set won't/don't for all received commands */
910             bfr3[1] = (ca->telnet_cmd == 0xfd) ? 0xfc : 0xfe;
911             bfr3[2] = c;
912             if(ca->dev->ccwtrace)
913                 logmsg(_("HHCCA300D %4.4X: Sending TELNET CMD 0x%02x 0x%02x\n"),
914                         ca->dev->devnum,
915                         bfr3[1], bfr3[2]);
916             commadpt_ring_pushbfr(&ca->outbfr,bfr3,3);
917             continue;
918         }
919         if (ca->telnet_iac)
920         {
921             ca->telnet_iac = 0;
922             if(ca->dev->ccwtrace)
923                 logmsg(_("HHCCA300D %4.4X: Received TELNET IAC 0x%02x\n"),
924                         ca->dev->devnum,
925                         c);
926             switch (c)
927             {
928                 case 0xFB:  /* TELNET WILL option cmd */
929                 case 0xFD:  /* TELNET DO option cmd */
930                     ca->telnet_opt = 1;
931                     ca->telnet_cmd = c;
932                     break;
933                 case 0xF4:  /* TELNET interrupt */
934                     if (!ca->telnet_int)
935                     {
936                         ca->telnet_int = 1;
937                         commadpt_ring_flush(&ca->ttybuf);
938                         commadpt_ring_flush(&ca->inbfr);
939                         commadpt_ring_flush(&ca->rdwrk);
940                         commadpt_ring_flush(&ca->outbfr);
941                     }
942                     break;
943             }
944             continue;
945         }
946         if (c == 0xFF)
947         {  /* TELNET IAC */
948             ca->telnet_iac = 1;
949             continue;
950         }
951         else
952         {
953             ca->telnet_iac = 0;
954         }
955         if (c == ca->eol_char) { // char was CR ?
956             crflag = 1;
957         }
958         if (c == 0x03 && ca->dumb_break)
959         {  /* Ctrl-C */
960             ca->telnet_int = 1;
961             commadpt_ring_flush(&ca->ttybuf);
962             commadpt_ring_flush(&ca->inbfr);
963             commadpt_ring_flush(&ca->rdwrk);
964             commadpt_ring_flush(&ca->outbfr);
965             continue;
966         }
967         commadpt_ring_push(&ca->ttybuf,c);
968     }
969     if (crflag)
970     {   /* process complete line, perform editing and translation, etc. */
971         if (ca->prepend_length)
972         {
973             for (i1 = 0; i1 < ca->prepend_length; i1++) {
974                 tty_buf[tty_bp++] = ca->prepend_bytes[i1];
975                 if (tty_bp >= TTYLINE_SZ)
976                     tty_bp = TTYLINE_SZ - 1;   // prevent buf overflow
977             }
978         }
979         while (ca->ttybuf.havedata)
980         {
981             c = commadpt_ring_pop(&ca->ttybuf);
982             if ((c & 0x7f) == 0x08 && ca->dumb_bs)   // backspace editing
983             {
984                 if (tty_bp > 0)
985                     tty_bp --;
986                 continue;
987             }
988             if (ca->input_byte_skip_table[c])
989                 continue;  // skip this byte per cfg
990             if (!(ca->rxvt4apl || !ca->code_table_fromebcdic))
991             { /* tty33 and 2741 emulation are 7-bit, code=none and rxvt4apl want 8 bit */
992                 c &= 0x7f;     // make 7 bit ASCII
993             }
994             if  (ca->uctrans && c >= 'a' && c <= 'z')
995             {
996                 c = toupper( c );     /* make uppercase */
997             }
998             /* now map the character from ASCII into proper S/370 byte format */
999             if (ca->term == COMMADPT_TERM_TTY)
1000             {
1001                 if (byte_parity_table[(unsigned int)(c & 0x7f)])
1002                     c |= 0x80;     // make even parity
1003                 c = byte_reverse_table[(unsigned int)(c & 0xff)];
1004             }
1005             else
1006             {   /* 2741 */
1007                 if (ca->rxvt4apl)
1008                 {
1009                     if (overstrike_map[c] == 1)
1010                     {
1011                         for (j = 0; j < sizeof(overstrike_rxvt4apl_chars); j++)
1012                         {
1013                             if (c == overstrike_rxvt4apl_chars[j])
1014                             {
1015                                 tty_buf[tty_bp++] = overstrike_2741_pairs[j*2];
1016                                 if (tty_bp >= TTYLINE_SZ)
1017                                     tty_bp = TTYLINE_SZ - 1;   // prevent buf overflow
1018                                 tty_buf[tty_bp++] = 0xDD;      // 2741 backspace
1019                                 if (tty_bp >= TTYLINE_SZ)
1020                                     tty_bp = TTYLINE_SZ - 1;   // prevent buf overflow
1021                                 c = overstrike_2741_pairs[ (j*2) + 1];
1022                             }
1023                         }
1024                     }
1025                     else
1026                     {
1027                         c = rxvt4apl_to_2741[c];
1028                     }
1029                 }
1030                 else if (ca->code_table_fromebcdic)
1031                 {
1032                     c = host_to_guest(c & 0x7f);  // first translate to EBCDIC
1033                     c = ca->code_table_fromebcdic[ c ];   // then to 2741 code
1034                 }
1035             }
1036             tty_buf[tty_bp++] = c;
1037             if (tty_bp >= TTYLINE_SZ)
1038                 tty_bp = TTYLINE_SZ - 1;   // prevent buf overflow
1039         }
1040         if (ca->append_length)
1041         {
1042             for (i1 = 0; i1 < ca->append_length; i1++) {
1043                 tty_buf[tty_bp++] = ca->append_bytes[i1];
1044                 if (tty_bp >= TTYLINE_SZ)
1045                     tty_bp = TTYLINE_SZ - 1;   // prevent buf overflow
1046             }
1047         }
1048         if (tty_bp > 0) {
1049             for (i1 = 0; i1 < tty_bp; i1++) {
1050                 commadpt_ring_push(&ca->rdwrk, tty_buf[i1]);
1051                 dump_buf[dump_bp++] = tty_buf[i1];
1052                 if (dump_bp >= TTYLINE_SZ) dump_bp = TTYLINE_SZ - 1;
1053             }
1054         }
1055         logdump("RCV2",ca->dev,dump_buf,dump_bp);
1056         ca->eol_flag = 1; // set end of line flag
1057         if (ca->sendcr_opt)
1058         {
1059             /* move carriage to left margin */
1060             commadpt_ring_push(&ca->outbfr,0x0d);
1061         }
1062     } /* end of if(crflag) */
1063 }
1064 
1065 /*-------------------------------------------------------------------*/
1066 /* Communication Thread - Read socket data                           */
1067 /*-------------------------------------------------------------------*/
commadpt_read(COMMADPT * ca)1068 static void commadpt_read(COMMADPT *ca)
1069 {
1070 BYTE    bfr[256];
1071 int     gotdata;
1072 int     rc;
1073 
1074     gotdata=0;
1075     for (;;)
1076     {
1077      /* if (IS_BSC_LNCTL(ca))
1078         {
1079             rc=read_socket(ca->sfd,bfr,256);
1080         }
1081         else
1082         { */
1083             /* read_socket has changed from 3.04 to 3.06 - async needs old way */
1084             /* is BSC similarly broken? */
1085             /* --> Yes, it is! I propose to fully remove the if/else construct     */
1086             /*                 i.e. to handle BSC and async identically here (JW)  */
1087 #ifdef _MSVC_
1088             rc=recv(ca->sfd,bfr,256,0);
1089 #else
1090             rc=read(ca->sfd,bfr,256);
1091 #endif
1092      /* } */
1093         if (rc <= 0)
1094             break;
1095         logdump("RECV",ca->dev,bfr,rc);
1096         if (IS_ASYNC_LNCTL(ca))
1097         {
1098             commadpt_read_tty(ca, bfr, rc);
1099         }
1100         else
1101         {
1102             commadpt_ring_pushbfr(&ca->inbfr,bfr,(size_t)rc);
1103         }  /* end of else (async) */
1104         gotdata=1;
1105     }
1106     if(!gotdata)
1107     {
1108         if(ca->connect)
1109         {
1110             ca->connect=0;
1111             close_socket(ca->sfd);
1112             ca->sfd=-1;
1113             if(ca->curpending!=COMMADPT_PEND_IDLE)
1114             {
1115                 ca->curpending=COMMADPT_PEND_IDLE;
1116                 signal_condition(&ca->ipc);
1117             }
1118         }
1119     }
1120 }
1121 /*-------------------------------------------------------------------*/
1122 /* Communication Thread - Set TimeOut                                */
1123 /*-------------------------------------------------------------------*/
commadpt_setto(struct timeval * tv,int tmo)1124 static struct timeval *commadpt_setto(struct timeval *tv,int tmo)
1125 {
1126     if(tmo!=0)
1127     {
1128         if(tmo<0)
1129         {
1130             tv->tv_sec=0;
1131             tv->tv_usec=1;
1132         }
1133         else
1134         {
1135             tv->tv_sec=tmo/1000;
1136             tv->tv_usec=(tmo%1000)*1000;
1137         }
1138         return(tv);
1139     }
1140     return(NULL);
1141 }
1142 
1143 /*-------------------------------------------------------------------*/
1144 /* Communication Thread main loop                                    */
1145 /*-------------------------------------------------------------------*/
commadpt_thread(void * vca)1146 static void *commadpt_thread(void *vca)
1147 {
1148     COMMADPT    *ca;            /* Work CA Control Block Pointer     */
1149     int        sockopt;         /* Used for setsocketoption          */
1150     struct sockaddr_in sin;     /* bind socket address structure     */
1151     int devnum;                 /* device number copy for convenience*/
1152     int rc;                     /* return code from various rtns     */
1153     struct timeval tv;          /* select timeout structure          */
1154     struct timeval *seltv;      /* ptr to the timeout structure      */
1155     fd_set      rfd,wfd,xfd;    /* SELECT File Descriptor Sets       */
1156     BYTE        pipecom;        /* Byte read from IPC pipe           */
1157     int tempfd;                 /* Temporary FileDesc holder         */
1158     BYTE b;                     /* Work data byte                    */
1159     int writecont;              /* Write contention active           */
1160     int soerr;                  /* getsockopt SOERROR value          */
1161     socklen_t   soerrsz;        /* Size for getsockopt               */
1162     int maxfd;                  /* highest FD for select             */
1163     int ca_shutdown;            /* Thread shutdown internal flag     */
1164     int init_signaled;          /* Thread initialisation signaled    */
1165     int pollact;                /* A Poll Command is in progress     */
1166     int i;                      /* Ye Old Loop Counter               */
1167 
1168     /*---------------------END OF DECLARES---------------------------*/
1169 
1170     /* fetch the commadpt structure */
1171     ca=(COMMADPT *)vca;
1172 
1173     /* Obtain the CA lock */
1174     obtain_lock(&ca->lock);
1175 
1176     /* get a work copy of devnum (for messages) */
1177     devnum=ca->devnum;
1178 
1179     /* reset shutdown flag */
1180     ca_shutdown=0;
1181 
1182     init_signaled=0;
1183 
1184     logmsg(_("HHCCA002I %4.4X:Line Communication thread "TIDPAT" started\n"),devnum,thread_id());
1185 
1186     pollact=0;  /* Initialise Poll activity flag */
1187 
1188     /* Determine if we should listen */
1189     /* if this is a DIAL=OUT only line, no listen is necessary */
1190     if(ca->dolisten)
1191     {
1192         /* Create the socket for a listen */
1193         ca->lfd=socket(AF_INET,SOCK_STREAM,0);
1194         if(!socket_is_socket(ca->lfd))
1195         {
1196             logmsg(_("HHCCA003E %4.4X:Cannot obtain socket for incoming calls : %s\n"),devnum,strerror(HSO_errno));
1197             ca->have_cthread=0;
1198             release_lock(&ca->lock);
1199             return NULL;
1200         }
1201         /* Turn blocking I/O off */
1202         /* set socket to NON-blocking mode */
1203         socket_set_blocking_mode(ca->lfd,0);
1204 
1205         /* Reuse the address regardless of any */
1206         /* spurious connection on that port    */
1207         sockopt=1;
1208         setsockopt(ca->lfd,SOL_SOCKET,SO_REUSEADDR,(GETSET_SOCKOPT_T*)&sockopt,sizeof(sockopt));
1209 
1210         /* Bind the socket */
1211         sin.sin_family=AF_INET;
1212         sin.sin_addr.s_addr=ca->lhost;
1213         sin.sin_port=htons(ca->lport);
1214         while(1)
1215         {
1216             rc=bind(ca->lfd,(struct sockaddr *)&sin,sizeof(sin));
1217             if(rc<0)
1218             {
1219                 if(HSO_errno==HSO_EADDRINUSE)
1220                 {
1221                     logmsg(_("HHCCA004W %4.4X:Waiting 5 seconds for port %d to become available\n"),devnum,ca->lport);
1222                     /*
1223                      * Check for a shutdown condition on entry
1224                      */
1225                     if(ca->curpending==COMMADPT_PEND_SHUTDOWN)
1226                     {
1227                         ca_shutdown=1;
1228                         ca->curpending=COMMADPT_PEND_IDLE;
1229                         signal_condition(&ca->ipc);
1230                         break;
1231                     }
1232 
1233                     /* Set to wait 5 seconds or input on the IPC pipe */
1234                     /* whichever comes 1st                            */
1235                     if(!init_signaled)
1236                     {
1237                         ca->curpending=COMMADPT_PEND_IDLE;
1238                         signal_condition(&ca->ipc);
1239                         init_signaled=1;
1240                     }
1241 
1242                     FD_ZERO(&rfd);
1243                     FD_ZERO(&wfd);
1244                     FD_ZERO(&xfd);
1245                     FD_SET(ca->pipe[1],&rfd);
1246                     tv.tv_sec=5;
1247                     tv.tv_usec=0;
1248 
1249                     release_lock(&ca->lock);
1250                     rc=select(ca->pipe[1]+1,&rfd,&wfd,&wfd,&tv);
1251                     obtain_lock(&ca->lock);
1252                     /*
1253                      * Check for a shutdown condition again after the sleep
1254                      */
1255                     if(ca->curpending==COMMADPT_PEND_SHUTDOWN)
1256                     {
1257                         ca_shutdown=1;
1258                         ca->curpending=COMMADPT_PEND_IDLE;
1259                         signal_condition(&ca->ipc);
1260                         break;
1261                     }
1262                     if(rc!=0)
1263                     {
1264                         /* Ignore any other command at this stage */
1265                         read_pipe(ca->pipe[1],&b,1);
1266                         ca->curpending=COMMADPT_PEND_IDLE;
1267                         signal_condition(&ca->ipc);
1268                     }
1269                 }
1270                 else
1271                 {
1272                     logmsg(_("HHCCA018E %4.4X:Bind failed : %s\n"),devnum,strerror(HSO_errno));
1273                     ca_shutdown=1;
1274                     break;
1275                 }
1276             }
1277             else
1278             {
1279                 break;
1280             }
1281         }
1282         /* Start the listen */
1283         if(!ca_shutdown)
1284         {
1285             listen(ca->lfd,10);
1286             logmsg(_("HHCCA005I %4.4X:Listening on port %d for incoming TCP connections\n"),
1287                     devnum,
1288                     ca->lport);
1289             ca->listening=1;
1290         }
1291     }
1292     if(!init_signaled)
1293     {
1294         ca->curpending=COMMADPT_PEND_IDLE;
1295         signal_condition(&ca->ipc);
1296         init_signaled=1;
1297     }
1298 
1299     /* The MAIN select loop */
1300     /* It will listen on the following sockets : */
1301     /* ca->lfd : The listen socket */
1302     /* ca->sfd :
1303      *         read : When a read, prepare or DIAL command is in effect
1304      *        write : When a write contention occurs
1305      * ca->pipe[0] : Always
1306      *
1307      * A 3 Seconds timer is started for a read operation
1308      */
1309 
1310     while(!ca_shutdown)
1311     {
1312         FD_ZERO(&rfd);
1313         FD_ZERO(&wfd);
1314         FD_ZERO(&xfd);
1315         maxfd=0;
1316         if(ca->listening)
1317         {
1318                 FD_SET(ca->lfd,&rfd);
1319                 maxfd=maxfd<ca->lfd?ca->lfd:maxfd;
1320         }
1321         seltv=NULL;
1322         if(ca->dev->ccwtrace)
1323         {
1324             logmsg(_("HHCCA300D %4.4X:cthread - Entry - DevExec = %s\n"),
1325                     devnum,
1326                     commadpt_pendccw_text[ca->curpending]);
1327         }
1328         writecont=0;
1329         switch(ca->curpending)
1330         {
1331             case COMMADPT_PEND_SHUTDOWN:
1332                 ca_shutdown=1;
1333                 break;
1334             case COMMADPT_PEND_IDLE:
1335                 break;
1336             case COMMADPT_PEND_READ:
1337                 if(!ca->connect)
1338                 {
1339                     ca->curpending=COMMADPT_PEND_IDLE;
1340                     signal_condition(&ca->ipc);
1341                     break;
1342                 }
1343                 if(ca->inbfr.havedata || ca->eol_flag)
1344                 {
1345                     if (ca->term == COMMADPT_TERM_2741) {
1346                         usleep(10000);
1347                     }
1348                     ca->curpending=COMMADPT_PEND_IDLE;
1349                     signal_condition(&ca->ipc);
1350                     break;
1351                 }
1352                 seltv=commadpt_setto(&tv,ca->rto);
1353                 FD_SET(ca->sfd,&rfd);
1354                 maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1355                 break;
1356             case COMMADPT_PEND_POLL:
1357                 /* Poll active check - provision for write contention */
1358                 /* pollact will be reset when NON syn data is received*/
1359                 /* or when the read times out                         */
1360                 /* Also prevents WRITE from exiting early             */
1361                 if(!pollact && !writecont)
1362                 {
1363                     int gotenq;
1364 
1365                     pollact=1;
1366                     gotenq=0;
1367                     /* Send SYN+SYN */
1368                     commadpt_ring_push(&ca->outbfr,0x32);
1369                     commadpt_ring_push(&ca->outbfr,0x32);
1370                     /* Fill the Output ring with POLL Data */
1371                     /* Up to 7 chars or ENQ                */
1372                     for(i=0;i<7;i++)
1373                     {
1374                         if(!ca->pollbfr.havedata)
1375                         {
1376                             break;
1377                         }
1378                         ca->pollused++;
1379                         b=commadpt_ring_pop(&ca->pollbfr);
1380                         if(b!=0x2D)
1381                         {
1382                             commadpt_ring_push(&ca->outbfr,b);
1383                         }
1384                         else
1385                         {
1386                             gotenq=1;
1387                             break;
1388                         }
1389                     }
1390                     if(!gotenq)
1391                     {
1392                         if(ca->dev->ccwtrace)
1393                         {
1394                             logmsg(_("HHCCA300D %4.4X:Poll Command abort - Poll address >7 Bytes\n"),devnum);
1395                         }
1396                         ca->badpoll=1;
1397                         ca->curpending=COMMADPT_PEND_IDLE;
1398                         signal_condition(&ca->ipc);
1399                         break;
1400                     }
1401                     b=commadpt_ring_pop(&ca->pollbfr);
1402                     ca->pollix=b;
1403                     seltv=commadpt_setto(&tv,ca->pto);
1404                 }
1405                 if(!writecont && ca->pto!=0)
1406                 {
1407                     /* Set tv value (have been set earlier) */
1408                     seltv=&tv;
1409                     /* Set to read data still               */
1410                     FD_SET(ca->sfd,&rfd);
1411                     maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1412                 }
1413                 /* DO NOT BREAK - Continue with WRITE processing */
1414             case COMMADPT_PEND_WRITE:
1415                 if(!writecont)
1416                 {
1417                     while(ca->outbfr.havedata)
1418                     {
1419                         b=commadpt_ring_pop(&ca->outbfr);
1420                         if(ca->dev->ccwtrace)
1421                         {
1422                                 logmsg(_("HHCCA300D %4.4X:Writing 1 byte in socket : %2.2X\n"),ca->devnum,b);
1423                         }
1424                         rc=write_socket(ca->sfd,&b,1);
1425                         if(rc!=1)
1426                         {
1427                             if(0
1428 #ifndef WIN32
1429                                 || EAGAIN == errno
1430 #endif
1431                                 || HSO_EWOULDBLOCK == HSO_errno
1432                             )
1433                             {
1434                                 /* Contending for write */
1435                                 writecont=1;
1436                                 FD_SET(ca->sfd,&wfd);
1437                                 maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1438                                 break;
1439                             }
1440                             else
1441                             {
1442                                 close_socket(ca->sfd);
1443                                 ca->sfd=-1;
1444                                 ca->connect=0;
1445                                 ca->curpending=COMMADPT_PEND_IDLE;
1446                                 signal_condition(&ca->ipc);
1447                                 break;
1448                             }
1449                         }
1450                     }
1451                     if (IS_ASYNC_LNCTL(ca)) {
1452             /* Sleep for 0.01 sec - for faithful emulation we would
1453              * slow everything down to 110 or 150 baud or worse :)
1454              * Without this sleep, CPU use is excessive.
1455              */
1456                         usleep(10000);
1457                     }
1458                 }
1459                 else
1460                 {
1461                         FD_SET(ca->sfd,&wfd);
1462                         maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1463                 }
1464                 if(!writecont && !pollact)
1465                 {
1466                         ca->curpending=COMMADPT_PEND_IDLE;
1467                         signal_condition(&ca->ipc);
1468                         break;
1469                 }
1470                 break;
1471             case COMMADPT_PEND_DIAL:
1472                 if(ca->connect)
1473                 {
1474                     ca->curpending=COMMADPT_PEND_IDLE;
1475                     signal_condition(&ca->ipc);
1476                     break;
1477                 }
1478                 rc=commadpt_initiate_userdial(ca);
1479                 if(rc!=0 || (rc==0 && ca->connect))
1480                 {
1481                     ca->curpending=COMMADPT_PEND_IDLE;
1482                     signal_condition(&ca->ipc);
1483                     break;
1484                 }
1485                 FD_SET(ca->sfd,&wfd);
1486                 maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1487                 break;
1488             case COMMADPT_PEND_ENABLE:
1489                 if(ca->connect)
1490                 {
1491                     ca->curpending=COMMADPT_PEND_IDLE;
1492                     signal_condition(&ca->ipc);
1493                     break;
1494                 }
1495                 switch(ca->dialin+ca->dialout*2)
1496                 {
1497                     case 0: /* DIAL=NO */
1498                         /* callissued is set here when the call */
1499                         /* actually failed. But we want to time */
1500                         /* a bit for program issuing ENABLES in */
1501                         /* a tight loop                         */
1502                         if(ca->callissued)
1503                         {
1504                             seltv=commadpt_setto(&tv,ca->eto);
1505                             break;
1506                         }
1507                         /* Issue a Connect out */
1508                         rc=commadpt_connout(ca);
1509                         if(rc==0)
1510                         {
1511                             /* Call issued */
1512                             if(ca->connect)
1513                             {
1514                                 /* Call completed already */
1515                                 ca->curpending=COMMADPT_PEND_IDLE;
1516                                 signal_condition(&ca->ipc);
1517                             }
1518                             else
1519                             {
1520                                 /* Call initiated - FD will be ready */
1521                                 /* for writing when the connect ends */
1522                                 /* getsockopt/SOERROR will tell if   */
1523                                 /* the call was sucessfull or not    */
1524                                 FD_SET(ca->sfd,&wfd);
1525                                 maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1526                                 ca->callissued=1;
1527                             }
1528                         }
1529                         /* Call did not succeed                                 */
1530                         /* Manual says : on a leased line, if DSR is not up     */
1531                         /* the terminate enable after a timeout.. That is       */
1532                         /* what the call just did (although the time out        */
1533                         /* was probably instantaneous)                          */
1534                         /* This is the equivalent of the comm equipment         */
1535                         /* being offline                                        */
1536                         /*       INITIATE A 3 SECOND TIMEOUT                    */
1537                         /* to prevent OSes from issuing a loop of ENABLES       */
1538                         else
1539                         {
1540                             seltv=commadpt_setto(&tv,ca->eto);
1541                         }
1542                         break;
1543                     default:
1544                     case 3: /* DIAL=INOUT */
1545                     case 1: /* DIAL=IN */
1546                         /* Wait forever */
1547                         break;
1548                     case 2: /* DIAL=OUT */
1549                         /* Makes no sense                               */
1550                         /* line must be enabled through a DIAL command  */
1551                         ca->curpending=COMMADPT_PEND_IDLE;
1552                         signal_condition(&ca->ipc);
1553                         break;
1554                 }
1555                 /* For cases not DIAL=OUT, the listen is already started */
1556                 break;
1557 
1558                 /* The CCW Executor says : DISABLE */
1559             case COMMADPT_PEND_DISABLE:
1560                 if(ca->connect)
1561                 {
1562                     close_socket(ca->sfd);
1563                     ca->sfd=-1;
1564                     ca->connect=0;
1565                 }
1566                 ca->curpending=COMMADPT_PEND_IDLE;
1567                 signal_condition(&ca->ipc);
1568                 break;
1569 
1570                 /* A PREPARE has been issued */
1571             case COMMADPT_PEND_PREPARE:
1572                 if(!ca->connect || ca->inbfr.havedata)
1573                 {
1574                     ca->curpending=COMMADPT_PEND_IDLE;
1575                     signal_condition(&ca->ipc);
1576                     break;
1577                 }
1578                 FD_SET(ca->sfd,&rfd);
1579                 maxfd=maxfd<ca->sfd?ca->sfd:maxfd;
1580                 break;
1581 
1582                 /* Don't know - shouldn't be here anyway */
1583             default:
1584                 break;
1585         }
1586 
1587         /* If the CA is shutting down, exit the loop now */
1588         if(ca_shutdown)
1589         {
1590             ca->curpending=COMMADPT_PEND_IDLE;
1591             signal_condition(&ca->ipc);
1592             break;
1593         }
1594 
1595         /* Set the IPC pipe in the select */
1596         FD_SET(ca->pipe[0],&rfd);
1597 
1598         /* The the MAX File Desc for Arg 1 of SELECT */
1599         maxfd=maxfd<ca->pipe[0]?ca->pipe[0]:maxfd;
1600         maxfd++;
1601 
1602         /* Release the CA Lock before the select - all FDs addressed by the select are only */
1603         /* handled by the thread, and communication from CCW Executor/others to this thread */
1604         /* is via the pipe, which queues the info                                           */
1605         release_lock(&ca->lock);
1606 
1607         if(ca->dev->ccwtrace)
1608         {
1609                 logmsg(_("HHCCA300D %4.4X:cthread - Select IN maxfd = %d / Devexec = %s\n"),devnum,maxfd,commadpt_pendccw_text[ca->curpending]);
1610         }
1611         rc=select(maxfd,&rfd,&wfd,&xfd,seltv);
1612 
1613         if(ca->dev->ccwtrace)
1614         {
1615                 logmsg(_("HHCCA300D %4.4X:cthread - Select OUT rc=%d\n"),devnum,rc);
1616         }
1617         /* Get the CA lock back */
1618         obtain_lock(&ca->lock);
1619 
1620         if(rc==-1)
1621         {
1622             if(errno==EINTR)
1623             {
1624                 continue;  /* thanks Fish! */
1625             }
1626             logmsg(_("HHCCA006T %4.4X:Select failed : %s\n"),devnum,strerror(HSO_errno));
1627             break;
1628         }
1629 
1630         /* Select timed out */
1631         if(rc==0)
1632         {
1633             pollact=0;  /* Poll not active */
1634             if(ca->dev->ccwtrace)
1635             {
1636                 logmsg(_("HHCCA300D %4.4X:cthread - Select TIME OUT\n"),devnum);
1637             }
1638             /* Reset Call issued flag */
1639             ca->callissued=0;
1640 
1641             /* timeout condition */
1642             signal_condition(&ca->ipc);
1643             ca->curpending=COMMADPT_PEND_IDLE;
1644             continue;
1645         }
1646 
1647         if(FD_ISSET(ca->pipe[0],&rfd))
1648         {
1649             rc=read_pipe(ca->pipe[0],&pipecom,1);
1650             if(rc==0)
1651             {
1652                 if(ca->dev->ccwtrace)
1653                 {
1654                         logmsg(_("HHCCA300D %4.4X:cthread - IPC Pipe closed\n"),devnum);
1655                 }
1656                 /* Pipe closed : terminate thread & release CA */
1657                 ca_shutdown=1;
1658                 break;
1659             }
1660             if(ca->dev->ccwtrace)
1661             {
1662                 logmsg(_("HHCCA300D %4.4X:cthread - IPC Pipe Data ; code = %d\n"),devnum,pipecom);
1663             }
1664             switch(pipecom)
1665             {
1666                 case 0: /* redrive select */
1667                         /* occurs when a new CCW is being executed */
1668                     break;
1669                 case 1: /* Halt current I/O */
1670                     ca->callissued=0;
1671                     if(ca->curpending==COMMADPT_PEND_DIAL)
1672                     {
1673                         close_socket(ca->sfd);
1674                         ca->sfd=-1;
1675                     }
1676                     ca->curpending=COMMADPT_PEND_IDLE;
1677                     ca->haltpending=1;
1678                     signal_condition(&ca->ipc);
1679                     signal_condition(&ca->ipc_halt);    /* Tell the halt initiator too */
1680                     break;
1681                 default:
1682                     break;
1683             }
1684             continue;
1685         }
1686         if(ca->connect)
1687         {
1688             if(FD_ISSET(ca->sfd,&rfd))
1689             {
1690                 int dopoll;
1691                 dopoll=0;
1692                 if(ca->dev->ccwtrace)
1693                 {
1694                         logmsg(_("HHCCA300D %4.4X:cthread - inbound socket data\n"),devnum);
1695                 }
1696                 if(pollact && IS_BSC_LNCTL(ca))
1697                 {
1698                     switch(commadpt_read_poll(ca))
1699                     {
1700                         case 0: /* Only SYNs received */
1701                                 /* Continue the timeout */
1702                             dopoll=1;
1703                             break;
1704                         case 1: /* EOT Received */
1705                             /* Send next poll sequence */
1706                             pollact=0;
1707                             dopoll=1;
1708                             break;
1709                         case 2: /* Something else received */
1710                             /* Index byte already stored in inbfr */
1711                             /* read the remaining data and return */
1712                             ca->pollsm=1;
1713                             dopoll=0;
1714                             break;
1715                         default:
1716                             /* Same as 0 */
1717                             dopoll=1;
1718                             break;
1719                     }
1720                 }
1721                 if(IS_ASYNC_LNCTL(ca) || !dopoll)
1722                 {
1723                     commadpt_read(ca);
1724                     if(IS_ASYNC_LNCTL(ca) && !ca->eol_flag && !ca->telnet_int) {
1725                         /* async: EOL char not yet received and not attn: no data to read */
1726                         /* ... just remain in COMMADPT_PEND_READ state ... */
1727                     } else {
1728                         ca->curpending=COMMADPT_PEND_IDLE;
1729                         signal_condition(&ca->ipc);
1730                     }
1731                     continue;
1732                 }
1733             }
1734         }
1735         if(ca->sfd>=0)
1736         {
1737             if(FD_ISSET(ca->sfd,&wfd))
1738             {
1739                 if(ca->dev->ccwtrace)
1740                 {
1741                         logmsg(_("HHCCA300D %4.4X:cthread - socket write available\n"),devnum);
1742                 }
1743                 switch(ca->curpending)
1744                 {
1745                     case COMMADPT_PEND_DIAL:
1746                     case COMMADPT_PEND_ENABLE:  /* Leased line enable call case */
1747                     soerrsz=sizeof(soerr);
1748                     getsockopt(ca->sfd,SOL_SOCKET,SO_ERROR,(GETSET_SOCKOPT_T*)&soerr,&soerrsz);
1749                     if(soerr==0)
1750                     {
1751                         ca->connect=1;
1752                     }
1753                     else
1754                     {
1755                         logmsg(_("HHCCA007W %4.4X:Outgoing call failed during %s command : %s\n"),devnum,commadpt_pendccw_text[ca->curpending],strerror(soerr));
1756                         if(ca->curpending==COMMADPT_PEND_ENABLE)
1757                         {
1758                             /* Ensure top of the loop doesn't restart a new call */
1759                             /* but starts a 3 second timer instead               */
1760                             ca->callissued=1;
1761                         }
1762                         ca->connect=0;
1763                         close_socket(ca->sfd);
1764                         ca->sfd=-1;
1765                     }
1766                     signal_condition(&ca->ipc);
1767                     ca->curpending=COMMADPT_PEND_IDLE;
1768                     break;
1769 
1770                     case COMMADPT_PEND_WRITE:
1771                     writecont=0;
1772                     break;
1773 
1774                     default:
1775                     break;
1776                 }
1777                 continue;
1778             }
1779         }
1780         /* Test for incoming call */
1781         if(ca->listening)
1782         {
1783             if(FD_ISSET(ca->lfd,&rfd))
1784             {
1785                 logmsg(_("HHCCA008I %4.4X:cthread - Incoming Call\n"),devnum);
1786                 tempfd=accept(ca->lfd,NULL,0);
1787                 if(tempfd<0)
1788                 {
1789                     continue;
1790                 }
1791                 /* If the line is already connected, just close */
1792                 /* this call                                    */
1793                 if(ca->connect)
1794                 {
1795                     close_socket(tempfd);
1796                     continue;
1797                 }
1798                 /* Turn non-blocking I/O on */
1799                 /* set socket to NON-blocking mode */
1800                 socket_set_blocking_mode(tempfd,0);
1801 
1802                 /* Check the line type & current operation */
1803 
1804                 /* if DIAL=IN or DIAL=INOUT or DIAL=NO */
1805                 if(ca->dialin || (ca->dialin+ca->dialout==0))
1806                 {
1807                     /* check if ENABLE is in progress */
1808                     if(ca->curpending==COMMADPT_PEND_ENABLE)
1809                     {
1810                         /* Accept the call, indicate the line */
1811                         /* is connected and notify CCW exec   */
1812                         ca->curpending=COMMADPT_PEND_IDLE;
1813                         ca->connect=1;
1814                         ca->sfd=tempfd;
1815                         signal_condition(&ca->ipc);
1816                         if (IS_ASYNC_LNCTL(ca)) {
1817                             connect_message(ca->sfd, ca->devnum, ca->term, ca->binary_opt);
1818                         }
1819                         continue;
1820                     }
1821                     /* if this is a leased line, accept the */
1822                     /* call anyway                          */
1823                     if(ca->dialin==0)
1824                     {
1825                         ca->connect=1;
1826                         ca->sfd=tempfd;
1827                         if (IS_ASYNC_LNCTL(ca)) {
1828                             connect_message(ca->sfd, ca->devnum, ca->term, ca->binary_opt);
1829                         }
1830                         continue;
1831                     }
1832                 }
1833                 /* All other cases : just reject the call */
1834                 close_socket(tempfd);
1835             }
1836         }
1837     }
1838     ca->curpending=COMMADPT_PEND_CLOSED;
1839     /* Check if we already signaled the init process  */
1840     if(!init_signaled)
1841     {
1842         signal_condition(&ca->ipc);
1843     }
1844     /* The CA is shutting down - terminate the thread */
1845     /* NOTE : the requestor was already notified upon */
1846     /*        detection of PEND_SHTDOWN. However      */
1847     /*        the requestor will only run when the    */
1848     /*        lock is released, because back          */
1849     /*        notification was made while holding     */
1850     /*        the lock                                */
1851     logmsg(_("HHCCA009I %4.4X:BSC utility thread terminated\n"),ca->devnum);
1852     release_lock(&ca->lock);
1853     return NULL;
1854 }
1855 /*-------------------------------------------------------------------*/
1856 /* Wakeup the comm thread                                            */
1857 /* Code : 0 -> Just wakeup the thread to redrive the select          */
1858 /* Code : 1 -> Halt the current executing I/O                        */
1859 /*-------------------------------------------------------------------*/
commadpt_wakeup(COMMADPT * ca,BYTE code)1860 static void commadpt_wakeup(COMMADPT *ca,BYTE code)
1861 {
1862     write_pipe(ca->pipe[1],&code,1);
1863 }
1864 /*-------------------------------------------------------------------*/
1865 /* Wait for a copndition from the thread                             */
1866 /* MUST HOLD the CA lock                                             */
1867 /*-------------------------------------------------------------------*/
commadpt_wait(DEVBLK * dev)1868 static void commadpt_wait(DEVBLK *dev)
1869 {
1870     COMMADPT *ca;
1871     ca=dev->commadpt;
1872     wait_condition(&ca->ipc,&ca->lock);
1873 }
1874 
1875 /*-------------------------------------------------------------------*/
1876 /* Halt currently executing I/O command                              */
1877 /*-------------------------------------------------------------------*/
commadpt_halt(DEVBLK * dev)1878 static void    commadpt_halt(DEVBLK *dev)
1879 {
1880     if(!dev->busy)
1881     {
1882         return;
1883     }
1884     obtain_lock(&dev->commadpt->lock);
1885     commadpt_wakeup(dev->commadpt,1);
1886     /* Due to the mysteries of the host OS scheduling */
1887     /* the wait_condition may or may not exit after   */
1888     /* the CCW executor thread relinquishes control   */
1889     /* This however should not be of any concern      */
1890     /*                                                */
1891     /* but returning from the wait guarantees that    */
1892     /* the working thread will (or has) notified      */
1893     /* the CCW executor to terminate the current I/O  */
1894     wait_condition(&dev->commadpt->ipc_halt,&dev->commadpt->lock);
1895     dev->commadpt->haltprepare = 1; /* part of APL\360 2741 race cond I circumvention */
1896     release_lock(&dev->commadpt->lock);
1897 }
1898 /* The following 3 MSG functions ensure only 1 (one)  */
1899 /* hardcoded instance exist for the same numbered msg */
1900 /* that is issued on multiple situations              */
msg013e(DEVBLK * dev,char * kw,char * kv)1901 static void msg013e(DEVBLK *dev,char *kw,char *kv)
1902 {
1903         logmsg(_("HHCCA013E %4.4X:Incorrect %s specification %s\n"),dev->devnum,kw,kv);
1904 }
msg015e(DEVBLK * dev,char * dialt,char * kw)1905 static void msg015e(DEVBLK *dev,char *dialt,char *kw)
1906 {
1907         logmsg(_("HHCCA015E %4.4X:Missing parameter : DIAL=%s and %s not specified\n"),dev->devnum,dialt,kw);
1908 }
msg016w017i(DEVBLK * dev,char * dialt,char * kw,char * kv)1909 static void msg016w017i(DEVBLK *dev,char *dialt,char *kw,char *kv)
1910 {
1911         logmsg(_("HHCCA016W %4.4X:Conflicting parameter : DIAL=%s and %s=%s specified\n"),dev->devnum,dialt,kw,kv);
1912         logmsg(_("HHCCA017I %4.4X:RPORT parameter ignored\n"),dev->devnum);
1913 }
1914 /*-------------------------------------------------------------------*/
1915 /* Device Initialisation                                             */
1916 /*-------------------------------------------------------------------*/
commadpt_init_handler(DEVBLK * dev,int argc,char * argv[])1917 static int commadpt_init_handler (DEVBLK *dev, int argc, char *argv[])
1918 {
1919     char thread_name[32];
1920     int i,j;
1921     int ix;
1922     int rc;
1923     int pc; /* Parse code */
1924     int errcnt;
1925     struct in_addr in_temp;
1926     char    *dialt;
1927     char        fmtbfr[64];
1928     int etospec;        /* ETO= Specified */
1929     union {
1930         int num;
1931         char text[80];
1932     } res;
1933     char bf[4];
1934 
1935         dev->devtype=0x2703;
1936         if(dev->ccwtrace)
1937         {
1938                 logmsg(_("HHCCA300D %4.4X:Initialisation starting\n"),dev->devnum);
1939         }
1940 
1941         rc=commadpt_alloc_device(dev);
1942         if(rc<0)
1943         {
1944                 logmsg(_("HHCCA010I %4.4X:initialisation not performed\n"),
1945                         dev->devnum);
1946             return(-1);
1947         }
1948         if(dev->ccwtrace)
1949         {
1950                 logmsg(_("HHCCA300D %4.4X:Initialisation : Control block allocated\n"),dev->devnum);
1951         }
1952         errcnt=0;
1953         /*
1954          * Initialise ports & hosts
1955         */
1956         dev->commadpt->sfd=-1;
1957         dev->commadpt->lport=0;
1958         dev->commadpt->rport=0;
1959         dev->commadpt->lhost=INADDR_ANY;
1960         dev->commadpt->rhost=INADDR_NONE;
1961         dev->commadpt->dialin=0;
1962         dev->commadpt->dialout=1;
1963         dev->commadpt->rto=3000;        /* Read Time-Out in milis */
1964         dev->commadpt->pto=3000;        /* Poll Time-out in milis */
1965         dev->commadpt->eto=10000;       /* Enable Time-out in milis */
1966         dev->commadpt->lnctl=COMMADPT_LNCTL_BSC;
1967         dev->commadpt->term=COMMADPT_TERM_TTY;
1968         dev->commadpt->uctrans=FALSE;
1969         dev->commadpt->code_table_toebcdic   = xlate_table_ebcd_toebcdic;
1970         dev->commadpt->code_table_fromebcdic = xlate_table_ebcd_fromebcdic;
1971         memset(dev->commadpt->byte_skip_table, 0, sizeof(dev->commadpt->byte_skip_table) );
1972         memset(dev->commadpt->input_byte_skip_table, 0, sizeof(dev->commadpt->input_byte_skip_table) );
1973         dev->commadpt->dumb_bs=0;
1974         dev->commadpt->dumb_break=0;
1975         dev->commadpt->prepend_length = 0;
1976         dev->commadpt->append_length = 0;
1977         dev->commadpt->rxvt4apl = 0;
1978         dev->commadpt->overstrike_flag = 0;
1979         dev->commadpt->crlf_opt = 0;
1980         dev->commadpt->sendcr_opt = 0;
1981         dev->commadpt->binary_opt = 0;
1982         dev->commadpt->eol_char = 0x0d;   // default is ascii CR
1983         memset(dev->commadpt->prepend_bytes, 0, sizeof(dev->commadpt->prepend_bytes));
1984         memset(dev->commadpt->append_bytes, 0, sizeof(dev->commadpt->append_bytes));
1985         etospec=0;
1986 
1987         for(i=0;i<argc;i++)
1988         {
1989             pc=parser(ptab,argv[i],&res);
1990             if(pc<0)
1991             {
1992                 logmsg(_("HHCCA011E %4.4X:Error parsing %s\n"),dev->devnum,argv[i]);
1993                 errcnt++;
1994                 continue;
1995             }
1996             if(pc==0)
1997             {
1998                 logmsg(_("HHCCA012E %4.4X:Unrecognized parameter %s\n"),dev->devnum,argv[i]);
1999                 errcnt++;
2000                 continue;
2001             }
2002             switch(pc)
2003             {
2004                 case COMMADPT_KW_LPORT:
2005                     rc=commadpt_getport(res.text);
2006                     if(rc<0)
2007                     {
2008                         errcnt++;
2009                         msg013e(dev,"LPORT",res.text);
2010                         break;
2011                     }
2012                     dev->commadpt->lport=rc;
2013                     break;
2014                 case COMMADPT_KW_LHOST:
2015                     if(strcmp(res.text,"*")==0)
2016                     {
2017                         dev->commadpt->lhost=INADDR_ANY;
2018                         break;
2019                     }
2020                     rc=commadpt_getaddr(&dev->commadpt->lhost,res.text);
2021                     if(rc!=0)
2022                     {
2023                         msg013e(dev,"LHOST",res.text);
2024                         errcnt++;
2025                     }
2026                     break;
2027                 case COMMADPT_KW_RPORT:
2028                     rc=commadpt_getport(res.text);
2029                     if(rc<0)
2030                     {
2031                         errcnt++;
2032                         msg013e(dev,"RPORT",res.text);
2033                         break;
2034                     }
2035                     dev->commadpt->rport=rc;
2036                     break;
2037                 case COMMADPT_KW_RHOST:
2038                     if(strcmp(res.text,"*")==0)
2039                     {
2040                         dev->commadpt->rhost=INADDR_NONE;
2041                         break;
2042                     }
2043                     rc=commadpt_getaddr(&dev->commadpt->rhost,res.text);
2044                     if(rc!=0)
2045                     {
2046                         msg013e(dev,"RHOST",res.text);
2047                         errcnt++;
2048                     }
2049                     break;
2050                 case COMMADPT_KW_READTO:
2051                     dev->commadpt->rto=atoi(res.text);
2052                     break;
2053                 case COMMADPT_KW_POLLTO:
2054                     dev->commadpt->pto=atoi(res.text);
2055                     break;
2056                 case COMMADPT_KW_ENABLETO:
2057                     dev->commadpt->eto=atoi(res.text);
2058                     etospec=1;
2059                     break;
2060                 case COMMADPT_KW_LNCTL:
2061                     if(strcasecmp(res.text,"tele2")==0
2062                     || strcasecmp(res.text,"ibm1")==0 )
2063                     {
2064                         dev->commadpt->lnctl = COMMADPT_LNCTL_ASYNC;
2065                         dev->commadpt->rto=28000;        /* Read Time-Out in milis */
2066                     }
2067                     else
2068                         if(strcasecmp(res.text,"bsc")==0)
2069                         {
2070                             dev->commadpt->lnctl = COMMADPT_LNCTL_BSC;
2071                         }
2072                         else
2073                         {
2074                             msg013e(dev,"LNCTL",res.text);
2075                         }
2076                     break;
2077                 case COMMADPT_KW_TERM:
2078                     if(strcasecmp(res.text,"tty")==0)
2079                     {
2080                         dev->commadpt->term = COMMADPT_TERM_TTY;
2081                     }
2082                     else if(strcasecmp(res.text,"2741")==0)
2083                     {
2084                         dev->commadpt->term = COMMADPT_TERM_2741;
2085                     }
2086                     else if(strcasecmp(res.text,"rxvt4apl")==0)
2087                     {
2088                         dev->commadpt->term = COMMADPT_TERM_2741;
2089                         dev->commadpt->rxvt4apl = 1;
2090                     }
2091                     else
2092                     {
2093                         msg013e(dev,"TERM",res.text);
2094                     }
2095 
2096                     break;
2097                 case COMMADPT_KW_CODE:
2098                     if(strcasecmp(res.text,"corr")==0)
2099                     {
2100                         dev->commadpt->code_table_toebcdic   = xlate_table_cc_toebcdic;
2101                         dev->commadpt->code_table_fromebcdic = xlate_table_cc_fromebcdic;
2102                     }
2103                     else
2104                         if(strcasecmp(res.text,"ebcd")==0)
2105                         {
2106                             dev->commadpt->code_table_toebcdic   = xlate_table_ebcd_toebcdic;
2107                             dev->commadpt->code_table_fromebcdic = xlate_table_ebcd_fromebcdic;
2108                         }
2109                         else
2110                             if(strcasecmp(res.text,"none")==0)
2111                             {
2112                                 dev->commadpt->code_table_toebcdic   = NULL;
2113                                 dev->commadpt->code_table_fromebcdic = NULL;
2114                             }
2115                             else
2116                             {
2117                                 msg013e(dev,"CODE",res.text);
2118                             }
2119                     break;
2120                 case COMMADPT_KW_CRLF:
2121                     if(strcasecmp(res.text,"no")==0)
2122                     {
2123                         dev->commadpt->crlf_opt = FALSE;
2124                     }
2125                     else if(strcasecmp(res.text,"yes")==0)
2126                     {
2127                         dev->commadpt->crlf_opt = TRUE;
2128                     }
2129                     else
2130                     {
2131                         msg013e(dev,"CRLF",res.text);
2132                     }
2133                     break;
2134                 case COMMADPT_KW_SENDCR:
2135                     if(strcasecmp(res.text,"no")==0)
2136                     {
2137                         dev->commadpt->sendcr_opt = FALSE;
2138                     }
2139                     else if(strcasecmp(res.text,"yes")==0)
2140                     {
2141                         dev->commadpt->sendcr_opt = TRUE;
2142                     }
2143                     else
2144                     {
2145                         msg013e(dev,"SENDCR",res.text);
2146                     }
2147                     break;
2148                 case COMMADPT_KW_BINARY:
2149                     if(strcasecmp(res.text,"no")==0)
2150                     {
2151                         dev->commadpt->binary_opt = FALSE;
2152                     }
2153                     else if(strcasecmp(res.text,"yes")==0)
2154                     {
2155                         dev->commadpt->binary_opt = TRUE;
2156                     }
2157                     else
2158                     {
2159                         msg013e(dev,"BINARY",res.text);
2160                     }
2161                     break;
2162                 case COMMADPT_KW_UCTRANS:
2163                     if(strcasecmp(res.text,"no")==0)
2164                     {
2165                         dev->commadpt->uctrans = FALSE;
2166                     }
2167                     else
2168                         if(strcasecmp(res.text,"yes")==0)
2169                         {
2170                             dev->commadpt->uctrans = TRUE;
2171                         }
2172                         else
2173                         {
2174                             msg013e(dev,"UCTRANS",res.text);
2175                         }
2176                     break;
2177                 case COMMADPT_KW_EOL:
2178                     if  (strlen(res.text) < 2)
2179                         break;
2180                     bf[0] = res.text[0];
2181                     bf[1] = res.text[1];
2182                     bf[2] = 0;
2183                     sscanf(bf, "%x", &ix);
2184                     dev->commadpt->eol_char = ix;
2185                     break;
2186                 case COMMADPT_KW_SKIP:
2187                     if  (strlen(res.text) < 2)
2188                         break;
2189                     for (j=0; j < (int)strlen(res.text); j+= 2)
2190                     {
2191                         bf[0] = res.text[j+0];
2192                         bf[1] = res.text[j+1];
2193                         bf[2] = 0;
2194                         sscanf(bf, "%x", &ix);
2195                         dev->commadpt->byte_skip_table[ix] = 1;
2196                     }
2197                     break;
2198                 case COMMADPT_KW_PREPEND:
2199                     if  (strlen(res.text) != 2 && strlen(res.text) != 4
2200                       && strlen(res.text) != 6 && strlen(res.text) != 8)
2201                         break;
2202                     for (j=0; j < (int)strlen(res.text); j+= 2)
2203                     {
2204                         bf[0] = res.text[j+0];
2205                         bf[1] = res.text[j+1];
2206                         bf[2] = 0;
2207                         sscanf(bf, "%x", &ix);
2208                         dev->commadpt->prepend_bytes[j>>1] = ix;
2209                     }
2210                     dev->commadpt->prepend_length = strlen(res.text) >> 1;
2211                     break;
2212                 case COMMADPT_KW_APPEND:
2213                     if  (strlen(res.text) != 2 && strlen(res.text) != 4
2214                       && strlen(res.text) != 6 && strlen(res.text) != 8)
2215                         break;
2216                     for (j=0; j < (int)strlen(res.text); j+= 2)
2217                     {
2218                         bf[0] = res.text[j+0];
2219                         bf[1] = res.text[j+1];
2220                         bf[2] = 0;
2221                         sscanf(bf, "%x", &ix);
2222                         dev->commadpt->append_bytes[j>>1] = ix;
2223                     }
2224                     dev->commadpt->append_length = strlen(res.text) >> 1;
2225                     break;
2226                 case COMMADPT_KW_ISKIP:
2227                     if  (strlen(res.text) < 2)
2228                         break;
2229                     for (j=0; j < (int)strlen(res.text); j+= 2)
2230                     {
2231                         bf[0] = res.text[j+0];
2232                         bf[1] = res.text[j+1];
2233                         bf[2] = 0;
2234                         sscanf(bf, "%x", &ix);
2235                         dev->commadpt->input_byte_skip_table[ix] = 1;
2236                     }
2237                     break;
2238                 case COMMADPT_KW_BS:
2239                     if(strcasecmp(res.text,"dumb")==0) {
2240                         dev->commadpt->dumb_bs = 1;
2241                     }
2242                     break;
2243                 case COMMADPT_KW_BREAK:
2244                     if(strcasecmp(res.text,"dumb")==0)
2245                         dev->commadpt->dumb_break = 1;
2246                     break;
2247                 case COMMADPT_KW_SWITCHED:
2248                 case COMMADPT_KW_DIAL:
2249                     if(strcasecmp(res.text,"yes")==0 || strcmp(res.text,"1")==0 || strcasecmp(res.text,"inout")==0)
2250                     {
2251                         dev->commadpt->dialin=1;
2252                         dev->commadpt->dialout=1;
2253                         break;
2254                     }
2255                     if(strcasecmp(res.text,"no")==0 || strcmp(res.text,"0")==0)
2256                     {
2257                         dev->commadpt->dialin=0;
2258                         dev->commadpt->dialout=0;
2259                         break;
2260                     }
2261                     if(strcasecmp(res.text,"in")==0)
2262                     {
2263                         dev->commadpt->dialin=1;
2264                         dev->commadpt->dialout=0;
2265                         break;
2266                     }
2267                     if(strcasecmp(res.text,"out")==0)
2268                     {
2269                         dev->commadpt->dialin=0;
2270                         dev->commadpt->dialout=1;
2271                         break;
2272                     }
2273                     logmsg(_("HHCCA014E %4.4X:Incorrect switched/dial specification %s; defaulting to DIAL=OUT\n"),dev->devnum,res.text);
2274                     dev->commadpt->dialin=0;
2275                     dev->commadpt->dialout=0;
2276                     break;
2277                 default:
2278                     break;
2279             }
2280         }
2281         /*
2282          * Check parameters consistency
2283          * when DIAL=NO :
2284          *     lport must not be 0
2285          *     lhost may be anything
2286          *     rport must not be 0
2287          *     rhost must not be INADDR_NONE
2288          * when DIAL=IN or DIAL=INOUT
2289          *     lport must NOT be 0
2290          *     lhost may be anything
2291          *     rport MUST be 0
2292          *     rhost MUST be INADDR_NONE
2293          * when DIAL=OUT
2294          *     lport MUST be 0
2295          *     lhost MUST be INADDR_ANY
2296          *     rport MUST be 0
2297          *     rhost MUST be INADDR_NONE
2298         */
2299         switch(dev->commadpt->dialin+dev->commadpt->dialout*2)
2300         {
2301                 case 0:
2302                     dialt="NO";
2303                     break;
2304                 case 1:
2305                     dialt="IN";
2306                     break;
2307                 case 2:
2308                     dialt="OUT";
2309                     break;
2310                 case 3:
2311                     dialt="INOUT";
2312                     break;
2313                 default:
2314                     dialt="*ERR*";
2315                     break;
2316         }
2317         switch(dev->commadpt->dialin+dev->commadpt->dialout*2)
2318         {
2319             case 0: /* DIAL = NO */
2320                 dev->commadpt->eto=0;
2321                 if(dev->commadpt->lport==0)
2322                 {
2323                     msg015e(dev,dialt,"LPORT");
2324                     errcnt++;
2325                 }
2326                 if(dev->commadpt->rport==0)
2327                 {
2328                     msg015e(dev,dialt,"RPORT");
2329                     errcnt++;
2330                 }
2331                 if(dev->commadpt->rhost==INADDR_NONE)
2332                 {
2333                     msg015e(dev,dialt,"RHOST");
2334                     errcnt++;
2335                 }
2336                 if(etospec)
2337                 {
2338                     snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->eto);
2339                     msg016w017i(dev,dialt,"ETO",fmtbfr);
2340                     errcnt++;
2341                 }
2342                 dev->commadpt->eto=0;
2343                 break;
2344             case 1: /* DIAL = IN */
2345             case 3: /* DIAL = INOUT */
2346                 if(dev->commadpt->lport==0)
2347                 {
2348                     msg015e(dev,dialt,"LPORT");
2349                     errcnt++;
2350                 }
2351                 if(dev->commadpt->rport!=0)
2352                 {
2353                     snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->rport);
2354                     msg016w017i(dev,dialt,"RPORT",fmtbfr);
2355                 }
2356                 if(dev->commadpt->rhost!=INADDR_NONE)
2357                 {
2358                     in_temp.s_addr=dev->commadpt->rhost;
2359                     msg016w017i(dev,dialt,"RHOST",inet_ntoa(in_temp));
2360                     dev->commadpt->rhost=INADDR_NONE;
2361                 }
2362                 break;
2363             case 2: /* DIAL = OUT */
2364                 if(dev->commadpt->lport!=0)
2365                 {
2366                     snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->lport);
2367                     msg016w017i(dev,dialt,"LPORT",fmtbfr);
2368                     dev->commadpt->lport=0;
2369                 }
2370                 if(dev->commadpt->rport!=0)
2371                 {
2372                     snprintf(fmtbfr,sizeof(fmtbfr),"%d",dev->commadpt->rport);
2373                     msg016w017i(dev,dialt,"RPORT",fmtbfr);
2374                     dev->commadpt->rport=0;
2375                 }
2376                 if(dev->commadpt->lhost!=INADDR_ANY)    /* Actually it's more like INADDR_NONE */
2377                 {
2378                     in_temp.s_addr=dev->commadpt->lhost;
2379                     msg016w017i(dev,dialt,"LHOST",inet_ntoa(in_temp));
2380                     dev->commadpt->lhost=INADDR_ANY;
2381                 }
2382                 if(dev->commadpt->rhost!=INADDR_NONE)
2383                 {
2384                     in_temp.s_addr=dev->commadpt->rhost;
2385                     msg016w017i(dev,dialt,"RHOST",inet_ntoa(in_temp));
2386                     dev->commadpt->rhost=INADDR_NONE;
2387                 }
2388                 break;
2389         }
2390         if(errcnt>0)
2391         {
2392             logmsg(_("HHCCA021I %4.4X:Initialisation failed due to previous errors\n"),dev->devnum);
2393             return -1;
2394         }
2395         in_temp.s_addr=dev->commadpt->lhost;
2396         in_temp.s_addr=dev->commadpt->rhost;
2397         dev->bufsize=256;
2398         dev->numsense=2;
2399         memset(dev->sense,0,sizeof(dev->sense));
2400 
2401         /* Initialise various flags & statuses */
2402         dev->commadpt->enabled=0;
2403         dev->commadpt->connect=0;
2404         dev->fd=100;    /* Ensures 'close' function called */
2405         dev->commadpt->devnum=dev->devnum;
2406 
2407         dev->commadpt->telnet_opt=0;
2408         dev->commadpt->telnet_iac=0;
2409         dev->commadpt->telnet_int=0;
2410         dev->commadpt->eol_flag=0;
2411         dev->commadpt->telnet_cmd=0;
2412 
2413         dev->commadpt->haltpending=0;
2414         dev->commadpt->haltprepare=0;
2415 
2416         /* Initialize the device identifier bytes */
2417         dev->numdevid = sysblk.legacysenseid ? 7 : 0;
2418         dev->devid[0] = 0xFF;
2419         dev->devid[1] = dev->devtype >> 8;
2420         dev->devid[2] = dev->devtype & 0xFF;
2421         dev->devid[3] = 0x00;
2422         dev->devid[4] = dev->devtype >> 8;
2423         dev->devid[5] = dev->devtype & 0xFF;
2424         dev->devid[6] = 0x00;
2425 
2426         /* Initialize the CA lock */
2427         initialize_lock(&dev->commadpt->lock);
2428 
2429         /* Initialise thread->I/O & halt initiation EVB */
2430         initialize_condition(&dev->commadpt->ipc);
2431         initialize_condition(&dev->commadpt->ipc_halt);
2432 
2433         /* Allocate I/O -> Thread signaling pipe */
2434         create_pipe(dev->commadpt->pipe);
2435 
2436         /* Point to the halt routine for HDV/HIO/HSCH handling */
2437         dev->halt_device=commadpt_halt;
2438 
2439         /* Obtain the CA lock */
2440         obtain_lock(&dev->commadpt->lock);
2441 
2442         /* Indicate listen required if DIAL!=OUT */
2443         if(dev->commadpt->dialin ||
2444                 (!dev->commadpt->dialin && !dev->commadpt->dialout))
2445         {
2446             dev->commadpt->dolisten=1;
2447         }
2448         else
2449         {
2450             dev->commadpt->dolisten=0;
2451         }
2452 
2453         /* Start the async worker thread */
2454 
2455     /* Set thread-name for debugging purposes */
2456         snprintf(thread_name,sizeof(thread_name),
2457                  "commadpt %4.4X thread",dev->devnum);
2458         thread_name[sizeof(thread_name)-1]=0;
2459 
2460         dev->commadpt->curpending=COMMADPT_PEND_TINIT;
2461         rc = create_thread(&dev->commadpt->cthread,DETACHED,commadpt_thread,dev->commadpt,thread_name);
2462         if(rc)
2463         {
2464             logmsg(D_("HHCCA022E create_thread: %s\n"),strerror(errno));
2465             release_lock(&dev->commadpt->lock);
2466             return -1;
2467         }
2468         commadpt_wait(dev);
2469         if(dev->commadpt->curpending!=COMMADPT_PEND_IDLE)
2470         {
2471             logmsg(_("HHCCA019E %4.4x : BSC comm thread did not initialise\n"),dev->devnum);
2472             /* Release the CA lock */
2473             release_lock(&dev->commadpt->lock);
2474             return -1;
2475         }
2476         dev->commadpt->have_cthread=1;
2477 
2478         /* Release the CA lock */
2479         release_lock(&dev->commadpt->lock);
2480         /* Indicate succesfull completion */
2481         return 0;
2482 }
2483 
2484 static char *commadpt_lnctl_names[]={
2485     "NONE",
2486     "BSC",
2487     "ASYNC"
2488 };
2489 
2490 /*-------------------------------------------------------------------*/
2491 /* Query the device definition                                       */
2492 /*-------------------------------------------------------------------*/
commadpt_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)2493 static void commadpt_query_device (DEVBLK *dev, char **class,
2494                 int buflen, char *buffer)
2495 {
2496     BEGIN_DEVICE_CLASS_QUERY( "LINE", dev, class, buflen, buffer );
2497 
2498     snprintf(buffer,buflen,"%s STA=%s CN=%s, EIB=%s OP=%s",
2499             commadpt_lnctl_names[dev->commadpt->lnctl],
2500             dev->commadpt->enabled?"ENA":"DISA",
2501             dev->commadpt->connect?"YES":"NO",
2502             dev->commadpt->eibmode?"YES":"NO",
2503             commadpt_pendccw_text[dev->commadpt->curpending]);
2504 }
2505 
2506 /*-------------------------------------------------------------------*/
2507 /* Close the device                                                  */
2508 /* Invoked by HERCULES shutdown & DEVINIT processing                 */
2509 /*-------------------------------------------------------------------*/
commadpt_close_device(DEVBLK * dev)2510 static int commadpt_close_device ( DEVBLK *dev )
2511 {
2512     if(dev->ccwtrace)
2513     {
2514         logmsg(_("HHCCA300D %4.4X:Closing down\n"),dev->devnum);
2515     }
2516 
2517     /* Terminate current I/O thread if necessary */
2518     if(dev->busy)
2519     {
2520         commadpt_halt(dev);
2521     }
2522 
2523     /* Obtain the CA lock */
2524     obtain_lock(&dev->commadpt->lock);
2525 
2526     /* Terminate worker thread if it is still up */
2527     if(dev->commadpt->have_cthread)
2528     {
2529         dev->commadpt->curpending=COMMADPT_PEND_SHUTDOWN;
2530         commadpt_wakeup(dev->commadpt,0);
2531         commadpt_wait(dev);
2532         dev->commadpt->cthread=(TID)-1;
2533         dev->commadpt->have_cthread=0;
2534     }
2535 
2536 
2537     /* Free all work storage */
2538     /* The CA lock will be released by the cleanup routine */
2539     commadpt_clean_device(dev);
2540 
2541     /* Indicate to hercules the device is no longer opened */
2542     dev->fd=-1;
2543 
2544     if(dev->ccwtrace)
2545     {
2546         logmsg(_("HHCCA300D %4.4X:Closed down\n"),dev->devnum);
2547     }
2548     return 0;
2549 }
2550 
2551 
2552 /*-------------------------------------------------------------------*/
2553 /* Execute a Channel Command Word                                    */
2554 /*-------------------------------------------------------------------*/
commadpt_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)2555 static void commadpt_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags,
2556         BYTE chained, U16 count, BYTE prevcode, int ccwseq,
2557         BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual)
2558 {
2559 U32 num;                        /* Work : Actual CCW transfer count                   */
2560 BYTE    b;                      /* Input processing work variable : Current character */
2561 BYTE    setux;                  /* EOT kludge */
2562 BYTE    turnxpar;               /* Write contains turn to transparent mode */
2563 int     i;                      /* work */
2564 u_int   j;                      /* work */
2565 BYTE    gotdle;                 /* Write routine DLE marker */
2566 BYTE    b1, b2;                 /* 2741 overstrike rewriting */
2567     UNREFERENCED(flags);
2568     UNREFERENCED(chained);
2569     UNREFERENCED(prevcode);
2570     UNREFERENCED(ccwseq);
2571     *residual = 0;
2572     /*
2573      * Obtain the COMMADPT lock
2574      */
2575     if(dev->ccwtrace)
2576     {
2577         logmsg(_("HHCCA300D %4.4X:CCW Exec - Entry code = %x\n"),dev->devnum,code);
2578     }
2579     obtain_lock(&dev->commadpt->lock);
2580     if(code != 0x06) /* for any command other than PREPARE */
2581     {
2582         dev->commadpt->haltprepare = 0;
2583     }
2584     switch (code)
2585     {
2586         /*---------------------------------------------------------------*/
2587         /* CONTROL NO-OP                                                 */
2588         /*---------------------------------------------------------------*/
2589         case 0x03:
2590             *residual=0;
2591             *unitstat=CSW_CE|CSW_DE;
2592             break;
2593 
2594         /*---------------------------------------------------------------*/
2595         /* BASIC SENSE                                                   */
2596         /*---------------------------------------------------------------*/
2597         case 0x04:
2598             num=count<dev->numsense?count:dev->numsense;
2599             *more=count<dev->numsense?1:0;
2600             memcpy(iobuf,dev->sense,num);
2601             *residual=count-num;
2602             *unitstat=CSW_CE|CSW_DE;
2603             break;
2604 
2605         /*---------------------------------------------------------------*/
2606         /* SENSE ID                                                      */
2607         /*---------------------------------------------------------------*/
2608         case 0xE4:
2609             /* Calculate residual byte count */
2610             num = (count < dev->numdevid) ? count : dev->numdevid;
2611             *residual = count - num;
2612             *more = count < dev->numdevid ? 1 : 0;
2613 
2614             /* Copy device identifier bytes to channel I/O Buffer */
2615             memcpy (iobuf, dev->devid, num);
2616 
2617             /* Return unit status */
2618             *unitstat = CSW_CE | CSW_DE;
2619             break;
2620 
2621         /*---------------------------------------------------------------*/
2622         /* ENABLE                                                        */
2623         /*---------------------------------------------------------------*/
2624         case 0x27:
2625             if(dev->commadpt->dialin+dev->commadpt->dialout*2==2)
2626             {
2627                 /* Enable makes no sense on a dial out only line */
2628                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2629                 dev->sense[0]=SENSE_IR;
2630                 dev->sense[1]=0x2E; /* Simulate Failed Call In */
2631                 break;
2632             }
2633             if(dev->commadpt->connect)
2634             {
2635                 /* Already connected */
2636                 dev->commadpt->enabled=1;
2637                 *unitstat=CSW_CE|CSW_DE;
2638                 break;
2639             }
2640             dev->commadpt->curpending=COMMADPT_PEND_ENABLE;
2641             commadpt_wakeup(dev->commadpt,0);
2642             commadpt_wait(dev);
2643             /* If the line is not connected now, then ENABLE failed */
2644             if(dev->commadpt->connect)
2645             {
2646                 *unitstat=CSW_CE|CSW_DE;
2647                 dev->commadpt->enabled=1;
2648                 /* Clean the input buffer */
2649                 commadpt_ring_flush(&dev->commadpt->inbfr);
2650                 break;
2651             }
2652             if(dev->commadpt->haltpending)
2653             {
2654                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
2655                 dev->commadpt->haltpending=0;
2656                 break;
2657             }
2658             if(dev->commadpt->dialin)
2659             {
2660                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2661                 dev->sense[0]=SENSE_IR;
2662                 dev->sense[1]=0x2e;
2663             }
2664             else
2665             {
2666                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2667                 dev->sense[0]=SENSE_IR;
2668                 dev->sense[1]=0x21;
2669             }
2670             break;
2671 
2672         /*---------------------------------------------------------------*/
2673         /* DISABLE                                                       */
2674         /*---------------------------------------------------------------*/
2675         case 0x2F:
2676             /* Reset some flags */
2677             dev->commadpt->xparwwait=0;
2678             commadpt_ring_flush(&dev->commadpt->inbfr);      /* Flush buffers */
2679             commadpt_ring_flush(&dev->commadpt->outbfr);      /* Flush buffers */
2680             commadpt_ring_flush(&dev->commadpt->ttybuf);      /* Flush buffers */
2681 
2682             if((!dev->commadpt->dialin && !dev->commadpt->dialout) || !dev->commadpt->connect)
2683             {
2684                 *unitstat=CSW_CE|CSW_DE;
2685                 dev->commadpt->enabled=0;
2686                 break;
2687             }
2688             dev->commadpt->curpending=COMMADPT_PEND_DISABLE;
2689             commadpt_wakeup(dev->commadpt,0);
2690             commadpt_wait(dev);
2691             dev->commadpt->enabled=0;
2692             *unitstat=CSW_CE|CSW_DE;
2693             break;
2694         /*---------------------------------------------------------------*/
2695         /* SET MODE                                                      */
2696         /*---------------------------------------------------------------*/
2697         case 0x23:
2698             /* Transparent Write Wait State test */
2699             if(dev->commadpt->xparwwait)
2700             {
2701                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2702                 dev->sense[0]=SENSE_CR;
2703                 return;
2704             }
2705             num=1;
2706             *residual=count-num;
2707             *unitstat=CSW_CE|CSW_DE;
2708             if(dev->ccwtrace)
2709             {
2710                 logmsg(_("HHCCA300D %4.4X Set Mode : %s\n"),dev->devnum,iobuf[0]&0x40 ? "EIB":"NO EIB");
2711             }
2712             dev->commadpt->eibmode=(iobuf[0]&0x40)?1:0;
2713             break;
2714         /*---------------------------------------------------------------*/
2715         /* POLL Command                                                  */
2716         /*---------------------------------------------------------------*/
2717         case 0x09:
2718             /* Transparent Write Wait State test */
2719             if(dev->commadpt->xparwwait)
2720             {
2721                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2722                 dev->sense[0]=SENSE_CR;
2723                 return;
2724             }
2725             /* Save POLL data */
2726             commadpt_ring_flush(&dev->commadpt->pollbfr);
2727             commadpt_ring_pushbfr(&dev->commadpt->pollbfr,iobuf,count);
2728             /* Set some utility variables */
2729             dev->commadpt->pollused=0;
2730             dev->commadpt->badpoll=0;
2731             /* Tell thread */
2732             dev->commadpt->curpending=COMMADPT_PEND_POLL;
2733             commadpt_wakeup(dev->commadpt,0);
2734             commadpt_wait(dev);
2735             /* Flush the output & poll rings */
2736             commadpt_ring_flush(&dev->commadpt->outbfr);
2737             commadpt_ring_flush(&dev->commadpt->pollbfr);
2738             /* Check for HALT */
2739             if(dev->commadpt->haltpending)
2740             {
2741                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
2742                 dev->commadpt->haltpending=0;
2743                 break;
2744             }
2745             /* Check for bad poll data */
2746             if(dev->commadpt->badpoll)
2747             {
2748                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2749                 dev->sense[0]=0x08;
2750                 dev->sense[1]=0x84;
2751                 break;
2752             }
2753             /* Determine remaining length */
2754             *residual=count-dev->commadpt->pollused;
2755             /* Determine if SM should be set (succesfull or unsucessfull POLLs) */
2756             /* exhausting poll data when all stations reported NO data          */
2757             /* does not set Status Modifier                                     */
2758             *unitstat=CSW_CE|CSW_DE|(dev->commadpt->pollsm?CSW_SM:0);
2759             /* NOTE : The index byte (and rest) are in the Input Ring */
2760             break;
2761 
2762         /*---------------------------------------------------------------*/
2763         /* DIAL                                                          */
2764         /* Info on DIAL DATA :                                           */
2765         /* Dial character formats :                                      */
2766         /*                        x x x x 0 0 0 0 : 0                    */
2767         /*                            ........                           */
2768         /*                        x x x x 1 0 0 1 : 9                    */
2769         /*                        x x x x 1 1 0 0 : SEP                  */
2770         /*                        x x x x 1 1 0 1 : EON                  */
2771         /* EON is ignored                                                */
2772         /* format is : AAA/SEP/BBB/SEP/CCC/SEP/DDD/SEP/PPPP              */
2773         /*          where A,B,C,D,P are numbers from 0 to 9              */
2774         /* This perfoms an outgoing call to AAA.BBB.CCC.DDD port PPPP    */
2775         /*---------------------------------------------------------------*/
2776         case 0x29:
2777             /* The line must have dial-out capability */
2778             if(!dev->commadpt->dialout)
2779             {
2780                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2781                 dev->sense[0]=SENSE_CR;
2782                 dev->sense[1]=0x04;
2783                 break;
2784             }
2785             /* The line must be disabled */
2786             if(dev->commadpt->enabled)
2787             {
2788                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2789                 dev->sense[0]=SENSE_CR;
2790                 dev->sense[1]=0x05;
2791                 break;
2792             }
2793             num=count>sizeof(dev->commadpt->dialdata) ? sizeof(dev->commadpt->dialdata) : count;
2794             memcpy(dev->commadpt->dialdata,iobuf,num);
2795             dev->commadpt->curpending=COMMADPT_PEND_DIAL;
2796             commadpt_wakeup(dev->commadpt,0);
2797             commadpt_wait(dev);
2798             *residual=count-num;
2799             if(dev->commadpt->haltpending)
2800             {
2801                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
2802                 dev->commadpt->haltpending=0;
2803                 break;
2804             }
2805             if(!dev->commadpt->connect)
2806             {
2807                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2808                 dev->sense[0]=SENSE_IR;
2809                 dev->commadpt->enabled=0;
2810             }
2811             else
2812             {
2813                 *unitstat=CSW_CE|CSW_DE;
2814                 dev->commadpt->enabled=1;
2815             }
2816             break;
2817 
2818         /*---------------------------------------------------------------*/
2819         /* READ                                                          */
2820         /*---------------------------------------------------------------*/
2821         case 0x02:
2822         case 0x0a:          /* also INHIBIT */
2823             setux=0;
2824             /* Check the line is enabled */
2825             if(!dev->commadpt->enabled)
2826             {
2827                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2828                 dev->sense[0]=SENSE_CR;
2829                 dev->sense[1]=0x06;
2830                 break;
2831             }
2832             /* Transparent Write Wait State test */
2833             if(dev->commadpt->xparwwait)
2834             {
2835                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2836                 dev->sense[0]=SENSE_CR;
2837                 break;
2838             }
2839             /* Check for any remaining data in read work buffer */
2840             /* for async, we allow all reads to wait (even if data is available now) */
2841             /* (APL\360 2741 race cond III circumvention) see APLSASUP label UNRZ19 */
2842             if(dev->commadpt->readcomp && IS_BSC_LNCTL(dev->commadpt))
2843             {
2844                 if (dev->commadpt->rdwrk.havedata)
2845                 {
2846                     num=(U32)commadpt_ring_popbfr(&dev->commadpt->rdwrk,iobuf,count);
2847                     if(dev->commadpt->rdwrk.havedata)
2848                     {
2849                         *more=1;
2850                     }
2851                     *residual=count-num;
2852                     *unitstat=CSW_CE|CSW_DE;
2853                     break;
2854                 }
2855             }
2856             if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int)
2857             {
2858                 dev->commadpt->telnet_int = 0;
2859                 *residual=count;
2860                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
2861                 dev->sense[0]=SENSE_IR;
2862                 break;
2863             }
2864             /* Catch a race condition.                                                           */
2865             /* TCAM likes to issue halt I/O as a matter of routine, and it expects to get back a */
2866             /* unit exception along with the normal channel end + device end.                    */
2867             /* Sometimes the halt I/O loses the race (with the write CCW) and we catch up here.  */
2868             if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->haltpending)
2869             {
2870                 dev->commadpt->haltpending = 0;
2871                 *residual=0;
2872                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
2873                 break;
2874             }
2875 #if 0
2876             // MHP TEST 2740
2877             *residual=count;
2878             *unitstat=CSW_CE|CSW_DE;
2879             break;
2880 #endif
2881             if(dev->commadpt->datalostcond)
2882             {
2883                 dev->commadpt->datalostcond=0;
2884                 commadpt_ring_flush(&dev->commadpt->inbfr);
2885                 *residual=count;
2886                 *unitstat=CSW_CE|CSW_DE;
2887                 break;
2888             }
2889             dev->commadpt->readcomp=0;
2890             *unitstat=0;
2891             num=0;
2892                 /* The following is the BIG READ ROUTINE MESS */
2893                 /* the manual's indications on when to exit   */
2894                 /* a read and what to transfer to the main    */
2895                 /* storage is fuzzy (at best)                 */
2896                 /*                                            */
2897                 /* The line input can be in 3 possible        */
2898                 /* conditions :                               */
2899                 /*     Transparent Text Mode                  */
2900                 /*     Text Mode                              */
2901                 /*     none of the above (initial status)     */
2902                 /* transition from one mode to the other is   */
2903                 /* also not very well documented              */
2904                 /* so the following code is based on          */
2905                 /* empirical knowledge and some interpretation*/
2906                 /* also... the logic should probably be       */
2907                 /* rewritten                                  */
2908 
2909                 /* We will remain in READ state with the thread */
2910                 /* as long as we haven't met a read ending condition */
2911             while(1)
2912             {
2913                 /* READ state */
2914                 dev->commadpt->curpending=COMMADPT_PEND_READ;
2915                 /* Tell worker thread */
2916                 commadpt_wakeup(dev->commadpt,0);
2917                 /* Wait for some data */
2918                 commadpt_wait(dev);
2919 
2920                 /* If we are not connected, the read fails */
2921                 if(!dev->commadpt->connect)
2922                 {
2923                     *unitstat=CSW_DE|CSW_CE|CSW_UC;
2924                     dev->sense[0]=SENSE_IR;
2925                     break;
2926                 }
2927 
2928                 /* If the I/O was halted - indicate Unit Check */
2929                 if(dev->commadpt->haltpending)
2930                 {
2931                     *unitstat=CSW_CE|CSW_DE|CSW_UX;
2932                     dev->commadpt->haltpending=0;
2933                     break;
2934                 }
2935 
2936                 if (IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int)
2937                 {
2938                     dev->commadpt->telnet_int = 0;
2939                     *residual=count;
2940                     *unitstat=CSW_CE|CSW_DE|CSW_UC;
2941                     dev->sense[0]=SENSE_IR;
2942                     break;
2943                 }
2944 
2945                 /* If no data is present - 3 seconds have passed without */
2946                 /* receiving data (or a SYNC)                            */
2947                 /* (28 seconds for LNCTL_ASYNC)                          */
2948                 /* INHIBIT command does not time out                     */
2949                 /* eol_flag set means data is present */
2950                 if(!dev->commadpt->inbfr.havedata && code != 0x0a && !dev->commadpt->eol_flag)
2951                 {
2952                     *unitstat=CSW_DE|CSW_CE|CSW_UC;
2953                     dev->sense[0]=0x01;
2954                     dev->sense[1]=0xe3;
2955                     break;
2956                 }
2957                 if (IS_BSC_LNCTL(dev->commadpt))
2958                 {
2959                     /* Start processing data flow here */
2960                     /* Pop bytes until we run out of data or */
2961                     /* until the processing indicates the read */
2962                     /* should now terminate */
2963                     while( dev->commadpt->inbfr.havedata
2964                             && !dev->commadpt->readcomp)
2965                     {
2966                         /* fetch 1 byte from the input ring */
2967                         b=commadpt_ring_pop(&dev->commadpt->inbfr);
2968                         if(!dev->commadpt->gotdle)
2969                         {
2970                             if(b==0x10)
2971                             {
2972                                 dev->commadpt->gotdle=1;
2973                                 continue;
2974                             }
2975                         }
2976                         if(dev->commadpt->in_textmode)
2977                         {
2978                             if(dev->commadpt->in_xparmode)
2979                             {
2980                                 /* TRANSPARENT MODE READ */
2981                                 if(dev->commadpt->gotdle)
2982                                 {
2983                                     switch(b)
2984                                     {
2985                                         case 0x10:
2986                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
2987                                             break;
2988                                         case 0x32:
2989                                             break;
2990                                         case 0x1F: /* ITB - Exit xparent, set EIB - do NOT exit read yet */
2991                                             dev->commadpt->in_xparmode=0;
2992                                             commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
2993                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
2994                                             if(dev->commadpt->eibmode)
2995                                             {
2996                                                 commadpt_ring_push(&dev->commadpt->rdwrk,0);
2997                                             }
2998                                             break;
2999                                         case 0x26: /* ETB - Same as ITB but DO exit read now */
3000                                             dev->commadpt->in_xparmode=0;
3001                                             commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3002                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
3003                                             if(dev->commadpt->eibmode)
3004                                             {
3005                                                 commadpt_ring_push(&dev->commadpt->rdwrk,0);
3006                                             }
3007                                             dev->commadpt->readcomp=1;
3008                                             break;
3009                                         case 0x03: /* ETX - Same as ETB */
3010                                             dev->commadpt->in_xparmode=0;
3011                                             commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3012                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
3013                                             if(dev->commadpt->eibmode)
3014                                             {
3015                                                 commadpt_ring_push(&dev->commadpt->rdwrk,0);
3016                                             }
3017                                             dev->commadpt->readcomp=1;
3018                                             break;
3019                                         case 0x2D: /* ENQ */
3020                                             dev->commadpt->in_xparmode=0;
3021                                             dev->commadpt->in_textmode=0;
3022                                             commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3023                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
3024                                             dev->commadpt->readcomp=1;
3025                                             break;
3026                                         default:
3027                                             commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3028                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
3029                                             break;
3030                                     }
3031                                 }
3032                                 else
3033                                 {
3034                                     commadpt_ring_push(&dev->commadpt->rdwrk,b);
3035                                 }
3036                             }
3037                             else
3038                             {
3039                                 if(b!=0x32)
3040                                 {
3041                                      /* TEXT MODE READ */
3042                                     if(dev->commadpt->gotdle)
3043                                     {
3044                                         switch(b)
3045                                         {
3046                                             case 0x02: /* STX */
3047                                             dev->commadpt->in_xparmode=1;
3048                                             break;
3049                                             case 0x2D: /* ENQ */
3050                                             dev->commadpt->readcomp=1;
3051                                             break;
3052                                             default:
3053                                                 if((b&0xf0)==0x60 || (b&0xf0)==0x70)
3054                                                 {
3055                                                     dev->commadpt->readcomp=1;
3056                                                 }
3057                                                 break;
3058                                         }
3059                                         commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3060                                         commadpt_ring_push(&dev->commadpt->rdwrk,b);
3061                                     }
3062                                     else
3063                                     {
3064                                         switch(b)
3065                                         {
3066                                             case 0x2D:      /* ENQ */
3067                                                 dev->commadpt->readcomp=1;
3068                                                 dev->commadpt->in_textmode=0;
3069                                                 commadpt_ring_push(&dev->commadpt->rdwrk,b);
3070                                                 break;
3071                                             case 0x3D:      /* NAK */
3072                                                 dev->commadpt->readcomp=1;
3073                                                 commadpt_ring_push(&dev->commadpt->rdwrk,b);
3074                                                 break;
3075                                             case 0x26:      /* ETB */
3076                                             case 0x03:      /* ETX */
3077                                                 dev->commadpt->readcomp=1;
3078                                                 dev->commadpt->in_textmode=0;
3079                                                 commadpt_ring_push(&dev->commadpt->rdwrk,b);
3080                                                 if(dev->commadpt->eibmode)
3081                                                 {
3082                                                     commadpt_ring_push(&dev->commadpt->rdwrk,0);
3083                                                 }
3084                                                 break;
3085                                             case 0x1F:      /* ITB */
3086                                                 commadpt_ring_push(&dev->commadpt->rdwrk,b);
3087                                                 if(dev->commadpt->eibmode)
3088                                                 {
3089                                                     commadpt_ring_push(&dev->commadpt->rdwrk,0);
3090                                                 }
3091                                                 break;
3092                                             default:
3093                                                 commadpt_ring_push(&dev->commadpt->rdwrk,b);
3094                                                 break;
3095                                         }
3096                                     }
3097                                 }
3098                             }
3099                         }
3100                         else
3101                         {
3102                             if(b!=0x32)
3103                             {
3104                                 if(dev->commadpt->gotdle)
3105                                 {
3106                                     if((b & 0xf0) == 0x60 || (b&0xf0)==0x70)
3107                                     {
3108                                         commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3109                                         commadpt_ring_push(&dev->commadpt->rdwrk,b);
3110                                         dev->commadpt->readcomp=1;
3111                                     }
3112                                     else
3113                                     {
3114                                         if(b==0x02)
3115                                         {
3116                                             commadpt_ring_push(&dev->commadpt->rdwrk,0x10);
3117                                             commadpt_ring_push(&dev->commadpt->rdwrk,b);
3118                                             dev->commadpt->in_textmode=1;
3119                                             dev->commadpt->in_xparmode=1;
3120                                         }
3121                                     }
3122                                 }
3123                                 else
3124                                 {
3125                                     switch(b)
3126                                     {
3127                                         case 0x37:  /* EOT */
3128                                             setux=1;
3129                                             dev->commadpt->readcomp=1;
3130                                             break;
3131                                         case 0x01:
3132                                         case 0x02:
3133                                             dev->commadpt->in_textmode=1;
3134                                             break;
3135                                         case 0x2D: /* ENQ */
3136                                             dev->commadpt->readcomp=1;
3137                                             break;
3138                                         case 0x3D: /* NAK */
3139                                             dev->commadpt->readcomp=1;
3140                                             break;
3141                                         default:
3142                                             break;
3143                                     }
3144                                     commadpt_ring_push(&dev->commadpt->rdwrk,b);
3145                                 }
3146                             }
3147                         }
3148                         dev->commadpt->gotdle=0;
3149                     } /* END WHILE - READ FROM DATA BUFFER */
3150                 } /* end of if (bsc) */
3151                 /* If readcomp is set, then we may exit the read loop */
3152                 if(dev->commadpt->readcomp || dev->commadpt->eol_flag)
3153                 {
3154                     if (dev->commadpt->rdwrk.havedata || dev->commadpt->eol_flag)
3155                     {
3156                             num=commadpt_ring_popbfr(&dev->commadpt->rdwrk,iobuf,count);
3157                         if(dev->commadpt->rdwrk.havedata)
3158                         {
3159                             *more=1;
3160                         }
3161                         *residual=count-num;
3162                         *unitstat=CSW_CE|CSW_DE|(setux?CSW_UX:0);
3163                         logdump("Read",dev,iobuf,num);
3164                         if(IS_ASYNC_LNCTL(dev->commadpt)&& !dev->commadpt->rdwrk.havedata && *residual > 0)
3165                             dev->commadpt->eol_flag = 0;
3166                         break;
3167                     }
3168                 }
3169             } /* END WHILE - READ FROM THREAD */
3170             break;
3171 
3172         /*---------------------------------------------------------------*/
3173         /* WRITE                                                         */
3174         /*---------------------------------------------------------------*/
3175         case 0x01:
3176         case 0x0d:       /* also CCW=BREAK */
3177                 logdump("Writ",dev,iobuf,count);
3178                 *residual=count;
3179 
3180                 /* Check if we have an opened path */
3181                 if(!dev->commadpt->connect)
3182                 {
3183                     *unitstat=CSW_CE|CSW_DE|CSW_UC;
3184                     dev->sense[0]=SENSE_IR;
3185                     break;
3186                 }
3187 
3188                 /* Check if the line has been enabled */
3189                 if(!dev->commadpt->enabled)
3190                 {
3191                     *unitstat=CSW_CE|CSW_DE|CSW_UC;
3192                     dev->sense[0]=SENSE_CR;
3193                     break;
3194                 }
3195 
3196                 dev->commadpt->haltpending = 0; /* circumvent APL\360 2741 race cond II */
3197                 /* read 1 byte to check for pending input */
3198                 i=read_socket(dev->commadpt->sfd,&b,1);
3199                 if (IS_ASYNC_LNCTL(dev->commadpt))
3200                 {
3201                     if(i>0)
3202                     {
3203                         logdump("RCV0",dev,&b,1);
3204                         commadpt_read_tty(dev->commadpt,&b,1);
3205                     }
3206                 }
3207                 else
3208                 {
3209                     if(i>0)
3210                     {
3211                     /* Push it in the communication input buffer ring */
3212                         commadpt_ring_push(&dev->commadpt->inbfr,b);
3213                     }
3214                     /* Set UX on write if line has pending inbound data */
3215                     if(dev->commadpt->inbfr.havedata)
3216                     {
3217                         dev->commadpt->datalostcond=1;
3218                         *unitstat=CSW_CE|CSW_DE|CSW_UX;
3219                         break;
3220                     }
3221                 }  /* end of else (async) */
3222                 /*
3223                  * Fill in the Write Buffer
3224                  */
3225 
3226                 /* To start : not transparent mode, no DLE received yet */
3227                 turnxpar=0;
3228                 gotdle=0;
3229                 if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int
3230                    /* ugly hack for TSO ATTN to fix IEA000I 0C3,IOE,01,0E40,40008900002C,,,TCAM */
3231                    && !(iobuf[0] == 0xdf && iobuf[1] == 0xdf && iobuf[2] == 0xdf && count == 3))
3232                 {
3233                        dev->commadpt->telnet_int = 0;
3234                        *residual=count;
3235                        *unitstat=CSW_CE|CSW_DE|CSW_UC;
3236                        dev->sense[0]=SENSE_IR;
3237                        break;
3238                 }
3239 
3240                 /* Scan the I/O buffer */
3241                 for(i=0;i<count;i++)
3242                 {
3243                     /* Get 1 byte */
3244                     b=iobuf[i];
3245 
3246                     if (IS_ASYNC_LNCTL(dev->commadpt))
3247                     {
3248                         if (dev->commadpt->byte_skip_table[b])
3249                         continue;
3250                         if (dev->commadpt->term == COMMADPT_TERM_TTY)
3251                         {
3252                             b = byte_reverse_table[b] & 0x7f;
3253                         }
3254                         else
3255                         { /* 2741 */
3256                             if (count == 1 && b == CIRCLE_D)
3257                             {
3258                                 b = 0x00; /* map initial Circle-D to NUL */
3259                             }
3260                             else if (dev->commadpt->rxvt4apl)
3261                             {
3262                                 if (dev->commadpt->overstrike_flag == 1 && (b & 0x7f) == 0x5d)
3263                                 { /* char is another backspace but overstrike was expected */
3264                                     dev->commadpt->overstrike_flag = 0;
3265                                     dev->commadpt->saved_char = b;
3266                                     b = rxvt4apl_from_2741[b];
3267                                 }
3268                                 else if (dev->commadpt->overstrike_flag == 1)
3269                                 {
3270                                     dev->commadpt->overstrike_flag = 0;
3271                                     if (((u_int)dev->commadpt->saved_char) > ((u_int)b))
3272                                     {
3273                                         b1 = b;
3274                                         b2 = dev->commadpt->saved_char;
3275                                     }
3276                                     else
3277                                     {
3278                                         b1 = dev->commadpt->saved_char;
3279                                         b2 = b;
3280                                     }
3281                                     b = '?';
3282                                     for (j = 0; j < sizeof(overstrike_2741_pairs); j+=2) {
3283                                         if (overstrike_2741_pairs[j] == b1 && overstrike_2741_pairs[j+1] == b2) {
3284                                             b = overstrike_rxvt4apl_chars[j>>1];
3285                                         }
3286                                     }
3287                                 }
3288                                 else if ((b & 0x7f) == 0x5d /* 2741 backspace */
3289                                       && (dev->commadpt->saved_char & 0x7f) != 0x5d
3290                                       && (dev->commadpt->saved_char & 0x7f) != 0x3b
3291                                       && (dev->commadpt->saved_char & 0x7f) != 0x7f)
3292                                 {
3293                                     dev->commadpt->overstrike_flag = 1;
3294                                     b = rxvt4apl_from_2741[b];
3295                                 }
3296                                 else
3297                                 {
3298                                     dev->commadpt->overstrike_flag = 0;
3299                                     dev->commadpt->saved_char = b;
3300                                     b = rxvt4apl_from_2741[b];
3301                                     if (b == 0x0d && dev->commadpt->crlf_opt) /* ascii CR? */
3302                                     {   /* 2741 NL has been mapped to CR, we need to append LF to this (sigh) */
3303                                         commadpt_ring_push(&dev->commadpt->outbfr,b);
3304                                         b = 0x0a;
3305                                     }
3306                                 }
3307                             }
3308                             else if (dev->commadpt->code_table_toebcdic)
3309                             {
3310                                 b = dev->commadpt->code_table_toebcdic[b];  // first translate to EBCDIC
3311                                 b = guest_to_host(b) & 0x7f; // then EBCDIC to ASCII
3312                             }
3313                         }
3314                     }
3315                     else
3316                     {   /* line is BSC */
3317                         /* If we are in transparent mode, we must double the DLEs */
3318                         if(turnxpar)
3319                         {
3320                             /* Check for a DLE */
3321                             if(b==0x10)
3322                             {
3323                                 /* put another one in the output buffer */
3324                                 commadpt_ring_push(&dev->commadpt->outbfr,0x10);
3325                             }
3326                         }
3327                         else        /* non transparent mode */
3328                         {
3329                             if(b==0x10)
3330                             {
3331                                 gotdle=1;   /* Indicate we have a DLE for next pass */
3332                             }
3333                             else
3334                             {
3335                                 /* If there was a DLE on previous pass */
3336                                 if(gotdle)
3337                             {
3338                                 /* check for DLE/ETX */
3339                                 if(b==0x02)
3340                                 {
3341                                     /* Indicate transparent mode on */
3342                                     turnxpar=1;
3343                                 }
3344                             }
3345                         }
3346                     }
3347                 }  /* end of else (async) */
3348                 /* Put the current byte on the output ring */
3349                 commadpt_ring_push(&dev->commadpt->outbfr,b);
3350             }
3351             if (IS_BSC_LNCTL(dev->commadpt))
3352             {
3353                 /* If we had a DLE/STX, the line is now in Transparent Write Wait state */
3354                 /* meaning that no CCW codes except Write, No-Op, Sense are allowed     */
3355                 /* (that's what the manual says.. I doubt DISABLE is disallowed)        */
3356                 /* Anyway.. The program will have an opportunity to turn XPARENT mode   */
3357                 /* off on the next CCW.                                                 */
3358                 /* CAVEAT : The manual doesn't say if the line remains in transparent   */
3359                 /*          Write Wait state if the next CCW doesn't start with DLE/ETX */
3360                 /*          or DLE/ITB                                                  */
3361                 if(turnxpar)
3362                 {
3363                     dev->commadpt->xparwwait=1;
3364                 }
3365                 else
3366                 {
3367                     dev->commadpt->xparwwait=0;
3368                 }
3369             }  /* end of if(bsc line) */
3370             /* Indicate to the worker thread the current operation is OUTPUT */
3371             dev->commadpt->curpending=COMMADPT_PEND_WRITE;
3372 
3373             /* All bytes written out - residual = 0 */
3374             *residual=0;
3375 
3376             /* Wake-up the worker thread */
3377             commadpt_wakeup(dev->commadpt,0);
3378 
3379             /* Wait for operation completion */
3380             commadpt_wait(dev);
3381 
3382             /* Check if the line is still connected */
3383             if(!dev->commadpt->connect)
3384             {
3385                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
3386                 dev->sense[0]=SENSE_IR;
3387                 break;
3388             }
3389 
3390             /* Check if the I/O was interrupted */
3391             if(dev->commadpt->haltpending)
3392             {
3393                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
3394                 dev->commadpt->haltpending = 0;
3395                 break;
3396             }
3397             *unitstat=CSW_CE|CSW_DE;
3398             break;
3399 
3400         /*---------------------------------------------------------------*/
3401         /* PREPARE                                                       */
3402         /* NOTE : DO NOT SET RESIDUAL to 0 : Otherwise, channel.c        */
3403         /*        will reflect a channel prot check - residual           */
3404         /*        should indicate NO data was transfered for this        */
3405         /*        pseudo-read operation                                  */
3406         /*---------------------------------------------------------------*/
3407         case 0x06:
3408             *residual=count;
3409             /* PREPARE not allowed unless line is enabled */
3410             if(!dev->commadpt->enabled)
3411             {
3412                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
3413                 dev->sense[0]=SENSE_CR;
3414                 dev->sense[1]=0x06;
3415                 break;
3416             }
3417 
3418             if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->haltprepare)
3419             {  /* circumvent APL\360 2741 race cond I */
3420                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
3421                 break;
3422             } /* end of if(async) */
3423 
3424             if(IS_ASYNC_LNCTL(dev->commadpt) && dev->commadpt->telnet_int)
3425             {
3426                 dev->commadpt->telnet_int = 0;
3427                 *unitstat=CSW_CE|CSW_DE;
3428                 if(dev->commadpt->haltpending)
3429                 {
3430                     dev->commadpt->haltpending=0;
3431                     *unitstat |= CSW_UX;
3432                 }
3433                 break;
3434             } /* end of if(async) */
3435 
3436             /* Transparent Write Wait State test */
3437             if(dev->commadpt->xparwwait)
3438             {
3439                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
3440                 dev->sense[0]=SENSE_CR;
3441                 return;
3442             }
3443 
3444             /* If data is present, prepare ends immediatly */
3445             if(dev->commadpt->inbfr.havedata)
3446             {
3447                 *unitstat=CSW_CE|CSW_DE;
3448                 break;
3449             }
3450 
3451             /* Indicate to the worker thread to notify us when data arrives */
3452             dev->commadpt->curpending=COMMADPT_PEND_PREPARE;
3453 
3454             /* Wakeup worker thread */
3455             commadpt_wakeup(dev->commadpt,0);
3456 
3457             /* Wait for completion */
3458             commadpt_wait(dev);
3459 
3460             /* If I/O was halted (this one happens often) */
3461             if(dev->commadpt->haltpending)
3462             {
3463                 *unitstat=CSW_CE|CSW_DE|CSW_UX;
3464                 dev->commadpt->haltpending=0;
3465                 break;
3466             }
3467 
3468             /* Check if the line is still connected */
3469             if(!dev->commadpt->connect)
3470             {
3471                 *unitstat=CSW_CE|CSW_DE|CSW_UC;
3472                 dev->sense[0]=SENSE_IR;
3473                 break;
3474             }
3475 
3476             /* Normal Prepare exit condition - data is present in the input buffer */
3477             *unitstat=CSW_CE|CSW_DE;
3478             dev->commadpt->telnet_int = 0;
3479             break;
3480 
3481         default:
3482         /*---------------------------------------------------------------*/
3483         /* INVALID OPERATION                                             */
3484         /*---------------------------------------------------------------*/
3485             /* Set command reject sense byte, and unit check status */
3486             *unitstat=CSW_CE+CSW_DE+CSW_UC;
3487             dev->sense[0]=SENSE_CR;
3488             break;
3489 
3490     }
3491     release_lock(&dev->commadpt->lock);
3492 }
3493 
3494 
3495 /*---------------------------------------------------------------*/
3496 /* DEVICE FUNCTION POINTERS                                      */
3497 /*---------------------------------------------------------------*/
3498 
3499 #if defined(OPTION_DYNAMIC_LOAD)
3500 static
3501 #endif
3502 DEVHND comadpt_device_hndinfo = {
3503         &commadpt_init_handler,        /* Device Initialisation      */
3504         &commadpt_execute_ccw,         /* Device CCW execute         */
3505         &commadpt_close_device,        /* Device Close               */
3506         &commadpt_query_device,        /* Device Query               */
3507         NULL,                          /* Device Start channel pgm   */
3508         NULL,                          /* Device End channel pgm     */
3509         NULL,                          /* Device Resume channel pgm  */
3510         NULL,                          /* Device Suspend channel pgm */
3511         NULL,                          /* Device Read                */
3512         NULL,                          /* Device Write               */
3513         NULL,                          /* Device Query used          */
3514         NULL,                          /* Device Reserve             */
3515         NULL,                          /* Device Release             */
3516         NULL,                          /* Device Attention           */
3517         commadpt_immed_command,        /* Immediate CCW Codes        */
3518         NULL,                          /* Signal Adapter Input       */
3519         NULL,                          /* Signal Adapter Output      */
3520         NULL,                          /* Hercules suspend           */
3521         NULL                           /* Hercules resume            */
3522 };
3523 
3524 
3525 /* Libtool static name colision resolution */
3526 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
3527 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
3528 #define hdl_ddev hdt2703_LTX_hdl_ddev
3529 #define hdl_depc hdt2703_LTX_hdl_depc
3530 #define hdl_reso hdt2703_LTX_hdl_reso
3531 #define hdl_init hdt2703_LTX_hdl_init
3532 #define hdl_fini hdt2703_LTX_hdl_fini
3533 #endif
3534 
3535 
3536 #if defined(OPTION_DYNAMIC_LOAD)
3537 HDL_DEPENDENCY_SECTION;
3538 {
3539      HDL_DEPENDENCY(HERCULES);
3540      HDL_DEPENDENCY(DEVBLK);
3541      HDL_DEPENDENCY(SYSBLK);
3542 }
3543 END_DEPENDENCY_SECTION
3544 
3545 
3546 #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
3547   #undef sysblk
3548   HDL_RESOLVER_SECTION;
3549   {
3550     HDL_RESOLVE_PTRVAR( psysblk, sysblk );
3551   }
3552   END_RESOLVER_SECTION
3553 #endif
3554 
3555 
3556 HDL_DEVICE_SECTION;
3557 {
3558     HDL_DEVICE(2703, comadpt_device_hndinfo );
3559 }
3560 END_DEVICE_SECTION
3561 #endif
3562