1 /* CONSOLE.C (c)Copyright Roger Bowler, 1999-2011 */
2 /* Hercules Console Device Handler */
3
4 /*-------------------------------------------------------------------*/
5 /* This module contains device handling functions for console */
6 /* devices for the Hercules ESA/390 emulator. */
7 /* */
8 /* Telnet support is provided for two classes of console device: */
9 /* - local non-SNA 3270 display consoles via tn3270 */
10 /* - local non-SNA 3270 printers via tn3270 */
11 /* - 1052 and 3215 console printer keyboards via regular telnet */
12 /*-------------------------------------------------------------------*/
13
14 /*-------------------------------------------------------------------*/
15 /* This module also takes care of the differences between the */
16 /* remote 3270 and local non-SNA 3270 devices. In particular */
17 /* the support of command chaining, which is not supported on */
18 /* the remote 3270 implementation on which telnet 3270 is based. */
19 /* In the local non-SNA environment a chained read or write will */
20 /* continue at the buffer address where the previous command ended. */
21 /* In order to achieve this, this module will keep track of the */
22 /* buffer location, and adjust the buffer address on chained read */
23 /* and write operations. */
24 /* 03/06/00 Jan Jaeger. */
25 /*-------------------------------------------------------------------*/
26
27 /*-------------------------------------------------------------------*/
28 /* Add code to bypass bug in telnet client from TCP/IP for OS/390 */
29 /* where telnet responds with the server response rather then the */
30 /* client response as documented in RFC1576. */
31 /* 20/06/00 Jan Jaeger. */
32 /*-------------------------------------------------------------------*/
33
34 /*-------------------------------------------------------------------*/
35 /* Corrections to buffer position calculations in find_buffer_pos */
36 /* and get_screen_pos subroutines (symptom: message IEE305I) */
37 /* 09/12/00 Roger Bowler. */
38 /*-------------------------------------------------------------------*/
39
40 /*-------------------------------------------------------------------*/
41 /* When using VTAM with local non-SNA 3270 devices, ensure that */
42 /* enough bufferspace is available when doing IND$FILE type */
43 /* filetransfers. Code IOBUF=(,3992) in ATCSTRxx, and/or BUFNUM=xxx */
44 /* on the LBUILD LOCAL statement defining the 3270 device. JJ */
45 /* */
46 /*-------------------------------------------------------------------*/
47
48 /*-------------------------------------------------------------------*/
49 /* Ignore "Negotiate About Window Size" client option (for now) so */
50 /* WinNT version of telnet works. -- Greg Price (implemted by Fish) */
51 /*-------------------------------------------------------------------*/
52
53 #include "hstdinc.h"
54 #include "hercules.h"
55
56 #include "devtype.h"
57
58 #include "opcode.h"
59
60 #include "sr.h"
61
62 #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
63 SYSBLK *psysblk;
64 #define sysblk (*psysblk)
65 #define config_cnslport (*config_cnslport)
66 static
67 #else
68 #if defined(OPTION_DYNAMIC_LOAD) && defined(_MSVC_)
69 DLL_IMPORT
70 #else
71 extern
72 #endif
73 #endif
74 char *config_cnslport;
75
76 /*-------------------------------------------------------------------*/
77 /* Ivan Warren 20040227 */
78 /* This table is used by channel.c to determine if a CCW code is an */
79 /* immediate command or not */
80 /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */
81 /* 0 : Command is NOT an immediate command */
82 /* 1 : Command is an immediate command */
83 /* Note : An immediate command is defined as a command which returns */
84 /* CE (channel end) during initialisation (that is, no data is */
85 /* actually transfered. In this case, IL is not indicated for a CCW */
86 /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */
87 /* effect */
88 /*-------------------------------------------------------------------*/
89 static BYTE constty_immed[256]=
90 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
91 { 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, /* 00 */
92 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10 */
93 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20 */
94 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 30 */
95 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */
96 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
97 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */
98 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
100 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */
101 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */
102 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */
103 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */
104 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
105 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
106 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* F0 */
107
108 static BYTE loc3270_immed[256]=
109 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
110 { 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1, /* 00 */
111 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 10 */
112 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 20 */
113 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 30 */
114 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, /* 40 */
115 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
116 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */
117 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
118 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
119 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */
120 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */
121 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */
122 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */
123 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
124 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
125 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* F0 */
126 /*-------------------------------------------------------------------*/
127 /* Telnet command definitions */
128 /*-------------------------------------------------------------------*/
129 #define BINARY 0 /* Binary Transmission */
130 #define IS 0 /* Used by terminal-type negotiation */
131 #define SEND 1 /* Used by terminal-type negotiation */
132 #define ECHO_OPTION 1 /* Echo option */
133 #define SUPPRESS_GA 3 /* Suppress go-ahead option */
134 #define TIMING_MARK 6 /* Timing mark option */
135 #define TERMINAL_TYPE 24 /* Terminal type option */
136 #define NAWS 31 /* Negotiate About Window Size */
137 #define EOR 25 /* End of record option */
138 #define EOR_MARK 239 /* End of record marker */
139 #define SE 240 /* End of subnegotiation parameters */
140 #define NOP 241 /* No operation */
141 #define DATA_MARK 242 /* The data stream portion of a Synch.
142 This should always be accompanied
143 by a TCP Urgent notification */
144 #define BRK 243 /* Break character */
145 #define IP 244 /* Interrupt Process */
146 #define AO 245 /* Abort Output */
147 #define AYT 246 /* Are You There */
148 #define EC 247 /* Erase character */
149 #define EL 248 /* Erase Line */
150 #define GA 249 /* Go ahead */
151 #define SB 250 /* Subnegotiation of indicated option */
152 #define WILL 251 /* Indicates the desire to begin
153 performing, or confirmation that
154 you are now performing, the
155 indicated option */
156 #define WONT 252 /* Indicates the refusal to perform,
157 or continue performing, the
158 indicated option */
159 #define DO 253 /* Indicates the request that the
160 other party perform, or
161 confirmation that you are expecting
162 the other party to perform, the
163 indicated option */
164 #define DONT 254 /* Indicates the demand that the
165 other party stop performing,
166 or confirmation that you are no
167 longer expecting the other party
168 to perform, the indicated option */
169 #define IAC 255 /* Interpret as Command */
170
171 /*-------------------------------------------------------------------*/
172 /* 3270 definitions */
173 /*-------------------------------------------------------------------*/
174
175 /* 3270 local commands (CCWs) */
176 #define L3270_EAU 0x0F /* Erase All Unprotected */
177 #define L3270_EW 0x05 /* Erase/Write */
178 #define L3270_EWA 0x0D /* Erase/Write Alternate */
179 #define L3270_RB 0x02 /* Read Buffer */
180 #define L3270_RM 0x06 /* Read Modified */
181 #define L3270_WRT 0x01 /* Write */
182 #define L3270_WSF 0x11 /* Write Structured Field */
183
184 #define L3270_NOP 0x03 /* No Operation */
185 #define L3270_SELRM 0x0B /* Select RM */
186 #define L3270_SELRB 0x1B /* Select RB */
187 #define L3270_SELRMP 0x2B /* Select RMP */
188 #define L3270_SELRBP 0x3B /* Select RBP */
189 #define L3270_SELWRT 0x4B /* Select WRT */
190 #define L3270_SENSE 0x04 /* Sense */
191 #define L3270_SENSEID 0xE4 /* Sense ID */
192
193 /* 3270 remote commands */
194 #define R3270_EAU 0x6F /* Erase All Unprotected */
195 #define R3270_EW 0xF5 /* Erase/Write */
196 #define R3270_EWA 0x7E /* Erase/Write Alternate */
197 #define R3270_RB 0xF2 /* Read Buffer */
198 #define R3270_RM 0xF6 /* Read Modified */
199 #define R3270_RMA 0x6E /* Read Modified All */
200 #define R3270_WRT 0xF1 /* Write */
201 #define R3270_WSF 0xF3 /* Write Structured Field */
202
203 /* 3270 orders */
204 #define O3270_SBA 0x11 /* Set Buffer Address */
205 #define O3270_SF 0x1D /* Start Field */
206 #define O3270_SFE 0x29 /* Start Field Extended */
207 #define O3270_SA 0x28 /* Set Attribute */
208 #define O3270_IC 0x13 /* Insert Cursor */
209 #define O3270_MF 0x2C /* Modify Field */
210 #define O3270_PT 0x05 /* Program Tab */
211 #define O3270_RA 0x3C /* Repeat to Address */
212 #define O3270_EUA 0x12 /* Erase Unprotected to Addr */
213 #define O3270_GE 0x08 /* Graphic Escape */
214
215 /* Inbound structured fields */
216 #define SF3270_AID 0x88 /* Aid value of inbound SF */
217 #define SF3270_3270DS 0x80 /* SFID of 3270 datastream SF*/
218
219 /* 12 bit 3270 buffer address code conversion table */
220 static BYTE sba_code[] = { "\x40\xC1\xC2\xC3\xC4\xC5\xC6\xC7"
221 "\xC8\xC9\x4A\x4B\x4C\x4D\x4E\x4F"
222 "\x50\xD1\xD2\xD3\xD4\xD5\xD6\xD7"
223 "\xD8\xD9\x5A\x5B\x5C\x5D\x5E\x5F"
224 "\x60\x61\xE2\xE3\xE4\xE5\xE6\xE7"
225 "\xE8\xE9\x6A\x6B\x6C\x6D\x6E\x6F"
226 "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7"
227 "\xF8\xF9\x7A\x7B\x7C\x7D\x7E\x7F" };
228
229 /*-------------------------------------------------------------------*/
230 /* Internal macro definitions */
231 /*-------------------------------------------------------------------*/
232
233 /* DEBUG_LVL: 0 = none
234 1 = status
235 2 = headers
236 3 = buffers
237 */
238 #define DEBUG_LVL 0
239
240 #if DEBUG_LVL == 0
241 #define TNSDEBUG1 1 ? ((void)0) : logmsg
242 #define TNSDEBUG2 1 ? ((void)0) : logmsg
243 #define TNSDEBUG3 1 ? ((void)0) : logmsg
244 #endif
245 #if DEBUG_LVL == 1
246 #define TNSDEBUG1 logmsg
247 #define TNSDEBUG2 1 ? ((void)0) : logmsg
248 #define TNSDEBUG3 1 ? ((void)0) : logmsg
249 #endif
250 #if DEBUG_LVL == 2
251 #define TNSDEBUG1 logmsg
252 #define TNSDEBUG2 logmsg
253 #define TNSDEBUG3 1 ? ((void)0) : logmsg
254 #endif
255 #if DEBUG_LVL == 3
256 #define TNSDEBUG1 logmsg
257 #define TNSDEBUG2 logmsg
258 #define TNSDEBUG3 logmsg
259 #endif
260
261 #define TNSERROR logmsg
262
263 #define BUFLEN_3270 65536 /* 3270 Send/Receive buffer */
264 #define BUFLEN_1052 150 /* 1052 Send/Receive buffer */
265
266
267 #undef FIX_QWS_BUG_FOR_MCS_CONSOLES
268
269 /*-------------------------------------------------------------------*/
270 /* Static data areas */
271 /*-------------------------------------------------------------------*/
272 static HOST_INFO cons_hostinfo; /* Host info for this system */
273
274
275 /*-------------------------------------------------------------------*/
276 /* SUBROUTINE TO TRACE THE CONTENTS OF AN ASCII MESSAGE PACKET */
277 /*-------------------------------------------------------------------*/
278 #if DEBUG_LVL == 3
279 static void
packet_trace(BYTE * addr,int len)280 packet_trace(BYTE *addr, int len)
281 {
282 int i, offset;
283 BYTE c;
284 BYTE print_chars[17];
285
286 for (offset=0; offset < len; )
287 {
288 memset(print_chars,0,sizeof(print_chars));
289 logmsg("+%4.4X ", offset);
290 for (i=0; i < 16; i++)
291 {
292 c = *addr++;
293 if (offset < len) {
294 logmsg("%2.2X", c);
295 print_chars[i] = '.';
296 if (isprint(c)) print_chars[i] = c;
297 c = guest_to_host(c);
298 if (isprint(c)) print_chars[i] = c;
299 }
300 else {
301 logmsg(" ");
302 }
303 offset++;
304 if ((offset & 3) == 0) {
305 logmsg(" ");
306 }
307 } /* end for(i) */
308 logmsg(" %s\n", print_chars);
309 } /* end for(offset) */
310
311 } /* end function packet_trace */
312 #else
313 #define packet_trace( _addr, _len)
314 #endif
315
316
317 #if 1
get_inet_socket(char * host_serv)318 struct sockaddr_in * get_inet_socket(char *host_serv)
319 {
320 char *host = NULL;
321 char *serv;
322 struct sockaddr_in *sin;
323
324 if((serv = strchr(host_serv,':')))
325 {
326 *serv++ = '\0';
327 if(*host_serv)
328 host = host_serv;
329 }
330 else
331 serv = host_serv;
332
333 if(!(sin = malloc(sizeof(struct sockaddr_in))))
334 return sin;
335
336 sin->sin_family = AF_INET;
337
338 if(host)
339 {
340 struct hostent *hostent;
341
342 hostent = gethostbyname(host);
343
344 if(!hostent)
345 {
346 logmsg(_("HHCGI001I Unable to determine IP address from %s\n"),
347 host);
348 free(sin);
349 return NULL;
350 }
351
352 memcpy(&sin->sin_addr,*hostent->h_addr_list,sizeof(sin->sin_addr));
353 }
354 else
355 sin->sin_addr.s_addr = INADDR_ANY;
356
357 if(serv)
358 {
359 if(!isdigit(*serv))
360 {
361 struct servent *servent;
362
363 servent = getservbyname(serv, "tcp");
364
365 if(!servent)
366 {
367 logmsg(_("HHCGI002I Unable to determine port number from %s\n"),
368 host);
369 free(sin);
370 return NULL;
371 }
372
373 sin->sin_port = servent->s_port;
374 }
375 else
376 sin->sin_port = htons(atoi(serv));
377
378 }
379 else
380 {
381 logmsg(_("HHCGI003E Invalid parameter: %s\n"),
382 host_serv);
383 free(sin);
384 return NULL;
385 }
386
387 return sin;
388
389 }
390
391 #endif
392 /*-------------------------------------------------------------------*/
393 /* SUBROUTINE TO REMOVE ANY IAC SEQUENCES FROM THE DATA STREAM */
394 /* Returns the new length after deleting IAC commands */
395 /*-------------------------------------------------------------------*/
396 static int
remove_iac(BYTE * buf,int len)397 remove_iac (BYTE *buf, int len)
398 {
399 int m, n, c;
400
401 for (m=0, n=0; m < len; ) {
402 /* Interpret IAC commands */
403 if (buf[m] == IAC) {
404 /* Treat IAC in last byte of buffer as IAC NOP */
405 c = (++m < len)? buf[m++] : NOP;
406 /* Process IAC command */
407 switch (c) {
408 case IAC: /* Insert single IAC in buffer */
409 buf[n++] = IAC;
410 break;
411 case BRK: /* Set ATTN indicator */
412 break;
413 case IP: /* Set SYSREQ indicator */
414 break;
415 case WILL: /* Skip option negotiation command */
416 case WONT:
417 case DO:
418 case DONT:
419 m++;
420 break;
421 case SB: /* Skip until IAC SE sequence found */
422 for (; m < len; m++) {
423 if (buf[m] != IAC) continue;
424 if (++m >= len) break;
425 if (buf[m] == SE) { m++; break; }
426 } /* end for */
427 default: /* Ignore NOP or unknown command */
428 break;
429 } /* end switch(c) */
430 } else {
431 /* Copy data bytes */
432 if (n < m) buf[n] = buf[m];
433 m++; n++;
434 }
435 } /* end for */
436
437 if (n < m) {
438 TNSDEBUG3("console: DBG001: %d IAC bytes removed, newlen=%d\n",
439 m-n, n);
440 packet_trace (buf, n);
441 }
442
443 return n;
444
445 } /* end function remove_iac */
446
447
448 /*-------------------------------------------------------------------*/
449 /* SUBROUTINE TO DOUBLE UP ANY IAC BYTES IN THE DATA STREAM */
450 /* Returns the new length after inserting extra IAC bytes */
451 /*-------------------------------------------------------------------*/
452 static int
double_up_iac(BYTE * buf,int len)453 double_up_iac (BYTE *buf, int len)
454 {
455 int m, n, x, newlen;
456
457 /* Count the number of IAC bytes in the data */
458 for (x=0, n=0; n < len; n++)
459 if (buf[n] == IAC) x++;
460
461 /* Exit if nothing to do */
462 if (x == 0) return len;
463
464 /* Insert extra IAC bytes backwards from the end of the buffer */
465 newlen = len + x;
466 TNSDEBUG3("console: DBG002: %d IAC bytes added, newlen=%d\n",
467 x, newlen);
468 for (n=newlen, m=len; n > m; ) {
469 buf[--n] = buf[--m];
470 if (buf[n] == IAC) buf[--n] = IAC;
471 }
472 packet_trace (buf, newlen);
473 return newlen;
474
475 } /* end function double_up_iac */
476
477
478 /*-------------------------------------------------------------------*/
479 /* SUBROUTINE TO TRANSLATE A NULL-TERMINATED STRING TO EBCDIC */
480 /*-------------------------------------------------------------------*/
481 static BYTE *
translate_to_ebcdic(char * str)482 translate_to_ebcdic (char *str)
483 {
484 int i; /* Array subscript */
485 BYTE c; /* Character work area */
486
487 for (i = 0; str[i] != '\0'; i++)
488 {
489 c = str[i];
490 str[i] = (isprint(c) ? host_to_guest(c) : SPACE);
491 }
492
493 return (BYTE *)str;
494 } /* end function translate_to_ebcdic */
495
496
497 /*-------------------------------------------------------------------*/
498 /* SUBROUTINE TO SEND A DATA PACKET TO THE CLIENT */
499 /*-------------------------------------------------------------------*/
500 static int
send_packet(int csock,BYTE * buf,int len,char * caption)501 send_packet (int csock, BYTE *buf, int len, char *caption)
502 {
503 int rc; /* Return code */
504
505 if (caption != NULL) {
506 TNSDEBUG2("console: DBG003: Sending %s\n", caption);
507 packet_trace (buf, len);
508 }
509
510 rc = send (csock, buf, len, 0);
511
512 if (rc < 0) {
513 TNSERROR("console: DBG021: send: %s\n", strerror(HSO_errno));
514 return -1;
515 } /* end if(rc) */
516
517 return 0;
518
519 } /* end function send_packet */
520
521
522 /*-------------------------------------------------------------------*/
523 /* SUBROUTINE TO RECEIVE A DATA PACKET FROM THE CLIENT */
524 /* This subroutine receives bytes from the client. It stops when */
525 /* the receive buffer is full, or when the last two bytes received */
526 /* consist of the IAC character followed by a specified delimiter. */
527 /* If zero bytes are received, this means the client has closed the */
528 /* connection, and this is treated as an error. */
529 /* Input: */
530 /* csock is the socket number */
531 /* buf points to area to receive data */
532 /* reqlen is the number of bytes requested */
533 /* delim is the delimiter character (0=no delimiter) */
534 /* Output: */
535 /* buf is updated with data received */
536 /* The return value is the number of bytes received, or */
537 /* -1 if an error occurred. */
538 /*-------------------------------------------------------------------*/
539 static int
recv_packet(int csock,BYTE * buf,int reqlen,BYTE delim)540 recv_packet (int csock, BYTE *buf, int reqlen, BYTE delim)
541 {
542 int rc=0; /* Return code */
543 int rcvlen=0; /* Length of data received */
544
545 while (rcvlen < reqlen) {
546
547 rc = recv (csock, buf + rcvlen, reqlen - rcvlen, 0);
548
549 if (rc < 0) {
550 TNSERROR("console: DBG022: recv: %s\n", strerror(HSO_errno));
551 return -1;
552 }
553
554 if (rc == 0) {
555 TNSDEBUG1("console: DBG004: Connection closed by client\n");
556 return -1;
557 }
558
559 rcvlen += rc;
560
561 if (delim != '\0' && rcvlen >= 2
562 && buf[rcvlen-2] == IAC && buf[rcvlen-1] == delim)
563 break;
564 }
565
566 TNSDEBUG2("console: DBG005: Packet received length=%d\n", rcvlen);
567 packet_trace (buf, rcvlen);
568
569 return rcvlen;
570
571 } /* end function recv_packet */
572
573
574 /*-------------------------------------------------------------------*/
575 /* SUBROUTINE TO RECEIVE A PACKET AND COMPARE WITH EXPECTED VALUE */
576 /*-------------------------------------------------------------------*/
577 static int
expect(int csock,BYTE * expected,int len,char * caption)578 expect (int csock, BYTE *expected, int len, char *caption)
579 {
580 int rc; /* Return code */
581 BYTE buf[512]; /* Receive buffer */
582 #if 1
583 /* TCP/IP for MVS returns the server sequence rather then
584 the client sequence during bin negotiation 19/06/00 Jan Jaeger */
585 static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY };
586 static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY };
587 #endif
588
589 UNREFERENCED(caption);
590
591 rc = recv_packet (csock, buf, len, 0);
592 if (rc < 0) return -1;
593
594 #if 1
595 /* TCP/IP FOR MVS DOES NOT COMPLY TO RFC 1576 THIS IS A BYPASS */
596 if(memcmp(buf, expected, len) != 0
597 && !(len == sizeof(will_bin)
598 && memcmp(expected, will_bin, len) == 0
599 && memcmp(buf, do_bin, len) == 0) )
600 #else
601 if (memcmp(buf, expected, len) != 0)
602 #endif
603 {
604 TNSDEBUG2("console: DBG006: Expected %s\n", caption);
605 return -1;
606 }
607 TNSDEBUG2("console: DBG007: Received %s\n", caption);
608
609 return 0;
610
611 } /* end function expect */
612
613
614 /*-------------------------------------------------------------------*/
615 /* SUBROUTINE TO NEGOTIATE TELNET PARAMETERS */
616 /* This subroutine negotiates the terminal type with the client */
617 /* and uses the terminal type to determine whether the client */
618 /* is to be supported as a 3270 display console or as a 1052/3215 */
619 /* printer-keyboard console. */
620 /* */
621 /* Valid display terminal types are "IBM-NNNN", "IBM-NNNN-M", and */
622 /* "IBM-NNNN-M-E", where NNNN is 3270, 3277, 3278, 3279, 3178, 3179, */
623 /* or 3180, M indicates the screen size (2=25x80, 3=32x80, 4=43x80, */
624 /* 5=27x132, X=determined by Read Partition Query command), and */
625 /* -E is an optional suffix indicating that the terminal supports */
626 /* extended attributes. Displays are negotiated into tn3270 mode. */
627 /* An optional device number suffix (example: IBM-3270@01F) may */
628 /* be specified to request allocation to a specific device number. */
629 /* Valid 3270 printer type is "IBM-3287-1" */
630 /* */
631 /* Terminal types whose first four characters are not "IBM-" are */
632 /* handled as printer-keyboard consoles using telnet line mode. */
633 /* */
634 /* Input: */
635 /* csock Socket number for client connection */
636 /* Output: */
637 /* class D=3270 display console, K=printer-keyboard console */
638 /* P=3270 printer */
639 /* model 3270 model indicator (2,3,4,5,X) */
640 /* extatr 3270 extended attributes (Y,N) */
641 /* devn Requested device number, or FFFF=any device number */
642 /* Return value: */
643 /* 0=negotiation successful, -1=negotiation error */
644 /*-------------------------------------------------------------------*/
645 static int
negotiate(int csock,BYTE * class,BYTE * model,BYTE * extatr,U16 * devn,char * group)646 negotiate(int csock, BYTE *class, BYTE *model, BYTE *extatr, U16 *devn,char *group)
647 {
648 int rc; /* Return code */
649 char *termtype; /* Pointer to terminal type */
650 char *s; /* String pointer */
651 BYTE c; /* Trailing character */
652 U16 devnum; /* Requested device number */
653 BYTE buf[512]; /* Telnet negotiation buffer */
654 static BYTE do_term[] = { IAC, DO, TERMINAL_TYPE };
655 static BYTE will_term[] = { IAC, WILL, TERMINAL_TYPE };
656 static BYTE req_type[] = { IAC, SB, TERMINAL_TYPE, SEND, IAC, SE };
657 static BYTE type_is[] = { IAC, SB, TERMINAL_TYPE, IS };
658 static BYTE do_eor[] = { IAC, DO, EOR, IAC, WILL, EOR };
659 static BYTE will_eor[] = { IAC, WILL, EOR, IAC, DO, EOR };
660 static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY };
661 static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY };
662 #if 0
663 static BYTE do_tmark[] = { IAC, DO, TIMING_MARK };
664 static BYTE will_tmark[] = { IAC, WILL, TIMING_MARK };
665 static BYTE wont_sga[] = { IAC, WONT, SUPPRESS_GA };
666 static BYTE dont_sga[] = { IAC, DONT, SUPPRESS_GA };
667 #endif
668 static BYTE wont_echo[] = { IAC, WONT, ECHO_OPTION };
669 static BYTE dont_echo[] = { IAC, DONT, ECHO_OPTION };
670 static BYTE will_naws[] = { IAC, WILL, NAWS };
671
672 /* Perform terminal-type negotiation */
673 rc = send_packet (csock, do_term, sizeof(do_term),
674 "IAC DO TERMINAL_TYPE");
675 if (rc < 0) return -1;
676
677 rc = expect (csock, will_term, sizeof(will_term),
678 "IAC WILL TERMINAL_TYPE");
679 if (rc < 0) return -1;
680
681 /* Request terminal type */
682 rc = send_packet (csock, req_type, sizeof(req_type),
683 "IAC SB TERMINAL_TYPE SEND IAC SE");
684 if (rc < 0) return -1;
685
686 rc = recv_packet (csock, buf, sizeof(buf)-2, SE);
687 if (rc < 0) return -1;
688
689 /* Ignore Negotiate About Window Size */
690 if (rc >= (int)sizeof(will_naws) &&
691 memcmp (buf, will_naws, sizeof(will_naws)) == 0)
692 {
693 memmove(buf, &buf[sizeof(will_naws)], (rc - sizeof(will_naws)));
694 rc -= sizeof(will_naws);
695 }
696
697 if (rc < (int)(sizeof(type_is) + 2)
698 || memcmp(buf, type_is, sizeof(type_is)) != 0
699 || buf[rc-2] != IAC || buf[rc-1] != SE) {
700 TNSDEBUG2("console: DBG008: Expected IAC SB TERMINAL_TYPE IS\n");
701 return -1;
702 }
703 buf[rc-2] = '\0';
704 termtype = (char *)(buf + sizeof(type_is));
705 TNSDEBUG2("console: DBG009: Received IAC SB TERMINAL_TYPE IS %s IAC SE\n",
706 termtype);
707
708 /* Check terminal type string for device name suffix */
709 s = strchr (termtype, '@');
710 if(s!=NULL)
711 {
712 if(strlen(s)<16)
713 {
714 strlcpy(group,&s[1],16);
715 }
716 }
717 else
718 {
719 group[0]=0;
720 }
721
722 if (s != NULL && sscanf (s, "@%hx%c", &devnum,&c) == 1)
723 {
724 *devn = devnum;
725 group[0]=0;
726 }
727 else
728 {
729 *devn = 0xFFFF;
730 }
731
732 /* Test for non-display terminal type */
733 if (memcmp(termtype, "IBM-", 4) != 0)
734 {
735 #if 0
736 /* Perform line mode negotiation */
737 rc = send_packet (csock, do_tmark, sizeof(do_tmark),
738 "IAC DO TIMING_MARK");
739 if (rc < 0) return -1;
740
741 rc = expect (csock, will_tmark, sizeof(will_tmark),
742 "IAC WILL TIMING_MARK");
743 if (rc < 0) return 0;
744
745 rc = send_packet (csock, wont_sga, sizeof(wont_sga),
746 "IAC WONT SUPPRESS_GA");
747 if (rc < 0) return -1;
748
749 rc = expect (csock, dont_sga, sizeof(dont_sga),
750 "IAC DONT SUPPRESS_GA");
751 if (rc < 0) return -1;
752 #endif
753
754 if (memcmp(termtype, "ANSI", 4) == 0)
755 {
756 rc = send_packet (csock, wont_echo, sizeof(wont_echo),
757 "IAC WONT ECHO");
758 if (rc < 0) return -1;
759
760 rc = expect (csock, dont_echo, sizeof(dont_echo),
761 "IAC DONT ECHO");
762 if (rc < 0) return -1;
763 }
764
765 /* Return printer-keyboard terminal class */
766 *class = 'K';
767 *model = '-';
768 *extatr = '-';
769 return 0;
770 }
771
772 /* Determine display terminal model */
773 if (memcmp(termtype+4,"DYNAMIC",7) == 0) {
774 *model = 'X';
775 *extatr = 'Y';
776 } else {
777 if (!(memcmp(termtype+4, "3277", 4) == 0
778 || memcmp(termtype+4, "3270", 4) == 0
779 || memcmp(termtype+4, "3178", 4) == 0
780 || memcmp(termtype+4, "3278", 4) == 0
781 || memcmp(termtype+4, "3179", 4) == 0
782 || memcmp(termtype+4, "3180", 4) == 0
783 || memcmp(termtype+4, "3287", 4) == 0
784 || memcmp(termtype+4, "3279", 4) == 0))
785 return -1;
786
787 *model = '2';
788 *extatr = 'N';
789
790 if (termtype[8]=='-') {
791 if (termtype[9] < '1' || termtype[9] > '5')
792 return -1;
793 *model = termtype[9];
794 if (memcmp(termtype+4, "328",3) == 0) *model = '2';
795 if (memcmp(termtype+10, "-E", 2) == 0)
796 *extatr = 'Y';
797 }
798 }
799
800 /* Perform end-of-record negotiation */
801 rc = send_packet (csock, do_eor, sizeof(do_eor),
802 "IAC DO EOR IAC WILL EOR");
803 if (rc < 0) return -1;
804
805 rc = expect (csock, will_eor, sizeof(will_eor),
806 "IAC WILL EOR IAC DO EOR");
807 if (rc < 0) return -1;
808
809 /* Perform binary negotiation */
810 rc = send_packet (csock, do_bin, sizeof(do_bin),
811 "IAC DO BINARY IAC WILL BINARY");
812 if (rc < 0) return -1;
813
814 rc = expect (csock, will_bin, sizeof(will_bin),
815 "IAC WILL BINARY IAC DO BINARY");
816 if (rc < 0) return -1;
817
818 /* Return display terminal class */
819 if (memcmp(termtype+4,"3287",4)==0) *class='P';
820 else *class = 'D';
821 return 0;
822
823 } /* end function negotiate */
824
825
826 /*-------------------------------------------------------------------*/
827 /* SUBROUTINE TO RECEIVE 3270 DATA FROM THE CLIENT */
828 /* This subroutine receives bytes from the client and appends them */
829 /* to any data already in the 3270 receive buffer. */
830 /* If zero bytes are received, this means the client has closed the */
831 /* connection, and attention and unit check status is returned. */
832 /* If the buffer is filled before receiving end of record, then */
833 /* attention and unit check status is returned. */
834 /* If the data ends with IAC followed by EOR_MARK, then the data */
835 /* is scanned to remove any IAC sequences, attention status is */
836 /* returned, and the read pending indicator is set. */
837 /* If the data accumulated in the buffer does not yet constitute a */
838 /* complete record, then zero status is returned, and a further */
839 /* call must be made to this subroutine when more data is available. */
840 /*-------------------------------------------------------------------*/
841 static BYTE
recv_3270_data(DEVBLK * dev)842 recv_3270_data (DEVBLK *dev)
843 {
844 int rc; /* Return code */
845 int eor = 0; /* 1=End of record received */
846
847 /* If there is a complete data record already in the buffer
848 then discard it before reading more data */
849 if (dev->readpending)
850 {
851 dev->rlen3270 = 0;
852 dev->readpending = 0;
853 }
854
855 /*
856 The following chunk of code was added to try and catch
857 a race condition that may or may no longer still exist.
858 */
859 TNSDEBUG1("console: DBG031: verifying data is available...\n");
860 {
861 fd_set readset;
862 struct timeval tv = {0,0}; /* (non-blocking poll) */
863
864 FD_ZERO( &readset );
865 FD_SET( dev->fd, &readset );
866
867 while ( (rc = select ( dev->fd+1, &readset, NULL, NULL, &tv )) < 0
868 && HSO_EINTR == HSO_errno )
869 ; /* NOP (keep retrying if EINTR) */
870
871 if (rc < 0)
872 {
873 TNSERROR("console: DBG032: select failed: %s\n", strerror(HSO_errno));
874 return 0;
875 }
876
877 ASSERT(rc <= 1);
878
879 if (!FD_ISSET(dev->fd, &readset))
880 {
881 ASSERT(rc == 0);
882 TNSDEBUG1("console: DBG033: no data available; returning 0...\n");
883 return 0;
884 }
885
886 ASSERT(rc == 1);
887 }
888 TNSDEBUG1("console: DBG034: data IS available; attempting recv...\n");
889
890 /* Receive bytes from client */
891 rc = recv (dev->fd, dev->buf + dev->rlen3270,
892 BUFLEN_3270 - dev->rlen3270, 0);
893
894 if (rc < 0) {
895 if ( HSO_ECONNRESET == HSO_errno )
896 logmsg( _( "HHCTE014I %4.4X device %4.4X client %s connection reset\n" ),
897 dev->devtype, dev->devnum, inet_ntoa(dev->ipaddr) );
898 else
899 TNSERROR("console: DBG023: recv: %s\n", strerror(HSO_errno));
900 dev->sense[0] = SENSE_EC;
901 return (CSW_ATTN | CSW_UC);
902 }
903
904 /* If zero bytes were received then client has closed connection */
905 if (rc == 0) {
906 logmsg (_("HHCTE007I %4.4X device %4.4X client %s connection closed\n"),
907 dev->devtype, dev->devnum, inet_ntoa(dev->ipaddr));
908 dev->sense[0] = SENSE_IR;
909 return (CSW_ATTN | CSW_UC | CSW_DE);
910 }
911
912 /* Update number of bytes in receive buffer */
913 dev->rlen3270 += rc;
914
915 /* Check whether Attn indicator was received */
916 if (dev->rlen3270 >= 2
917 && dev->buf[dev->rlen3270 - 2] == IAC
918 && dev->buf[dev->rlen3270 - 1] == BRK)
919 eor = 1;
920
921 /* Check whether SysRq indicator was received */
922 if (dev->rlen3270 >= 2
923 && dev->buf[dev->rlen3270 - 2] == IAC
924 && dev->buf[dev->rlen3270 - 1] == IP)
925 eor = 1;
926
927 /* Check whether end of record marker was received */
928 if (dev->rlen3270 >= 2
929 && dev->buf[dev->rlen3270 - 2] == IAC
930 && dev->buf[dev->rlen3270 - 1] == EOR_MARK)
931 eor = 1;
932
933 /* If record is incomplete, test for buffer full */
934 if (eor == 0 && dev->rlen3270 >= BUFLEN_3270)
935 {
936 TNSDEBUG1("console: DBG010: 3270 buffer overflow\n");
937 dev->sense[0] = SENSE_DC;
938 return (CSW_ATTN | CSW_UC);
939 }
940
941 /* Return zero status if record is incomplete */
942 if (eor == 0)
943 return 0;
944
945 /* Trace the complete 3270 data packet */
946 TNSDEBUG2("console: DBG011: Packet received length=%d\n",
947 dev->rlen3270);
948 packet_trace (dev->buf, dev->rlen3270);
949
950 /* Strip off the telnet EOR marker */
951 dev->rlen3270 -= 2;
952
953 /* Remove any embedded IAC commands */
954 dev->rlen3270 = remove_iac (dev->buf, dev->rlen3270);
955
956 /* Set the read pending indicator and return attention status */
957 dev->readpending = 1;
958 return (CSW_ATTN);
959
960 } /* end function recv_3270_data */
961
962
963 /*-------------------------------------------------------------------*/
964 /* SUBROUTINE TO SOLICIT 3270 DATA FROM THE CLIENT */
965 /* This subroutine sends a Read or Read Modified command to the */
966 /* client and then receives the data into the 3270 receive buffer. */
967 /* This subroutine is called by loc3270_execute_ccw as a result of */
968 /* processing a Read Buffer CCW, or a Read Modified CCW when no */
969 /* data is waiting in the 3270 read buffer. It waits until the */
970 /* client sends end of record. Certain tn3270 clients fail to */
971 /* flush their buffer until the user presses an attention key; */
972 /* these clients cause this routine to hang and are not supported. */
973 /* Since this routine is only called while a channel program is */
974 /* active on the device, we can rely on the dev->busy flag to */
975 /* prevent the connection thread from issuing a read and capturing */
976 /* the incoming data intended for this routine. */
977 /* The caller MUST hold the device lock. */
978 /* Returns zero status if successful, or unit check if error. */
979 /*-------------------------------------------------------------------*/
980 static BYTE
solicit_3270_data(DEVBLK * dev,BYTE cmd)981 solicit_3270_data (DEVBLK *dev, BYTE cmd)
982 {
983 int rc; /* Return code */
984 int len; /* Data length */
985 BYTE buf[32]; /* tn3270 write buffer */
986
987 /* Clear the inbound buffer of any unsolicited
988 data accumulated by the connection thread */
989 dev->rlen3270 = 0;
990 dev->readpending = 0;
991
992 /* Construct a 3270 read command in the outbound buffer */
993 len = 0;
994 buf[len++] = cmd;
995
996 /* Append telnet EOR marker to outbound buffer */
997 buf[len++] = IAC;
998 buf[len++] = EOR_MARK;
999
1000 /* Send the 3270 read command to the client */
1001 rc = send_packet(dev->fd, buf, len, "3270 Read Command");
1002 if (rc < 0)
1003 {
1004 dev->sense[0] = SENSE_DC;
1005 return (CSW_UC);
1006 }
1007
1008 /* Receive response data from the client */
1009 do {
1010 len = dev->rlen3270;
1011 rc = recv_3270_data (dev);
1012 TNSDEBUG2("console: DBG012: read buffer: %d bytes received\n",
1013 dev->rlen3270 - len);
1014 } while(rc == 0);
1015
1016 /* Close the connection if an error occurred */
1017 if (rc & CSW_UC)
1018 {
1019 dev->connected = 0;
1020 dev->fd = -1;
1021 dev->sense[0] = SENSE_DC;
1022
1023 return (CSW_UC);
1024 }
1025
1026 /* Return zero status to indicate response received */
1027 return 0;
1028
1029 } /* end function solicit_3270_data */
1030
1031
1032 /*-------------------------------------------------------------------*/
1033 /* SUBROUTINE TO RECEIVE 1052/3215 DATA FROM THE CLIENT */
1034 /* This subroutine receives keyboard input characters from the */
1035 /* client, and appends the characters to any data already in the */
1036 /* keyboard buffer. */
1037 /* If zero bytes are received, this means the client has closed the */
1038 /* connection, and attention and unit check status is returned. */
1039 /* If the buffer is filled before receiving end of record, then */
1040 /* attention and unit check status is returned. */
1041 /* If a break indication (control-C, IAC BRK, or IAC IP) is */
1042 /* received, the attention and unit exception status is returned. */
1043 /* When carriage return and line feed (CRLF) is received, then */
1044 /* the CRLF is discarded, the data in the keyboard buffer is */
1045 /* translated to EBCDIC, the read pending indicator is set, and */
1046 /* attention status is returned. */
1047 /* If CRLF has not yet been received, then zero status is returned, */
1048 /* and a further call must be made to this subroutine when more */
1049 /* data is available. */
1050 /*-------------------------------------------------------------------*/
1051 static BYTE
recv_1052_data(DEVBLK * dev)1052 recv_1052_data (DEVBLK *dev)
1053 {
1054 int num; /* Number of bytes received */
1055 int i; /* Array subscript */
1056 BYTE buf[BUFLEN_1052]; /* Receive buffer */
1057 BYTE c; /* Character work area */
1058
1059 /* Receive bytes from client */
1060 num = recv (dev->fd, buf, BUFLEN_1052, 0);
1061
1062 /* Return unit check if error on receive */
1063 if (num < 0) {
1064 TNSERROR("console: DBG024: recv: %s\n", strerror(HSO_errno));
1065 dev->sense[0] = SENSE_EC;
1066 return (CSW_ATTN | CSW_UC);
1067 }
1068
1069 /* If zero bytes were received then client has closed connection */
1070 if (num == 0) {
1071 logmsg (_("HHCTE008I Device %4.4X connection closed by client %s\n"),
1072 dev->devnum, inet_ntoa(dev->ipaddr));
1073 dev->sense[0] = SENSE_IR;
1074 return (CSW_ATTN | CSW_UC);
1075 }
1076
1077 /* Trace the bytes received */
1078 TNSDEBUG2("console: DBG013: Bytes received length=%d\n", num);
1079 packet_trace (buf, num);
1080
1081 /* Copy received bytes to keyboard buffer */
1082 for (i = 0; i < num; i++)
1083 {
1084 /* Decrement keyboard buffer pointer if backspace received */
1085 if (buf[i] == 0x08)
1086 {
1087 if (dev->keybdrem > 0) dev->keybdrem--;
1088 continue;
1089 }
1090
1091 /* Return unit exception if control-C received */
1092 if (buf[i] == 0x03)
1093 {
1094 dev->keybdrem = 0;
1095 return (CSW_ATTN | CSW_UX);
1096 }
1097
1098 /* Return unit check if buffer is full */
1099 if (dev->keybdrem >= BUFLEN_1052)
1100 {
1101 TNSDEBUG1("console: DBG014: Console keyboard buffer overflow\n");
1102 dev->keybdrem = 0;
1103 dev->sense[0] = SENSE_EC;
1104 return (CSW_ATTN | CSW_UC);
1105 }
1106
1107 /* Copy character to keyboard buffer */
1108 dev->buf[dev->keybdrem++] = buf[i];
1109
1110 /* Decrement keyboard buffer pointer if telnet
1111 erase character sequence received */
1112 if (dev->keybdrem >= 2
1113 && dev->buf[dev->keybdrem - 2] == IAC
1114 && dev->buf[dev->keybdrem - 1] == EC)
1115 {
1116 dev->keybdrem -= 2;
1117 if (dev->keybdrem > 0) dev->keybdrem--;
1118 continue;
1119 }
1120
1121 /* Zeroize keyboard buffer pointer if telnet
1122 erase line sequence received */
1123 if (dev->keybdrem >= 2
1124 && dev->buf[dev->keybdrem - 2] == IAC
1125 && dev->buf[dev->keybdrem - 1] == EL)
1126 {
1127 dev->keybdrem = 0;
1128 continue;
1129 }
1130
1131 /* Zeroize keyboard buffer pointer if telnet
1132 carriage return sequence received */
1133 if (dev->keybdrem >= 2
1134 && dev->buf[dev->keybdrem - 2] == '\r'
1135 && dev->buf[dev->keybdrem - 1] == '\0')
1136 {
1137 dev->keybdrem = 0;
1138 continue;
1139 }
1140
1141 /* Return unit exception if telnet break sequence received */
1142 if (dev->keybdrem >= 2
1143 && dev->buf[dev->keybdrem - 2] == IAC
1144 && (dev->buf[dev->keybdrem - 1] == BRK
1145 || dev->buf[dev->keybdrem - 1] == IP))
1146 {
1147 dev->keybdrem = 0;
1148 return (CSW_ATTN | CSW_UX);
1149 }
1150
1151 /* Return unit check with overrun if telnet CRLF
1152 sequence received and more data follows the CRLF */
1153 if (dev->keybdrem >= 2
1154 && dev->buf[dev->keybdrem - 2] == '\r'
1155 && dev->buf[dev->keybdrem - 1] == '\n'
1156 && i < num - 1)
1157 {
1158 TNSDEBUG1("console: DBG015: Console keyboard buffer overrun\n");
1159 dev->keybdrem = 0;
1160 dev->sense[0] = SENSE_OR;
1161 return (CSW_ATTN | CSW_UC);
1162 }
1163
1164 } /* end for(i) */
1165
1166 /* Return zero status if CRLF was not yet received */
1167 if (dev->keybdrem < 2
1168 || dev->buf[dev->keybdrem - 2] != '\r'
1169 || dev->buf[dev->keybdrem - 1] != '\n')
1170 return 0;
1171
1172 /* Trace the complete keyboard data packet */
1173 TNSDEBUG2("console: DBG016: Packet received length=%d\n",
1174 dev->keybdrem);
1175 packet_trace (dev->buf, dev->keybdrem);
1176
1177 /* Strip off the CRLF sequence */
1178 dev->keybdrem -= 2;
1179
1180 /* Translate the keyboard buffer to EBCDIC */
1181 for (i = 0; i < dev->keybdrem; i++)
1182 {
1183 c = dev->buf[i];
1184 dev->buf[i] = (isprint(c) ? host_to_guest(c) : SPACE);
1185 } /* end for(i) */
1186
1187 /* Trace the EBCDIC input data */
1188 TNSDEBUG2("console: DBG017: Input data line length=%d\n",
1189 dev->keybdrem);
1190 packet_trace (dev->buf, dev->keybdrem);
1191
1192 /* Return attention status */
1193 return (CSW_ATTN);
1194
1195 } /* end function recv_1052_data */
1196
1197 /* The following code and functions are here
1198 * to build a more fancy logo
1199 */
1200 #define SF_ATTR_PROTECTED 0x20
1201 #define SF_ATTR_NUMERIC 0x10
1202 /* One of */
1203 #define SF_ATTR_WDISPNSEL 0x00
1204 #define SF_ATTR_WDISPSEL 0x04
1205 #define SF_ATTR_HIGHLIGHT 0x08
1206 #define SF_ATTR_INVISIBLE 0x0C
1207
1208 #define SF_ATTR_MDT 0x01
1209
1210 /*
1211 static char *herclogo[]={
1212 " HHH HHH The S/370, ESA/390 and z/Architecture",
1213 " HHH HHH Emulator",
1214 " HHH HHH",
1215 " HHH HHH EEEE RRR CCC U U L EEEE SSS",
1216 " HHHHHHHHHHHHHHHH E R R C U U L E S",
1217 " HHHHHHHHHHHHHHHH EEE RRR C U U L EEE SS",
1218 " HHHHHHHHHHHHHHHH E R R C U U L E S",
1219 " HHH HHH EEEE R R CCC UU LLLL EEEE SSS ",
1220 " HHH HHH",
1221 " HHH HHH",
1222 " HHH HHH My PC thinks it's a MAINFRAME",
1223 "",
1224 " Copyright (C) 1999-2010 Roger Bowler, Jan Jaeger, and others"};
1225 */
1226
1227 static char *herclogo[]={
1228 "@ALIGN NONE",
1229 "@SBA 0,0",
1230 "@SF P",
1231 "Hercules Version :",
1232 "@SF HP",
1233 "$(VERSION)",
1234 "@NL",
1235 "@SF P",
1236 "Host name :",
1237 "@SF HP",
1238 "$(HOSTNAME)",
1239 "@NL",
1240 "@SF P",
1241 "Host OS :",
1242 "@SF HP",
1243 "$(HOSTOS)-$(HOSTOSREL) $(HOSTOSVER)",
1244 "@NL",
1245 "@SF P",
1246 "Host Architecture :",
1247 "@SF HP",
1248 "$(HOSTARCH)",
1249 "@NL",
1250 "@SF P",
1251 "Processors :",
1252 "@SF HP",
1253 "$(HOSTNUMCPUS)",
1254 "@NL",
1255 "@SF P",
1256 "Chanl Subsys :",
1257 "@SF HP",
1258 "$(CSS)",
1259 "@NL",
1260 "@SF P",
1261 "Device number :",
1262 "@SF HP",
1263 "$(CCUU)",
1264 "@NL",
1265 "@SF P",
1266 "Subchannel :",
1267 "@SF HP",
1268 "$(SUBCHAN)",
1269 "@SF P",
1270 "@ALIGN LEFT",
1271 "",
1272 "",
1273 " HHH HHH The S/370, ESA/390 and z/Architecture",
1274 " HHH HHH Emulator",
1275 " HHH HHH",
1276 " HHH HHH EEEE RRR CCC U U L EEEE SSS",
1277 " HHHHHHHHHHHHHHHH E R R C U U L E S",
1278 " HHHHHHHHHHHHHHHH EEE RRR C U U L EEE SS",
1279 " HHHHHHHHHHHHHHHH E R R C U U L E S",
1280 " HHH HHH EEEE R R CCC UU LLLL EEEE SSS",
1281 " HHH HHH",
1282 " HHH HHH",
1283 " HHH HHH My PC thinks it's a MAINFRAME",
1284 "",
1285 " Copyright (C) 1999-2010 Roger Bowler, Jan Jaeger, and others"};
1286
1287 #define LOGO_BUFFERSIZE 256;
1288
buffer_addchar(char * b,size_t * l,size_t * al,char c)1289 static char *buffer_addchar(char *b,size_t *l,size_t *al,char c)
1290 {
1291 size_t len;
1292 size_t alen;
1293 len=*l;
1294 alen=*al;
1295 if(len>=alen)
1296 {
1297 if(!alen)
1298 {
1299 alen=LOGO_BUFFERSIZE;
1300 b=malloc(alen);
1301 if(!b)
1302 {
1303 return NULL;
1304 }
1305 }
1306 else
1307 {
1308 alen+=LOGO_BUFFERSIZE;
1309 b=realloc(b,alen);
1310 if(!b)
1311 {
1312 return NULL;
1313 }
1314 }
1315 }
1316 b[len++]=c;
1317 *al=alen;
1318 *l=len;
1319 return b;
1320 }
1321
buffer_addstring(char * b,size_t * l,size_t * al,char * s)1322 static char *buffer_addstring(char *b,size_t *l,size_t *al,char *s)
1323 {
1324 size_t i;
1325 for(i=0;s[i]!=0;i++)
1326 {
1327 b=buffer_addchar(b,l,al,s[i]);
1328 if(!b)
1329 {
1330 return NULL;
1331 }
1332 }
1333 return b;
1334 }
1335
buffer_addsba(char * b,size_t * l,size_t * al,int x,int y)1336 static char *buffer_addsba(char *b,size_t *l,size_t *al,int x, int y)
1337 {
1338 int pos;
1339 pos=x*80+y;
1340 b=buffer_addchar(b,l,al,0x11);
1341 if(!b) return NULL;
1342 b=buffer_addchar(b,l,al,sba_code[pos>>6]);
1343 if(!b) return NULL;
1344 b=buffer_addchar(b,l,al,sba_code[pos & 0x3f]);
1345 return b;
1346 }
buffer_addsf(char * b,size_t * l,size_t * al,int a)1347 static char *buffer_addsf(char *b,size_t *l,size_t *al,int a)
1348 {
1349 b=buffer_addchar(b,l,al,0x1d);
1350 if(!b) return NULL;
1351 b=buffer_addchar(b,l,al,sba_code[a & 0x3f]);
1352 return b;
1353 }
1354
1355 #define ALIGN_NONE 0
1356 #define ALIGN_CENTER 1
1357 #define ALIGN_LEFT 2
1358 #define ALIGN_RIGHT 3
build_logo(char ** logodata,size_t logosize,size_t * blen)1359 static char *build_logo(char **logodata,size_t logosize,size_t *blen)
1360 {
1361 size_t len;
1362 size_t alen;
1363 char *bfr;
1364 char *cline;
1365 size_t i,j;
1366 char *verb;
1367 char *rest;
1368 int xpos,ypos;
1369 int attr;
1370 int align;
1371 char *wrk;
1372
1373 bfr=NULL;
1374 len=0;
1375 alen=0;
1376 bfr=buffer_addchar(bfr,&len,&alen,0xf5);
1377 bfr=buffer_addchar(bfr,&len,&alen,0x42);
1378 if(bfr==NULL)
1379 {
1380 *blen=0;
1381 return NULL;
1382 }
1383 align=ALIGN_NONE;
1384 xpos=0;
1385 ypos=0;
1386 attr=SF_ATTR_PROTECTED;
1387 for(i=0;i<logosize;i++)
1388 {
1389 cline=malloc(strlen(logodata[i])+1);
1390 strcpy(cline,logodata[i]);
1391 while(1)
1392 {
1393 if(cline[0]!='@')
1394 {
1395 #if defined(OPTION_CONFIG_SYMBOLS)
1396 wrk=resolve_symbol_string(cline);
1397 free(cline);
1398 cline=wrk;
1399 #endif
1400 switch(align)
1401 {
1402 case ALIGN_RIGHT:
1403 ypos=strlen(cline);
1404 if(ypos<80)
1405 {
1406 ypos=80-ypos;
1407 }
1408 else
1409 {
1410 ypos=0;
1411 }
1412 break;
1413 case ALIGN_CENTER:
1414 ypos=strlen(cline);
1415 if(ypos<80)
1416 {
1417 ypos=(80-ypos)/2;
1418 }
1419 break;
1420 case ALIGN_LEFT:
1421 ypos=0;
1422 break;
1423 default:
1424 break;
1425 }
1426 bfr=buffer_addsba(bfr,&len,&alen,xpos,ypos);
1427 bfr=buffer_addsf(bfr,&len,&alen,attr);
1428 if(align==ALIGN_NONE)
1429 {
1430 ypos+=strlen(cline);
1431 ypos++;
1432 }
1433 else
1434 {
1435 xpos++;
1436 ypos=0;
1437 }
1438 bfr=buffer_addstring(bfr,&len,&alen,(char *)translate_to_ebcdic(cline));
1439 break;
1440 }
1441 verb=strtok(cline," \t");
1442 if(verb==NULL)
1443 {
1444 break;
1445 }
1446 rest=strtok(NULL," \t");
1447 if(strcasecmp(verb,"@sba")==0)
1448 {
1449 if(rest==NULL)
1450 {
1451 break;
1452 }
1453 wrk=strtok(rest,",");
1454 if(wrk!=NULL)
1455 {
1456 xpos=atoi(wrk);
1457 }
1458 wrk=strtok(NULL,",");
1459 if(wrk!=NULL)
1460 {
1461 ypos=atoi(wrk);
1462 }
1463 break;
1464 }
1465 if(strcasecmp(verb,"@sf")==0)
1466 {
1467 attr=SF_ATTR_PROTECTED;
1468 if(rest==NULL)
1469 {
1470 break;
1471 }
1472 for(j=0;rest[j]!=0;j++)
1473 {
1474 switch(rest[j])
1475 {
1476 case 'h':
1477 case 'H':
1478 attr|=SF_ATTR_HIGHLIGHT;
1479 break;
1480 case 'i':
1481 case 'I':
1482 attr&=~SF_ATTR_PROTECTED;
1483 break;
1484 default:
1485 break;
1486 }
1487 }
1488 break;
1489 }
1490 if(strcasecmp(verb,"@nl")==0)
1491 {
1492 xpos++;
1493 ypos=0;
1494 break;
1495 }
1496 if(strcasecmp(verb,"@align")==0)
1497 {
1498 align=ALIGN_NONE;
1499 if(rest==NULL)
1500 {
1501 break;
1502 }
1503 while(1)
1504 {
1505 if(strcasecmp(rest,"center")==0)
1506 {
1507 align=ALIGN_CENTER;
1508 break;
1509 }
1510 if(strcasecmp(rest,"right")==0)
1511 {
1512 align=ALIGN_RIGHT;
1513 break;
1514 }
1515 if(strcasecmp(rest,"none")==0)
1516 {
1517 align=ALIGN_NONE;
1518 break;
1519 }
1520 if(strcasecmp(rest,"left")==0)
1521 {
1522 align=ALIGN_LEFT;
1523 break;
1524 }
1525 break;
1526 }
1527 break;
1528 }
1529 break;
1530 }
1531 free(cline);
1532 }
1533 bfr=buffer_addchar(bfr,&len,&alen,IAC);
1534 bfr=buffer_addchar(bfr,&len,&alen,EOR_MARK);
1535 *blen=len;
1536 return bfr;
1537 }
1538
1539 /*-------------------------------------------------------------------*/
1540 /* NEW CLIENT CONNECTION THREAD */
1541 /*-------------------------------------------------------------------*/
1542 static void *
connect_client(int * csockp)1543 connect_client (int *csockp)
1544 {
1545 int rc; /* Return code */
1546 DEVBLK *dev; /* -> Device block */
1547 size_t len; /* Data length */
1548 int csock; /* Socket for conversation */
1549 struct sockaddr_in client; /* Client address structure */
1550 socklen_t namelen; /* Length of client structure*/
1551 char *clientip; /* Addr of client ip address */
1552 U16 devnum; /* Requested device number */
1553 BYTE class; /* D=3270, P=3287, K=3215/1052 */
1554 BYTE model; /* 3270 model (2,3,4,5,X) */
1555 BYTE extended; /* Extended attributes (Y,N) */
1556 char buf[1920]; /* Message buffer */
1557 char conmsg[256]; /* Connection message */
1558 char devmsg[64]; /* Device message */
1559 char hostmsg[256]; /* Host ID message */
1560 char num_procs[16]; /* #of processors string */
1561 char rejmsg[256]; /* Rejection message */
1562 char group[16]; /* Console group */
1563 size_t logoheight;
1564 char *logobfr;
1565 char *logoout;
1566
1567 logobfr=NULL;
1568 /* Load the socket address from the thread parameter */
1569 csock = *csockp;
1570
1571 /* Obtain the client's IP address */
1572 namelen = sizeof(client);
1573 rc = getpeername (csock, (struct sockaddr *)&client, &namelen);
1574
1575 /* Log the client's IP address and hostname */
1576 clientip = strdup(inet_ntoa(client.sin_addr));
1577
1578 #if 0
1579 // The following isn't really needed and hangs under unusual
1580 // network configuration settings and thus has been removed.
1581 {
1582 struct hostent* pHE; /* Addr of hostent structure */
1583 char* clientname; /* Addr of client hostname */
1584
1585 pHE = gethostbyaddr ((unsigned char*)(&client.sin_addr),
1586 sizeof(client.sin_addr), AF_INET);
1587
1588 if (pHE != NULL && pHE->h_name != NULL
1589 && pHE->h_name[0] != '\0') {
1590 clientname = (char*) pHE->h_name;
1591 } else {
1592 clientname = "host name unknown";
1593 }
1594
1595 TNSDEBUG1("console: DBG018: Received connection from %s (%s)\n",
1596 clientip, clientname);
1597 }
1598 #else
1599 TNSDEBUG1("console: DBG018: Received connection from %s\n",
1600 clientip );
1601 #endif
1602
1603 /* Negotiate telnet parameters */
1604 rc = negotiate (csock, &class, &model, &extended, &devnum, group);
1605 if (rc != 0)
1606 {
1607 close_socket (csock);
1608 if (clientip) free(clientip);
1609 return NULL;
1610 }
1611
1612 /* Look for an available console device */
1613 for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
1614 {
1615 /* Loop if the device is invalid */
1616 if ( !dev->allocated )
1617 continue;
1618
1619 /* Loop if non-matching device type */
1620 if (class == 'D' && dev->devtype != 0x3270)
1621 continue;
1622
1623 if (class == 'P' && dev->devtype != 0x3287)
1624 continue;
1625
1626 if (class == 'K' && dev->devtype != 0x1052
1627 && dev->devtype != 0x3215)
1628 continue;
1629
1630 /* Loop if a specific device number was requested and
1631 this device is not the requested device number */
1632 if (devnum != 0xFFFF && dev->devnum != devnum)
1633 continue;
1634
1635 /* Loop if no specific device number was requested, and
1636 either a group was requested OR the device is in a group,
1637 and the device group does not match the requested group */
1638 if (devnum==0xFFFF && (group[0] || dev->filename[0]))
1639 {
1640 if (strncasecmp(group,dev->filename,16)!=0)
1641 {
1642 continue;
1643 }
1644 }
1645
1646 /* Obtain the device lock */
1647 obtain_lock (&dev->lock);
1648
1649 /* Test for available device */
1650 if (dev->connected == 0)
1651 {
1652 /* Check ipaddr mask to see if client allowed on this device */
1653 if ( (client.sin_addr.s_addr & dev->acc_ipmask) != dev->acc_ipaddr )
1654 {
1655 release_lock (&dev->lock);
1656 if ( 0xFFFF == devnum ) /* If they did NOT request a spe- */
1657 continue; /* cifc devnum, then keep looking */
1658 dev = NULL; /* Otherwise they did, */
1659 break; /* but it's not available */
1660 }
1661
1662 /* Claim this device for the client */
1663 dev->connected = 1;
1664 dev->fd = csock;
1665 dev->ipaddr = client.sin_addr;
1666 dev->mod3270 = model;
1667 dev->eab3270 = (extended == 'Y' ? 1 : 0);
1668
1669 /* Reset the console device */
1670 dev->readpending = 0;
1671 dev->rlen3270 = 0;
1672 dev->keybdrem = 0;
1673
1674 memset (&dev->scsw, 0, sizeof(SCSW));
1675 memset (&dev->pciscsw, 0, sizeof(SCSW));
1676 dev->busy = dev->reserved = dev->suspended =
1677 dev->pending = dev->pcipending = dev->attnpending = 0;
1678
1679 release_lock (&dev->lock);
1680
1681 break;
1682 }
1683
1684 /* Release the device lock */
1685 release_lock (&dev->lock);
1686
1687 } /* end for(dev) */
1688
1689 /* Build connection message for client */
1690
1691 if ( cons_hostinfo.num_procs > 1 )
1692 snprintf( num_procs, sizeof(num_procs), "MP=%d", cons_hostinfo.num_procs );
1693 else
1694 strlcpy( num_procs, "UP", sizeof(num_procs) );
1695
1696 snprintf
1697 (
1698 hostmsg, sizeof(hostmsg),
1699
1700 "running on %s (%s-%s.%s %s %s)"
1701
1702 ,cons_hostinfo.nodename
1703 ,cons_hostinfo.sysname
1704 ,cons_hostinfo.release
1705 ,cons_hostinfo.version
1706 ,cons_hostinfo.machine
1707 ,num_procs
1708 );
1709 snprintf (conmsg, sizeof(conmsg),
1710 "Hercules version %s built on %s %s",
1711 VERSION, __DATE__, __TIME__);
1712
1713 /* Reject the connection if no available console device */
1714 if (dev == NULL)
1715 {
1716 /* Build the rejection message */
1717 if (devnum == 0xFFFF)
1718 {
1719 if(!group[0])
1720 {
1721 snprintf (rejmsg, sizeof(rejmsg),
1722 "Connection rejected, no available %s device",
1723 (class=='D' ? "3270" : (class=='P' ? "3287" : "1052 or 3215")));
1724 }
1725 else
1726 {
1727 snprintf (rejmsg, sizeof(rejmsg),
1728 "Connection rejected, no available %s devices in the %s group",
1729 (class=='D' ? "3270" : (class=='P' ? "3287" : "1052 or 3215")),group);
1730 }
1731 }
1732 else
1733 {
1734 snprintf (rejmsg, sizeof(rejmsg),
1735 "Connection rejected, device %4.4X unavailable",
1736 devnum);
1737 }
1738
1739 TNSDEBUG1( "DBG019: %s\n", rejmsg);
1740
1741 /* Send connection rejection message to client */
1742 if (class != 'K')
1743 {
1744 len = snprintf (buf, sizeof(buf),
1745 "\xF5\x40\x11\x40\x40\x1D\x60%s"
1746 "\x11\xC1\x50\x1D\x60%s"
1747 "\x11\xC2\x60\x1D\x60%s",
1748 translate_to_ebcdic(conmsg),
1749 translate_to_ebcdic(hostmsg),
1750 translate_to_ebcdic(rejmsg));
1751
1752 if (len < sizeof(buf))
1753 {
1754 buf[len++] = IAC;
1755 }
1756 else
1757 {
1758 ASSERT(FALSE);
1759 }
1760
1761 if (len < sizeof(buf))
1762 {
1763 buf[len++] = EOR_MARK;
1764 }
1765 else
1766 {
1767 ASSERT(FALSE);
1768 }
1769 }
1770 else
1771 {
1772 len = snprintf (buf, sizeof(buf), "%s\r\n%s\r\n%s\r\n", conmsg, hostmsg, rejmsg);
1773 }
1774
1775 if (class != 'P') /* do not write connection resp on 3287 */
1776 {
1777 rc = send_packet (csock, (BYTE *)buf, len, "CONNECTION RESPONSE");
1778 }
1779
1780 /* Close the connection and terminate the thread */
1781 SLEEP (5);
1782 close_socket (csock);
1783 if (clientip) free(clientip);
1784 return NULL;
1785 }
1786 else
1787 {
1788 snprintf (devmsg, sizeof(devmsg), "Connected to device %d:%4.4X",
1789 SSID_TO_LCSS(dev->ssid), dev->devnum);
1790 }
1791
1792 logmsg (_("HHCTE009I Client %s connected to %4.4X device %d:%4.4X\n"),
1793 clientip, dev->devtype, SSID_TO_LCSS(dev->ssid), dev->devnum);
1794
1795 /* Send connection message to client */
1796 if (class != 'K')
1797 {
1798 #if defined(OPTION_CONFIG_SYMBOLS)
1799 set_symbol("VERSION",VERSION);
1800 set_symbol("BDATE",__DATE__);
1801 set_symbol("BTIME",__TIME__);
1802 set_symbol("HOSTNAME",cons_hostinfo.nodename);
1803 set_symbol("HOSTOS",cons_hostinfo.sysname);
1804 set_symbol("HOSTOSREL",cons_hostinfo.release);
1805 set_symbol("HOSTOSVER",cons_hostinfo.version);
1806 set_symbol("HOSTARCH",cons_hostinfo.machine);
1807 set_symbol("HOSTNUMCPUS",num_procs);
1808 set_symbol("LPARNAME",str_lparname());
1809 snprintf(conmsg,sizeof(conmsg),"%3.3X",dev->devnum);
1810 set_symbol("CUU",conmsg);
1811 snprintf(conmsg,sizeof(conmsg),"%3.3x",dev->devnum);
1812 set_symbol("cuu",conmsg);
1813 snprintf(conmsg,sizeof(conmsg),"%4.4X",dev->devnum);
1814 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1815 if (dev == sysblk.sysgdev)
1816 strncpy(conmsg,"SYSG",sizeof(conmsg));
1817 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
1818 set_symbol("CCUU",conmsg);
1819 snprintf(conmsg,sizeof(conmsg),"%4.4x",dev->devnum);
1820 set_symbol("ccuu",conmsg);
1821 snprintf(conmsg,sizeof(conmsg),"%d",SSID_TO_LCSS(dev->ssid));
1822 set_symbol("CSS",conmsg);
1823 snprintf(conmsg,sizeof(conmsg),"%4.4X",dev->subchan);
1824 set_symbol("SUBCHAN",conmsg);
1825 #endif // defined(OPTION_CONFIG_SYMBOLS)
1826 if(sysblk.herclogo!=NULL)
1827 {
1828 logobfr=build_logo(sysblk.herclogo,sysblk.logolines,&len);
1829 }
1830 else
1831 {
1832 logoheight=sizeof(herclogo)/sizeof(char *);
1833 logobfr=build_logo(herclogo,logoheight,&len);
1834 }
1835 logoout=logobfr;
1836 }
1837 else
1838 {
1839 len = snprintf (buf, sizeof(buf), "%s\r\n%s\r\n%s\r\n",
1840 conmsg, hostmsg, devmsg);
1841 logoout=buf;
1842 }
1843
1844 if (class != 'P') /* do not write connection resp on 3287 */
1845 {
1846 rc = send_packet (csock, (BYTE *)logoout, len, "CONNECTION RESPONSE");
1847 }
1848 if(logobfr)
1849 {
1850 free(logobfr);
1851 }
1852
1853 /* Raise attention interrupt for the device,
1854 IF...
1855 (1) this is NOT a 3287 printer device, -AND-
1856 (2) this is NOT the System-370 mode initial power-on state
1857 and it is not the SYSG console
1858 */
1859 if (class != 'P'
1860 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
1861 && dev != sysblk.sysgdev
1862 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
1863 && !INITIAL_POWERON_370())
1864 device_attention (dev, CSW_DE);
1865
1866 /* Try to detect dropped connections */
1867 socket_keepalive( csock, sysblk.kaidle, sysblk.kaintv, sysblk.kacnt );
1868
1869 /* Signal connection thread to redrive its select loop */
1870 SIGNAL_CONSOLE_THREAD();
1871
1872 if (clientip) free(clientip);
1873 return NULL;
1874
1875 } /* end function connect_client */
1876
1877
1878 /*-------------------------------------------------------------------*/
1879 /* CONSOLE CONNECTION AND ATTENTION HANDLER THREAD */
1880 /*-------------------------------------------------------------------*/
1881
1882 static int console_cnslcnt = 0; /* count of connected terms */
1883 static LOCK console_lock; /* console_cnslcnt lock */
1884 static int did_init = 0; /* console_lock initialized */
1885
console_shutdown(void * unused)1886 static void console_shutdown(void * unused)
1887 {
1888 UNREFERENCED(unused);
1889
1890 obtain_lock( &console_lock );
1891 {
1892 console_cnslcnt = 0;
1893 SIGNAL_CONSOLE_THREAD();
1894 }
1895 release_lock( &console_lock );
1896 }
1897
1898 static void *
console_connection_handler(void * arg)1899 console_connection_handler (void *arg)
1900 {
1901 int rc = 0; /* Return code */
1902 int lsock; /* Socket for listening */
1903 int csock; /* Socket for conversation */
1904 struct sockaddr_in *server; /* Server address structure */
1905 fd_set readset; /* Read bit map for select */
1906 int maxfd; /* Highest fd for select */
1907 int optval; /* Argument for setsockopt */
1908 TID tidneg; /* Negotiation thread id */
1909 DEVBLK *dev; /* -> Device block */
1910 BYTE unitstat; /* Status after receive data */
1911
1912 UNREFERENCED(arg);
1913
1914 hdl_adsc("console_shutdown",console_shutdown, NULL);
1915
1916 /* Display thread started message on control panel */
1917 logmsg (_("HHCTE001I Console connection thread started: "
1918 "tid="TIDPAT", pid=%d\n"),
1919 thread_id(), getpid());
1920
1921 /* Get information about this system */
1922 init_hostinfo( &cons_hostinfo );
1923
1924 /* Obtain a socket */
1925 lsock = socket (AF_INET, SOCK_STREAM, 0);
1926
1927 if (lsock < 0)
1928 {
1929 TNSERROR("console: DBG025: socket: %s\n", strerror(HSO_errno));
1930 return NULL;
1931 }
1932
1933 /* Allow previous instance of socket to be reused */
1934 optval = 1;
1935 setsockopt (lsock, SOL_SOCKET, SO_REUSEADDR,
1936 (GETSET_SOCKOPT_T*)&optval, sizeof(optval));
1937
1938 /* Prepare the sockaddr structure for the bind */
1939 if(!( server = get_inet_socket(config_cnslport) ))
1940 {
1941 logmsg(_("HHCTE010E CNSLPORT statement invalid: %s\n"),
1942 config_cnslport);
1943 return NULL;
1944 }
1945
1946 /* Attempt to bind the socket to the port */
1947 do
1948 {
1949 rc = bind (lsock, (struct sockaddr *)server, sizeof(struct sockaddr_in));
1950
1951 if (rc == 0 || HSO_errno != HSO_EADDRINUSE) break;
1952
1953 logmsg (_("HHCTE002W Waiting for port %u to become free\n"),
1954 ntohs(server->sin_port));
1955 SLEEP(10);
1956 }
1957 while (console_cnslcnt);
1958
1959 if (rc != 0)
1960 {
1961 TNSERROR("console: DBG026: bind: %s\n", strerror(HSO_errno));
1962 return NULL;
1963 }
1964
1965 /* Put the socket into listening state */
1966 if ((rc = listen (lsock, 10)) < 0)
1967 {
1968 TNSERROR("console: DBG027: listen: %s\n", strerror(HSO_errno));
1969 return NULL;
1970 }
1971
1972 logmsg (_("HHCTE003I Waiting for console connection on port %u\n"),
1973 ntohs(server->sin_port));
1974
1975 /* Handle connection requests and attention interrupts */
1976 for (;;)
1977 {
1978 /* Check if time to exit */
1979 int time_to_exit;
1980 obtain_lock( &console_lock );
1981 time_to_exit = console_cnslcnt <= 0 ? 1 : 0;
1982 release_lock( &console_lock );
1983 if (time_to_exit) break;
1984
1985 /* Initialize the select parameters */
1986
1987 FD_ZERO ( &readset ); maxfd=INT_MIN;
1988 FD_SET ( lsock, &readset ); maxfd = lsock;
1989 SUPPORT_WAKEUP_CONSOLE_SELECT_VIA_PIPE( maxfd, &readset );
1990
1991 /* Include the socket for each valid connected console */
1992 for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
1993 {
1994 if ( !dev->allocated) continue;
1995
1996 obtain_lock( &dev->lock );
1997 {
1998 if ( dev->console )
1999 {
2000 if ( dev->connected )
2001 {
2002 /* VERIFY that the file descriptor is valid.
2003 If it's NOT, then IGNORE this console device
2004 since it's thus obvious that SOMETHING has
2005 gone wrong SOMEWHERE at some point! (some
2006 sort of race condition SOMEWHERE, obviously)
2007 */
2008 if (dev->fd < 0)
2009 {
2010 // Ah-HA! We may have FINALLY found (or at
2011 // least have gotten a little bit closer to
2012 // finding) the ROOT CAUSE of our problematic
2013 // "DBG028 select: Bad FIle Number" problem!
2014 logmsg
2015 (
2016 "\n"
2017 "*********** DBG028 CONSOLE BUG ***********\n"
2018 "device %4.4X: 'connected', but dev->fd = -1\n"
2019 "\n"
2020
2021 ,dev->devnum
2022 );
2023 dev->connected = 0; // (since it's not connected!)
2024 }
2025 else
2026 {
2027 /* Add it to our read set only if it's
2028 not busy nor interrupt pending */
2029 if (1
2030 && (!dev->busy || (dev->scsw.flag3 & SCSW3_AC_SUSP))
2031 && !IOPENDING(dev)
2032 && !(dev->scsw.flag3 & SCSW3_SC_PEND)
2033 )
2034 {
2035 FD_SET (dev->fd, &readset);
2036 if (dev->fd > maxfd) maxfd = dev->fd;
2037 }
2038 }
2039 }
2040 else // ( !dev->connected )
2041 {
2042 if ( dev->fd >= 0 )
2043 {
2044 close_socket ( dev->fd );
2045 dev->fd = -1;
2046 }
2047
2048 } /* if (dev->connected) */
2049
2050 } /* if (dev->console) */
2051 }
2052 release_lock( &dev->lock );
2053
2054 } /* end for(dev) */
2055
2056 /* Wait for a file descriptor to become ready */
2057 rc = select ( maxfd+1, &readset, NULL, NULL, NULL );
2058
2059 /* Clear the pipe signal if necessary */
2060 RECV_CONSOLE_THREAD_PIPE_SIGNAL();
2061
2062 /* Log select errors */
2063 if (rc < 0 )
2064 {
2065 int select_errno = HSO_errno; // (preserve orig errno)
2066 static int issue_errmsg = 1; // (prevents msgs flood)
2067
2068 if (EBADF == select_errno)
2069 {
2070 // Don't issue message more frequently
2071 // than once every second or so, just in
2072 // case the condition that's causing it
2073 // keeps reoccurring over and over...
2074
2075 static struct timeval prev = {0,0};
2076 struct timeval curr;
2077 struct timeval diff;
2078
2079 gettimeofday( &curr, NULL );
2080 timeval_subtract( &prev, &curr, &diff );
2081
2082 // Has it been longer than one second
2083 // since we last issued this message?
2084
2085 if (diff.tv_sec >= 1)
2086 {
2087 issue_errmsg = 1;
2088 prev.tv_sec = curr.tv_sec;
2089 prev.tv_usec = curr.tv_usec;
2090 }
2091 else
2092 issue_errmsg = 0; // (prevents msgs flood)
2093 }
2094 else
2095 issue_errmsg = 1;
2096 if ( issue_errmsg && EINTR != select_errno )
2097 {
2098 TNSERROR("console: DBG028: select: %s\n", strerror(select_errno));
2099 usleep(50000); // (wait a bit; maybe it'll fix itself??)
2100 }
2101 continue;
2102 }
2103
2104 /* If a client connection request has arrived then accept it */
2105 if (FD_ISSET(lsock, &readset))
2106 {
2107 /* Accept a connection and create conversation socket */
2108 csock = accept (lsock, NULL, NULL);
2109
2110 if (csock < 0)
2111 {
2112 TNSERROR("console: DBG029: accept: %s\n", strerror(HSO_errno));
2113 continue;
2114 }
2115
2116 /* Create a thread to complete the client connection */
2117 if ( create_thread (&tidneg, DETACHED,
2118 connect_client, &csock, "connect_client")
2119 )
2120 {
2121 TNSERROR("console: DBG030: connect_client create_thread: %s\n",
2122 strerror(errno));
2123 close_socket (csock);
2124 }
2125
2126 } /* end if(FD_ISSET(lsock, &readset)) */
2127
2128 /* Check if any connected client has data ready to send */
2129 for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
2130 {
2131 /* Obtain the device lock */
2132 obtain_lock (&dev->lock);
2133
2134 /* Test for valid connected console with data available */
2135 if (1
2136 && dev->allocated
2137 && dev->console
2138 && dev->connected
2139 && (!dev->busy || (dev->scsw.flag3 & SCSW3_AC_SUSP))
2140 && !( IOPENDING(dev) || (dev->scsw.flag3 & SCSW3_SC_PEND) )
2141 && FD_ISSET (dev->fd, &readset)
2142 )
2143 {
2144 /* Receive console input data from the client */
2145 if ((dev->devtype == 0x3270) || (dev->devtype == 0x3287))
2146 unitstat = recv_3270_data (dev);
2147 else
2148 unitstat = recv_1052_data (dev);
2149
2150 /* Nothing more to do if incomplete record received */
2151 if (unitstat == 0)
2152 {
2153 release_lock (&dev->lock);
2154 continue;
2155 }
2156
2157 /* Close the connection if an error occurred */
2158 if (unitstat & CSW_UC)
2159 {
2160 close_socket (dev->fd);
2161 dev->fd = -1;
2162 dev->connected = 0;
2163 }
2164
2165 /* Indicate that data is available at the device */
2166 if(dev->rlen3270)
2167 dev->readpending = 1;
2168
2169 /* Release the device lock */
2170 release_lock (&dev->lock);
2171
2172 /* Raise attention interrupt for the device */
2173
2174 /* Do NOT raise attention interrupt for 3287 */
2175 /* Otherwise zVM loops after ENABLE ccuu */
2176 /* Following 5 lines are repeated on Hercules console: */
2177 /* console: sending 3270 data */
2178 /* +0000 F5C2FFEF */
2179 /* console: Packet received length=7 */
2180 /* +0000 016CD902 00FFEF */
2181 /* I do not know what is this */
2182 /* console: CCUU attention requests raised */
2183
2184 /* Do not raise attention interrupt for the SYSG console */
2185
2186 /* Do NOT raise attention interrupt if this is */
2187 /* the System-370 mode initial power-on state */
2188
2189 if (1
2190 && dev->connected
2191 && dev->devtype != 0x3287
2192 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
2193 && dev != sysblk.sysgdev
2194 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
2195 && !INITIAL_POWERON_370()
2196 )
2197 {
2198 rc = device_attention (dev, unitstat);
2199
2200 /* Trace the attention request */
2201 TNSDEBUG2("console: DBG020: "
2202 "%4.4X attention request %s; rc=%d\n",
2203 dev->devnum,
2204 (rc == 0 ? "raised" : "rejected"), rc);
2205 }
2206
2207 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
2208 /* For the SYSG console, generate an external interrupt */
2209 if (dev == sysblk.sysgdev && dev->connected)
2210 {
2211 sclp_sysg_attention();
2212 }
2213 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
2214
2215 continue; /* (note: dev->lock already released) */
2216
2217 } /* end if(data available) */
2218
2219 /* Release the device lock */
2220 release_lock (&dev->lock);
2221
2222 } /* end for(dev) */
2223
2224 } /* end for */
2225
2226 /* Close all connected terminals */
2227 for (dev = sysblk.firstdev; dev != NULL; dev = dev->nextdev)
2228 {
2229 /* Obtain the device lock */
2230 obtain_lock (&dev->lock);
2231
2232 /* Test for connected console with data available */
2233 if (dev->console
2234 && dev->fd>=0)
2235 {
2236 close_socket(dev->fd);
2237 dev->connected=0;
2238 dev->fd=-1;
2239 }
2240 release_lock (&dev->lock);
2241 }
2242
2243 /* Close the listening socket */
2244 close_socket (lsock);
2245 free(server);
2246
2247 logmsg (_("HHCTE004I Console connection thread terminated\n"));
2248 sysblk.cnsltid = 0;
2249
2250 return NULL;
2251
2252 } /* end function console_connection_handler */
2253
2254
2255 static int
console_initialise()2256 console_initialise()
2257 {
2258 int rc = 0;
2259
2260 if (!did_init)
2261 {
2262 did_init = 1;
2263 initialize_lock( &console_lock );
2264 }
2265
2266 obtain_lock( &console_lock );
2267 {
2268 console_cnslcnt++;
2269
2270 if (!sysblk.cnsltid)
2271 {
2272 if ( create_thread (&sysblk.cnsltid, DETACHED,
2273 console_connection_handler, NULL,
2274 "console_connection_handler")
2275 )
2276 {
2277 logmsg (_("HHCTE005E Cannot create console thread: %s\n"),
2278 strerror(errno));
2279 rc = 1;
2280 }
2281 }
2282 }
2283 release_lock( &console_lock );
2284
2285 return rc;
2286 }
2287
2288
2289 static void
console_remove(DEVBLK * dev)2290 console_remove(DEVBLK *dev)
2291 {
2292 obtain_lock( &console_lock );
2293 {
2294 dev->connected = 0;
2295 dev->console = 0;
2296 dev->fd = -1;
2297
2298 if (console_cnslcnt <= 0)
2299 logmsg(_("** BUG! console_remove() error! **\n"));
2300 else
2301 console_cnslcnt--;
2302
2303 SIGNAL_CONSOLE_THREAD();
2304 }
2305 release_lock( &console_lock );
2306 }
2307
2308
2309 /*-------------------------------------------------------------------*/
2310 /* INITIALIZE THE 3270 DEVICE HANDLER */
2311 /*-------------------------------------------------------------------*/
2312 static int
loc3270_init_handler(DEVBLK * dev,int argc,char * argv[])2313 loc3270_init_handler ( DEVBLK *dev, int argc, char *argv[] )
2314 {
2315 int ac = 0;
2316
2317 /* Indicate that this is a console device */
2318 dev->console = 1;
2319
2320 /* Reset device dependent flags */
2321 dev->connected = 0;
2322
2323 /* Set number of sense bytes */
2324 dev->numsense = 1;
2325
2326 /* Set the size of the device buffer */
2327 dev->bufsize = BUFLEN_3270;
2328
2329 if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
2330 dev->devtype = 0x3270;
2331
2332 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
2333 /* Extra initialisation for the SYSG console */
2334 if (strcasecmp(dev->typname,"SYSG") == 0)
2335 {
2336 dev->pmcw.flag5 &= ~PMCW5_V; // Not a regular device
2337 if (sysblk.sysgdev != NULL)
2338 {
2339 logmsg(_("HHCTE017E Device %4.4X: Duplicate SYSG console definition\n"),
2340 dev->devnum);
2341 return -1;
2342 }
2343 }
2344 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
2345
2346 /* Initialize the device identifier bytes */
2347 dev->devid[0] = 0xFF;
2348 dev->devid[1] = 0x32; /* Control unit type is 3274-1D */
2349 dev->devid[2] = 0x74;
2350 dev->devid[3] = 0x1D;
2351 dev->devid[4] = 0x32; /* Device type is 3278-2 */
2352 if ((dev->devtype & 0xFF)==0x70)
2353 {
2354 dev->devid[5] = 0x78;
2355 dev->devid[6] = 0x02;
2356 }
2357 else
2358 {
2359 dev->devid[5] = dev->devtype & 0xFF; /* device type is 3287-1 */
2360 dev->devid[6] = 0x01;
2361 }
2362 dev->numdevid = 7;
2363
2364 dev->filename[0] = 0;
2365 dev->acc_ipaddr = 0;
2366 dev->acc_ipmask = 0;
2367
2368 if (argc > 0) // group name?
2369 {
2370 if ('*' == argv[ac][0] && '\0' == argv[ac][1])
2371 ; // NOP (not really a group name; an '*' is
2372 // simply used as an argument place holder)
2373 else
2374 strlcpy(dev->filename,argv[ac],sizeof(dev->filename));
2375
2376 argc--; ac++;
2377 if (argc > 0) // ip address?
2378 {
2379 if ((dev->acc_ipaddr = inet_addr(argv[ac])) == (in_addr_t)(-1))
2380 {
2381 logmsg(_("HHCTE011E Device %4.4X: Invalid IP address: %s\n"),
2382 dev->devnum, argv[ac]);
2383 return -1;
2384 }
2385 else
2386 {
2387 argc--; ac++;
2388 if (argc > 0) // ip addr mask?
2389 {
2390 if ((dev->acc_ipmask = inet_addr(argv[ac])) == (in_addr_t)(-1))
2391 {
2392 logmsg(_("HHCTE012E Device %4.4X: Invalid mask value: %s\n"),
2393 dev->devnum, argv[ac]);
2394 return -1;
2395 }
2396 else
2397 {
2398 argc--; ac++;
2399 if (argc > 0) // too many args?
2400 {
2401 logmsg(_("HHCTE013E Device %4.4X: Extraneous argument(s): %s...\n"),
2402 dev->devnum, argv[ac] );
2403 return -1;
2404 }
2405 }
2406 }
2407 else
2408 dev->acc_ipmask = (in_addr_t)(-1);
2409 }
2410 }
2411 }
2412
2413 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
2414 /* Extra initialisation for the SYSG console */
2415 if (strcasecmp(dev->typname,"SYSG") == 0)
2416 {
2417 /* Save the address of the SYSG console devblk */
2418 sysblk.sysgdev = dev;
2419 }
2420 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
2421
2422 return console_initialise();
2423 } /* end function loc3270_init_handler */
2424
2425
2426 /*-------------------------------------------------------------------*/
2427 /* QUERY THE 3270 DEVICE DEFINITION */
2428 /*-------------------------------------------------------------------*/
2429 static void
loc3270_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)2430 loc3270_query_device (DEVBLK *dev, char **class,
2431 int buflen, char *buffer)
2432 {
2433 BEGIN_DEVICE_CLASS_QUERY( "DSP", dev, class, buflen, buffer );
2434
2435 if (dev->connected)
2436 {
2437 snprintf (buffer, buflen, "%s",
2438 inet_ntoa(dev->ipaddr));
2439 }
2440 else
2441 {
2442 char acc[48];
2443
2444 if (dev->acc_ipaddr || dev->acc_ipmask)
2445 {
2446 char ip [16];
2447 char mask [16];
2448 struct in_addr xxxx;
2449
2450 xxxx.s_addr = dev->acc_ipaddr;
2451
2452 snprintf( ip, sizeof( ip ),
2453 "%s", inet_ntoa( xxxx ));
2454
2455 xxxx.s_addr = dev->acc_ipmask;
2456
2457 snprintf( mask, sizeof( mask ),
2458 "%s", inet_ntoa( xxxx ));
2459
2460 snprintf( acc, sizeof( acc ),
2461 "%s mask %s", ip, mask );
2462 }
2463 else
2464 acc[0] = 0;
2465
2466 if (dev->filename[0])
2467 {
2468 snprintf(buffer, buflen,
2469 "GROUP=%s%s%s",
2470 dev->filename, acc[0] ? " " : "", acc);
2471 }
2472 else
2473 {
2474 if (acc[0])
2475 {
2476 snprintf(buffer, buflen,
2477 "* %s", acc);
2478 }
2479 else
2480 buffer[0] = 0;
2481 }
2482 }
2483
2484 } /* end function loc3270_query_device */
2485
2486
2487 /*-------------------------------------------------------------------*/
2488 /* CLOSE THE 3270 DEVICE HANDLER */
2489 /*-------------------------------------------------------------------*/
2490 static int
loc3270_close_device(DEVBLK * dev)2491 loc3270_close_device ( DEVBLK *dev )
2492 {
2493
2494 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
2495 /* Clear the pointer to the SYSG console */
2496 if (dev == sysblk.sysgdev)
2497 {
2498 sysblk.sysgdev = NULL;
2499 }
2500 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
2501
2502 console_remove(dev);
2503
2504 return 0;
2505 } /* end function loc3270_close_device */
2506
2507
2508 /*-------------------------------------------------------------------*/
2509 /* 3270 Hercules Suspend/Resume text units */
2510 /*-------------------------------------------------------------------*/
2511 #define SR_DEV_3270_BUF ( SR_DEV_3270 | 0x001 )
2512 #define SR_DEV_3270_EWA ( SR_DEV_3270 | 0x002 )
2513 #define SR_DEV_3270_POS ( SR_DEV_3270 | 0x003 )
2514
2515 /*-------------------------------------------------------------------*/
2516 /* 3270 Hercules Suspend Routine */
2517 /*-------------------------------------------------------------------*/
2518 static int
loc3270_hsuspend(DEVBLK * dev,void * file)2519 loc3270_hsuspend(DEVBLK *dev, void *file)
2520 {
2521 size_t rc, len;
2522 BYTE buf[BUFLEN_3270];
2523
2524 if (!dev->connected) return 0;
2525 SR_WRITE_VALUE(file, SR_DEV_3270_POS, dev->pos3270, sizeof(dev->pos3270));
2526 SR_WRITE_VALUE(file, SR_DEV_3270_EWA, dev->ewa3270, 1);
2527 obtain_lock(&dev->lock);
2528 rc = solicit_3270_data (dev, R3270_RB);
2529 if (rc == 0 && dev->rlen3270 > 0 && dev->rlen3270 <= BUFLEN_3270)
2530 {
2531 len = dev->rlen3270;
2532 memcpy (buf, dev->buf, len);
2533 }
2534 else
2535 len = 0;
2536 release_lock(&dev->lock);
2537 if (len)
2538 SR_WRITE_BUF(file, SR_DEV_3270_BUF, buf, len);
2539 return 0;
2540 }
2541
2542 /*-------------------------------------------------------------------*/
2543 /* 3270 Hercules Resume Routine */
2544 /*-------------------------------------------------------------------*/
2545 static int
loc3270_hresume(DEVBLK * dev,void * file)2546 loc3270_hresume(DEVBLK *dev, void *file)
2547 {
2548 size_t rc, key, len, rbuflen = 0, pos = 0;
2549 BYTE *rbuf = NULL, buf[BUFLEN_3270];
2550
2551 do {
2552 SR_READ_HDR(file, key, len);
2553 switch (key) {
2554 case SR_DEV_3270_POS:
2555 SR_READ_VALUE(file, len, &pos, sizeof(pos));
2556 break;
2557 case SR_DEV_3270_EWA:
2558 SR_READ_VALUE(file, len, &rc, sizeof(rc));
2559 dev->ewa3270 = rc;
2560 break;
2561 case SR_DEV_3270_BUF:
2562 rbuflen = len;
2563 rbuf = malloc(len);
2564 if (rbuf == NULL)
2565 {
2566 logmsg(_("HHCTE090E %4.4X malloc() failed for resume buf: %s\n"),
2567 dev->devnum, strerror(errno));
2568 return 0;
2569 }
2570 SR_READ_BUF(file, rbuf, rbuflen);
2571 break;
2572 default:
2573 SR_READ_SKIP(file, len);
2574 break;
2575 } /* switch (key) */
2576 } while ((key & SR_DEV_MASK) == SR_DEV_3270);
2577
2578 /* Dequeue any I/O interrupts for this device */
2579 DEQUEUE_IO_INTERRUPT(&dev->ioint);
2580 DEQUEUE_IO_INTERRUPT(&dev->pciioint);
2581 DEQUEUE_IO_INTERRUPT(&dev->attnioint);
2582
2583 /* Restore the 3270 screen image if connected and buf was provided */
2584 if (dev->connected && rbuf && rbuflen > 3)
2585 {
2586 obtain_lock(&dev->lock);
2587
2588 /* Construct buffer to send to the 3270 */
2589 len = 0;
2590 buf[len++] = dev->ewa3270 ? R3270_EWA : R3270_EW;
2591 buf[len++] = 0xC2;
2592 memcpy (&buf[len], &rbuf[3], rbuflen - 3);
2593 len += rbuflen - 3;
2594 buf[len++] = O3270_SBA;
2595 buf[len++] = rbuf[1];
2596 buf[len++] = rbuf[2];
2597 buf[len++] = O3270_IC;
2598
2599 /* Double up any IAC's in the data */
2600 len = double_up_iac (buf, len);
2601
2602 /* Append telnet EOR marker */
2603 buf[len++] = IAC;
2604 buf[len++] = EOR_MARK;
2605
2606 /* Restore the 3270 screen */
2607 rc = send_packet(dev->fd, buf, len, "3270 data");
2608
2609 dev->pos3270 = pos;
2610
2611 release_lock(&dev->lock);
2612 }
2613
2614 if (rbuf) free(rbuf);
2615
2616 return 0;
2617 }
2618
2619
2620 /*-------------------------------------------------------------------*/
2621 /* INITIALIZE THE 1052/3215 DEVICE HANDLER */
2622 /*-------------------------------------------------------------------*/
2623 static int
constty_init_handler(DEVBLK * dev,int argc,char * argv[])2624 constty_init_handler ( DEVBLK *dev, int argc, char *argv[] )
2625 {
2626 int ac=0;
2627
2628 /* Indicate that this is a console device */
2629 dev->console = 1;
2630
2631 /* Set number of sense bytes */
2632 dev->numsense = 1;
2633
2634 /* Initialize device dependent fields */
2635 dev->keybdrem = 0;
2636
2637 /* Set length of print buffer */
2638 dev->bufsize = BUFLEN_1052;
2639
2640 /* Assume we want to prompt */
2641 dev->prompt1052 = 1;
2642
2643 /* Is there an argument? */
2644 if (argc > 0)
2645 {
2646 /* Look at the argument and set noprompt flag if specified. */
2647 if (strcasecmp(argv[ac], "noprompt") == 0)
2648 {
2649 dev->prompt1052 = 0;
2650 ac++; argc--;
2651 }
2652 // (else it's a group name...)
2653 }
2654
2655 if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
2656 dev->devtype = 0x1052;
2657
2658 /* Initialize the device identifier bytes */
2659 dev->devid[0] = 0xFF;
2660 dev->devid[1] = dev->devtype >> 8;
2661 dev->devid[2] = dev->devtype & 0xFF;
2662 dev->devid[3] = 0x00;
2663 dev->devid[4] = dev->devtype >> 8;
2664 dev->devid[5] = dev->devtype & 0xFF;
2665 dev->devid[6] = 0x00;
2666 dev->numdevid = 7;
2667
2668 dev->filename[0] = 0;
2669 dev->acc_ipaddr = 0;
2670 dev->acc_ipmask = 0;
2671
2672 if (argc > 0) // group name?
2673 {
2674 if ('*' == argv[ac][0] && '\0' == argv[ac][1])
2675 ; // NOP (not really a group name; an '*' is
2676 // simply used as an argument place holder)
2677 else
2678 strlcpy(dev->filename,argv[ac],sizeof(dev->filename));
2679
2680 argc--; ac++;
2681 if (argc > 0) // ip address?
2682 {
2683 if ((dev->acc_ipaddr = inet_addr(argv[ac])) == (in_addr_t)(-1))
2684 {
2685 logmsg(_("HHCTE011E Device %4.4X: Invalid IP address: %s\n"),
2686 dev->devnum, argv[ac]);
2687 return -1;
2688 }
2689 else
2690 {
2691 argc--; ac++;
2692 if (argc > 0) // ip addr mask?
2693 {
2694 if ((dev->acc_ipmask = inet_addr(argv[ac])) == (in_addr_t)(-1))
2695 {
2696 logmsg(_("HHCTE012E Device %4.4X: Invalid mask value: %s\n"),
2697 dev->devnum, argv[ac]);
2698 return -1;
2699 }
2700 else
2701 {
2702 argc--; ac++;
2703 if (argc > 0) // too many args?
2704 {
2705 logmsg(_("HHCTE013E Device %4.4X: Extraneous argument(s): %s...\n"),
2706 dev->devnum, argv[ac] );
2707 return -1;
2708 }
2709 }
2710 }
2711 else
2712 dev->acc_ipmask = (in_addr_t)(-1);
2713 }
2714 }
2715 }
2716
2717 return console_initialise();
2718 } /* end function constty_init_handler */
2719
2720
2721 /*-------------------------------------------------------------------*/
2722 /* QUERY THE 1052/3215 DEVICE DEFINITION */
2723 /*-------------------------------------------------------------------*/
2724 static void
constty_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)2725 constty_query_device (DEVBLK *dev, char **class,
2726 int buflen, char *buffer)
2727 {
2728 BEGIN_DEVICE_CLASS_QUERY( "CON", dev, class, buflen, buffer );
2729
2730 if (dev->connected)
2731 {
2732 snprintf (buffer, buflen, "%s%s",
2733 inet_ntoa(dev->ipaddr),
2734 dev->prompt1052 ? "" : " noprompt");
2735 }
2736 else
2737 {
2738 char acc[48];
2739
2740 if (dev->acc_ipaddr || dev->acc_ipmask)
2741 {
2742 char ip [16];
2743 char mask [16];
2744 struct in_addr xxxx;
2745
2746 xxxx.s_addr = dev->acc_ipaddr;
2747
2748 snprintf( ip, sizeof( ip ),
2749 "%s", inet_ntoa( xxxx ));
2750
2751 xxxx.s_addr = dev->acc_ipmask;
2752
2753 snprintf( mask, sizeof( mask ),
2754 "%s", inet_ntoa( xxxx ));
2755
2756 snprintf( acc, sizeof( acc ),
2757 "%s mask %s", ip, mask );
2758 }
2759 else
2760 acc[0] = 0;
2761
2762 if (dev->filename[0])
2763 {
2764 snprintf(buffer, buflen,
2765 "GROUP=%s%s%s%s",
2766 dev->filename,
2767 !dev->prompt1052 ? " noprompt" : "",
2768 acc[0] ? " " : "", acc);
2769 }
2770 else
2771 {
2772 if (acc[0])
2773 {
2774 if (!dev->prompt1052)
2775 snprintf(buffer, buflen,
2776 "noprompt %s", acc);
2777 else
2778 snprintf(buffer, buflen,
2779 "* %s", acc);
2780 }
2781 else
2782 {
2783 if (!dev->prompt1052)
2784 strlcpy(buffer,"noprompt",buflen);
2785 else
2786 buffer[0] = 0;
2787 }
2788 }
2789 }
2790 } /* end function constty_query_device */
2791
2792
2793 /*-------------------------------------------------------------------*/
2794 /* CLOSE THE 1052/3215 DEVICE HANDLER */
2795 /*-------------------------------------------------------------------*/
2796 static int
constty_close_device(DEVBLK * dev)2797 constty_close_device ( DEVBLK *dev )
2798 {
2799 console_remove(dev);
2800
2801 return 0;
2802 } /* end function constty_close_device */
2803
2804
2805 /*-------------------------------------------------------------------*/
2806 /* SUBROUTINE TO ADVANCE TO NEXT CHAR OR ORDER IN A 3270 DATA STREAM */
2807 /* Input: */
2808 /* buf Buffer containing 3270 data stream */
2809 /* off Offset in buffer of current character or order */
2810 /* pos Position on screen of current character or order */
2811 /* Output: */
2812 /* off Offset in buffer of next character or order */
2813 /* pos Position on screen of next character or order */
2814 /*-------------------------------------------------------------------*/
2815 static void
next_3270_pos(BYTE * buf,int * off,int * pos)2816 next_3270_pos (BYTE *buf, int *off, int *pos)
2817 {
2818 int i;
2819
2820 /* Copy the offset and advance the offset by 1 byte */
2821 i = (*off)++;
2822
2823 /* Advance the offset past the argument bytes and set position */
2824 switch (buf[i]) {
2825
2826 /* The Repeat to Address order has 3 argument bytes (or in case
2827 of a Graphics Escape 4 bytes) and sets the screen position */
2828 case O3270_RA:
2829
2830 *off += (buf[i+3] == O3270_GE) ? 4 : 3;
2831 if ((buf[i+1] & 0xC0) == 0x00)
2832 *pos = (buf[i+1] << 8) | buf[i+2];
2833 else
2834 *pos = ((buf[i+1] & 0x3F) << 6)
2835 | (buf[i+2] & 0x3F);
2836 break;
2837
2838 /* The Start Field Extended and Modify Field orders have
2839 a count byte followed by a variable number of type-
2840 attribute pairs, and advance the screen position by 1 */
2841 case O3270_SFE:
2842 case O3270_MF:
2843
2844 *off += (1 + 2*buf[i+1]);
2845 (*pos)++;
2846 break;
2847
2848 /* The Set Buffer Address and Erase Unprotected to Address
2849 orders have 2 argument bytes and set the screen position */
2850 case O3270_SBA:
2851 case O3270_EUA:
2852
2853 *off += 2;
2854 if ((buf[i+1] & 0xC0) == 0x00)
2855 *pos = (buf[i+1] << 8) | buf[i+2];
2856 else
2857 *pos = ((buf[i+1] & 0x3F) << 6)
2858 | (buf[i+2] & 0x3F);
2859 break;
2860
2861 /* The Set Attribute order has 2 argument bytes and
2862 does not change the screen position */
2863 case O3270_SA:
2864
2865 *off += 2;
2866 break;
2867
2868 /* Insert Cursor and Program Tab have no argument
2869 bytes and do not change the screen position */
2870 case O3270_IC:
2871 case O3270_PT:
2872
2873 break;
2874
2875 /* The Start Field and Graphics Escape orders have one
2876 argument byte, and advance the screen position by 1 */
2877 case O3270_SF:
2878 case O3270_GE:
2879
2880 (*off)++;
2881 (*pos)++;
2882 break;
2883
2884 /* All other characters advance the screen position by 1 */
2885 default:
2886
2887 (*pos)++;
2888 break;
2889
2890 } /* end switch */
2891
2892 } /* end function next_3270_pos */
2893
2894
2895 /*-------------------------------------------------------------------*/
2896 /* SUBROUTINE TO FIND A GIVEN SCREEN POSITION IN A 3270 READ BUFFER */
2897 /* Input: */
2898 /* buf Buffer containing an inbound 3270 data stream */
2899 /* size Number of bytes in buffer */
2900 /* pos Screen position whose offset in buffer is desired */
2901 /* Return value: */
2902 /* Offset in buffer of the character or order corresponding to */
2903 /* the given screen position, or zero if position not found. */
2904 /*-------------------------------------------------------------------*/
2905 static int
find_buffer_pos(BYTE * buf,int size,int pos)2906 find_buffer_pos (BYTE *buf, int size, int pos)
2907 {
2908 int wpos; /* Current screen position */
2909 int woff; /* Current offset in buffer */
2910
2911 /* Screen position 0 is at offset 3 in the device buffer,
2912 following the AID and cursor address bytes */
2913 wpos = 0;
2914 woff = 3;
2915
2916 while (woff < size)
2917 {
2918 /* Exit if desired screen position has been reached */
2919 if (wpos >= pos)
2920 {
2921 // logmsg (_("console: Pos %4.4X reached at %4.4X\n"),
2922 // wpos, woff);
2923
2924 #ifdef FIX_QWS_BUG_FOR_MCS_CONSOLES
2925 /* There is a bug in QWS3270 when used to emulate an
2926 MCS console with EAB. At position 1680 the Read
2927 Buffer contains two 6-byte SFE orders (12 bytes)
2928 preceding the entry area, whereas MCS expects the
2929 entry area to start 4 bytes after screen position
2930 1680 in the buffer. The bypass is to add 8 to the
2931 calculated buffer offset if this appears to be an
2932 MCS console read buffer command */
2933 if (pos == 0x0690 && buf[woff] == O3270_SFE
2934 && buf[woff+6] == O3270_SFE)
2935 {
2936 woff += 8;
2937 // logmsg (_("console: Pos %4.4X adjusted to %4.4X\n"),
2938 // wpos, woff);
2939 }
2940 #endif /*FIX_QWS_BUG_FOR_MCS_CONSOLES*/
2941
2942 return woff;
2943 }
2944
2945 /* Process next character or order, update screen position */
2946 next_3270_pos (buf, &woff, &wpos);
2947
2948 } /* end while */
2949
2950 /* Return offset zero if the position cannot be determined */
2951 return 0;
2952
2953 } /* end function find_buffer_pos */
2954
2955
2956 /*-------------------------------------------------------------------*/
2957 /* SUBROUTINE TO UPDATE THE CURRENT SCREEN POSITION */
2958 /* Input: */
2959 /* pos Current screen position */
2960 /* buf Pointer to the byte in the 3270 data stream */
2961 /* corresponding to the current screen position */
2962 /* size Number of bytes remaining in buffer */
2963 /* Output: */
2964 /* pos Updated screen position after end of buffer */
2965 /*-------------------------------------------------------------------*/
2966 static void
get_screen_pos(int * pos,BYTE * buf,int size)2967 get_screen_pos (int *pos, BYTE *buf, int size)
2968 {
2969 int woff = 0; /* Current offset in buffer */
2970
2971 while (woff < size)
2972 {
2973 /* Process next character or order, update screen position */
2974 next_3270_pos (buf, &woff, pos);
2975
2976 } /* end while */
2977
2978 } /* end function get_screen_pos */
2979
2980
2981 /*-------------------------------------------------------------------*/
2982 /* EXECUTE A 3270 CHANNEL COMMAND WORD */
2983 /*-------------------------------------------------------------------*/
2984 static void
loc3270_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)2985 loc3270_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags,
2986 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
2987 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual )
2988 {
2989 int rc; /* Return code */
2990 int num; /* Number of bytes to copy */
2991 int len; /* Data length */
2992 int aid; /* First read: AID present */
2993 U32 off; /* Offset in device buffer */
2994 BYTE cmd; /* tn3270 command code */
2995 BYTE buf[BUFLEN_3270]; /* tn3270 write buffer */
2996
2997 UNREFERENCED(prevcode);
2998 UNREFERENCED(ccwseq);
2999
3000 /* Clear the current screen position at start of CCW chain */
3001 if (!chained)
3002 dev->pos3270 = 0;
3003
3004 /* Unit check with intervention required if no client connected */
3005 if (!dev->connected && !IS_CCW_SENSE(code))
3006 {
3007 dev->sense[0] = SENSE_IR;
3008 /* *unitstat = CSW_CE | CSW_DE | CSW_UC; */
3009 *unitstat = CSW_UC; /* *ISW3274DR* (as per GA23-0218-11 3.1.3.2.2 Table 5-5) */
3010 return;
3011 }
3012
3013 /* Process depending on CCW opcode */
3014 switch (code) {
3015
3016 case L3270_NOP:
3017 /*---------------------------------------------------------------*/
3018 /* CONTROL NO-OPERATION */
3019 /*---------------------------------------------------------------*/
3020 /* Reset the buffer address */
3021 dev->pos3270 = 0;
3022
3023 *unitstat = CSW_CE | CSW_DE;
3024 break;
3025
3026 case L3270_SELRM:
3027 case L3270_SELRB:
3028 case L3270_SELRMP:
3029 case L3270_SELRBP:
3030 case L3270_SELWRT:
3031 /*---------------------------------------------------------------*/
3032 /* SELECT */
3033 /*---------------------------------------------------------------*/
3034 /* Reset the buffer address */
3035 dev->pos3270 = 0;
3036
3037 /*
3038 *residual = 0;
3039 */
3040 *unitstat = CSW_CE | CSW_DE;
3041 break;
3042
3043 case L3270_EAU:
3044 /*---------------------------------------------------------------*/
3045 /* ERASE ALL UNPROTECTED */
3046 /*---------------------------------------------------------------*/
3047 dev->pos3270 = 0;
3048 cmd = R3270_EAU;
3049 goto write;
3050
3051 case L3270_WRT:
3052 /*---------------------------------------------------------------*/
3053 /* WRITE */
3054 /*---------------------------------------------------------------*/
3055 cmd = R3270_WRT;
3056 goto write;
3057
3058 case L3270_EW:
3059 /*---------------------------------------------------------------*/
3060 /* ERASE/WRITE */
3061 /*---------------------------------------------------------------*/
3062 dev->pos3270 = 0;
3063 cmd = R3270_EW;
3064 dev->ewa3270 = 0;
3065 goto write;
3066
3067 case L3270_EWA:
3068 /*---------------------------------------------------------------*/
3069 /* ERASE/WRITE ALTERNATE */
3070 /*---------------------------------------------------------------*/
3071 dev->pos3270 = 0;
3072 cmd = R3270_EWA;
3073 dev->ewa3270 = 1;
3074 goto write;
3075
3076 case L3270_WSF:
3077 /*---------------------------------------------------------------*/
3078 /* WRITE STRUCTURED FIELD */
3079 /*---------------------------------------------------------------*/
3080 /* Process WSF command if device has extended attributes */
3081 if (dev->eab3270)
3082 {
3083 dev->pos3270 = 0;
3084 cmd = R3270_WSF;
3085 goto write;
3086 }
3087
3088 /* Operation check, device does not have extended attributes */
3089 dev->sense[0] = SENSE_OC;
3090 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3091 break;
3092
3093 write:
3094 /*---------------------------------------------------------------*/
3095 /* All write commands, and the EAU control command, come here */
3096 /*---------------------------------------------------------------*/
3097 /* Initialize the data length */
3098 len = 0;
3099
3100 /* Calculate number of bytes to move and residual byte count */
3101 num = sizeof(buf) / 2;
3102 num = (count < num) ? count : num;
3103 if(cmd == R3270_EAU)
3104 num = 0;
3105 *residual = count - num;
3106
3107 /* Move the 3270 command code to the first byte of the buffer
3108 unless data-chained from previous CCW */
3109 if ((chained & CCW_FLAGS_CD) == 0)
3110 {
3111 buf[len++] = cmd;
3112 /* If this is a chained write then we start at the
3113 current buffer address rather then the cursor address.
3114 If the first action the datastream takes is not a
3115 positioning action then insert a SBA to position to
3116 the current buffer address */
3117 if(chained
3118 && cmd == R3270_WRT
3119 && dev->pos3270 != 0
3120 && iobuf[1] != O3270_SBA
3121 && iobuf[1] != O3270_RA
3122 && iobuf[1] != O3270_EUA)
3123 {
3124 /* Copy the write control character and adjust buffer */
3125 buf[len++] = *iobuf++; num--;
3126 /* Insert the SBA order */
3127 buf[len++] = O3270_SBA;
3128 if(dev->pos3270 < 4096)
3129 {
3130 buf[len++] = sba_code[dev->pos3270 >> 6];
3131 buf[len++] = sba_code[dev->pos3270 & 0x3F];
3132 }
3133 else
3134 {
3135 buf[len++] = dev->pos3270 >> 8;
3136 buf[len++] = dev->pos3270 & 0xFF;
3137 }
3138 } /* if(iobuf[0] != SBA, RA or EUA) */
3139
3140 /* Save the screen position at completion of the write.
3141 This is necessary in case a Read Buffer command is chained
3142 from another write or read, this does not apply for the
3143 write structured field command */
3144 if(cmd != R3270_WSF)
3145 get_screen_pos (&dev->pos3270, iobuf+1, num-1);
3146
3147 } /* if(!data_chained) */
3148 else /* if(data_chained) */
3149 if(cmd != R3270_WSF)
3150 get_screen_pos (&dev->pos3270, iobuf, num);
3151
3152 /* Copy data from channel buffer to device buffer */
3153 memcpy (buf + len, iobuf, num);
3154 len += num;
3155
3156 /* Double up any IAC bytes in the data */
3157 len = double_up_iac (buf, len);
3158
3159 /* Append telnet EOR marker at end of data */
3160 if ((flags & CCW_FLAGS_CD) == 0) {
3161 buf[len++] = IAC;
3162 buf[len++] = EOR_MARK;
3163 }
3164
3165 /* Send the data to the client */
3166 rc = send_packet(dev->fd, buf, len, "3270 data");
3167 if (rc < 0)
3168 {
3169 dev->sense[0] = SENSE_DC;
3170 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3171 break;
3172 }
3173
3174 /* Return normal status */
3175 *unitstat = CSW_CE | CSW_DE;
3176 break;
3177
3178 case L3270_RB:
3179 /*---------------------------------------------------------------*/
3180 /* READ BUFFER */
3181 /*---------------------------------------------------------------*/
3182 /* Obtain the device lock */
3183 obtain_lock (&dev->lock);
3184
3185 /* AID is only present during the first read */
3186 aid = dev->readpending != 2;
3187
3188 /* Receive buffer data from client if not data chained */
3189 if ((chained & CCW_FLAGS_CD) == 0)
3190 {
3191 /* Send read buffer command to client and await response */
3192 rc = solicit_3270_data (dev, R3270_RB);
3193 if (rc & CSW_UC)
3194 {
3195 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3196 release_lock (&dev->lock);
3197 break;
3198 }
3199
3200 /* Set AID in buffer flag */
3201 aid = 1;
3202
3203 /* Save the AID of the current inbound transmission */
3204 dev->aid3270 = dev->buf[0];
3205 if(dev->pos3270 != 0 && dev->aid3270 != SF3270_AID)
3206 {
3207 /* Find offset in buffer of current screen position */
3208 off = find_buffer_pos (dev->buf, dev->rlen3270,
3209 dev->pos3270);
3210
3211 /* Shift out unwanted characters from buffer */
3212 num = (dev->rlen3270 > off ? dev->rlen3270 - off : 0);
3213 memmove (dev->buf + 3, dev->buf + off, num);
3214 dev->rlen3270 = 3 + num;
3215 }
3216
3217 } /* end if(!CCW_FLAGS_CD) */
3218
3219 /* Calculate number of bytes to move and residual byte count */
3220 len = dev->rlen3270;
3221 num = (count < len) ? count : len;
3222 *residual = count - num;
3223 if (count < len) *more = 1;
3224
3225 /* Save the screen position at completion of the read.
3226 This is necessary in case a Read Buffer command is chained
3227 from another write or read. */
3228 if(dev->aid3270 != SF3270_AID)
3229 {
3230 if(aid)
3231 get_screen_pos(&dev->pos3270, dev->buf+3, num-3);
3232 else
3233 get_screen_pos(&dev->pos3270, dev->buf, num);
3234 }
3235
3236 /* Indicate that the AID bytes have been skipped */
3237 if(dev->readpending == 1)
3238 dev->readpending = 2;
3239
3240 /* Copy data from device buffer to channel buffer */
3241 memcpy (iobuf, dev->buf, num);
3242
3243 /* If data chaining is specified, save remaining data */
3244 if ((flags & CCW_FLAGS_CD) && len > count)
3245 {
3246 memmove (dev->buf, dev->buf + count, len - count);
3247 dev->rlen3270 = len - count;
3248 }
3249 else
3250 {
3251 dev->rlen3270 = 0;
3252 dev->readpending = 0;
3253 }
3254
3255 /* Return normal status */
3256 *unitstat = CSW_CE | CSW_DE;
3257
3258 /* Release the device lock */
3259 release_lock (&dev->lock);
3260
3261 /* Signal connection thread to redrive its select loop */
3262 SIGNAL_CONSOLE_THREAD();
3263
3264 break;
3265
3266 case L3270_RM:
3267 /*---------------------------------------------------------------*/
3268 /* READ MODIFIED */
3269 /*---------------------------------------------------------------*/
3270 /* Obtain the device lock */
3271 obtain_lock (&dev->lock);
3272
3273 /* AID is only present during the first read */
3274 aid = dev->readpending != 2;
3275
3276 /* If not data chained from previous Read Modified CCW,
3277 and if the connection thread has not already accumulated
3278 a complete Read Modified record in the inbound buffer,
3279 then solicit a Read Modified operation at the client */
3280 if ((chained & CCW_FLAGS_CD) == 0
3281 && !dev->readpending)
3282 {
3283 /* Send read modified command to client, await response */
3284 rc = solicit_3270_data (dev, R3270_RM);
3285 if (rc & CSW_UC)
3286 {
3287 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3288 release_lock (&dev->lock);
3289 break;
3290 }
3291
3292 /* Set AID in buffer flag */
3293 aid = 1;
3294
3295 dev->aid3270 = dev->buf[0];
3296 if(dev->pos3270 != 0 && dev->aid3270 != SF3270_AID)
3297 {
3298 /* Find offset in buffer of current screen position */
3299 off = find_buffer_pos (dev->buf, dev->rlen3270,
3300 dev->pos3270);
3301
3302 /* Shift out unwanted characters from buffer */
3303 num = (dev->rlen3270 > off ? dev->rlen3270 - off : 0);
3304 memmove (dev->buf + 3, dev->buf + off, num);
3305 dev->rlen3270 = 3 + num;
3306 }
3307
3308 } /* end if(!CCW_FLAGS_CD) */
3309
3310 /* Calculate number of bytes to move and residual byte count */
3311 len = dev->rlen3270;
3312 num = (count < len) ? count : len;
3313 *residual = count - num;
3314 if (count < len) *more = 1;
3315
3316 /* Save the screen position at completion of the read.
3317 This is necessary in case a Read Buffer command is chained
3318 from another write or read. */
3319 if(dev->aid3270 != SF3270_AID)
3320 {
3321 if(aid)
3322 get_screen_pos(&dev->pos3270, dev->buf+3, num-3);
3323 else
3324 get_screen_pos(&dev->pos3270, dev->buf, num);
3325 }
3326
3327 /* Indicate that the AID bytes have been skipped */
3328 if(dev->readpending == 1)
3329 dev->readpending = 2;
3330
3331 /* Copy data from device buffer to channel buffer */
3332 memcpy (iobuf, dev->buf, num);
3333
3334 /* If data chaining is specified, save remaining data */
3335 if ((flags & CCW_FLAGS_CD) && len > count)
3336 {
3337 memmove (dev->buf, dev->buf + count, len - count);
3338 dev->rlen3270 = len - count;
3339 }
3340 else
3341 {
3342 dev->rlen3270 = 0;
3343 dev->readpending = 0;
3344 }
3345
3346 /* Set normal status */
3347 *unitstat = CSW_CE | CSW_DE;
3348
3349 /* Release the device lock */
3350 release_lock (&dev->lock);
3351
3352 /* Signal connection thread to redrive its select loop */
3353 SIGNAL_CONSOLE_THREAD();
3354
3355 break;
3356
3357 case L3270_SENSE:
3358 /*---------------------------------------------------------------*/
3359 /* SENSE */
3360 /*---------------------------------------------------------------*/
3361 /* Calculate residual byte count */
3362 num = (count < dev->numsense) ? count : dev->numsense;
3363 *residual = count - num;
3364 if (count < dev->numsense) *more = 1;
3365
3366 /* Copy device sense bytes to channel I/O buffer */
3367 memcpy (iobuf, dev->sense, num);
3368
3369 /* Clear the device sense bytes */
3370 memset (dev->sense, 0, sizeof(dev->sense));
3371
3372 /* Reset the buffer address */
3373 dev->pos3270 = 0;
3374
3375 /* Return unit status */
3376 *unitstat = CSW_CE | CSW_DE;
3377 break;
3378
3379 case L3270_SENSEID:
3380 /*---------------------------------------------------------------*/
3381 /* SENSE ID */
3382 /*---------------------------------------------------------------*/
3383 /* Calculate residual byte count */
3384 num = (count < dev->numdevid) ? count : dev->numdevid;
3385 *residual = count - num;
3386 if (count < dev->numdevid) *more = 1;
3387
3388 /* Copy device identifier bytes to channel I/O buffer */
3389 memcpy (iobuf, dev->devid, num);
3390
3391 /* Reset the buffer address */
3392 dev->pos3270 = 0;
3393
3394 /* Return unit status */
3395 *unitstat = CSW_CE | CSW_DE;
3396 break;
3397
3398 default:
3399 /*---------------------------------------------------------------*/
3400 /* INVALID OPERATION */
3401 /*---------------------------------------------------------------*/
3402 /* Set command reject sense byte, and unit check status */
3403 dev->sense[0] = SENSE_CR;
3404 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3405
3406 } /* end switch(code) */
3407
3408 } /* end function loc3270_execute_ccw */
3409
3410
3411 /*-------------------------------------------------------------------*/
3412 /* EXECUTE A 1052/3215 CHANNEL COMMAND WORD */
3413 /*-------------------------------------------------------------------*/
3414 static void
constty_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)3415 constty_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags,
3416 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
3417 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual )
3418 {
3419 int rc; /* Return code */
3420 int len; /* Length of data */
3421 int num; /* Number of bytes to move */
3422 BYTE c; /* Print character */
3423 BYTE stat; /* Unit status */
3424
3425 UNREFERENCED(chained);
3426 UNREFERENCED(prevcode);
3427 UNREFERENCED(ccwseq);
3428
3429 /* Unit check with intervention required if no client connected */
3430 if (dev->connected == 0 && !IS_CCW_SENSE(code))
3431 {
3432 dev->sense[0] = SENSE_IR;
3433 *unitstat = CSW_UC;
3434 return;
3435 }
3436
3437 /* Process depending on CCW opcode */
3438 switch (code) {
3439
3440 case 0x01:
3441 /*---------------------------------------------------------------*/
3442 /* WRITE NO CARRIER RETURN */
3443 /*---------------------------------------------------------------*/
3444
3445 case 0x09:
3446 /*---------------------------------------------------------------*/
3447 /* WRITE AUTO CARRIER RETURN */
3448 /*---------------------------------------------------------------*/
3449
3450 /* Calculate number of bytes to write and set residual count */
3451 num = (count < BUFLEN_1052) ? count : BUFLEN_1052;
3452 *residual = count - num;
3453
3454 /* Translate data in channel buffer to ASCII */
3455 for (len = 0; len < num; len++)
3456 {
3457 c = guest_to_host(iobuf[len]);
3458 if (!isprint(c) && c != 0x0a && c != 0x0d) c = SPACE;
3459 iobuf[len] = c;
3460 } /* end for(len) */
3461
3462 ASSERT(len == num);
3463
3464 /* Perform end of record processing if not data-chaining */
3465 if ((flags & CCW_FLAGS_CD) == 0)
3466 {
3467 /* Append carriage return and newline if required */
3468 if (code == 0x09)
3469 {
3470 if (len < BUFLEN_1052)
3471 iobuf[len++] = '\r';
3472
3473 if (len < BUFLEN_1052)
3474 iobuf[len++] = '\n';
3475 }
3476 } /* end if(!data-chaining) */
3477
3478 /* Send the data to the client */
3479 rc = send_packet (dev->fd, iobuf, len, NULL);
3480 if (rc < 0)
3481 {
3482 dev->sense[0] = SENSE_EC;
3483 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3484 break;
3485 }
3486
3487 /* Return normal status */
3488 *unitstat = CSW_CE | CSW_DE;
3489 break;
3490
3491 case 0x03:
3492 /*---------------------------------------------------------------*/
3493 /* CONTROL NO-OPERATION */
3494 /*---------------------------------------------------------------*/
3495 *unitstat = CSW_CE | CSW_DE;
3496 break;
3497
3498 case 0x0A:
3499 /*---------------------------------------------------------------*/
3500 /* READ INQUIRY */
3501 /*---------------------------------------------------------------*/
3502
3503 /* Solicit console input if no data in the device buffer */
3504 if (!dev->keybdrem)
3505 {
3506 /* Display prompting message on console if allowed */
3507 if (dev->prompt1052)
3508 {
3509 snprintf ((char *)dev->buf, dev->bufsize,
3510 _("HHCTE006A Enter input for console device %4.4X\n"),
3511 dev->devnum);
3512 len = strlen((char *)dev->buf);
3513 rc = send_packet (dev->fd, dev->buf, len, NULL);
3514 if (rc < 0)
3515 {
3516 dev->sense[0] = SENSE_EC;
3517 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3518 break;
3519 }
3520 }
3521
3522 /* Accumulate client input data into device buffer */
3523 while (1) {
3524
3525 /* Receive client data and increment dev->keybdrem */
3526 stat = recv_1052_data (dev);
3527
3528 /* Exit if error or end of line */
3529 if (stat != 0)
3530 break;
3531
3532 } /* end while */
3533
3534 /* Exit if error status */
3535 if (stat != CSW_ATTN)
3536 {
3537 *unitstat = (CSW_CE | CSW_DE) | (stat & ~CSW_ATTN);
3538 break;
3539 }
3540
3541 }
3542
3543 /* Calculate number of bytes to move and residual byte count */
3544 len = dev->keybdrem;
3545 num = (count < len) ? count : len;
3546 *residual = count - num;
3547 if (count < len) *more = 1;
3548
3549 /* Copy data from device buffer to channel buffer */
3550 memcpy (iobuf, dev->buf, num);
3551
3552 /* If data chaining is specified, save remaining data */
3553 if ((flags & CCW_FLAGS_CD) && len > count)
3554 {
3555 memmove (dev->buf, dev->buf + count, len - count);
3556 dev->keybdrem = len - count;
3557 }
3558 else
3559 {
3560 dev->keybdrem = 0;
3561 }
3562
3563 /* Return normal status */
3564 *unitstat = CSW_CE | CSW_DE;
3565 break;
3566
3567 case 0x0B:
3568 /*---------------------------------------------------------------*/
3569 /* AUDIBLE ALARM */
3570 /*---------------------------------------------------------------*/
3571 rc = send_packet (dev->fd, (BYTE *)"\a", 1, NULL);
3572 /*
3573 *residual = 0;
3574 */
3575 *unitstat = CSW_CE | CSW_DE;
3576 break;
3577
3578 case 0x04:
3579 /*---------------------------------------------------------------*/
3580 /* SENSE */
3581 /*---------------------------------------------------------------*/
3582 /* Calculate residual byte count */
3583 num = (count < dev->numsense) ? count : dev->numsense;
3584 *residual = count - num;
3585 if (count < dev->numsense) *more = 1;
3586
3587 /* Copy device sense bytes to channel I/O buffer */
3588 memcpy (iobuf, dev->sense, num);
3589
3590 /* Clear the device sense bytes */
3591 memset (dev->sense, 0, sizeof(dev->sense));
3592
3593 /* Return unit status */
3594 *unitstat = CSW_CE | CSW_DE;
3595 break;
3596
3597 case 0xE4:
3598 /*---------------------------------------------------------------*/
3599 /* SENSE ID */
3600 /*---------------------------------------------------------------*/
3601 /* Calculate residual byte count */
3602 num = (count < dev->numdevid) ? count : dev->numdevid;
3603 *residual = count - num;
3604 if (count < dev->numdevid) *more = 1;
3605
3606 /* Copy device identifier bytes to channel I/O buffer */
3607 memcpy (iobuf, dev->devid, num);
3608
3609 /* Return unit status */
3610 *unitstat = CSW_CE | CSW_DE;
3611 break;
3612
3613 default:
3614 /*---------------------------------------------------------------*/
3615 /* INVALID OPERATION */
3616 /*---------------------------------------------------------------*/
3617 /* Set command reject sense byte, and unit check status */
3618 dev->sense[0] = SENSE_CR;
3619 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3620
3621 } /* end switch(code) */
3622
3623 } /* end function constty_execute_ccw */
3624
3625 #if defined(OPTION_DYNAMIC_LOAD)
3626 static
3627 #endif
3628 DEVHND constty_device_hndinfo = {
3629 &constty_init_handler, /* Device Initialisation */
3630 &constty_execute_ccw, /* Device CCW execute */
3631 &constty_close_device, /* Device Close */
3632 &constty_query_device, /* Device Query */
3633 NULL, /* Device Start channel pgm */
3634 NULL, /* Device End channel pgm */
3635 NULL, /* Device Resume channel pgm */
3636 NULL, /* Device Suspend channel pgm */
3637 NULL, /* Device Read */
3638 NULL, /* Device Write */
3639 NULL, /* Device Query used */
3640 NULL, /* Device Reserve */
3641 NULL, /* Device Release */
3642 NULL, /* Device Attention */
3643 constty_immed, /* Immediate CCW Codes */
3644 NULL, /* Signal Adapter Input */
3645 NULL, /* Signal Adapter Output */
3646 NULL, /* Hercules suspend */
3647 NULL /* Hercules resume */
3648 };
3649
3650 /* Libtool static name colision resolution */
3651 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
3652 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
3653 #define hdl_ddev hdt3270_LTX_hdl_ddev
3654 #define hdl_depc hdt3270_LTX_hdl_depc
3655 #define hdl_reso hdt3270_LTX_hdl_reso
3656 #define hdl_init hdt3270_LTX_hdl_init
3657 #define hdl_fini hdt3270_LTX_hdl_fini
3658 #endif
3659
3660
3661 #if defined(OPTION_DYNAMIC_LOAD)
3662 static
3663 #endif
3664 DEVHND loc3270_device_hndinfo = {
3665 &loc3270_init_handler, /* Device Initialisation */
3666 &loc3270_execute_ccw, /* Device CCW execute */
3667 &loc3270_close_device, /* Device Close */
3668 &loc3270_query_device, /* Device Query */
3669 NULL, /* Device Start channel pgm */
3670 NULL, /* Device End channel pgm */
3671 NULL, /* Device Resume channel pgm */
3672 NULL, /* Device Suspend channel pgm */
3673 NULL, /* Device Read */
3674 NULL, /* Device Write */
3675 NULL, /* Device Query used */
3676 NULL, /* Device Reserve */
3677 NULL, /* Device Release */
3678 NULL, /* Device Attention */
3679 loc3270_immed, /* Immediate CCW Codes */
3680 NULL, /* Signal Adapter Input */
3681 NULL, /* Signal Adapter Output */
3682 &loc3270_hsuspend, /* Hercules suspend */
3683 &loc3270_hresume /* Hercules resume */
3684 };
3685
3686
3687 #if defined(OPTION_DYNAMIC_LOAD)
3688 HDL_DEPENDENCY_SECTION;
3689 {
3690 HDL_DEPENDENCY(HERCULES);
3691 HDL_DEPENDENCY(DEVBLK);
3692 HDL_DEPENDENCY(SYSBLK);
3693 }
3694 END_DEPENDENCY_SECTION
3695
3696
3697 #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
3698 #undef sysblk
3699 #undef config_cnslport
3700 HDL_RESOLVER_SECTION;
3701 {
3702 HDL_RESOLVE_PTRVAR( psysblk, sysblk );
3703 HDL_RESOLVE( config_cnslport );
3704 }
3705 END_RESOLVER_SECTION
3706 #endif
3707
3708
3709 HDL_DEVICE_SECTION
3710 {
3711 HDL_DEVICE(1052, constty_device_hndinfo );
3712 HDL_DEVICE(3215, constty_device_hndinfo );
3713 HDL_DEVICE(3270, loc3270_device_hndinfo );
3714 HDL_DEVICE(3287, loc3270_device_hndinfo );
3715
3716 #if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
3717 HDL_DEVICE(SYSG, loc3270_device_hndinfo );
3718 #endif /*defined(_FEATURE_INTEGRATED_3270_CONSOLE)*/
3719 }
3720 END_DEVICE_SECTION
3721 #endif
3722