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